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

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

DEFINITIONS

This source file includes following definitions.
  1. default_s2k_func
  2. free_init_creds_ctx
  3. get_config_time
  4. init_cred
  5. report_expiration
  6. print_expire
  7. get_init_creds_common
  8. change_password
  9. krb5_keyblock_key_proc
  10. krb5_get_init_creds_keytab
  11. init_creds_init_as_req
  12. free_paid
  13. set_paid
  14. pa_etype_info2
  15. pa_etype_info
  16. pa_pw_or_afs3_salt
  17. find_pa_data
  18. process_pa_info
  19. make_pa_enc_timestamp
  20. add_enc_ts_padata
  21. pa_data_to_md_ts_enc
  22. pa_data_to_key_plain
  23. pa_data_to_md_pkinit
  24. pa_data_add_pac_request
  25. process_pa_data_to_md
  26. process_pa_data_to_key
  27. init_cred_loop
  28. krb5_get_init_creds
  29. krb5_get_init_creds_password
  30. init_creds_keyblock_key_proc
  31. krb5_get_init_creds_keyblock

   1 /*
   2  * Copyright (c) 1997 - 2007 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 typedef struct krb5_get_init_creds_ctx {
  39     KDCOptions flags;
  40     krb5_creds cred;
  41     krb5_addresses *addrs;
  42     krb5_enctype *etypes;
  43     krb5_preauthtype *pre_auth_types;
  44     const char *in_tkt_service;
  45     unsigned nonce;
  46     unsigned pk_nonce;
  47 
  48     krb5_data req_buffer;
  49     AS_REQ as_req;
  50     int pa_counter;
  51 
  52     const char *password;
  53     krb5_s2k_proc key_proc;
  54 
  55     krb5_get_init_creds_tristate req_pac;
  56 
  57     krb5_pk_init_ctx pk_init_ctx;
  58     int ic_flags;
  59 } krb5_get_init_creds_ctx;
  60 
  61 static krb5_error_code
  62 default_s2k_func(krb5_context context, krb5_enctype type,
     /* [<][>][^][v][top][bottom][index][help] */
  63                  krb5_const_pointer keyseed,
  64                  krb5_salt salt, krb5_data *s2kparms,
  65                  krb5_keyblock **key)
  66 {
  67     krb5_error_code ret;
  68     krb5_data password;
  69     krb5_data opaque;
  70 
  71     password.data = rk_UNCONST(keyseed);
  72     password.length = strlen(keyseed);
  73     if (s2kparms)
  74         opaque = *s2kparms;
  75     else
  76         krb5_data_zero(&opaque);
  77         
  78     *key = malloc(sizeof(**key));
  79     if (*key == NULL)
  80         return ENOMEM;
  81     ret = krb5_string_to_key_data_salt_opaque(context, type, password,
  82                                               salt, opaque, *key);
  83     if (ret) {
  84         free(*key);
  85         *key = NULL;
  86     }
  87     return ret;
  88 }
  89 
  90 static void
  91 free_init_creds_ctx(krb5_context context, krb5_get_init_creds_ctx *ctx)
     /* [<][>][^][v][top][bottom][index][help] */
  92 {
  93     if (ctx->etypes)
  94         free(ctx->etypes);
  95     if (ctx->pre_auth_types)
  96         free (ctx->pre_auth_types);
  97     free_AS_REQ(&ctx->as_req);
  98     memset(&ctx->as_req, 0, sizeof(ctx->as_req));
  99 }
 100 
 101 static int
 102 get_config_time (krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 103                  const char *realm,
 104                  const char *name,
 105                  int def)
 106 {
 107     int ret;
 108 
 109     ret = krb5_config_get_time (context, NULL,
 110                                 "realms",
 111                                 realm,
 112                                 name,
 113                                 NULL);
 114     if (ret >= 0)
 115         return ret;
 116     ret = krb5_config_get_time (context, NULL,
 117                                 "libdefaults",
 118                                 name,
 119                                 NULL);
 120     if (ret >= 0)
 121         return ret;
 122     return def;
 123 }
 124 
 125 static krb5_error_code
 126 init_cred (krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 127            krb5_creds *cred,
 128            krb5_principal client,
 129            krb5_deltat start_time,
 130            const char *in_tkt_service,
 131            krb5_get_init_creds_opt *options)
 132 {
 133     krb5_error_code ret;
 134     krb5_const_realm client_realm;
 135     int tmp;
 136     krb5_timestamp now;
 137 
 138     krb5_timeofday (context, &now);
 139 
 140     memset (cred, 0, sizeof(*cred));
 141 
 142     if (client)
 143         krb5_copy_principal(context, client, &cred->client);
 144     else {
 145         ret = krb5_get_default_principal (context,
 146                                           &cred->client);
 147         if (ret)
 148             goto out;
 149     }
 150 
 151     client_realm = krb5_principal_get_realm (context, cred->client);
 152 
 153     if (start_time)
 154         cred->times.starttime  = now + start_time;
 155 
 156     if (options->flags & KRB5_GET_INIT_CREDS_OPT_TKT_LIFE)
 157         tmp = options->tkt_life;
 158     else
 159         tmp = 10 * 60 * 60;
 160     cred->times.endtime = now + tmp;
 161 
 162     if ((options->flags & KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE) &&
 163         options->renew_life > 0) {
 164         cred->times.renew_till = now + options->renew_life;
 165     }
 166 
 167     if (in_tkt_service) {
 168         ret = krb5_parse_name (context, in_tkt_service, &cred->server);
 169         if (ret)
 170             goto out;
 171         krb5_principal_set_realm (context, cred->server, client_realm);
 172     } else {
 173         ret = krb5_make_principal(context, &cred->server,
 174                                   client_realm, KRB5_TGS_NAME, client_realm,
 175                                   NULL);
 176         if (ret)
 177             goto out;
 178     }
 179     return 0;
 180 
 181 out:
 182     krb5_free_cred_contents (context, cred);
 183     return ret;
 184 }
 185 
 186 /*
 187  * Print a message (str) to the user about the expiration in `lr'
 188  */
 189 
 190 static void
 191 report_expiration (krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 192                    krb5_prompter_fct prompter,
 193                    krb5_data *data,
 194                    const char *str,
 195                    time_t now)
 196 {
 197     char *p;
 198         
 199     asprintf (&p, "%s%s", str, ctime(&now));
 200     (*prompter) (context, data, NULL, p, 0, NULL);
 201     free (p);
 202 }
 203 
 204 /*
 205  * Parse the last_req data and show it to the user if it's interesting
 206  */
 207 
 208 static void
 209 print_expire (krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 210               krb5_const_realm realm,
 211               krb5_kdc_rep *rep,
 212               krb5_prompter_fct prompter,
 213               krb5_data *data)
 214 {
 215     int i;
 216     LastReq *lr = &rep->enc_part.last_req;
 217     krb5_timestamp sec;
 218     time_t t;
 219     krb5_boolean reported = FALSE;
 220 
 221     krb5_timeofday (context, &sec);
 222 
 223     t = sec + get_config_time (context,
 224                                realm,
 225                                "warn_pwexpire",
 226                                7 * 24 * 60 * 60);
 227 
 228     for (i = 0; i < lr->len; ++i) {
 229         if (lr->val[i].lr_value <= t) {
 230             switch (abs(lr->val[i].lr_type)) {
 231             case LR_PW_EXPTIME :
 232                 report_expiration(context, prompter, data,
 233                                   "Your password will expire at ",
 234                                   lr->val[i].lr_value);
 235                 reported = TRUE;
 236                 break;
 237             case LR_ACCT_EXPTIME :
 238                 report_expiration(context, prompter, data,
 239                                   "Your account will expire at ",
 240                                   lr->val[i].lr_value);
 241                 reported = TRUE;
 242                 break;
 243             }
 244         }
 245     }
 246 
 247     if (!reported
 248         && rep->enc_part.key_expiration
 249         && *rep->enc_part.key_expiration <= t) {
 250         report_expiration(context, prompter, data,
 251                           "Your password/account will expire at ",
 252                           *rep->enc_part.key_expiration);
 253     }
 254 }
 255 
 256 static krb5_addresses no_addrs = { 0, NULL };
 257 
 258 static krb5_error_code
 259 get_init_creds_common(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 260                       krb5_principal client,
 261                       krb5_deltat start_time,
 262                       const char *in_tkt_service,
 263                       krb5_get_init_creds_opt *options,
 264                       krb5_get_init_creds_ctx *ctx)
 265 {
 266     krb5_get_init_creds_opt default_opt;
 267     krb5_error_code ret;
 268     krb5_enctype *etypes;
 269     krb5_preauthtype *pre_auth_types;
 270 
 271     memset(ctx, 0, sizeof(*ctx));
 272 
 273     if (options == NULL) {
 274         krb5_get_init_creds_opt_init (&default_opt);
 275         options = &default_opt;
 276     } else {
 277         _krb5_get_init_creds_opt_free_krb5_error(options);
 278     }
 279 
 280     if (options->opt_private) {
 281         ctx->password = options->opt_private->password;
 282         ctx->key_proc = options->opt_private->key_proc;
 283         ctx->req_pac = options->opt_private->req_pac;
 284         ctx->pk_init_ctx = options->opt_private->pk_init_ctx;
 285         ctx->ic_flags = options->opt_private->flags;
 286     } else
 287         ctx->req_pac = KRB5_INIT_CREDS_TRISTATE_UNSET;
 288 
 289     if (ctx->key_proc == NULL)
 290         ctx->key_proc = default_s2k_func;
 291 
 292     if (ctx->ic_flags & KRB5_INIT_CREDS_CANONICALIZE)
 293         ctx->flags.canonicalize = 1;
 294 
 295     ctx->pre_auth_types = NULL;
 296     ctx->addrs = NULL;
 297     ctx->etypes = NULL;
 298     ctx->pre_auth_types = NULL;
 299     ctx->in_tkt_service = in_tkt_service;
 300 
 301     ret = init_cred (context, &ctx->cred, client, start_time,
 302                      in_tkt_service, options);
 303     if (ret)
 304         return ret;
 305 
 306     if (options->flags & KRB5_GET_INIT_CREDS_OPT_FORWARDABLE)
 307         ctx->flags.forwardable = options->forwardable;
 308 
 309     if (options->flags & KRB5_GET_INIT_CREDS_OPT_PROXIABLE)
 310         ctx->flags.proxiable = options->proxiable;
 311 
 312     if (start_time)
 313         ctx->flags.postdated = 1;
 314     if (ctx->cred.times.renew_till)
 315         ctx->flags.renewable = 1;
 316     if (options->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST) {
 317         ctx->addrs = options->address_list;
 318     } else if (options->opt_private) {
 319         switch (options->opt_private->addressless) {
 320         case KRB5_INIT_CREDS_TRISTATE_UNSET:
 321 #if KRB5_ADDRESSLESS_DEFAULT == TRUE
 322             ctx->addrs = &no_addrs;
 323 #else
 324             ctx->addrs = NULL;
 325 #endif
 326             break;
 327         case KRB5_INIT_CREDS_TRISTATE_FALSE:
 328             ctx->addrs = NULL;
 329             break;
 330         case KRB5_INIT_CREDS_TRISTATE_TRUE:
 331             ctx->addrs = &no_addrs;
 332             break;
 333         }
 334     }
 335     if (options->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST) {
 336         etypes = malloc((options->etype_list_length + 1)
 337                         * sizeof(krb5_enctype));
 338         if (etypes == NULL) {
 339             krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
 340             return ENOMEM;
 341         }
 342         memcpy (etypes, options->etype_list,
 343                 options->etype_list_length * sizeof(krb5_enctype));
 344         etypes[options->etype_list_length] = ETYPE_NULL;
 345         ctx->etypes = etypes;
 346     }
 347     if (options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST) {
 348         pre_auth_types = malloc((options->preauth_list_length + 1)
 349                                 * sizeof(krb5_preauthtype));
 350         if (pre_auth_types == NULL) {
 351             krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
 352             return ENOMEM;
 353         }
 354         memcpy (pre_auth_types, options->preauth_list,
 355                 options->preauth_list_length * sizeof(krb5_preauthtype));
 356         pre_auth_types[options->preauth_list_length] = KRB5_PADATA_NONE;
 357         ctx->pre_auth_types = pre_auth_types;
 358     }
 359     if (options->flags & KRB5_GET_INIT_CREDS_OPT_SALT)
 360         ;                       /* XXX */
 361     if (options->flags & KRB5_GET_INIT_CREDS_OPT_ANONYMOUS)
 362         ctx->flags.request_anonymous = options->anonymous;
 363     return 0;
 364 }
 365 
 366 static krb5_error_code
 367 change_password (krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 368                  krb5_principal client,
 369                  const char *password,
 370                  char *newpw,
 371                  size_t newpw_sz,
 372                  krb5_prompter_fct prompter,
 373                  void *data,
 374                  krb5_get_init_creds_opt *old_options)
 375 {
 376     krb5_prompt prompts[2];
 377     krb5_error_code ret;
 378     krb5_creds cpw_cred;
 379     char buf1[BUFSIZ], buf2[BUFSIZ];
 380     krb5_data password_data[2];
 381     int result_code;
 382     krb5_data result_code_string;
 383     krb5_data result_string;
 384     char *p;
 385     krb5_get_init_creds_opt options;
 386 
 387     memset (&cpw_cred, 0, sizeof(cpw_cred));
 388 
 389     krb5_get_init_creds_opt_init (&options);
 390     krb5_get_init_creds_opt_set_tkt_life (&options, 60);
 391     krb5_get_init_creds_opt_set_forwardable (&options, FALSE);
 392     krb5_get_init_creds_opt_set_proxiable (&options, FALSE);
 393     if (old_options && old_options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST)
 394         krb5_get_init_creds_opt_set_preauth_list (&options,
 395                                                   old_options->preauth_list,
 396                                                   old_options->preauth_list_length);                                    
 397 
 398     krb5_data_zero (&result_code_string);
 399     krb5_data_zero (&result_string);
 400 
 401     ret = krb5_get_init_creds_password (context,
 402                                         &cpw_cred,
 403                                         client,
 404                                         password,
 405                                         prompter,
 406                                         data,
 407                                         0,
 408                                         "kadmin/changepw",
 409                                         &options);
 410     if (ret)
 411         goto out;
 412 
 413     for(;;) {
 414         password_data[0].data   = buf1;
 415         password_data[0].length = sizeof(buf1);
 416 
 417         prompts[0].hidden = 1;
 418         prompts[0].prompt = "New password: ";
 419         prompts[0].reply  = &password_data[0];
 420         prompts[0].type   = KRB5_PROMPT_TYPE_NEW_PASSWORD;
 421 
 422         password_data[1].data   = buf2;
 423         password_data[1].length = sizeof(buf2);
 424 
 425         prompts[1].hidden = 1;
 426         prompts[1].prompt = "Repeat new password: ";
 427         prompts[1].reply  = &password_data[1];
 428         prompts[1].type   = KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN;
 429 
 430         ret = (*prompter) (context, data, NULL, "Changing password",
 431                            2, prompts);
 432         if (ret) {
 433             memset (buf1, 0, sizeof(buf1));
 434             memset (buf2, 0, sizeof(buf2));
 435             goto out;
 436         }
 437 
 438         if (strcmp (buf1, buf2) == 0)
 439             break;
 440         memset (buf1, 0, sizeof(buf1));
 441         memset (buf2, 0, sizeof(buf2));
 442     }
 443 
 444     ret = krb5_set_password (context,
 445                              &cpw_cred,
 446                              buf1,
 447                              client,
 448                              &result_code,
 449                              &result_code_string,
 450                              &result_string);
 451     if (ret)
 452         goto out;
 453     asprintf (&p, "%s: %.*s\n",
 454               result_code ? "Error" : "Success",
 455               (int)result_string.length,
 456               result_string.length > 0 ? (char*)result_string.data : "");
 457 
 458     ret = (*prompter) (context, data, NULL, p, 0, NULL);
 459     free (p);
 460     if (result_code == 0) {
 461         strlcpy (newpw, buf1, newpw_sz);
 462         ret = 0;
 463     } else {
 464         ret = ENOTTY;
 465         krb5_set_error_message(context, ret,
 466                                N_("failed changing password", ""));
 467     }
 468 
 469 out:
 470     memset (buf1, 0, sizeof(buf1));
 471     memset (buf2, 0, sizeof(buf2));
 472     krb5_data_free (&result_string);
 473     krb5_data_free (&result_code_string);
 474     krb5_free_cred_contents (context, &cpw_cred);
 475     return ret;
 476 }
 477 
 478 krb5_error_code KRB5_LIB_FUNCTION
 479 krb5_keyblock_key_proc (krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 480                         krb5_keytype type,
 481                         krb5_data *salt,
 482                         krb5_const_pointer keyseed,
 483                         krb5_keyblock **key)
 484 {
 485     return krb5_copy_keyblock (context, keyseed, key);
 486 }
 487 
 488 krb5_error_code KRB5_LIB_FUNCTION
 489 krb5_get_init_creds_keytab(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 490                            krb5_creds *creds,
 491                            krb5_principal client,
 492                            krb5_keytab keytab,
 493                            krb5_deltat start_time,
 494                            const char *in_tkt_service,
 495                            krb5_get_init_creds_opt *options)
 496 {
 497     krb5_get_init_creds_ctx ctx;
 498     krb5_error_code ret;
 499     krb5_keytab_key_proc_args *a;
 500 
 501     ret = get_init_creds_common(context, client, start_time,
 502                                 in_tkt_service, options, &ctx);
 503     if (ret)
 504         goto out;
 505 
 506     a = malloc (sizeof(*a));
 507     if (a == NULL) {
 508         ret = ENOMEM;
 509         krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
 510         goto out;
 511     }
 512     a->principal = ctx.cred.client;
 513     a->keytab    = keytab;
 514 
 515     ret = krb5_get_in_cred (context,
 516                             KDCOptions2int(ctx.flags),
 517                             ctx.addrs,
 518                             ctx.etypes,
 519                             ctx.pre_auth_types,
 520                             NULL,
 521                             krb5_keytab_key_proc,
 522                             a,
 523                             NULL,
 524                             NULL,
 525                             &ctx.cred,
 526                             NULL);
 527     free (a);
 528 
 529     if (ret == 0 && creds)
 530         *creds = ctx.cred;
 531     else
 532         krb5_free_cred_contents (context, &ctx.cred);
 533 
 534  out:
 535     free_init_creds_ctx(context, &ctx);
 536     return ret;
 537 }
 538 
 539 /*
 540  *
 541  */
 542 
 543 static krb5_error_code
 544 init_creds_init_as_req (krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 545                         KDCOptions opts,
 546                         const krb5_creds *creds,
 547                         const krb5_addresses *addrs,
 548                         const krb5_enctype *etypes,
 549                         AS_REQ *a)
 550 {
 551     krb5_error_code ret;
 552 
 553     memset(a, 0, sizeof(*a));
 554 
 555     a->pvno = 5;
 556     a->msg_type = krb_as_req;
 557     a->req_body.kdc_options = opts;
 558     a->req_body.cname = malloc(sizeof(*a->req_body.cname));
 559     if (a->req_body.cname == NULL) {
 560         ret = ENOMEM;
 561         krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
 562         goto fail;
 563     }
 564     a->req_body.sname = malloc(sizeof(*a->req_body.sname));
 565     if (a->req_body.sname == NULL) {
 566         ret = ENOMEM;
 567         krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
 568         goto fail;
 569     }
 570 
 571     ret = _krb5_principal2principalname (a->req_body.cname, creds->client);
 572     if (ret)
 573         goto fail;
 574     ret = copy_Realm(&creds->client->realm, &a->req_body.realm);
 575     if (ret)
 576         goto fail;
 577 
 578     ret = _krb5_principal2principalname (a->req_body.sname, creds->server);
 579     if (ret)
 580         goto fail;
 581 
 582     if(creds->times.starttime) {
 583         a->req_body.from = malloc(sizeof(*a->req_body.from));
 584         if (a->req_body.from == NULL) {
 585             ret = ENOMEM;
 586             krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
 587             goto fail;
 588         }
 589         *a->req_body.from = creds->times.starttime;
 590     }
 591     if(creds->times.endtime){
 592         ALLOC(a->req_body.till, 1);
 593         *a->req_body.till = creds->times.endtime;
 594     }
 595     if(creds->times.renew_till){
 596         a->req_body.rtime = malloc(sizeof(*a->req_body.rtime));
 597         if (a->req_body.rtime == NULL) {
 598             ret = ENOMEM;
 599             krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
 600             goto fail;
 601         }
 602         *a->req_body.rtime = creds->times.renew_till;
 603     }
 604     a->req_body.nonce = 0;
 605     ret = krb5_init_etype (context,
 606                            &a->req_body.etype.len,
 607                            &a->req_body.etype.val,
 608                            etypes);
 609     if (ret)
 610         goto fail;
 611 
 612     /*
 613      * This means no addresses
 614      */
 615 
 616     if (addrs && addrs->len == 0) {
 617         a->req_body.addresses = NULL;
 618     } else {
 619         a->req_body.addresses = malloc(sizeof(*a->req_body.addresses));
 620         if (a->req_body.addresses == NULL) {
 621             ret = ENOMEM;
 622             krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
 623             goto fail;
 624         }
 625 
 626         if (addrs)
 627             ret = krb5_copy_addresses(context, addrs, a->req_body.addresses);
 628         else {
 629             ret = krb5_get_all_client_addrs (context, a->req_body.addresses);
 630             if(ret == 0 && a->req_body.addresses->len == 0) {
 631                 free(a->req_body.addresses);
 632                 a->req_body.addresses = NULL;
 633             }
 634         }
 635         if (ret)
 636             goto fail;
 637     }
 638 
 639     a->req_body.enc_authorization_data = NULL;
 640     a->req_body.additional_tickets = NULL;
 641 
 642     a->padata = NULL;
 643 
 644     return 0;
 645  fail:
 646     free_AS_REQ(a);
 647     memset(a, 0, sizeof(*a));
 648     return ret;
 649 }
 650 
 651 struct pa_info_data {
 652     krb5_enctype etype;
 653     krb5_salt salt;
 654     krb5_data *s2kparams;
 655 };
 656 
 657 static void
 658 free_paid(krb5_context context, struct pa_info_data *ppaid)
     /* [<][>][^][v][top][bottom][index][help] */
 659 {
 660     krb5_free_salt(context, ppaid->salt);
 661     if (ppaid->s2kparams)
 662         krb5_free_data(context, ppaid->s2kparams);
 663 }
 664 
 665 
 666 static krb5_error_code
 667 set_paid(struct pa_info_data *paid, krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 668          krb5_enctype etype,
 669          krb5_salttype salttype, void *salt_string, size_t salt_len,
 670          krb5_data *s2kparams)
 671 {
 672     paid->etype = etype;
 673     paid->salt.salttype = salttype;
 674     paid->salt.saltvalue.data = malloc(salt_len + 1);
 675     if (paid->salt.saltvalue.data == NULL) {
 676         krb5_clear_error_message(context);
 677         return ENOMEM;
 678     }
 679     memcpy(paid->salt.saltvalue.data, salt_string, salt_len);
 680     ((char *)paid->salt.saltvalue.data)[salt_len] = '\0';
 681     paid->salt.saltvalue.length = salt_len;
 682     if (s2kparams) {
 683         krb5_error_code ret;
 684 
 685         ret = krb5_copy_data(context, s2kparams, &paid->s2kparams);
 686         if (ret) {
 687             krb5_clear_error_message(context);
 688             krb5_free_salt(context, paid->salt);
 689             return ret;
 690         }
 691     } else
 692         paid->s2kparams = NULL;
 693 
 694     return 0;
 695 }
 696 
 697 static struct pa_info_data *
 698 pa_etype_info2(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 699                const krb5_principal client,
 700                const AS_REQ *asreq,
 701                struct pa_info_data *paid,
 702                heim_octet_string *data)
 703 {
 704     krb5_error_code ret;
 705     ETYPE_INFO2 e;
 706     size_t sz;
 707     int i, j;
 708 
 709     memset(&e, 0, sizeof(e));
 710     ret = decode_ETYPE_INFO2(data->data, data->length, &e, &sz);
 711     if (ret)
 712         goto out;
 713     if (e.len == 0)
 714         goto out;
 715     for (j = 0; j < asreq->req_body.etype.len; j++) {
 716         for (i = 0; i < e.len; i++) {
 717             if (asreq->req_body.etype.val[j] == e.val[i].etype) {
 718                 krb5_salt salt;
 719                 if (e.val[i].salt == NULL)
 720                     ret = krb5_get_pw_salt(context, client, &salt);
 721                 else {
 722                     salt.saltvalue.data = *e.val[i].salt;
 723                     salt.saltvalue.length = strlen(*e.val[i].salt);
 724                     ret = 0;
 725                 }
 726                 if (ret == 0)
 727                     ret = set_paid(paid, context, e.val[i].etype,
 728                                    KRB5_PW_SALT,
 729                                    salt.saltvalue.data,
 730                                    salt.saltvalue.length,
 731                                    e.val[i].s2kparams);
 732                 if (e.val[i].salt == NULL)
 733                     krb5_free_salt(context, salt);
 734                 if (ret == 0) {
 735                     free_ETYPE_INFO2(&e);
 736                     return paid;
 737                 }
 738             }
 739         }
 740     }
 741  out:
 742     free_ETYPE_INFO2(&e);
 743     return NULL;
 744 }
 745 
 746 static struct pa_info_data *
 747 pa_etype_info(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 748               const krb5_principal client,
 749               const AS_REQ *asreq,
 750               struct pa_info_data *paid,
 751               heim_octet_string *data)
 752 {
 753     krb5_error_code ret;
 754     ETYPE_INFO e;
 755     size_t sz;
 756     int i, j;
 757 
 758     memset(&e, 0, sizeof(e));
 759     ret = decode_ETYPE_INFO(data->data, data->length, &e, &sz);
 760     if (ret)
 761         goto out;
 762     if (e.len == 0)
 763         goto out;
 764     for (j = 0; j < asreq->req_body.etype.len; j++) {
 765         for (i = 0; i < e.len; i++) {
 766             if (asreq->req_body.etype.val[j] == e.val[i].etype) {
 767                 krb5_salt salt;
 768                 salt.salttype = KRB5_PW_SALT;
 769                 if (e.val[i].salt == NULL)
 770                     ret = krb5_get_pw_salt(context, client, &salt);
 771                 else {
 772                     salt.saltvalue = *e.val[i].salt;
 773                     ret = 0;
 774                 }
 775                 if (e.val[i].salttype)
 776                     salt.salttype = *e.val[i].salttype;
 777                 if (ret == 0) {
 778                     ret = set_paid(paid, context, e.val[i].etype,
 779                                    salt.salttype,
 780                                    salt.saltvalue.data,
 781                                    salt.saltvalue.length,
 782                                    NULL);
 783                     if (e.val[i].salt == NULL)
 784                         krb5_free_salt(context, salt);
 785                 }
 786                 if (ret == 0) {
 787                     free_ETYPE_INFO(&e);
 788                     return paid;
 789                 }
 790             }
 791         }
 792     }
 793  out:
 794     free_ETYPE_INFO(&e);
 795     return NULL;
 796 }
 797 
 798 static struct pa_info_data *
 799 pa_pw_or_afs3_salt(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 800                    const krb5_principal client,
 801                    const AS_REQ *asreq,
 802                    struct pa_info_data *paid,
 803                    heim_octet_string *data)
 804 {
 805     krb5_error_code ret;
 806     if (paid->etype == ENCTYPE_NULL)
 807         return NULL;
 808     ret = set_paid(paid, context,
 809                    paid->etype,
 810                    paid->salt.salttype,
 811                    data->data,
 812                    data->length,
 813                    NULL);
 814     if (ret)
 815         return NULL;
 816     return paid;
 817 }
 818 
 819 
 820 struct pa_info {
 821     krb5_preauthtype type;
 822     struct pa_info_data *(*salt_info)(krb5_context,
 823                                       const krb5_principal,
 824                                       const AS_REQ *,
 825                                       struct pa_info_data *,
 826                                       heim_octet_string *);
 827 };
 828 
 829 static struct pa_info pa_prefs[] = {
 830     { KRB5_PADATA_ETYPE_INFO2, pa_etype_info2 },
 831     { KRB5_PADATA_ETYPE_INFO, pa_etype_info },
 832     { KRB5_PADATA_PW_SALT, pa_pw_or_afs3_salt },
 833     { KRB5_PADATA_AFS3_SALT, pa_pw_or_afs3_salt }
 834 };
 835 
 836 static PA_DATA *
 837 find_pa_data(const METHOD_DATA *md, int type)
     /* [<][>][^][v][top][bottom][index][help] */
 838 {
 839     int i;
 840     if (md == NULL)
 841         return NULL;
 842     for (i = 0; i < md->len; i++)
 843         if (md->val[i].padata_type == type)
 844             return &md->val[i];
 845     return NULL;
 846 }
 847 
 848 static struct pa_info_data *
 849 process_pa_info(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 850                 const krb5_principal client,
 851                 const AS_REQ *asreq,
 852                 struct pa_info_data *paid,
 853                 METHOD_DATA *md)
 854 {
 855     struct pa_info_data *p = NULL;
 856     int i;
 857 
 858     for (i = 0; p == NULL && i < sizeof(pa_prefs)/sizeof(pa_prefs[0]); i++) {
 859         PA_DATA *pa = find_pa_data(md, pa_prefs[i].type);
 860         if (pa == NULL)
 861             continue;
 862         paid->salt.salttype = pa_prefs[i].type;
 863         p = (*pa_prefs[i].salt_info)(context, client, asreq,
 864                                      paid, &pa->padata_value);
 865     }
 866     return p;
 867 }
 868 
 869 static krb5_error_code
 870 make_pa_enc_timestamp(krb5_context context, METHOD_DATA *md,
     /* [<][>][^][v][top][bottom][index][help] */
 871                       krb5_enctype etype, krb5_keyblock *key)
 872 {
 873     PA_ENC_TS_ENC p;
 874     unsigned char *buf;
 875     size_t buf_size;
 876     size_t len;
 877     EncryptedData encdata;
 878     krb5_error_code ret;
 879     int32_t usec;
 880     int usec2;
 881     krb5_crypto crypto;
 882 
 883     krb5_us_timeofday (context, &p.patimestamp, &usec);
 884     usec2         = usec;
 885     p.pausec      = &usec2;
 886 
 887     ASN1_MALLOC_ENCODE(PA_ENC_TS_ENC, buf, buf_size, &p, &len, ret);
 888     if (ret)
 889         return ret;
 890     if(buf_size != len)
 891         krb5_abortx(context, "internal error in ASN.1 encoder");
 892 
 893     ret = krb5_crypto_init(context, key, 0, &crypto);
 894     if (ret) {
 895         free(buf);
 896         return ret;
 897     }
 898     ret = krb5_encrypt_EncryptedData(context,
 899                                      crypto,
 900                                      KRB5_KU_PA_ENC_TIMESTAMP,
 901                                      buf,
 902                                      len,
 903                                      0,
 904                                      &encdata);
 905     free(buf);
 906     krb5_crypto_destroy(context, crypto);
 907     if (ret)
 908         return ret;
 909                 
 910     ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_size, &encdata, &len, ret);
 911     free_EncryptedData(&encdata);
 912     if (ret)
 913         return ret;
 914     if(buf_size != len)
 915         krb5_abortx(context, "internal error in ASN.1 encoder");
 916 
 917     ret = krb5_padata_add(context, md, KRB5_PADATA_ENC_TIMESTAMP, buf, len);
 918     if (ret)
 919         free(buf);
 920     return ret;
 921 }
 922 
 923 static krb5_error_code
 924 add_enc_ts_padata(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 925                   METHOD_DATA *md,
 926                   krb5_principal client,
 927                   krb5_s2k_proc key_proc,
 928                   krb5_const_pointer keyseed,
 929                   krb5_enctype *enctypes,
 930                   unsigned netypes,
 931                   krb5_salt *salt,
 932                   krb5_data *s2kparams)
 933 {
 934     krb5_error_code ret;
 935     krb5_salt salt2;
 936     krb5_enctype *ep;
 937     int i;
 938 
 939     if(salt == NULL) {
 940         /* default to standard salt */
 941         ret = krb5_get_pw_salt (context, client, &salt2);
 942         salt = &salt2;
 943     }
 944     if (!enctypes) {
 945         enctypes = context->etypes;
 946         netypes = 0;
 947         for (ep = enctypes; *ep != ETYPE_NULL; ep++)
 948             netypes++;
 949     }
 950 
 951     for (i = 0; i < netypes; ++i) {
 952         krb5_keyblock *key;
 953 
 954         ret = (*key_proc)(context, enctypes[i], keyseed,
 955                           *salt, s2kparams, &key);
 956         if (ret)
 957             continue;
 958         ret = make_pa_enc_timestamp (context, md, enctypes[i], key);
 959         krb5_free_keyblock (context, key);
 960         if (ret)
 961             return ret;
 962     }
 963     if(salt == &salt2)
 964         krb5_free_salt(context, salt2);
 965     return 0;
 966 }
 967 
 968 static krb5_error_code
 969 pa_data_to_md_ts_enc(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 970                      const AS_REQ *a,
 971                      const krb5_principal client,
 972                      krb5_get_init_creds_ctx *ctx,
 973                      struct pa_info_data *ppaid,
 974                      METHOD_DATA *md)
 975 {
 976     if (ctx->key_proc == NULL || ctx->password == NULL)
 977         return 0;
 978 
 979     if (ppaid) {
 980         add_enc_ts_padata(context, md, client,
 981                           ctx->key_proc, ctx->password,
 982                           &ppaid->etype, 1,
 983                           &ppaid->salt, ppaid->s2kparams);
 984     } else {
 985         krb5_salt salt;
 986         
 987         /* make a v5 salted pa-data */
 988         add_enc_ts_padata(context, md, client,
 989                           ctx->key_proc, ctx->password,
 990                           a->req_body.etype.val, a->req_body.etype.len,
 991                           NULL, NULL);
 992         
 993         /* make a v4 salted pa-data */
 994         salt.salttype = KRB5_PW_SALT;
 995         krb5_data_zero(&salt.saltvalue);
 996         add_enc_ts_padata(context, md, client,
 997                           ctx->key_proc, ctx->password,
 998                           a->req_body.etype.val, a->req_body.etype.len,
 999                           &salt, NULL);
1000     }
1001     return 0;
1002 }
1003 
1004 static krb5_error_code
1005 pa_data_to_key_plain(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
1006                      const krb5_principal client,
1007                      krb5_get_init_creds_ctx *ctx,
1008                      krb5_salt salt,
1009                      krb5_data *s2kparams,
1010                      krb5_enctype etype,
1011                      krb5_keyblock **key)
1012 {
1013     krb5_error_code ret;
1014 
1015     ret = (*ctx->key_proc)(context, etype, ctx->password,
1016                            salt, s2kparams, key);
1017     return ret;
1018 }
1019 
1020 
1021 static krb5_error_code
1022 pa_data_to_md_pkinit(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
1023                      const AS_REQ *a,
1024                      const krb5_principal client,
1025                      krb5_get_init_creds_ctx *ctx,
1026                      METHOD_DATA *md)
1027 {
1028     if (ctx->pk_init_ctx == NULL)
1029         return 0;
1030 #ifdef PKINIT
1031     return _krb5_pk_mk_padata(context,
1032                              ctx->pk_init_ctx,
1033                              &a->req_body,
1034                              ctx->pk_nonce,
1035                              md);
1036 #else
1037     krb5_set_error_message(context, EINVAL,
1038                            N_("no support for PKINIT compiled in", ""));
1039     return EINVAL;
1040 #endif
1041 }
1042 
1043 static krb5_error_code
1044 pa_data_add_pac_request(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
1045                         krb5_get_init_creds_ctx *ctx,
1046                         METHOD_DATA *md)
1047 {
1048     size_t len, length;
1049     krb5_error_code ret;
1050     PA_PAC_REQUEST req;
1051     void *buf;
1052 
1053     switch (ctx->req_pac) {
1054     case KRB5_INIT_CREDS_TRISTATE_UNSET:
1055         return 0; /* don't bother */
1056     case KRB5_INIT_CREDS_TRISTATE_TRUE:
1057         req.include_pac = 1;
1058         break;
1059     case KRB5_INIT_CREDS_TRISTATE_FALSE:
1060         req.include_pac = 0;
1061     }   
1062 
1063     ASN1_MALLOC_ENCODE(PA_PAC_REQUEST, buf, length,
1064                        &req, &len, ret);
1065     if (ret)
1066         return ret;
1067     if(len != length)
1068         krb5_abortx(context, "internal error in ASN.1 encoder");
1069 
1070     ret = krb5_padata_add(context, md, KRB5_PADATA_PA_PAC_REQUEST, buf, len);
1071     if (ret)
1072         free(buf);
1073 
1074     return 0;
1075 }
1076 
1077 /*
1078  * Assumes caller always will free `out_md', even on error.
1079  */
1080 
1081 static krb5_error_code
1082 process_pa_data_to_md(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
1083                       const krb5_creds *creds,
1084                       const AS_REQ *a,
1085                       krb5_get_init_creds_ctx *ctx,
1086                       METHOD_DATA *in_md,
1087                       METHOD_DATA **out_md,
1088                       krb5_prompter_fct prompter,
1089                       void *prompter_data)
1090 {
1091     krb5_error_code ret;
1092 
1093     ALLOC(*out_md, 1);
1094     if (*out_md == NULL) {
1095         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1096         return ENOMEM;
1097     }
1098     (*out_md)->len = 0;
1099     (*out_md)->val = NULL;
1100 
1101     /*
1102      * Make sure we don't sent both ENC-TS and PK-INIT pa data, no
1103      * need to expose our password protecting our PKCS12 key.
1104      */
1105 
1106     if (ctx->pk_init_ctx) {
1107 
1108         ret = pa_data_to_md_pkinit(context, a, creds->client, ctx, *out_md);
1109         if (ret)
1110             return ret;
1111 
1112     } else if (in_md->len != 0) {
1113         struct pa_info_data paid, *ppaid;
1114         
1115         memset(&paid, 0, sizeof(paid));
1116         
1117         paid.etype = ENCTYPE_NULL;
1118         ppaid = process_pa_info(context, creds->client, a, &paid, in_md);
1119         
1120         pa_data_to_md_ts_enc(context, a, creds->client, ctx, ppaid, *out_md);
1121         if (ppaid)
1122             free_paid(context, ppaid);
1123     }
1124 
1125     pa_data_add_pac_request(context, ctx, *out_md);
1126 
1127     if ((*out_md)->len == 0) {
1128         free(*out_md);
1129         *out_md = NULL;
1130     }
1131 
1132     return 0;
1133 }
1134 
1135 static krb5_error_code
1136 process_pa_data_to_key(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
1137                        krb5_get_init_creds_ctx *ctx,
1138                        krb5_creds *creds,
1139                        AS_REQ *a,
1140                        krb5_kdc_rep *rep,
1141                        const krb5_krbhst_info *hi,
1142                        krb5_keyblock **key)
1143 {
1144     struct pa_info_data paid, *ppaid = NULL;
1145     krb5_error_code ret;
1146     krb5_enctype etype;
1147     PA_DATA *pa;
1148 
1149     memset(&paid, 0, sizeof(paid));
1150 
1151     etype = rep->kdc_rep.enc_part.etype;
1152 
1153     if (rep->kdc_rep.padata) {
1154         paid.etype = etype;
1155         ppaid = process_pa_info(context, creds->client, a, &paid,
1156                                 rep->kdc_rep.padata);
1157     }
1158     if (ppaid == NULL) {
1159         ret = krb5_get_pw_salt (context, creds->client, &paid.salt);
1160         if (ret)
1161             return ret;
1162         paid.etype = etype;
1163         paid.s2kparams = NULL;
1164     }
1165 
1166     pa = NULL;
1167     if (rep->kdc_rep.padata) {
1168         int idx = 0;
1169         pa = krb5_find_padata(rep->kdc_rep.padata->val,
1170                               rep->kdc_rep.padata->len,
1171                               KRB5_PADATA_PK_AS_REP,
1172                               &idx);
1173         if (pa == NULL) {
1174             idx = 0;
1175             pa = krb5_find_padata(rep->kdc_rep.padata->val,
1176                                   rep->kdc_rep.padata->len,
1177                                   KRB5_PADATA_PK_AS_REP_19,
1178                                   &idx);
1179         }
1180     }
1181     if (pa && ctx->pk_init_ctx) {
1182 #ifdef PKINIT
1183         ret = _krb5_pk_rd_pa_reply(context,
1184                                    a->req_body.realm,
1185                                    ctx->pk_init_ctx,
1186                                    etype,
1187                                    hi,
1188                                    ctx->pk_nonce,
1189                                    &ctx->req_buffer,
1190                                    pa,
1191                                    key);
1192 #else
1193         ret = EINVAL;
1194         krb5_set_error_message(context, ret, N_("no support for PKINIT compiled in", ""));
1195 #endif
1196     } else if (ctx->password)
1197         ret = pa_data_to_key_plain(context, creds->client, ctx,
1198                                    paid.salt, paid.s2kparams, etype, key);
1199     else {
1200         ret = EINVAL;
1201         krb5_set_error_message(context, ret, N_("No usable pa data type", ""));
1202     }
1203 
1204     free_paid(context, &paid);
1205     return ret;
1206 }
1207 
1208 static krb5_error_code
1209 init_cred_loop(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
1210                krb5_get_init_creds_opt *init_cred_opts,
1211                const krb5_prompter_fct prompter,
1212                void *prompter_data,
1213                krb5_get_init_creds_ctx *ctx,
1214                krb5_creds *creds,
1215                krb5_kdc_rep *ret_as_reply)
1216 {
1217     krb5_error_code ret;
1218     krb5_kdc_rep rep;
1219     METHOD_DATA md;
1220     krb5_data resp;
1221     size_t len;
1222     size_t size;
1223     krb5_krbhst_info *hi = NULL;
1224     krb5_sendto_ctx stctx = NULL;
1225 
1226 
1227     memset(&md, 0, sizeof(md));
1228     memset(&rep, 0, sizeof(rep));
1229 
1230     _krb5_get_init_creds_opt_free_krb5_error(init_cred_opts);
1231 
1232     if (ret_as_reply)
1233         memset(ret_as_reply, 0, sizeof(*ret_as_reply));
1234 
1235     ret = init_creds_init_as_req(context, ctx->flags, creds,
1236                                  ctx->addrs, ctx->etypes, &ctx->as_req);
1237     if (ret)
1238         return ret;
1239 
1240     ret = krb5_sendto_ctx_alloc(context, &stctx);
1241     if (ret)
1242         goto out;
1243     krb5_sendto_ctx_set_func(stctx, _krb5_kdc_retry, NULL);
1244 
1245     /* Set a new nonce. */
1246     krb5_generate_random_block (&ctx->nonce, sizeof(ctx->nonce));
1247     ctx->nonce &= 0xffffffff;
1248     /* XXX these just needs to be the same when using Windows PK-INIT */
1249     ctx->pk_nonce = ctx->nonce;
1250 
1251     /*
1252      * Increase counter when we want other pre-auth types then
1253      * KRB5_PA_ENC_TIMESTAMP.
1254      */
1255 #define MAX_PA_COUNTER 3
1256 
1257     ctx->pa_counter = 0;
1258     while (ctx->pa_counter < MAX_PA_COUNTER) {
1259 
1260         ctx->pa_counter++;
1261 
1262         if (ctx->as_req.padata) {
1263             free_METHOD_DATA(ctx->as_req.padata);
1264             free(ctx->as_req.padata);
1265             ctx->as_req.padata = NULL;
1266         }
1267 
1268         /* Set a new nonce. */
1269         ctx->as_req.req_body.nonce = ctx->nonce;
1270 
1271         /* fill_in_md_data */
1272         ret = process_pa_data_to_md(context, creds, &ctx->as_req, ctx,
1273                                     &md, &ctx->as_req.padata,
1274                                     prompter, prompter_data);
1275         if (ret)
1276             goto out;
1277 
1278         krb5_data_free(&ctx->req_buffer);
1279 
1280         ASN1_MALLOC_ENCODE(AS_REQ,
1281                            ctx->req_buffer.data, ctx->req_buffer.length,
1282                            &ctx->as_req, &len, ret);
1283         if (ret)
1284             goto out;
1285         if(len != ctx->req_buffer.length)
1286             krb5_abortx(context, "internal error in ASN.1 encoder");
1287 
1288         ret = krb5_sendto_context (context, stctx, &ctx->req_buffer,
1289                                    creds->client->realm, &resp);
1290         if (ret)
1291             goto out;
1292 
1293         memset (&rep, 0, sizeof(rep));
1294         ret = decode_AS_REP(resp.data, resp.length, &rep.kdc_rep, &size);
1295         if (ret == 0) {
1296             krb5_data_free(&resp);
1297             krb5_clear_error_message(context);
1298             break;
1299         } else {
1300             /* let's try to parse it as a KRB-ERROR */
1301             KRB_ERROR error;
1302 
1303             ret = krb5_rd_error(context, &resp, &error);
1304             if(ret && resp.data && ((char*)resp.data)[0] == 4)
1305                 ret = KRB5KRB_AP_ERR_V4_REPLY;
1306             krb5_data_free(&resp);
1307             if (ret)
1308                 goto out;
1309 
1310             ret = krb5_error_from_rd_error(context, &error, creds);
1311 
1312             /*
1313              * If no preauth was set and KDC requires it, give it one
1314              * more try.
1315              */
1316 
1317             if (ret == KRB5KDC_ERR_PREAUTH_REQUIRED) {
1318                 free_METHOD_DATA(&md);
1319                 memset(&md, 0, sizeof(md));
1320 
1321                 if (error.e_data) {
1322                     ret = decode_METHOD_DATA(error.e_data->data,
1323                                              error.e_data->length,
1324                                              &md,
1325                                              NULL);
1326                     if (ret)
1327                         krb5_set_error_message(context, ret,
1328                                                N_("failed to decode METHOD DATA", ""));
1329                 } else {
1330                     /* XXX guess what the server want here add add md */
1331                 }
1332                 krb5_free_error_contents(context, &error);
1333                 if (ret)
1334                     goto out;
1335             } else {
1336                 _krb5_get_init_creds_opt_set_krb5_error(context,
1337                                                         init_cred_opts,
1338                                                         &error);
1339                 if (ret_as_reply)
1340                     rep.error = error;
1341                 else
1342                     krb5_free_error_contents(context, &error);
1343                 goto out;
1344             }
1345         }
1346     }
1347 
1348     {
1349         krb5_keyblock *key = NULL;
1350         unsigned flags = EXTRACT_TICKET_AS_REQ;
1351 
1352         if (ctx->flags.request_anonymous)
1353             flags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH;
1354         if (ctx->flags.canonicalize) {
1355             flags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH;
1356             flags |= EXTRACT_TICKET_MATCH_REALM;
1357         }
1358         if (ctx->ic_flags & KRB5_INIT_CREDS_NO_C_CANON_CHECK)
1359             flags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH;
1360 
1361         ret = process_pa_data_to_key(context, ctx, creds,
1362                                      &ctx->as_req, &rep, hi, &key);
1363         if (ret)
1364             goto out;
1365         
1366         ret = _krb5_extract_ticket(context,
1367                                    &rep,
1368                                    creds,
1369                                    key,
1370                                    NULL,
1371                                    KRB5_KU_AS_REP_ENC_PART,
1372                                    NULL,
1373                                    ctx->nonce,
1374                                    flags,
1375                                    NULL,
1376                                    NULL);
1377         krb5_free_keyblock(context, key);
1378     }
1379 out:
1380     if (stctx)
1381         krb5_sendto_ctx_free(context, stctx);
1382     krb5_data_free(&ctx->req_buffer);
1383     free_METHOD_DATA(&md);
1384     memset(&md, 0, sizeof(md));
1385 
1386     if (ret == 0 && ret_as_reply)
1387         *ret_as_reply = rep;
1388     else
1389         krb5_free_kdc_rep (context, &rep);
1390     return ret;
1391 }
1392 
1393 krb5_error_code KRB5_LIB_FUNCTION
1394 krb5_get_init_creds(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
1395                     krb5_creds *creds,
1396                     krb5_principal client,
1397                     krb5_prompter_fct prompter,
1398                     void *data,
1399                     krb5_deltat start_time,
1400                     const char *in_tkt_service,
1401                     krb5_get_init_creds_opt *options)
1402 {
1403     krb5_get_init_creds_ctx ctx;
1404     krb5_kdc_rep kdc_reply;
1405     krb5_error_code ret;
1406     char buf[BUFSIZ];
1407     int done;
1408 
1409     memset(&kdc_reply, 0, sizeof(kdc_reply));
1410 
1411     ret = get_init_creds_common(context, client, start_time,
1412                                 in_tkt_service, options, &ctx);
1413     if (ret)
1414         goto out;
1415 
1416     done = 0;
1417     while(!done) {
1418         memset(&kdc_reply, 0, sizeof(kdc_reply));
1419 
1420         ret = init_cred_loop(context,
1421                              options,
1422                              prompter,
1423                              data,
1424                              &ctx,
1425                              &ctx.cred,
1426                              &kdc_reply);
1427         
1428         switch (ret) {
1429         case 0 :
1430             done = 1;
1431             break;
1432         case KRB5KDC_ERR_KEY_EXPIRED :
1433             /* try to avoid recursion */
1434 
1435             /* don't try to change password where then where none */
1436             if (prompter == NULL || ctx.password == NULL)
1437                 goto out;
1438 
1439             krb5_clear_error_message (context);
1440 
1441             if (ctx.in_tkt_service != NULL
1442                 && strcmp (ctx.in_tkt_service, "kadmin/changepw") == 0)
1443                 goto out;
1444 
1445             ret = change_password (context,
1446                                    client,
1447                                    ctx.password,
1448                                    buf,
1449                                    sizeof(buf),
1450                                    prompter,
1451                                    data,
1452                                    options);
1453             if (ret)
1454                 goto out;
1455             ctx.password = buf;
1456             break;
1457         default:
1458             goto out;
1459         }
1460     }
1461 
1462     if (prompter)
1463         print_expire (context,
1464                       krb5_principal_get_realm (context, ctx.cred.client),
1465                       &kdc_reply,
1466                       prompter,
1467                       data);
1468 
1469  out:
1470     memset (buf, 0, sizeof(buf));
1471     free_init_creds_ctx(context, &ctx);
1472     krb5_free_kdc_rep (context, &kdc_reply);
1473     if (ret == 0)
1474         *creds = ctx.cred;
1475     else
1476         krb5_free_cred_contents (context, &ctx.cred);
1477 
1478     return ret;
1479 }
1480 
1481 krb5_error_code KRB5_LIB_FUNCTION
1482 krb5_get_init_creds_password(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
1483                              krb5_creds *creds,
1484                              krb5_principal client,
1485                              const char *password,
1486                              krb5_prompter_fct prompter,
1487                              void *data,
1488                              krb5_deltat start_time,
1489                              const char *in_tkt_service,
1490                              krb5_get_init_creds_opt *in_options)
1491 {
1492     krb5_get_init_creds_opt *options;
1493     char buf[BUFSIZ];
1494     krb5_error_code ret;
1495 
1496     if (in_options == NULL) {
1497         const char *realm = krb5_principal_get_realm(context, client);
1498         ret = krb5_get_init_creds_opt_alloc(context, &options);
1499         if (ret == 0)
1500             krb5_get_init_creds_opt_set_default_flags(context,
1501                                                       NULL,
1502                                                       realm,
1503                                                       options);
1504     } else
1505         ret = _krb5_get_init_creds_opt_copy(context, in_options, &options);
1506     if (ret)
1507         return ret;
1508 
1509     if (password == NULL &&
1510         options->opt_private->password == NULL &&
1511         options->opt_private->pk_init_ctx == NULL)
1512     {
1513         krb5_prompt prompt;
1514         krb5_data password_data;
1515         char *p, *q;
1516 
1517         krb5_unparse_name (context, client, &p);
1518         asprintf (&q, "%s's Password: ", p);
1519         free (p);
1520         prompt.prompt = q;
1521         password_data.data   = buf;
1522         password_data.length = sizeof(buf);
1523         prompt.hidden = 1;
1524         prompt.reply  = &password_data;
1525         prompt.type   = KRB5_PROMPT_TYPE_PASSWORD;
1526 
1527         ret = (*prompter) (context, data, NULL, NULL, 1, &prompt);
1528         free (q);
1529         if (ret) {
1530             memset (buf, 0, sizeof(buf));
1531             krb5_get_init_creds_opt_free(context, options);
1532             ret = KRB5_LIBOS_PWDINTR;
1533             krb5_clear_error_message (context);
1534             return ret;
1535         }
1536         password = password_data.data;
1537     }
1538 
1539     if (options->opt_private->password == NULL) {
1540         ret = krb5_get_init_creds_opt_set_pa_password(context, options,
1541                                                       password, NULL);
1542         if (ret) {
1543             krb5_get_init_creds_opt_free(context, options);
1544             memset(buf, 0, sizeof(buf));
1545             return ret;
1546         }
1547     }
1548 
1549     ret = krb5_get_init_creds(context, creds, client, prompter,
1550                               data, start_time, in_tkt_service, options);
1551     krb5_get_init_creds_opt_free(context, options);
1552     memset(buf, 0, sizeof(buf));
1553     return ret;
1554 }
1555 
1556 static krb5_error_code
1557 init_creds_keyblock_key_proc (krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
1558                               krb5_enctype type,
1559                               krb5_salt salt,
1560                               krb5_const_pointer keyseed,
1561                               krb5_keyblock **key)
1562 {
1563     return krb5_copy_keyblock (context, keyseed, key);
1564 }
1565 
1566 krb5_error_code KRB5_LIB_FUNCTION
1567 krb5_get_init_creds_keyblock(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
1568                              krb5_creds *creds,
1569                              krb5_principal client,
1570                              krb5_keyblock *keyblock,
1571                              krb5_deltat start_time,
1572                              const char *in_tkt_service,
1573                              krb5_get_init_creds_opt *options)
1574 {
1575     struct krb5_get_init_creds_ctx ctx;
1576     krb5_error_code ret;
1577 
1578     ret = get_init_creds_common(context, client, start_time,
1579                                 in_tkt_service, options, &ctx);
1580     if (ret)
1581         goto out;
1582 
1583     ret = krb5_get_in_cred (context,
1584                             KDCOptions2int(ctx.flags),
1585                             ctx.addrs,
1586                             ctx.etypes,
1587                             ctx.pre_auth_types,
1588                             NULL,
1589                             init_creds_keyblock_key_proc,
1590                             keyblock,
1591                             NULL,
1592                             NULL,
1593                             &ctx.cred,
1594                             NULL);
1595 
1596     if (ret == 0 && creds)
1597         *creds = ctx.cred;
1598     else
1599         krb5_free_cred_contents (context, &ctx.cred);
1600 
1601  out:
1602     free_init_creds_ctx(context, &ctx);
1603     return ret;
1604 }

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