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

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

DEFINITIONS

This source file includes following definitions.
  1. krb5_init_etype
  2. check_server_referral
  3. check_client_referral
  4. decrypt_tkt
  5. _krb5_extract_ticket
  6. make_pa_enc_timestamp
  7. add_padata
  8. init_as_req
  9. set_ptypes
  10. krb5_get_in_cred
  11. krb5_get_in_tkt

   1 /*
   2  * Copyright (c) 1997 - 2008 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 
  36 RCSID("$Id$");
  37 
  38 krb5_error_code KRB5_LIB_FUNCTION
  39 krb5_init_etype (krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
  40                  unsigned *len,
  41                  krb5_enctype **val,
  42                  const krb5_enctype *etypes)
  43 {
  44     unsigned int i;
  45     krb5_error_code ret;
  46     krb5_enctype *tmp = NULL;
  47 
  48     ret = 0;
  49     if (etypes == NULL) {
  50         ret = krb5_get_default_in_tkt_etypes(context,
  51                                              &tmp);
  52         if (ret)
  53             return ret;
  54         etypes = tmp;
  55     }
  56 
  57     for (i = 0; etypes[i]; ++i)
  58         ;
  59     *len = i;
  60     *val = malloc(i * sizeof(**val));
  61     if (i != 0 && *val == NULL) {
  62         ret = ENOMEM;
  63         krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
  64         goto cleanup;
  65     }
  66     memmove (*val,
  67              etypes,
  68              i * sizeof(*tmp));
  69 cleanup:
  70     if (tmp != NULL)
  71         free (tmp);
  72     return ret;
  73 }
  74 
  75 static krb5_error_code
  76 check_server_referral(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
  77                       krb5_kdc_rep *rep,
  78                       unsigned flags,
  79                       krb5_const_principal requested,
  80                       krb5_const_principal returned,
  81                       const krb5_keyblock const * key)
  82 {
  83     krb5_error_code ret;
  84     PA_ServerReferralData ref;
  85     krb5_crypto session;
  86     EncryptedData ed;
  87     size_t len;
  88     krb5_data data;
  89     PA_DATA *pa;
  90     int i = 0, cmp;
  91 
  92     if (rep->kdc_rep.padata == NULL)
  93         goto noreferral;
  94 
  95     pa = krb5_find_padata(rep->kdc_rep.padata->val,
  96                           rep->kdc_rep.padata->len,
  97                           KRB5_PADATA_SERVER_REFERRAL, &i);
  98     if (pa == NULL)
  99         goto noreferral;
 100 
 101     memset(&ed, 0, sizeof(ed));
 102     memset(&ref, 0, sizeof(ref));
 103 
 104     ret = decode_EncryptedData(pa->padata_value.data,
 105                                pa->padata_value.length,
 106                                &ed, &len);
 107     if (ret)
 108         return ret;
 109     if (len != pa->padata_value.length) {
 110         free_EncryptedData(&ed);
 111         krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
 112                                N_("Referral EncryptedData wrong for realm %s",
 113                                   "realm"), requested->realm);
 114         return KRB5KRB_AP_ERR_MODIFIED;
 115     }
 116 
 117     ret = krb5_crypto_init(context, key, 0, &session);
 118     if (ret) {
 119         free_EncryptedData(&ed);
 120         return ret;
 121     }
 122 
 123     ret = krb5_decrypt_EncryptedData(context, session,
 124                                      KRB5_KU_PA_SERVER_REFERRAL,
 125                                      &ed, &data);
 126     free_EncryptedData(&ed);
 127     krb5_crypto_destroy(context, session);
 128     if (ret)
 129         return ret;
 130 
 131     ret = decode_PA_ServerReferralData(data.data, data.length, &ref, &len);
 132     if (ret) {
 133         krb5_data_free(&data);
 134         return ret;
 135     }
 136     krb5_data_free(&data);
 137 
 138     if (strcmp(requested->realm, returned->realm) != 0) {
 139         free_PA_ServerReferralData(&ref);
 140         krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
 141                                N_("server ref realm mismatch, "
 142                                   "requested realm %s got back %s", ""),
 143                                requested->realm, returned->realm);
 144         return KRB5KRB_AP_ERR_MODIFIED;
 145     }
 146 
 147     if (returned->name.name_string.len == 2 &&
 148         strcmp(returned->name.name_string.val[0], KRB5_TGS_NAME) == 0)
 149     {
 150         const char *realm = returned->name.name_string.val[1];
 151 
 152         if (ref.referred_realm == NULL
 153             || strcmp(*ref.referred_realm, realm) != 0)
 154         {
 155             free_PA_ServerReferralData(&ref);
 156             krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
 157                                    N_("tgt returned with wrong ref", ""));
 158             return KRB5KRB_AP_ERR_MODIFIED;
 159         }
 160     } else if (krb5_principal_compare(context, returned, requested) == 0) {
 161         free_PA_ServerReferralData(&ref);
 162         krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
 163                                N_("req princ no same as returned", ""));
 164         return KRB5KRB_AP_ERR_MODIFIED;
 165     }
 166 
 167     if (ref.requested_principal_name) {
 168         cmp = _krb5_principal_compare_PrincipalName(context,
 169                                                     requested,
 170                                                     ref.requested_principal_name);
 171         if (!cmp) {
 172             free_PA_ServerReferralData(&ref);
 173             krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
 174                                    N_("referred principal not same "
 175                                       "as requested", ""));
 176             return KRB5KRB_AP_ERR_MODIFIED;
 177         }
 178     } else if (flags & EXTRACT_TICKET_AS_REQ) {
 179         free_PA_ServerReferralData(&ref);
 180         krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
 181                                N_("Requested principal missing on AS-REQ", ""));
 182         return KRB5KRB_AP_ERR_MODIFIED;
 183     }
 184 
 185     free_PA_ServerReferralData(&ref);
 186 
 187     return ret;
 188 noreferral:
 189     if (krb5_principal_compare(context, requested, returned) == FALSE) {
 190         krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
 191                                N_("Not same server principal returned "
 192                                   "as requested", ""));
 193         return KRB5KRB_AP_ERR_MODIFIED;
 194     }
 195     return 0;
 196 }
 197 
 198 
 199 /*
 200  * Verify referral data
 201  */
 202 
 203 
 204 static krb5_error_code
 205 check_client_referral(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 206                       krb5_kdc_rep *rep,
 207                       krb5_const_principal requested,
 208                       krb5_const_principal mapped,
 209                       krb5_keyblock const * key)
 210 {
 211     krb5_error_code ret;
 212     PA_ClientCanonicalized canon;
 213     krb5_crypto crypto;
 214     krb5_data data;
 215     PA_DATA *pa;
 216     size_t len;
 217     int i = 0;
 218 
 219     if (rep->kdc_rep.padata == NULL)
 220         goto noreferral;
 221 
 222     pa = krb5_find_padata(rep->kdc_rep.padata->val,
 223                           rep->kdc_rep.padata->len,
 224                           KRB5_PADATA_CLIENT_CANONICALIZED, &i);
 225     if (pa == NULL)
 226         goto noreferral;
 227 
 228     ret = decode_PA_ClientCanonicalized(pa->padata_value.data,
 229                                         pa->padata_value.length,
 230                                         &canon, &len);
 231     if (ret) {
 232         krb5_set_error_message(context, ret,
 233                                N_("Failed to decode ClientCanonicalized "
 234                                   "from realm %s", ""), requested->realm);
 235         return ret;
 236     }
 237 
 238     ASN1_MALLOC_ENCODE(PA_ClientCanonicalizedNames, data.data, data.length,
 239                        &canon.names, &len, ret);
 240     if (ret) {
 241         free_PA_ClientCanonicalized(&canon);
 242         return ret;
 243     }
 244     if (data.length != len)
 245         krb5_abortx(context, "internal asn.1 error");
 246 
 247     ret = krb5_crypto_init(context, key, 0, &crypto);
 248     if (ret) {
 249         free(data.data);
 250         free_PA_ClientCanonicalized(&canon);
 251         return ret;
 252     }
 253 
 254     ret = krb5_verify_checksum(context, crypto, KRB5_KU_CANONICALIZED_NAMES,
 255                                data.data, data.length,
 256                                &canon.canon_checksum);
 257     krb5_crypto_destroy(context, crypto);
 258     free(data.data);
 259     if (ret) {
 260         krb5_set_error_message(context, ret,
 261                                N_("Failed to verify client canonicalized "
 262                                   "data from realm %s", ""),
 263                                requested->realm);
 264         free_PA_ClientCanonicalized(&canon);
 265         return ret;
 266     }
 267 
 268     if (!_krb5_principal_compare_PrincipalName(context,
 269                                                requested,
 270                                                &canon.names.requested_name))
 271     {
 272         free_PA_ClientCanonicalized(&canon);
 273         krb5_set_error_message(context, KRB5_PRINC_NOMATCH,
 274                                N_("Requested name doesn't match"
 275                                   " in client referral", ""));
 276         return KRB5_PRINC_NOMATCH;
 277     }
 278     if (!_krb5_principal_compare_PrincipalName(context,
 279                                                mapped,
 280                                                &canon.names.mapped_name))
 281     {
 282         free_PA_ClientCanonicalized(&canon);
 283         krb5_set_error_message(context, KRB5_PRINC_NOMATCH,
 284                                N_("Mapped name doesn't match"
 285                                   " in client referral", ""));
 286         return KRB5_PRINC_NOMATCH;
 287     }
 288 
 289     return 0;
 290 
 291 noreferral:
 292     if (krb5_principal_compare(context, requested, mapped) == FALSE) {
 293         krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
 294                                N_("Not same client principal returned "
 295                                   "as requested", ""));
 296         return KRB5KRB_AP_ERR_MODIFIED;
 297     }
 298     return 0;
 299 }
 300 
 301 
 302 
 303 static krb5_error_code
 304 decrypt_tkt (krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 305              krb5_keyblock *key,
 306              krb5_key_usage usage,
 307              krb5_const_pointer decrypt_arg,
 308              krb5_kdc_rep *dec_rep)
 309 {
 310     krb5_error_code ret;
 311     krb5_data data;
 312     size_t size;
 313     krb5_crypto crypto;
 314 
 315     ret = krb5_crypto_init(context, key, 0, &crypto);
 316     if (ret)
 317         return ret;
 318 
 319     ret = krb5_decrypt_EncryptedData (context,
 320                                       crypto,
 321                                       usage,
 322                                       &dec_rep->kdc_rep.enc_part,
 323                                       &data);
 324     krb5_crypto_destroy(context, crypto);
 325 
 326     if (ret)
 327         return ret;
 328 
 329     ret = krb5_decode_EncASRepPart(context,
 330                                    data.data,
 331                                    data.length,
 332                                    &dec_rep->enc_part,
 333                                    &size);
 334     if (ret)
 335         ret = krb5_decode_EncTGSRepPart(context,
 336                                         data.data,
 337                                         data.length,
 338                                         &dec_rep->enc_part,
 339                                         &size);
 340     krb5_data_free (&data);
 341     if (ret)
 342         return ret;
 343     return 0;
 344 }
 345 
 346 int
 347 _krb5_extract_ticket(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 348                      krb5_kdc_rep *rep,
 349                      krb5_creds *creds,
 350                      krb5_keyblock *key,
 351                      krb5_const_pointer keyseed,
 352                      krb5_key_usage key_usage,
 353                      krb5_addresses *addrs,
 354                      unsigned nonce,
 355                      unsigned flags,
 356                      krb5_decrypt_proc decrypt_proc,
 357                      krb5_const_pointer decryptarg)
 358 {
 359     krb5_error_code ret;
 360     krb5_principal tmp_principal;
 361     size_t len;
 362     time_t tmp_time;
 363     krb5_timestamp sec_now;
 364 
 365     /* decrypt */
 366 
 367     if (decrypt_proc == NULL)
 368         decrypt_proc = decrypt_tkt;
 369 
 370     ret = (*decrypt_proc)(context, key, key_usage, decryptarg, rep);
 371     if (ret)
 372         goto out;
 373 
 374     /* save session key */
 375 
 376     creds->session.keyvalue.length = 0;
 377     creds->session.keyvalue.data   = NULL;
 378     creds->session.keytype = rep->enc_part.key.keytype;
 379     ret = krb5_data_copy (&creds->session.keyvalue,
 380                           rep->enc_part.key.keyvalue.data,
 381                           rep->enc_part.key.keyvalue.length);
 382     if (ret) {
 383         krb5_clear_error_message(context);
 384         goto out;
 385     }
 386 
 387     /*
 388      * HACK:
 389      * this is really a ugly hack, to support using the Netbios Domain Name
 390      * as realm against windows KDC's, they always return the full realm
 391      * based on the DNS Name.
 392      */
 393     flags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH;
 394     flags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH;
 395 
 396    /* compare client and save */
 397     ret = _krb5_principalname2krb5_principal (context,
 398                                               &tmp_principal,
 399                                               rep->kdc_rep.cname,
 400                                               rep->kdc_rep.crealm);
 401     if (ret)
 402         goto out;
 403 
 404     /* check client referral and save principal */
 405     /* anonymous here ? */
 406     if((flags & EXTRACT_TICKET_ALLOW_CNAME_MISMATCH) == 0) {
 407         ret = check_client_referral(context, rep,
 408                                     creds->client,
 409                                     tmp_principal,
 410                                     &creds->session);
 411         if (ret) {
 412             krb5_free_principal (context, tmp_principal);
 413             goto out;
 414         }
 415     }
 416     krb5_free_principal (context, creds->client);
 417     creds->client = tmp_principal;
 418 
 419     /* check server referral and save principal */
 420     ret = _krb5_principalname2krb5_principal (context,
 421                                               &tmp_principal,
 422                                               rep->kdc_rep.ticket.sname,
 423                                               rep->kdc_rep.ticket.realm);
 424     if (ret)
 425         goto out;
 426     if((flags & EXTRACT_TICKET_ALLOW_SERVER_MISMATCH) == 0){
 427         ret = check_server_referral(context,
 428                                     rep,
 429                                     flags,
 430                                     creds->server,
 431                                     tmp_principal,
 432                                     &creds->session);
 433         if (ret) {
 434             krb5_free_principal (context, tmp_principal);
 435             goto out;
 436         }
 437     }
 438     krb5_free_principal(context, creds->server);
 439     creds->server = tmp_principal;
 440 
 441     /* verify names */
 442     if(flags & EXTRACT_TICKET_MATCH_REALM){
 443         const char *srealm = krb5_principal_get_realm(context, creds->server);
 444         const char *crealm = krb5_principal_get_realm(context, creds->client);
 445 
 446         if (strcmp(rep->enc_part.srealm, srealm) != 0 ||
 447             strcmp(rep->enc_part.srealm, crealm) != 0)
 448         {
 449             ret = KRB5KRB_AP_ERR_MODIFIED;
 450             krb5_clear_error_message(context);
 451             goto out;
 452         }
 453     }
 454 
 455     /* compare nonces */
 456 
 457     if (nonce != rep->enc_part.nonce) {
 458         ret = KRB5KRB_AP_ERR_MODIFIED;
 459         krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
 460         goto out;
 461     }
 462 
 463     /* set kdc-offset */
 464 
 465     krb5_timeofday (context, &sec_now);
 466     if (rep->enc_part.flags.initial
 467         && context->kdc_sec_offset == 0
 468         && krb5_config_get_bool (context, NULL,
 469                                  "libdefaults",
 470                                  "kdc_timesync",
 471                                  NULL)) {
 472         context->kdc_sec_offset = rep->enc_part.authtime - sec_now;
 473         krb5_timeofday (context, &sec_now);
 474     }
 475 
 476     /* check all times */
 477 
 478     if (rep->enc_part.starttime) {
 479         tmp_time = *rep->enc_part.starttime;
 480     } else
 481         tmp_time = rep->enc_part.authtime;
 482 
 483     if (creds->times.starttime == 0
 484         && abs(tmp_time - sec_now) > context->max_skew) {
 485         ret = KRB5KRB_AP_ERR_SKEW;
 486         krb5_set_error_message (context, ret,
 487                                 N_("time skew (%d) larger than max (%d)", ""),
 488                                abs(tmp_time - sec_now),
 489                                (int)context->max_skew);
 490         goto out;
 491     }
 492 
 493     if (creds->times.starttime != 0
 494         && tmp_time != creds->times.starttime) {
 495         krb5_clear_error_message (context);
 496         ret = KRB5KRB_AP_ERR_MODIFIED;
 497         goto out;
 498     }
 499 
 500     creds->times.starttime = tmp_time;
 501 
 502     if (rep->enc_part.renew_till) {
 503         tmp_time = *rep->enc_part.renew_till;
 504     } else
 505         tmp_time = 0;
 506 
 507     if (creds->times.renew_till != 0
 508         && tmp_time > creds->times.renew_till) {
 509         krb5_clear_error_message (context);
 510         ret = KRB5KRB_AP_ERR_MODIFIED;
 511         goto out;
 512     }
 513 
 514     creds->times.renew_till = tmp_time;
 515 
 516     creds->times.authtime = rep->enc_part.authtime;
 517 
 518     if (creds->times.endtime != 0
 519         && rep->enc_part.endtime > creds->times.endtime) {
 520         krb5_clear_error_message (context);
 521         ret = KRB5KRB_AP_ERR_MODIFIED;
 522         goto out;
 523     }
 524 
 525     creds->times.endtime  = rep->enc_part.endtime;
 526 
 527     if(rep->enc_part.caddr)
 528         krb5_copy_addresses (context, rep->enc_part.caddr, &creds->addresses);
 529     else if(addrs)
 530         krb5_copy_addresses (context, addrs, &creds->addresses);
 531     else {
 532         creds->addresses.len = 0;
 533         creds->addresses.val = NULL;
 534     }
 535     creds->flags.b = rep->enc_part.flags;
 536         
 537     creds->authdata.len = 0;
 538     creds->authdata.val = NULL;
 539 
 540     /* extract ticket */
 541     ASN1_MALLOC_ENCODE(Ticket, creds->ticket.data, creds->ticket.length,
 542                        &rep->kdc_rep.ticket, &len, ret);
 543     if(ret)
 544         goto out;
 545     if (creds->ticket.length != len)
 546         krb5_abortx(context, "internal error in ASN.1 encoder");
 547     creds->second_ticket.length = 0;
 548     creds->second_ticket.data   = NULL;
 549 
 550 
 551 out:
 552     memset (rep->enc_part.key.keyvalue.data, 0,
 553             rep->enc_part.key.keyvalue.length);
 554     return ret;
 555 }
 556 
 557 
 558 static krb5_error_code
 559 make_pa_enc_timestamp(krb5_context context, PA_DATA *pa,
     /* [<][>][^][v][top][bottom][index][help] */
 560                       krb5_enctype etype, krb5_keyblock *key)
 561 {
 562     PA_ENC_TS_ENC p;
 563     unsigned char *buf;
 564     size_t buf_size;
 565     size_t len;
 566     EncryptedData encdata;
 567     krb5_error_code ret;
 568     int32_t usec;
 569     int usec2;
 570     krb5_crypto crypto;
 571 
 572     krb5_us_timeofday (context, &p.patimestamp, &usec);
 573     usec2         = usec;
 574     p.pausec      = &usec2;
 575 
 576     ASN1_MALLOC_ENCODE(PA_ENC_TS_ENC, buf, buf_size, &p, &len, ret);
 577     if (ret)
 578         return ret;
 579     if(buf_size != len)
 580         krb5_abortx(context, "internal error in ASN.1 encoder");
 581     ret = krb5_crypto_init(context, key, 0, &crypto);
 582     if (ret) {
 583         free(buf);
 584         return ret;
 585     }
 586     ret = krb5_encrypt_EncryptedData(context,
 587                                      crypto,
 588                                      KRB5_KU_PA_ENC_TIMESTAMP,
 589                                      buf,
 590                                      len,
 591                                      0,
 592                                      &encdata);
 593     free(buf);
 594     krb5_crypto_destroy(context, crypto);
 595     if (ret)
 596         return ret;
 597                 
 598     ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_size, &encdata, &len, ret);
 599     free_EncryptedData(&encdata);
 600     if (ret)
 601         return ret;
 602     if(buf_size != len)
 603         krb5_abortx(context, "internal error in ASN.1 encoder");
 604     pa->padata_type = KRB5_PADATA_ENC_TIMESTAMP;
 605     pa->padata_value.length = len;
 606     pa->padata_value.data = buf;
 607     return 0;
 608 }
 609 
 610 static krb5_error_code
 611 add_padata(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 612            METHOD_DATA *md,
 613            krb5_principal client,
 614            krb5_key_proc key_proc,
 615            krb5_const_pointer keyseed,
 616            krb5_enctype *enctypes,
 617            unsigned netypes,
 618            krb5_salt *salt)
 619 {
 620     krb5_error_code ret;
 621     PA_DATA *pa2;
 622     krb5_salt salt2;
 623     krb5_enctype *ep;
 624     int i;
 625 
 626     if(salt == NULL) {
 627         /* default to standard salt */
 628         ret = krb5_get_pw_salt (context, client, &salt2);
 629         salt = &salt2;
 630     }
 631     if (!enctypes) {
 632         enctypes = context->etypes;
 633         netypes = 0;
 634         for (ep = enctypes; *ep != ETYPE_NULL; ep++)
 635             netypes++;
 636     }
 637     pa2 = realloc (md->val, (md->len + netypes) * sizeof(*md->val));
 638     if (pa2 == NULL) {
 639         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
 640         return ENOMEM;
 641     }
 642     md->val = pa2;
 643 
 644     for (i = 0; i < netypes; ++i) {
 645         krb5_keyblock *key;
 646 
 647         ret = (*key_proc)(context, enctypes[i], *salt, keyseed, &key);
 648         if (ret)
 649             continue;
 650         ret = make_pa_enc_timestamp (context, &md->val[md->len],
 651                                      enctypes[i], key);
 652         krb5_free_keyblock (context, key);
 653         if (ret)
 654             return ret;
 655         ++md->len;
 656     }
 657     if(salt == &salt2)
 658         krb5_free_salt(context, salt2);
 659     return 0;
 660 }
 661 
 662 static krb5_error_code
 663 init_as_req (krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 664              KDCOptions opts,
 665              krb5_creds *creds,
 666              const krb5_addresses *addrs,
 667              const krb5_enctype *etypes,
 668              const krb5_preauthtype *ptypes,
 669              const krb5_preauthdata *preauth,
 670              krb5_key_proc key_proc,
 671              krb5_const_pointer keyseed,
 672              unsigned nonce,
 673              AS_REQ *a)
 674 {
 675     krb5_error_code ret;
 676     krb5_salt salt;
 677 
 678     memset(a, 0, sizeof(*a));
 679 
 680     a->pvno = 5;
 681     a->msg_type = krb_as_req;
 682     a->req_body.kdc_options = opts;
 683     a->req_body.cname = malloc(sizeof(*a->req_body.cname));
 684     if (a->req_body.cname == NULL) {
 685         ret = ENOMEM;
 686         krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
 687         goto fail;
 688     }
 689     a->req_body.sname = malloc(sizeof(*a->req_body.sname));
 690     if (a->req_body.sname == NULL) {
 691         ret = ENOMEM;
 692         krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
 693         goto fail;
 694     }
 695     ret = _krb5_principal2principalname (a->req_body.cname, creds->client);
 696     if (ret)
 697         goto fail;
 698     ret = _krb5_principal2principalname (a->req_body.sname, creds->server);
 699     if (ret)
 700         goto fail;
 701     ret = copy_Realm(&creds->client->realm, &a->req_body.realm);
 702     if (ret)
 703         goto fail;
 704 
 705     if(creds->times.starttime) {
 706         a->req_body.from = malloc(sizeof(*a->req_body.from));
 707         if (a->req_body.from == NULL) {
 708             ret = ENOMEM;
 709             krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
 710             goto fail;
 711         }
 712         *a->req_body.from = creds->times.starttime;
 713     }
 714     if(creds->times.endtime){
 715         ALLOC(a->req_body.till, 1);
 716         *a->req_body.till = creds->times.endtime;
 717     }
 718     if(creds->times.renew_till){
 719         a->req_body.rtime = malloc(sizeof(*a->req_body.rtime));
 720         if (a->req_body.rtime == NULL) {
 721             ret = ENOMEM;
 722             krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
 723             goto fail;
 724         }
 725         *a->req_body.rtime = creds->times.renew_till;
 726     }
 727     a->req_body.nonce = nonce;
 728     ret = krb5_init_etype (context,
 729                            &a->req_body.etype.len,
 730                            &a->req_body.etype.val,
 731                            etypes);
 732     if (ret)
 733         goto fail;
 734 
 735     /*
 736      * This means no addresses
 737      */
 738 
 739     if (addrs && addrs->len == 0) {
 740         a->req_body.addresses = NULL;
 741     } else {
 742         a->req_body.addresses = malloc(sizeof(*a->req_body.addresses));
 743         if (a->req_body.addresses == NULL) {
 744             ret = ENOMEM;
 745             krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
 746             goto fail;
 747         }
 748 
 749         if (addrs)
 750             ret = krb5_copy_addresses(context, addrs, a->req_body.addresses);
 751         else {
 752             ret = krb5_get_all_client_addrs (context, a->req_body.addresses);
 753             if(ret == 0 && a->req_body.addresses->len == 0) {
 754                 free(a->req_body.addresses);
 755                 a->req_body.addresses = NULL;
 756             }
 757         }
 758         if (ret)
 759             return ret;
 760     }
 761 
 762     a->req_body.enc_authorization_data = NULL;
 763     a->req_body.additional_tickets = NULL;
 764 
 765     if(preauth != NULL) {
 766         int i;
 767         ALLOC(a->padata, 1);
 768         if(a->padata == NULL) {
 769             ret = ENOMEM;
 770             krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
 771             goto fail;
 772         }
 773         a->padata->val = NULL;
 774         a->padata->len = 0;
 775         for(i = 0; i < preauth->len; i++) {
 776             if(preauth->val[i].type == KRB5_PADATA_ENC_TIMESTAMP){
 777                 int j;
 778 
 779                 for(j = 0; j < preauth->val[i].info.len; j++) {
 780                     krb5_salt *sp = &salt;
 781                     if(preauth->val[i].info.val[j].salttype)
 782                         salt.salttype = *preauth->val[i].info.val[j].salttype;
 783                     else
 784                         salt.salttype = KRB5_PW_SALT;
 785                     if(preauth->val[i].info.val[j].salt)
 786                         salt.saltvalue = *preauth->val[i].info.val[j].salt;
 787                     else
 788                         if(salt.salttype == KRB5_PW_SALT)
 789                             sp = NULL;
 790                         else
 791                             krb5_data_zero(&salt.saltvalue);
 792                     ret = add_padata(context, a->padata, creds->client,
 793                                      key_proc, keyseed,
 794                                      &preauth->val[i].info.val[j].etype, 1,
 795                                      sp);
 796                     if (ret == 0)
 797                         break;
 798                 }
 799             }
 800         }
 801     } else
 802     /* not sure this is the way to use `ptypes' */
 803     if (ptypes == NULL || *ptypes == KRB5_PADATA_NONE)
 804         a->padata = NULL;
 805     else if (*ptypes ==  KRB5_PADATA_ENC_TIMESTAMP) {
 806         ALLOC(a->padata, 1);
 807         if (a->padata == NULL) {
 808             ret = ENOMEM;
 809             krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
 810             goto fail;
 811         }
 812         a->padata->len = 0;
 813         a->padata->val = NULL;
 814 
 815         /* make a v5 salted pa-data */
 816         add_padata(context, a->padata, creds->client,
 817                    key_proc, keyseed, a->req_body.etype.val,
 818                    a->req_body.etype.len, NULL);
 819         
 820         /* make a v4 salted pa-data */
 821         salt.salttype = KRB5_PW_SALT;
 822         krb5_data_zero(&salt.saltvalue);
 823         add_padata(context, a->padata, creds->client,
 824                    key_proc, keyseed, a->req_body.etype.val,
 825                    a->req_body.etype.len, &salt);
 826     } else {
 827         ret = KRB5_PREAUTH_BAD_TYPE;
 828         krb5_set_error_message (context, ret,
 829                                 N_("pre-auth type %d not supported", ""),
 830                                *ptypes);
 831         goto fail;
 832     }
 833     return 0;
 834 fail:
 835     free_AS_REQ(a);
 836     return ret;
 837 }
 838 
 839 static int
 840 set_ptypes(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 841            KRB_ERROR *error,
 842            const krb5_preauthtype **ptypes,
 843            krb5_preauthdata **preauth)
 844 {
 845     static krb5_preauthdata preauth2;
 846     static krb5_preauthtype ptypes2[] = { KRB5_PADATA_ENC_TIMESTAMP, KRB5_PADATA_NONE };
 847 
 848     if(error->e_data) {
 849         METHOD_DATA md;
 850         int i;
 851         decode_METHOD_DATA(error->e_data->data,
 852                            error->e_data->length,
 853                            &md,
 854                            NULL);
 855         for(i = 0; i < md.len; i++){
 856             switch(md.val[i].padata_type){
 857             case KRB5_PADATA_ENC_TIMESTAMP:
 858                 *ptypes = ptypes2;
 859                 break;
 860             case KRB5_PADATA_ETYPE_INFO:
 861                 *preauth = &preauth2;
 862                 ALLOC_SEQ(*preauth, 1);
 863                 (*preauth)->val[0].type = KRB5_PADATA_ENC_TIMESTAMP;
 864                 krb5_decode_ETYPE_INFO(context,
 865                                        md.val[i].padata_value.data,
 866                                        md.val[i].padata_value.length,
 867                                        &(*preauth)->val[0].info,
 868                                        NULL);
 869                 break;
 870             default:
 871                 break;
 872             }
 873         }
 874         free_METHOD_DATA(&md);
 875     } else {
 876         *ptypes = ptypes2;
 877     }
 878     return(1);
 879 }
 880 
 881 krb5_error_code KRB5_LIB_FUNCTION
 882 krb5_get_in_cred(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 883                  krb5_flags options,
 884                  const krb5_addresses *addrs,
 885                  const krb5_enctype *etypes,
 886                  const krb5_preauthtype *ptypes,
 887                  const krb5_preauthdata *preauth,
 888                  krb5_key_proc key_proc,
 889                  krb5_const_pointer keyseed,
 890                  krb5_decrypt_proc decrypt_proc,
 891                  krb5_const_pointer decryptarg,
 892                  krb5_creds *creds,
 893                  krb5_kdc_rep *ret_as_reply)
 894 {
 895     krb5_error_code ret;
 896     AS_REQ a;
 897     krb5_kdc_rep rep;
 898     krb5_data req, resp;
 899     size_t len;
 900     krb5_salt salt;
 901     krb5_keyblock *key;
 902     size_t size;
 903     KDCOptions opts;
 904     PA_DATA *pa;
 905     krb5_enctype etype;
 906     krb5_preauthdata *my_preauth = NULL;
 907     unsigned nonce;
 908     int done;
 909 
 910     opts = int2KDCOptions(options);
 911 
 912     krb5_generate_random_block (&nonce, sizeof(nonce));
 913     nonce &= 0xffffffff;
 914 
 915     do {
 916         done = 1;
 917         ret = init_as_req (context,
 918                            opts,
 919                            creds,
 920                            addrs,
 921                            etypes,
 922                            ptypes,
 923                            preauth,
 924                            key_proc,
 925                            keyseed,
 926                            nonce,
 927                            &a);
 928         if (my_preauth) {
 929             free_ETYPE_INFO(&my_preauth->val[0].info);
 930             free (my_preauth->val);
 931             my_preauth = NULL;
 932         }
 933         if (ret)
 934             return ret;
 935 
 936         ASN1_MALLOC_ENCODE(AS_REQ, req.data, req.length, &a, &len, ret);
 937         free_AS_REQ(&a);
 938         if (ret)
 939             return ret;
 940         if(len != req.length)
 941             krb5_abortx(context, "internal error in ASN.1 encoder");
 942 
 943         ret = krb5_sendto_kdc (context, &req, &creds->client->realm, &resp);
 944         krb5_data_free(&req);
 945         if (ret)
 946             return ret;
 947 
 948         memset (&rep, 0, sizeof(rep));
 949         ret = decode_AS_REP(resp.data, resp.length, &rep.kdc_rep, &size);
 950         if(ret) {
 951             /* let's try to parse it as a KRB-ERROR */
 952             KRB_ERROR error;
 953             int ret2;
 954 
 955             ret2 = krb5_rd_error(context, &resp, &error);
 956             if(ret2 && resp.data && ((char*)resp.data)[0] == 4)
 957                 ret = KRB5KRB_AP_ERR_V4_REPLY;
 958             krb5_data_free(&resp);
 959             if (ret2 == 0) {
 960                 ret = krb5_error_from_rd_error(context, &error, creds);
 961                 /* if no preauth was set and KDC requires it, give it
 962                    one more try */
 963                 if (!ptypes && !preauth
 964                     && ret == KRB5KDC_ERR_PREAUTH_REQUIRED
 965 #if 0
 966                         || ret == KRB5KDC_ERR_BADOPTION
 967 #endif
 968                     && set_ptypes(context, &error, &ptypes, &my_preauth)) {
 969                     done = 0;
 970                     preauth = my_preauth;
 971                     krb5_free_error_contents(context, &error);
 972                     krb5_clear_error_message(context);
 973                     continue;
 974                 }
 975                 if(ret_as_reply)
 976                     ret_as_reply->error = error;
 977                 else
 978                     free_KRB_ERROR (&error);
 979                 return ret;
 980             }
 981             return ret;
 982         }
 983         krb5_data_free(&resp);
 984     } while(!done);
 985 
 986     pa = NULL;
 987     etype = rep.kdc_rep.enc_part.etype;
 988     if(rep.kdc_rep.padata){
 989         int i = 0;
 990         pa = krb5_find_padata(rep.kdc_rep.padata->val, rep.kdc_rep.padata->len,
 991                               KRB5_PADATA_PW_SALT, &i);
 992         if(pa == NULL) {
 993             i = 0;
 994             pa = krb5_find_padata(rep.kdc_rep.padata->val,
 995                                   rep.kdc_rep.padata->len,
 996                                   KRB5_PADATA_AFS3_SALT, &i);
 997         }
 998     }
 999     if(pa) {
1000         salt.salttype = pa->padata_type;
1001         salt.saltvalue = pa->padata_value;
1002         
1003         ret = (*key_proc)(context, etype, salt, keyseed, &key);
1004     } else {
1005         /* make a v5 salted pa-data */
1006         ret = krb5_get_pw_salt (context, creds->client, &salt);
1007         
1008         if (ret)
1009             goto out;
1010         ret = (*key_proc)(context, etype, salt, keyseed, &key);
1011         krb5_free_salt(context, salt);
1012     }
1013     if (ret)
1014         goto out;
1015         
1016     {
1017         unsigned flags = 0;
1018         if (opts.request_anonymous)
1019             flags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH;
1020 
1021         ret = _krb5_extract_ticket(context,
1022                                    &rep,
1023                                    creds,
1024                                    key,
1025                                    keyseed,
1026                                    KRB5_KU_AS_REP_ENC_PART,
1027                                    NULL,
1028                                    nonce,
1029                                    flags,
1030                                    decrypt_proc,
1031                                    decryptarg);
1032     }
1033     memset (key->keyvalue.data, 0, key->keyvalue.length);
1034     krb5_free_keyblock_contents (context, key);
1035     free (key);
1036 
1037 out:
1038     if (ret == 0 && ret_as_reply)
1039         *ret_as_reply = rep;
1040     else
1041         krb5_free_kdc_rep (context, &rep);
1042     return ret;
1043 }
1044 
1045 krb5_error_code KRB5_LIB_FUNCTION
1046 krb5_get_in_tkt(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
1047                 krb5_flags options,
1048                 const krb5_addresses *addrs,
1049                 const krb5_enctype *etypes,
1050                 const krb5_preauthtype *ptypes,
1051                 krb5_key_proc key_proc,
1052                 krb5_const_pointer keyseed,
1053                 krb5_decrypt_proc decrypt_proc,
1054                 krb5_const_pointer decryptarg,
1055                 krb5_creds *creds,
1056                 krb5_ccache ccache,
1057                 krb5_kdc_rep *ret_as_reply)
1058 {
1059     krb5_error_code ret;
1060 
1061     ret = krb5_get_in_cred (context,
1062                             options,
1063                             addrs,
1064                             etypes,
1065                             ptypes,
1066                             NULL,
1067                             key_proc,
1068                             keyseed,
1069                             decrypt_proc,
1070                             decryptarg,
1071                             creds,
1072                             ret_as_reply);
1073     if(ret)
1074         return ret;
1075     if (ccache)
1076         ret = krb5_cc_store_cred (context, ccache, creds);
1077     return ret;
1078 }

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