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