root/source4/heimdal/lib/krb5/v4_glue.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. _krb5_krb_time_to_life
  2. _krb5_krb_life_to_time
  3. get_krb4_cc_name
  4. write_v4_cc
  5. _krb5_krb_tf_setup
  6. _krb5_krb_dest_tkt
  7. decrypt_etext
  8. storage_to_etext
  9. put_nir
  10. _krb5_krb_create_ticket
  11. _krb5_krb_create_ciph
  12. _krb5_krb_create_auth_reply
  13. _krb5_krb_cr_err_reply
  14. get_v4_stringz
  15. _krb5_krb_decomp_ticket
  16. _krb5_krb_rd_req
  17. _krb5_krb_free_auth_data

   1 /*
   2  * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
   3  * (Royal Institute of Technology, Stockholm, Sweden).
   4  * All rights reserved.
   5  *
   6  * Redistribution and use in source and binary forms, with or without
   7  * modification, are permitted provided that the following conditions
   8  * are met:
   9  *
  10  * 1. Redistributions of source code must retain the above copyright
  11  *    notice, this list of conditions and the following disclaimer.
  12  *
  13  * 2. Redistributions in binary form must reproduce the above copyright
  14  *    notice, this list of conditions and the following disclaimer in the
  15  *    documentation and/or other materials provided with the distribution.
  16  *
  17  * 3. Neither the name of the Institute nor the names of its contributors
  18  *    may be used to endorse or promote products derived from this software
  19  *    without specific prior written permission.
  20  *
  21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
  22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
  25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31  * SUCH DAMAGE.
  32  */
  33 
  34 #include "krb5_locl.h"
  35 RCSID("$Id$");
  36 
  37 #include "krb5-v4compat.h"
  38 
  39 #ifndef HEIMDAL_SMALLER
  40 
  41 /*
  42  *
  43  */
  44 
  45 #define RCHECK(r,func,label) \
  46         do { (r) = func ; if (r) goto label; } while(0);
  47 
  48 
  49 /* include this here, to avoid dependencies on libkrb */
  50 
  51 static const int _tkt_lifetimes[TKTLIFENUMFIXED] = {
  52    38400,   41055,   43894,   46929,   50174,   53643,   57352,   61318,
  53    65558,   70091,   74937,   80119,   85658,   91581,   97914,  104684,
  54   111922,  119661,  127935,  136781,  146239,  156350,  167161,  178720,
  55   191077,  204289,  218415,  233517,  249664,  266926,  285383,  305116,
  56   326213,  348769,  372885,  398668,  426234,  455705,  487215,  520904,
  57   556921,  595430,  636601,  680618,  727680,  777995,  831789,  889303,
  58   950794, 1016537, 1086825, 1161973, 1242318, 1328218, 1420057, 1518247,
  59  1623226, 1735464, 1855462, 1983758, 2120925, 2267576, 2424367, 2592000
  60 };
  61 
  62 int KRB5_LIB_FUNCTION
  63 _krb5_krb_time_to_life(time_t start, time_t end)
     /* [<][>][^][v][top][bottom][index][help] */
  64 {
  65     int i;
  66     time_t life = end - start;
  67 
  68     if (life > MAXTKTLIFETIME || life <= 0)
  69         return 0;
  70 #if 0
  71     if (krb_no_long_lifetimes)
  72         return (life + 5*60 - 1)/(5*60);
  73 #endif
  74 
  75     if (end >= NEVERDATE)
  76         return TKTLIFENOEXPIRE;
  77     if (life < _tkt_lifetimes[0])
  78         return (life + 5*60 - 1)/(5*60);
  79     for (i=0; i<TKTLIFENUMFIXED; i++)
  80         if (life <= _tkt_lifetimes[i])
  81             return i + TKTLIFEMINFIXED;
  82     return 0;
  83 
  84 }
  85 
  86 time_t KRB5_LIB_FUNCTION
  87 _krb5_krb_life_to_time(int start, int life_)
     /* [<][>][^][v][top][bottom][index][help] */
  88 {
  89     unsigned char life = (unsigned char) life_;
  90 
  91 #if 0
  92     if (krb_no_long_lifetimes)
  93         return start + life*5*60;
  94 #endif
  95 
  96     if (life == TKTLIFENOEXPIRE)
  97         return NEVERDATE;
  98     if (life < TKTLIFEMINFIXED)
  99         return start + life*5*60;
 100     if (life > TKTLIFEMAXFIXED)
 101         return start + MAXTKTLIFETIME;
 102     return start + _tkt_lifetimes[life - TKTLIFEMINFIXED];
 103 }
 104 
 105 /*
 106  * Get the name of the krb4 credentials cache, will use `tkfile' as
 107  * the name if that is passed in. `cc' must be free()ed by caller,
 108  */
 109 
 110 static krb5_error_code
 111 get_krb4_cc_name(const char *tkfile, char **cc)
     /* [<][>][^][v][top][bottom][index][help] */
 112 {
 113 
 114     *cc = NULL;
 115     if(tkfile == NULL) {
 116         char *path;
 117         if(!issuid()) {
 118             path = getenv("KRBTKFILE");
 119             if (path)
 120                 *cc = strdup(path);
 121         }
 122         if(*cc == NULL)
 123             if (asprintf(cc, "%s%u", TKT_ROOT, (unsigned)getuid()) < 0)
 124                 return errno;
 125     } else {
 126         *cc = strdup(tkfile);
 127         if (*cc == NULL)
 128             return ENOMEM;
 129     }
 130     return 0;
 131 }
 132 
 133 /*
 134  * Write a Kerberos 4 ticket file
 135  */
 136 
 137 #define KRB5_TF_LCK_RETRY_COUNT 50
 138 #define KRB5_TF_LCK_RETRY 1
 139 
 140 static krb5_error_code
 141 write_v4_cc(krb5_context context, const char *tkfile,
     /* [<][>][^][v][top][bottom][index][help] */
 142             krb5_storage *sp, int append)
 143 {
 144     krb5_error_code ret;
 145     struct stat sb;
 146     krb5_data data;
 147     char *path;
 148     int fd, i;
 149 
 150     ret = get_krb4_cc_name(tkfile, &path);
 151     if (ret) {
 152         krb5_set_error_message(context, ret,
 153                                N_("Failed getting the krb4 credentials "
 154                                  "cache name", ""));
 155         return ret;
 156     }
 157 
 158     fd = open(path, O_WRONLY|O_CREAT, 0600);
 159     if (fd < 0) {
 160         ret = errno;
 161         krb5_set_error_message(context, ret,
 162                                N_("Failed opening krb4 credential cache "
 163                                  "%s: %s", "path, error"),
 164                                path, strerror(ret));
 165         free(path);
 166         return ret;
 167     }
 168     rk_cloexec(fd);
 169 
 170     if (fstat(fd, &sb) != 0 || !S_ISREG(sb.st_mode)) {
 171         krb5_set_error_message(context, ret,
 172                                N_("krb4 credential cache %s is not a file", ""),
 173                                path);
 174         free(path);
 175         close(fd);
 176         return KRB5_FCC_PERM;
 177     }
 178 
 179     for (i = 0; i < KRB5_TF_LCK_RETRY_COUNT; i++) {
 180         if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
 181             sleep(KRB5_TF_LCK_RETRY);
 182         } else
 183             break;
 184     }
 185     if (i == KRB5_TF_LCK_RETRY_COUNT) {
 186         krb5_set_error_message(context, KRB5_FCC_PERM,
 187                                N_("Failed to lock credentail cache %s", ""),
 188                                path);
 189         free(path);
 190         close(fd);
 191         return KRB5_FCC_PERM;
 192     }
 193 
 194     if (!append) {
 195         ret = ftruncate(fd, 0);
 196         if (ret < 0) {
 197             flock(fd, LOCK_UN);
 198             krb5_set_error_message(context, KRB5_FCC_PERM,
 199                                    N_("Failed to truncate krb4 cc %s", ""),
 200                                    path);
 201             free(path);
 202             close(fd);
 203             return KRB5_FCC_PERM;
 204         }
 205     }
 206     ret = lseek(fd, 0L, SEEK_END);
 207     if (ret < 0) {
 208         ret = errno;
 209         flock(fd, LOCK_UN);
 210         free(path);
 211         close(fd);
 212         return ret;
 213     }
 214 
 215     krb5_storage_to_data(sp, &data);
 216 
 217     ret = write(fd, data.data, data.length);
 218     if (ret != data.length)
 219         ret = KRB5_CC_IO;
 220 
 221     krb5_free_data_contents(context, &data);
 222 
 223     flock(fd, LOCK_UN);
 224     free(path);
 225     close(fd);
 226 
 227     return 0;
 228 }
 229 
 230 /*
 231  *
 232  */
 233 
 234 krb5_error_code KRB5_LIB_FUNCTION
 235 _krb5_krb_tf_setup(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 236                    struct credentials *v4creds,
 237                    const char *tkfile,
 238                    int append)
 239 {
 240     krb5_error_code ret;
 241     krb5_storage *sp;
 242 
 243     sp = krb5_storage_emem();
 244     if (sp == NULL)
 245         return ENOMEM;
 246 
 247     krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_HOST);
 248     krb5_storage_set_eof_code(sp, KRB5_CC_IO);
 249 
 250     krb5_clear_error_message(context);
 251 
 252     if (!append) {
 253         RCHECK(ret, krb5_store_stringz(sp, v4creds->pname), error);
 254         RCHECK(ret, krb5_store_stringz(sp, v4creds->pinst), error);
 255     }
 256 
 257     /* cred */
 258     RCHECK(ret, krb5_store_stringz(sp, v4creds->service), error);
 259     RCHECK(ret, krb5_store_stringz(sp, v4creds->instance), error);
 260     RCHECK(ret, krb5_store_stringz(sp, v4creds->realm), error);
 261     ret = krb5_storage_write(sp, v4creds->session, 8);
 262     if (ret != 8) {
 263         ret = KRB5_CC_IO;
 264         goto error;
 265     }
 266     RCHECK(ret, krb5_store_int32(sp, v4creds->lifetime), error);
 267     RCHECK(ret, krb5_store_int32(sp, v4creds->kvno), error);
 268     RCHECK(ret, krb5_store_int32(sp, v4creds->ticket_st.length), error);
 269 
 270     ret = krb5_storage_write(sp, v4creds->ticket_st.dat,
 271                              v4creds->ticket_st.length);
 272     if (ret != v4creds->ticket_st.length) {
 273         ret = KRB5_CC_IO;
 274         goto error;
 275     }
 276     RCHECK(ret, krb5_store_int32(sp, v4creds->issue_date), error);
 277 
 278     ret = write_v4_cc(context, tkfile, sp, append);
 279 
 280  error:
 281     krb5_storage_free(sp);
 282 
 283     return ret;
 284 }
 285 
 286 /*
 287  *
 288  */
 289 
 290 krb5_error_code KRB5_LIB_FUNCTION
 291 _krb5_krb_dest_tkt(krb5_context context, const char *tkfile)
     /* [<][>][^][v][top][bottom][index][help] */
 292 {
 293     krb5_error_code ret;
 294     char *path;
 295 
 296     ret = get_krb4_cc_name(tkfile, &path);
 297     if (ret) {
 298         krb5_set_error_message(context, ret,
 299                                N_("Failed getting the krb4 credentials "
 300                                  "cache name", ""));
 301         return ret;
 302     }
 303 
 304     if (unlink(path) < 0) {
 305         ret = errno;
 306         krb5_set_error_message(context, ret,
 307                                N_("Failed removing the cache %s "
 308                                  "with error %s", "path, error"),
 309                                path, strerror(ret));
 310     }
 311     free(path);
 312 
 313     return ret;
 314 }
 315 
 316 /*
 317  *
 318  */
 319 
 320 static krb5_error_code
 321 decrypt_etext(krb5_context context, const krb5_keyblock *key,
     /* [<][>][^][v][top][bottom][index][help] */
 322               const krb5_data *cdata, krb5_data *data)
 323 {
 324     krb5_error_code ret;
 325     krb5_crypto crypto;
 326 
 327     ret = krb5_crypto_init(context, key, ETYPE_DES_PCBC_NONE, &crypto);
 328     if (ret)
 329         return ret;
 330 
 331     ret = krb5_decrypt(context, crypto, 0, cdata->data, cdata->length, data);
 332     krb5_crypto_destroy(context, crypto);
 333 
 334     return ret;
 335 }
 336 
 337 
 338 /*
 339  *
 340  */
 341 
 342 static const char eightzeros[8] = "\x00\x00\x00\x00\x00\x00\x00\x00";
 343 
 344 static krb5_error_code
 345 storage_to_etext(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 346                  krb5_storage *sp,
 347                  const krb5_keyblock *key,
 348                  krb5_data *enc_data)
 349 {
 350     krb5_error_code ret;
 351     krb5_crypto crypto;
 352     krb5_ssize_t size;
 353     krb5_data data;
 354 
 355     /* multiple of eight bytes, don't round up */
 356 
 357     size = krb5_storage_seek(sp, 0, SEEK_END);
 358     if (size < 0)
 359         return KRB4ET_RD_AP_UNDEC;
 360     size = ((size+7) & ~7) - size;
 361 
 362     ret = krb5_storage_write(sp, eightzeros, size);
 363     if (ret != size)
 364         return KRB4ET_RD_AP_UNDEC;
 365 
 366     ret = krb5_storage_to_data(sp, &data);
 367     if (ret)
 368         return ret;
 369 
 370     ret = krb5_crypto_init(context, key, ETYPE_DES_PCBC_NONE, &crypto);
 371     if (ret) {
 372         krb5_data_free(&data);
 373         return ret;
 374     }
 375 
 376     ret = krb5_encrypt(context, crypto, 0, data.data, data.length, enc_data);
 377 
 378     krb5_data_free(&data);
 379     krb5_crypto_destroy(context, crypto);
 380 
 381     return ret;
 382 }
 383 
 384 /*
 385  *
 386  */
 387 
 388 static krb5_error_code
 389 put_nir(krb5_storage *sp, const char *name,
     /* [<][>][^][v][top][bottom][index][help] */
 390         const char *instance, const char *realm)
 391 {
 392     krb5_error_code ret;
 393 
 394     RCHECK(ret, krb5_store_stringz(sp, name), error);
 395     RCHECK(ret, krb5_store_stringz(sp, instance), error);
 396     if (realm) {
 397         RCHECK(ret, krb5_store_stringz(sp, realm), error);
 398     }
 399  error:
 400     return ret;
 401 }
 402 
 403 /*
 404  *
 405  */
 406 
 407 krb5_error_code KRB5_LIB_FUNCTION
 408 _krb5_krb_create_ticket(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 409                         unsigned char flags,
 410                         const char *pname,
 411                         const char *pinstance,
 412                         const char *prealm,
 413                         int32_t paddress,
 414                         const krb5_keyblock *session,
 415                         int16_t life,
 416                         int32_t life_sec,
 417                         const char *sname,
 418                         const char *sinstance,
 419                         const krb5_keyblock *key,
 420                         krb5_data *enc_data)
 421 {
 422     krb5_error_code ret;
 423     krb5_storage *sp;
 424 
 425     krb5_data_zero(enc_data);
 426 
 427     sp = krb5_storage_emem();
 428     if (sp == NULL) {
 429         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
 430         return ENOMEM;
 431     }
 432     krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE);
 433 
 434     RCHECK(ret, krb5_store_int8(sp, flags), error);
 435     RCHECK(ret, put_nir(sp, pname, pinstance, prealm), error);
 436     RCHECK(ret, krb5_store_int32(sp, ntohl(paddress)), error);
 437 
 438     /* session key */
 439     ret = krb5_storage_write(sp,
 440                              session->keyvalue.data,
 441                              session->keyvalue.length);
 442     if (ret != session->keyvalue.length) {
 443         ret = KRB4ET_INTK_PROT;
 444         goto error;
 445     }
 446 
 447     RCHECK(ret, krb5_store_int8(sp, life), error);
 448     RCHECK(ret, krb5_store_int32(sp, life_sec), error);
 449     RCHECK(ret, put_nir(sp, sname, sinstance, NULL), error);
 450 
 451     ret = storage_to_etext(context, sp, key, enc_data);
 452 
 453  error:
 454     krb5_storage_free(sp);
 455     if (ret)
 456         krb5_set_error_message(context, ret,
 457                                N_("Failed to encode kerberos 4 ticket", ""));
 458 
 459     return ret;
 460 }
 461 
 462 /*
 463  *
 464  */
 465 
 466 krb5_error_code KRB5_LIB_FUNCTION
 467 _krb5_krb_create_ciph(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 468                       const krb5_keyblock *session,
 469                       const char *service,
 470                       const char *instance,
 471                       const char *realm,
 472                       uint32_t life,
 473                       unsigned char kvno,
 474                       const krb5_data *ticket,
 475                       uint32_t kdc_time,
 476                       const krb5_keyblock *key,
 477                       krb5_data *enc_data)
 478 {
 479     krb5_error_code ret;
 480     krb5_storage *sp;
 481 
 482     krb5_data_zero(enc_data);
 483 
 484     sp = krb5_storage_emem();
 485     if (sp == NULL) {
 486         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
 487         return ENOMEM;
 488     }
 489     krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE);
 490 
 491     /* session key */
 492     ret = krb5_storage_write(sp,
 493                              session->keyvalue.data,
 494                              session->keyvalue.length);
 495     if (ret != session->keyvalue.length) {
 496         ret = KRB4ET_INTK_PROT;
 497         goto error;
 498     }
 499 
 500     RCHECK(ret, put_nir(sp, service, instance, realm), error);
 501     RCHECK(ret, krb5_store_int8(sp, life), error);
 502     RCHECK(ret, krb5_store_int8(sp, kvno), error);
 503     RCHECK(ret, krb5_store_int8(sp, ticket->length), error);
 504     ret = krb5_storage_write(sp, ticket->data, ticket->length);
 505     if (ret != ticket->length) {
 506         ret = KRB4ET_INTK_PROT;
 507         goto error;
 508     }
 509     RCHECK(ret, krb5_store_int32(sp, kdc_time), error);
 510 
 511     ret = storage_to_etext(context, sp, key, enc_data);
 512 
 513  error:
 514     krb5_storage_free(sp);
 515     if (ret)
 516         krb5_set_error_message(context, ret,
 517                                N_("Failed to encode kerberos 4 ticket", ""));
 518 
 519     return ret;
 520 }
 521 
 522 /*
 523  *
 524  */
 525 
 526 krb5_error_code KRB5_LIB_FUNCTION
 527 _krb5_krb_create_auth_reply(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 528                             const char *pname,
 529                             const char *pinst,
 530                             const char *prealm,
 531                             int32_t time_ws,
 532                             int n,
 533                             uint32_t x_date,
 534                             unsigned char kvno,
 535                             const krb5_data *cipher,
 536                             krb5_data *data)
 537 {
 538     krb5_error_code ret;
 539     krb5_storage *sp;
 540 
 541     krb5_data_zero(data);
 542 
 543     sp = krb5_storage_emem();
 544     if (sp == NULL) {
 545         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
 546         return ENOMEM;
 547     }
 548     krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE);
 549 
 550     RCHECK(ret, krb5_store_int8(sp, KRB_PROT_VERSION), error);
 551     RCHECK(ret, krb5_store_int8(sp, AUTH_MSG_KDC_REPLY), error);
 552     RCHECK(ret, put_nir(sp, pname, pinst, prealm), error);
 553     RCHECK(ret, krb5_store_int32(sp, time_ws), error);
 554     RCHECK(ret, krb5_store_int8(sp, n), error);
 555     RCHECK(ret, krb5_store_int32(sp, x_date), error);
 556     RCHECK(ret, krb5_store_int8(sp, kvno), error);
 557     RCHECK(ret, krb5_store_int16(sp, cipher->length), error);
 558     ret = krb5_storage_write(sp, cipher->data, cipher->length);
 559     if (ret != cipher->length) {
 560         ret = KRB4ET_INTK_PROT;
 561         goto error;
 562     }
 563 
 564     ret = krb5_storage_to_data(sp, data);
 565 
 566  error:
 567     krb5_storage_free(sp);
 568     if (ret)
 569         krb5_set_error_message(context, ret,
 570                                N_("Failed to encode kerberos 4 ticket", ""));
 571         
 572     return ret;
 573 }
 574 
 575 /*
 576  *
 577  */
 578 
 579 krb5_error_code KRB5_LIB_FUNCTION
 580 _krb5_krb_cr_err_reply(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 581                        const char *name,
 582                        const char *inst,
 583                        const char *realm,
 584                        uint32_t time_ws,
 585                        uint32_t e,
 586                        const char *e_string,
 587                        krb5_data *data)
 588 {
 589     krb5_error_code ret;
 590     krb5_storage *sp;
 591 
 592     krb5_data_zero(data);
 593 
 594     if (name == NULL) name = "";
 595     if (inst == NULL) inst = "";
 596     if (realm == NULL) realm = "";
 597     if (e_string == NULL) e_string = "";
 598 
 599     sp = krb5_storage_emem();
 600     if (sp == NULL) {
 601         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
 602         return ENOMEM;
 603     }
 604     krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE);
 605 
 606     RCHECK(ret, krb5_store_int8(sp, KRB_PROT_VERSION), error);
 607     RCHECK(ret, krb5_store_int8(sp, AUTH_MSG_ERR_REPLY), error);
 608     RCHECK(ret, put_nir(sp, name, inst, realm), error);
 609     RCHECK(ret, krb5_store_int32(sp, time_ws), error);
 610     /* If it is a Kerberos 4 error-code, remove the et BASE */
 611     if (e >= ERROR_TABLE_BASE_krb && e <= ERROR_TABLE_BASE_krb + 255)
 612         e -= ERROR_TABLE_BASE_krb;
 613     RCHECK(ret, krb5_store_int32(sp, e), error);
 614     RCHECK(ret, krb5_store_stringz(sp, e_string), error);
 615 
 616     ret = krb5_storage_to_data(sp, data);
 617 
 618  error:
 619     krb5_storage_free(sp);
 620     if (ret)
 621         krb5_set_error_message(context, ret, "Failed to encode kerberos 4 error");
 622         
 623     return 0;
 624 }
 625 
 626 static krb5_error_code
 627 get_v4_stringz(krb5_storage *sp, char **str, size_t max_len)
     /* [<][>][^][v][top][bottom][index][help] */
 628 {
 629     krb5_error_code ret;
 630 
 631     ret = krb5_ret_stringz(sp, str);
 632     if (ret)
 633         return ret;
 634     if (strlen(*str) > max_len) {
 635         free(*str);
 636         *str = NULL;
 637         return KRB4ET_INTK_PROT;
 638     }
 639     return 0;
 640 }
 641 
 642 /*
 643  *
 644  */
 645 
 646 krb5_error_code KRB5_LIB_FUNCTION
 647 _krb5_krb_decomp_ticket(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 648                         const krb5_data *enc_ticket,
 649                         const krb5_keyblock *key,
 650                         const char *local_realm,
 651                         char **sname,
 652                         char **sinstance,
 653                         struct _krb5_krb_auth_data *ad)
 654 {
 655     krb5_error_code ret;
 656     krb5_ssize_t size;
 657     krb5_storage *sp = NULL;
 658     krb5_data ticket;
 659     unsigned char des_key[8];
 660 
 661     memset(ad, 0, sizeof(*ad));
 662     krb5_data_zero(&ticket);
 663 
 664     *sname = NULL;
 665     *sinstance = NULL;
 666 
 667     RCHECK(ret, decrypt_etext(context, key, enc_ticket, &ticket), error);
 668 
 669     sp = krb5_storage_from_data(&ticket);
 670     if (sp == NULL) {
 671         krb5_data_free(&ticket);
 672         krb5_set_error_message(context, ENOMEM, "alloc: out of memory");
 673         return ENOMEM;
 674     }
 675 
 676     krb5_storage_set_eof_code(sp, KRB4ET_INTK_PROT);
 677 
 678     RCHECK(ret, krb5_ret_int8(sp, &ad->k_flags), error);
 679     RCHECK(ret, get_v4_stringz(sp, &ad->pname, ANAME_SZ), error);
 680     RCHECK(ret, get_v4_stringz(sp, &ad->pinst, INST_SZ), error);
 681     RCHECK(ret, get_v4_stringz(sp, &ad->prealm, REALM_SZ), error);
 682     RCHECK(ret, krb5_ret_uint32(sp, &ad->address), error);
 683         
 684     size = krb5_storage_read(sp, des_key, sizeof(des_key));
 685     if (size != sizeof(des_key)) {
 686         ret = KRB4ET_INTK_PROT;
 687         goto error;
 688     }
 689 
 690     RCHECK(ret, krb5_ret_uint8(sp, &ad->life), error);
 691 
 692     if (ad->k_flags & 1)
 693         krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE);
 694     else
 695         krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE);
 696 
 697     RCHECK(ret, krb5_ret_uint32(sp, &ad->time_sec), error);
 698 
 699     RCHECK(ret, get_v4_stringz(sp, sname, ANAME_SZ), error);
 700     RCHECK(ret, get_v4_stringz(sp, sinstance, INST_SZ), error);
 701 
 702     ret = krb5_keyblock_init(context, ETYPE_DES_PCBC_NONE,
 703                              des_key, sizeof(des_key), &ad->session);
 704     if (ret)
 705         goto error;
 706 
 707     if (strlen(ad->prealm) == 0) {
 708         free(ad->prealm);
 709         ad->prealm = strdup(local_realm);
 710         if (ad->prealm == NULL) {
 711             ret = ENOMEM;
 712             goto error;
 713         }
 714     }
 715 
 716  error:
 717     memset(des_key, 0, sizeof(des_key));
 718     if (sp)
 719         krb5_storage_free(sp);
 720     krb5_data_free(&ticket);
 721     if (ret) {
 722         if (*sname) {
 723             free(*sname);
 724             *sname = NULL;
 725         }
 726         if (*sinstance) {
 727             free(*sinstance);
 728             *sinstance = NULL;
 729         }
 730         _krb5_krb_free_auth_data(context, ad);
 731         krb5_set_error_message(context, ret, "Failed to decode v4 ticket");
 732     }
 733     return ret;
 734 }
 735 
 736 /*
 737  *
 738  */
 739 
 740 krb5_error_code KRB5_LIB_FUNCTION
 741 _krb5_krb_rd_req(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 742                  krb5_data *authent,
 743                  const char *service,
 744                  const char *instance,
 745                  const char *local_realm,
 746                  int32_t from_addr,
 747                  const krb5_keyblock *key,
 748                  struct _krb5_krb_auth_data *ad)
 749 {
 750     krb5_error_code ret;
 751     krb5_storage *sp;
 752     krb5_data ticket, eaut, aut;
 753     krb5_ssize_t size;
 754     int little_endian;
 755     int8_t pvno;
 756     int8_t type;
 757     int8_t s_kvno;
 758     uint8_t ticket_length;
 759     uint8_t eaut_length;
 760     uint8_t time_5ms;
 761     char *realm = NULL;
 762     char *sname = NULL;
 763     char *sinstance = NULL;
 764     char *r_realm = NULL;
 765     char *r_name = NULL;
 766     char *r_instance = NULL;
 767 
 768     uint32_t r_time_sec;        /* Coarse time from authenticator */
 769     unsigned long delta_t;      /* Time in authenticator - local time */
 770     long tkt_age;               /* Age of ticket */
 771 
 772     struct timeval tv;
 773 
 774     krb5_data_zero(&ticket);
 775     krb5_data_zero(&eaut);
 776     krb5_data_zero(&aut);
 777 
 778     sp = krb5_storage_from_data(authent);
 779     if (sp == NULL) {
 780         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
 781         return ENOMEM;
 782     }
 783 
 784     krb5_storage_set_eof_code(sp, KRB4ET_INTK_PROT);
 785 
 786     ret = krb5_ret_int8(sp, &pvno);
 787     if (ret) {
 788         krb5_set_error_message(context, ret, N_("Failed reading v4 pvno", ""));
 789         goto error;
 790     }
 791 
 792     if (pvno != KRB_PROT_VERSION) {
 793         ret = KRB4ET_RD_AP_VERSION;
 794         krb5_set_error_message(context, ret, N_("Failed v4 pvno not 4", ""));
 795         goto error;
 796     }
 797 
 798     ret = krb5_ret_int8(sp, &type);
 799     if (ret) {
 800         krb5_set_error_message(context, ret, N_("Failed readin v4 type", ""));
 801         goto error;
 802     }
 803 
 804     little_endian = type & 1;
 805     type &= ~1;
 806 
 807     if(type != AUTH_MSG_APPL_REQUEST && type != AUTH_MSG_APPL_REQUEST_MUTUAL) {
 808         ret = KRB4ET_RD_AP_MSG_TYPE;
 809         krb5_set_error_message(context, ret,
 810                                N_("Not a valid v4 request type", ""));
 811         goto error;
 812     }
 813 
 814     RCHECK(ret, krb5_ret_int8(sp, &s_kvno), error);
 815     RCHECK(ret, get_v4_stringz(sp, &realm, REALM_SZ), error);
 816     RCHECK(ret, krb5_ret_uint8(sp, &ticket_length), error);
 817     RCHECK(ret, krb5_ret_uint8(sp, &eaut_length), error);
 818     RCHECK(ret, krb5_data_alloc(&ticket, ticket_length), error);
 819 
 820     size = krb5_storage_read(sp, ticket.data, ticket.length);
 821     if (size != ticket.length) {
 822         ret = KRB4ET_INTK_PROT;
 823         krb5_set_error_message(context, ret, N_("Failed reading v4 ticket", ""));
 824         goto error;
 825     }
 826 
 827     /* Decrypt and take apart ticket */
 828     ret = _krb5_krb_decomp_ticket(context, &ticket, key, local_realm,
 829                                   &sname, &sinstance, ad);
 830     if (ret)
 831         goto error;
 832 
 833     RCHECK(ret, krb5_data_alloc(&eaut, eaut_length), error);
 834 
 835     size = krb5_storage_read(sp, eaut.data, eaut.length);
 836     if (size != eaut.length) {
 837         ret = KRB4ET_INTK_PROT;
 838         krb5_set_error_message(context, ret,
 839                                N_("Failed reading v4 authenticator", ""));
 840         goto error;
 841     }
 842 
 843     krb5_storage_free(sp);
 844     sp = NULL;
 845 
 846     ret = decrypt_etext(context, &ad->session, &eaut, &aut);
 847     if (ret)
 848         goto error;
 849 
 850     sp = krb5_storage_from_data(&aut);
 851     if (sp == NULL) {
 852         ret = ENOMEM;
 853         krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
 854         goto error;
 855     }
 856 
 857     if (little_endian)
 858         krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE);
 859     else
 860         krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE);
 861 
 862     RCHECK(ret, get_v4_stringz(sp, &r_name, ANAME_SZ), error);
 863     RCHECK(ret, get_v4_stringz(sp, &r_instance, INST_SZ), error);
 864     RCHECK(ret, get_v4_stringz(sp, &r_realm, REALM_SZ), error);
 865 
 866     RCHECK(ret, krb5_ret_uint32(sp, &ad->checksum), error);
 867     RCHECK(ret, krb5_ret_uint8(sp, &time_5ms), error);
 868     RCHECK(ret, krb5_ret_uint32(sp, &r_time_sec), error);
 869 
 870     if (strcmp(ad->pname, r_name) != 0 ||
 871         strcmp(ad->pinst, r_instance) != 0 ||
 872         strcmp(ad->prealm, r_realm) != 0) {
 873         ret = KRB4ET_RD_AP_INCON;
 874         krb5_set_error_message(context, ret, N_("v4 principal mismatch", ""));
 875         goto error;
 876     }
 877 
 878     if (from_addr && ad->address && from_addr != ad->address) {
 879         ret = KRB4ET_RD_AP_BADD;
 880         krb5_set_error_message(context, ret,
 881                                N_("v4 bad address in ticket", ""));
 882         goto error;
 883     }
 884 
 885     gettimeofday(&tv, NULL);
 886     delta_t = abs((int)(tv.tv_sec - r_time_sec));
 887     if (delta_t > CLOCK_SKEW) {
 888         ret = KRB4ET_RD_AP_TIME;
 889         krb5_set_error_message(context, ret, N_("v4 clock skew", ""));
 890         goto error;
 891     }
 892 
 893     /* Now check for expiration of ticket */
 894 
 895     tkt_age = tv.tv_sec - ad->time_sec;
 896 
 897     if ((tkt_age < 0) && (-tkt_age > CLOCK_SKEW)) {
 898         ret = KRB4ET_RD_AP_NYV;
 899         krb5_set_error_message(context, ret,
 900                                N_("v4 clock skew for expiration", ""));
 901         goto error;
 902     }
 903 
 904     if (tv.tv_sec > _krb5_krb_life_to_time(ad->time_sec, ad->life)) {
 905         ret = KRB4ET_RD_AP_EXP;
 906         krb5_set_error_message(context, ret, N_("v4 ticket expired", ""));
 907         goto error;
 908     }
 909 
 910     ret = 0;
 911  error:
 912     krb5_data_free(&ticket);
 913     krb5_data_free(&eaut);
 914     krb5_data_free(&aut);
 915     if (realm)
 916         free(realm);
 917     if (sname)
 918         free(sname);
 919     if (sinstance)
 920         free(sinstance);
 921     if (r_name)
 922         free(r_name);
 923     if (r_instance)
 924         free(r_instance);
 925     if (r_realm)
 926         free(r_realm);
 927     if (sp)
 928         krb5_storage_free(sp);
 929 
 930     if (ret)
 931         krb5_clear_error_message(context);
 932 
 933     return ret;
 934 }
 935 
 936 /*
 937  *
 938  */
 939 
 940 void KRB5_LIB_FUNCTION
 941 _krb5_krb_free_auth_data(krb5_context context, struct _krb5_krb_auth_data *ad)
     /* [<][>][^][v][top][bottom][index][help] */
 942 {
 943     if (ad->pname)
 944         free(ad->pname);
 945     if (ad->pinst)
 946         free(ad->pinst);
 947     if (ad->prealm)
 948         free(ad->prealm);
 949     krb5_free_keyblock_contents(context, &ad->session);
 950     memset(ad, 0, sizeof(*ad));
 951 }
 952 
 953 #endif /* HEIMDAL_SMALLER */

/* [<][>][^][v][top][bottom][index][help] */