1/* 2 * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Portions Copyright (c) 2009 - 2010 Apple Inc. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36#include "krb5_locl.h" 37 38struct pa_info_data { 39 krb5_enctype etype; 40 krb5_salt salt; 41 krb5_data *s2kparams; 42}; 43 44struct krb5_init_creds_context_data { 45 KDCOptions flags; 46 krb5_creds cred; 47 krb5_addresses *addrs; 48 krb5_enctype *etypes; 49 krb5_preauthtype *pre_auth_types; 50 char *in_tkt_service; 51 unsigned nonce; 52 unsigned pk_nonce; 53 54 krb5_data req_buffer; 55 AS_REQ as_req; 56 int pa_counter; 57 58 /* password and keytab_data is freed on completion */ 59 char *password; 60 krb5_keytab_key_proc_args *keytab_data; 61 62 krb5_pointer *keyseed; 63 krb5_s2k_proc keyproc; 64 65 krb5_get_init_creds_tristate req_pac; 66 67 krb5_pk_init_ctx pk_init_ctx; 68 int ic_flags; 69 70 char *kdc_hostname; 71 72 int used_pa_types; 73#define USED_PKINIT 1 74#define USED_PKINIT_W2K 2 75#define USED_ENC_TS_GUESS 4 76#define USED_ENC_TS_INFO 8 77#define USED_ENC_TS_RENEG 16 78 int change_password; 79 80 struct pa_info_data paid; 81 82 METHOD_DATA md; 83 KRB_ERROR error; 84 AS_REP as_rep; 85 EncKDCRepPart enc_part; 86 87 krb5_prompter_fct prompter; 88 void *prompter_data; 89 int warned_user; 90 91 struct pa_info_data *ppaid; 92 93 struct fast_state { 94 enum PA_FX_FAST_REQUEST_enum type; 95 unsigned int flags; 96#define KRB5_FAST_REPLY_KEY_USE_TO_ENCRYPT_THE_REPLY 1 97#define KRB5_FAST_REPLY_KEY_USE_IN_TRANSACTION 2 98#define KRB5_FAST_KDC_REPLY_KEY_REPLACED 4 99#define KRB5_FAST_REPLY_REPLY_VERIFED 8 100#define KRB5_FAST_STRONG 16 101#define KRB5_FAST_EXPECTED 32 /* in exchange with KDC, fast was discovered */ 102#define KRB5_FAST_REQUIRED 64 /* fast required by action of caller */ 103#define KRB5_FAST_DISABLED 128 104 105#define KRB5_FAST_OPTIMISTIC 512 /* Optimistic try, like Anon + PKINIT or service fast bit */ 106#define KRB5_FAST_REQUIRE_ENC_PA 1024 107 108 krb5_keyblock *reply_key; 109 krb5_ccache armor_ccache; 110 krb5_crypto armor_crypto; 111 krb5_keyblock armor_key; 112 } fast_state; 113 114#ifdef PKINIT 115 hx509_cert client_cert; 116 krb5_data *pku2u_assertion; 117#endif 118 119 struct { 120 struct timeval run_time; 121 } stats; 122}; 123 124static void 125free_paid(krb5_context context, struct pa_info_data *ppaid) 126{ 127 krb5_free_salt(context, ppaid->salt); 128 if (ppaid->s2kparams) 129 krb5_free_data(context, ppaid->s2kparams); 130 memset(ppaid, 0, sizeof(*ppaid)); 131} 132 133static krb5_error_code KRB5_CALLCONV 134default_s2k_func(krb5_context context, krb5_enctype type, 135 krb5_const_pointer keyseed, 136 krb5_salt salt, krb5_data *s2kparms, 137 krb5_keyblock **key) 138{ 139 krb5_error_code ret; 140 krb5_data password; 141 krb5_data opaque; 142 143 _krb5_debugx(context, 5, "krb5_get_init_creds: using default_s2k_func"); 144 145 password.data = rk_UNCONST(keyseed); 146 password.length = strlen(keyseed); 147 if (s2kparms) 148 opaque = *s2kparms; 149 else 150 krb5_data_zero(&opaque); 151 152 *key = malloc(sizeof(**key)); 153 if (*key == NULL) 154 return ENOMEM; 155 ret = krb5_string_to_key_data_salt_opaque(context, type, password, 156 salt, opaque, *key); 157 if (ret) { 158 free(*key); 159 *key = NULL; 160 } 161 return ret; 162} 163 164static void 165free_init_creds_ctx(krb5_context context, krb5_init_creds_context ctx) 166{ 167 if (ctx->etypes) 168 free(ctx->etypes); 169 if (ctx->pre_auth_types) 170 free (ctx->pre_auth_types); 171 if (ctx->in_tkt_service) 172 free(ctx->in_tkt_service); 173 if (ctx->keytab_data) 174 free(ctx->keytab_data); 175 if (ctx->password) { 176 memset(ctx->password, 0, strlen(ctx->password)); 177 free(ctx->password); 178 } 179 /* 180 * FAST state 181 */ 182 if (ctx->fast_state.armor_ccache) 183 krb5_cc_close(context, ctx->fast_state.armor_ccache); 184 if (ctx->fast_state.armor_crypto) 185 krb5_crypto_destroy(context, ctx->fast_state.armor_crypto); 186 krb5_free_keyblock_contents(context, &ctx->fast_state.armor_key); 187 188 krb5_data_free(&ctx->req_buffer); 189 krb5_free_cred_contents(context, &ctx->cred); 190 free_METHOD_DATA(&ctx->md); 191 free_AS_REP(&ctx->as_rep); 192 free_EncKDCRepPart(&ctx->enc_part); 193 free_KRB_ERROR(&ctx->error); 194 free_AS_REQ(&ctx->as_req); 195 196#ifdef PKINIT 197 if (ctx->client_cert) 198 hx509_cert_free(ctx->client_cert); 199 if (ctx->pku2u_assertion) 200 krb5_free_data(context, ctx->pku2u_assertion); 201#endif 202 if (ctx->kdc_hostname) 203 free(ctx->kdc_hostname); 204 free_paid(context, &ctx->paid); 205 memset(ctx, 0, sizeof(*ctx)); 206} 207 208static krb5_deltat 209get_config_time (krb5_context context, 210 const char *realm, 211 const char *name, 212 int def) 213{ 214 krb5_deltat ret; 215 216 ret = krb5_config_get_time (context, NULL, 217 "realms", 218 realm, 219 name, 220 NULL); 221 if (ret >= 0) 222 return ret; 223 ret = krb5_config_get_time (context, NULL, 224 "libdefaults", 225 name, 226 NULL); 227 if (ret >= 0) 228 return ret; 229 return def; 230} 231 232static krb5_error_code 233init_cred (krb5_context context, 234 krb5_creds *cred, 235 krb5_principal client, 236 krb5_deltat start_time, 237 krb5_get_init_creds_opt *options) 238{ 239 krb5_error_code ret; 240 krb5_deltat tmp; 241 krb5_timestamp now; 242 243 krb5_timeofday (context, &now); 244 245 memset (cred, 0, sizeof(*cred)); 246 247 if (client) 248 krb5_copy_principal(context, client, &cred->client); 249 else { 250 ret = krb5_get_default_principal (context, 251 &cred->client); 252 if (ret) 253 goto out; 254 } 255 256 if (start_time) 257 cred->times.starttime = now + start_time; 258 259 if (options->flags & KRB5_GET_INIT_CREDS_OPT_TKT_LIFE) 260 tmp = options->tkt_life; 261 else 262 tmp = 10 * 60 * 60; 263 cred->times.endtime = now + tmp; 264 265 if ((options->flags & KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE) && 266 options->renew_life > 0) { 267 cred->times.renew_till = now + options->renew_life; 268 } 269 270 return 0; 271 272out: 273 krb5_free_cred_contents (context, cred); 274 return ret; 275} 276 277/* 278 * Print a message (str) to the user about the expiration in `lr' 279 */ 280 281static void 282report_expiration (krb5_context context, 283 krb5_prompter_fct prompter, 284 krb5_data *data, 285 const char *str, 286 time_t now) 287{ 288 char *p = NULL; 289 290 if (asprintf(&p, "%s%s", str, ctime(&now)) < 0 || p == NULL) 291 return; 292 (*prompter)(context, data, NULL, p, 0, NULL); 293 free(p); 294} 295 296/* 297 * Check the context, and in the case there is a expiration warning, 298 * use the prompter to print the warning. 299 * 300 * @param context A Kerberos 5 context. 301 * @param options An GIC options structure 302 * @param ctx The krb5_init_creds_context check for expiration. 303 */ 304 305krb5_error_code 306krb5_process_last_request(krb5_context context, 307 krb5_get_init_creds_opt *options, 308 krb5_init_creds_context ctx) 309{ 310 LastReq *lr; 311 size_t i; 312 313 /* 314 * First check if there is a API consumer. 315 */ 316 317 lr = &ctx->enc_part.last_req; 318 319 if (options && options->opt_private && options->opt_private->lr.func) { 320 krb5_last_req_entry **lre; 321 322 lre = calloc(lr->len + 1, sizeof(*lre)); 323 if (lre == NULL) { 324 krb5_set_error_message(context, ENOMEM, 325 N_("malloc: out of memory", "")); 326 return ENOMEM; 327 } 328 for (i = 0; i < lr->len; i++) { 329 lre[i] = calloc(1, sizeof(*lre[i])); 330 if (lre[i] == NULL) 331 break; 332 lre[i]->lr_type = lr->val[i].lr_type; 333 lre[i]->value = lr->val[i].lr_value; 334 } 335 336 (*options->opt_private->lr.func)(context, lre, 337 options->opt_private->lr.ctx); 338 339 for (i = 0; i < lr->len; i++) 340 free(lre[i]); 341 free(lre); 342 } 343 344 return krb5_init_creds_warn_user(context, ctx); 345} 346 347/** 348 * Warn the user using prompter in the krb5_init_creds_context about 349 * possible password and account expiration. 350 * 351 * @param context a Kerberos 5 context. 352 * @param ctx a krb5_init_creds_context context. 353 * 354 * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message(). 355 * @ingroup krb5_credential 356 */ 357 358KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 359krb5_init_creds_warn_user(krb5_context context, 360 krb5_init_creds_context ctx) 361{ 362 krb5_timestamp sec; 363 krb5_const_realm realm; 364 LastReq *lr; 365 time_t t, i; 366 367 if (ctx->prompter == NULL) 368 return 0; 369 370 if (ctx->warned_user) 371 return 0; 372 373 ctx->warned_user = 1; 374 375 krb5_timeofday (context, &sec); 376 377 realm = krb5_principal_get_realm (context, ctx->cred.client); 378 lr = &ctx->enc_part.last_req; 379 380 t = sec + get_config_time (context, 381 realm, 382 "warn_pwexpire", 383 7 * 24 * 60 * 60); 384 385 for (i = 0; i < lr->len; ++i) { 386 if (lr->val[i].lr_value <= t) { 387 switch (abs(lr->val[i].lr_type)) { 388 case LR_PW_EXPTIME : 389 report_expiration(context, ctx->prompter, 390 ctx->prompter_data, 391 "Your password will expire at ", 392 lr->val[i].lr_value); 393 break; 394 case LR_ACCT_EXPTIME : 395 report_expiration(context, ctx->prompter, 396 ctx->prompter_data, 397 "Your account will expire at ", 398 lr->val[i].lr_value); 399 break; 400 } 401 } 402 } 403 404 return 0; 405} 406 407static krb5_addresses no_addrs = { 0, NULL }; 408 409static krb5_error_code 410get_init_creds_common(krb5_context context, 411 krb5_principal client, 412 krb5_deltat start_time, 413 krb5_get_init_creds_opt *options, 414 krb5_init_creds_context ctx) 415{ 416 krb5_get_init_creds_opt *default_opt = NULL; 417 krb5_error_code ret; 418 krb5_enctype *etypes; 419 krb5_preauthtype *pre_auth_types; 420 421 memset(ctx, 0, sizeof(*ctx)); 422 423 if (options == NULL) { 424 const char *realm = krb5_principal_get_realm(context, client); 425 426 krb5_get_init_creds_opt_alloc (context, &default_opt); 427 options = default_opt; 428 krb5_get_init_creds_opt_set_default_flags(context, NULL, realm, options); 429 } 430 431 if (options->opt_private) { 432 if (options->opt_private->password) { 433 ret = krb5_init_creds_set_password(context, ctx, 434 options->opt_private->password); 435 if (ret) 436 goto out; 437 } 438 439 ctx->keyproc = options->opt_private->key_proc; 440 ctx->req_pac = options->opt_private->req_pac; 441 ctx->pk_init_ctx = options->opt_private->pk_init_ctx; 442 ctx->ic_flags = options->opt_private->flags; 443 } else 444 ctx->req_pac = KRB5_INIT_CREDS_TRISTATE_UNSET; 445 446 if (ctx->keyproc == NULL) 447 ctx->keyproc = default_s2k_func; 448 449 /* Enterprise name implicitly turns on canonicalize */ 450 if ((ctx->ic_flags & KRB5_INIT_CREDS_CANONICALIZE) || 451 krb5_principal_get_type(context, client) == KRB5_NT_ENTERPRISE_PRINCIPAL) 452 ctx->flags.canonicalize = 1; 453 454 ctx->pre_auth_types = NULL; 455 ctx->addrs = NULL; 456 ctx->etypes = NULL; 457 ctx->pre_auth_types = NULL; 458 459 ret = init_cred(context, &ctx->cred, client, start_time, options); 460 if (ret) { 461 if (default_opt) 462 krb5_get_init_creds_opt_free(context, default_opt); 463 return ret; 464 } 465 466 ret = krb5_init_creds_set_service(context, ctx, NULL); 467 if (ret) 468 goto out; 469 470 if (options->flags & KRB5_GET_INIT_CREDS_OPT_FORWARDABLE) 471 ctx->flags.forwardable = options->forwardable; 472 473 if (options->flags & KRB5_GET_INIT_CREDS_OPT_PROXIABLE) 474 ctx->flags.proxiable = options->proxiable; 475 476 if (start_time) 477 ctx->flags.postdated = 1; 478 if (ctx->cred.times.renew_till) 479 ctx->flags.renewable = 1; 480 if (options->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST) { 481 ctx->addrs = options->address_list; 482 } else if (options->opt_private) { 483 switch (options->opt_private->addressless) { 484 case KRB5_INIT_CREDS_TRISTATE_UNSET: 485#if KRB5_ADDRESSLESS_DEFAULT == TRUE 486 ctx->addrs = &no_addrs; 487#else 488 ctx->addrs = NULL; 489#endif 490 break; 491 case KRB5_INIT_CREDS_TRISTATE_FALSE: 492 ctx->addrs = NULL; 493 break; 494 case KRB5_INIT_CREDS_TRISTATE_TRUE: 495 ctx->addrs = &no_addrs; 496 break; 497 } 498 } 499 if (options->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST) { 500 if (ctx->etypes) 501 free(ctx->etypes); 502 503 etypes = malloc((options->etype_list_length + 1) 504 * sizeof(krb5_enctype)); 505 if (etypes == NULL) { 506 ret = ENOMEM; 507 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 508 goto out; 509 } 510 memcpy (etypes, options->etype_list, 511 options->etype_list_length * sizeof(krb5_enctype)); 512 etypes[options->etype_list_length] = ETYPE_NULL; 513 ctx->etypes = etypes; 514 } 515 if (options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST) { 516 pre_auth_types = malloc((options->preauth_list_length + 1) 517 * sizeof(krb5_preauthtype)); 518 if (pre_auth_types == NULL) { 519 ret = ENOMEM; 520 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 521 goto out; 522 } 523 memcpy (pre_auth_types, options->preauth_list, 524 options->preauth_list_length * sizeof(krb5_preauthtype)); 525 pre_auth_types[options->preauth_list_length] = KRB5_PADATA_NONE; 526 ctx->pre_auth_types = pre_auth_types; 527 } 528 if (options->flags & KRB5_GET_INIT_CREDS_OPT_ANONYMOUS) 529 ctx->flags.request_anonymous = options->anonymous; 530 if (default_opt) 531 krb5_get_init_creds_opt_free(context, default_opt); 532 533 return 0; 534 out: 535 if (default_opt) 536 krb5_get_init_creds_opt_free(context, default_opt); 537 return ret; 538} 539 540static krb5_error_code 541change_password (krb5_context context, 542 krb5_principal client, 543 const char *password, 544 char *newpw, 545 size_t newpw_sz, 546 krb5_prompter_fct prompter, 547 void *data, 548 krb5_get_init_creds_opt *old_options) 549{ 550 krb5_prompt prompts[2]; 551 krb5_error_code ret; 552 krb5_creds cpw_cred; 553 char buf1[BUFSIZ], buf2[BUFSIZ]; 554 krb5_data password_data[2]; 555 int result_code; 556 krb5_data result_code_string; 557 krb5_data result_string; 558 char *p; 559 krb5_get_init_creds_opt *options; 560 561 memset (&cpw_cred, 0, sizeof(cpw_cred)); 562 563 ret = krb5_get_init_creds_opt_alloc(context, &options); 564 if (ret) 565 return ret; 566 krb5_get_init_creds_opt_set_tkt_life (options, 60); 567 krb5_get_init_creds_opt_set_forwardable (options, FALSE); 568 krb5_get_init_creds_opt_set_proxiable (options, FALSE); 569 if (old_options && old_options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST) 570 krb5_get_init_creds_opt_set_preauth_list (options, 571 old_options->preauth_list, 572 old_options->preauth_list_length); 573 574 krb5_data_zero (&result_code_string); 575 krb5_data_zero (&result_string); 576 577 ret = krb5_get_init_creds_password (context, 578 &cpw_cred, 579 client, 580 password, 581 prompter, 582 data, 583 0, 584 "kadmin/changepw", 585 options); 586 krb5_get_init_creds_opt_free(context, options); 587 if (ret) 588 goto out; 589 590 for(;;) { 591 password_data[0].data = buf1; 592 password_data[0].length = sizeof(buf1); 593 594 prompts[0].hidden = 1; 595 prompts[0].prompt = "New password: "; 596 prompts[0].reply = &password_data[0]; 597 prompts[0].type = KRB5_PROMPT_TYPE_NEW_PASSWORD; 598 599 password_data[1].data = buf2; 600 password_data[1].length = sizeof(buf2); 601 602 prompts[1].hidden = 1; 603 prompts[1].prompt = "Repeat new password: "; 604 prompts[1].reply = &password_data[1]; 605 prompts[1].type = KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN; 606 607 ret = (*prompter) (context, data, NULL, "Changing password", 608 2, prompts); 609 if (ret) { 610 ret = KRB5_LIBOS_PWDINTR; 611 memset (buf1, 0, sizeof(buf1)); 612 memset (buf2, 0, sizeof(buf2)); 613 goto out; 614 } 615 616 if (strcmp (buf1, buf2) == 0) 617 break; 618 memset (buf1, 0, sizeof(buf1)); 619 memset (buf2, 0, sizeof(buf2)); 620 } 621 622 ret = krb5_set_password (context, 623 &cpw_cred, 624 buf1, 625 NULL, 626 &result_code, 627 &result_code_string, 628 &result_string); 629 if (ret) 630 goto out; 631 632 if (result_code == 0) { 633 p = strdup("Success"); 634 } else if (asprintf(&p, "Failed: %.*s %.*s: %d\n", 635 (int)result_code_string.length, 636 result_code_string.length > 0 ? (char*)result_code_string.data : "", 637 (int)result_string.length, 638 result_string.length > 0 ? (char*)result_string.data : "", 639 result_code) < 0) 640 { 641 ret = ENOMEM; 642 goto out; 643 } 644 645 /* return the result */ 646 (*prompter) (context, data, NULL, p, 0, NULL); 647 648 if (result_code == 0) { 649 strlcpy (newpw, buf1, newpw_sz); 650 ret = 0; 651 } else { 652 ret = ENOTTY; 653 krb5_set_error_message(context, ret, 654 N_("failed changing password: %s", ""), p); 655 } 656 free (p); 657 658out: 659 memset (buf1, 0, sizeof(buf1)); 660 memset (buf2, 0, sizeof(buf2)); 661 krb5_data_free (&result_string); 662 krb5_data_free (&result_code_string); 663 krb5_free_cred_contents (context, &cpw_cred); 664 return ret; 665} 666 667 668KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 669krb5_keyblock_key_proc (krb5_context context, 670 krb5_keytype type, 671 krb5_data *salt, 672 krb5_const_pointer keyseed, 673 krb5_keyblock **key) 674{ 675 return krb5_copy_keyblock (context, keyseed, key); 676} 677 678/* 679 * 680 */ 681 682static krb5_error_code 683init_as_req (krb5_context context, 684 KDCOptions opts, 685 const krb5_creds *creds, 686 const krb5_addresses *addrs, 687 const krb5_enctype *etypes, 688 AS_REQ *a) 689{ 690 krb5_error_code ret; 691 692 memset(a, 0, sizeof(*a)); 693 694 a->pvno = 5; 695 a->msg_type = krb_as_req; 696 a->req_body.kdc_options = opts; 697 a->req_body.cname = malloc(sizeof(*a->req_body.cname)); 698 if (a->req_body.cname == NULL) { 699 ret = ENOMEM; 700 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 701 goto fail; 702 } 703 a->req_body.sname = calloc(1, sizeof(*a->req_body.sname)); 704 if (a->req_body.sname == NULL) { 705 ret = ENOMEM; 706 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 707 goto fail; 708 } 709 710 ret = _krb5_principal2principalname (a->req_body.cname, creds->client); 711 if (ret) 712 goto fail; 713 ret = copy_Realm(&creds->client->realm, &a->req_body.realm); 714 if (ret) 715 goto fail; 716 717 ret = _krb5_principal2principalname (a->req_body.sname, creds->server); 718 if (ret) 719 goto fail; 720 721 if(creds->times.starttime) { 722 a->req_body.from = malloc(sizeof(*a->req_body.from)); 723 if (a->req_body.from == NULL) { 724 ret = ENOMEM; 725 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 726 goto fail; 727 } 728 *a->req_body.from = creds->times.starttime; 729 } 730 if(creds->times.endtime){ 731 ALLOC(a->req_body.till, 1); 732 *a->req_body.till = creds->times.endtime; 733 } 734 if(creds->times.renew_till){ 735 a->req_body.rtime = malloc(sizeof(*a->req_body.rtime)); 736 if (a->req_body.rtime == NULL) { 737 ret = ENOMEM; 738 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 739 goto fail; 740 } 741 *a->req_body.rtime = creds->times.renew_till; 742 } 743 a->req_body.nonce = 0; 744 ret = _krb5_init_etype(context, 745 KRB5_PDU_AS_REQUEST, 746 &a->req_body.etype.len, 747 &a->req_body.etype.val, 748 etypes); 749 if (ret) 750 goto fail; 751 752 /* 753 * This means no addresses 754 */ 755 756 if (addrs && addrs->len == 0) { 757 a->req_body.addresses = NULL; 758 } else { 759 a->req_body.addresses = malloc(sizeof(*a->req_body.addresses)); 760 if (a->req_body.addresses == NULL) { 761 ret = ENOMEM; 762 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 763 goto fail; 764 } 765 766 if (addrs) 767 ret = krb5_copy_addresses(context, addrs, a->req_body.addresses); 768 else { 769 ret = krb5_get_all_client_addrs (context, a->req_body.addresses); 770 if(ret == 0 && a->req_body.addresses->len == 0) { 771 free(a->req_body.addresses); 772 a->req_body.addresses = NULL; 773 } 774 } 775 if (ret) 776 goto fail; 777 } 778 779 a->req_body.enc_authorization_data = NULL; 780 a->req_body.additional_tickets = NULL; 781 782 a->padata = NULL; 783 784 return 0; 785 fail: 786 free_AS_REQ(a); 787 memset(a, 0, sizeof(*a)); 788 return ret; 789} 790 791static krb5_error_code 792set_paid(struct pa_info_data *paid, krb5_context context, 793 krb5_enctype etype, 794 krb5_salttype salttype, void *salt_string, size_t salt_len, 795 krb5_data *s2kparams) 796{ 797 paid->etype = etype; 798 paid->salt.salttype = salttype; 799 paid->salt.saltvalue.data = malloc(salt_len + 1); 800 if (paid->salt.saltvalue.data == NULL) { 801 krb5_clear_error_message(context); 802 return ENOMEM; 803 } 804 memcpy(paid->salt.saltvalue.data, salt_string, salt_len); 805 ((char *)paid->salt.saltvalue.data)[salt_len] = '\0'; 806 paid->salt.saltvalue.length = salt_len; 807 if (s2kparams) { 808 krb5_error_code ret; 809 810 ret = krb5_copy_data(context, s2kparams, &paid->s2kparams); 811 if (ret) { 812 krb5_clear_error_message(context); 813 krb5_free_salt(context, paid->salt); 814 return ret; 815 } 816 } else 817 paid->s2kparams = NULL; 818 819 return 0; 820} 821 822static struct pa_info_data * 823pa_etype_info2(krb5_context context, 824 const krb5_principal client, 825 const AS_REQ *asreq, 826 struct pa_info_data *paid, 827 heim_octet_string *data) 828{ 829 krb5_error_code ret; 830 ETYPE_INFO2 e; 831 size_t sz; 832 size_t i, j; 833 834 memset(&e, 0, sizeof(e)); 835 ret = decode_ETYPE_INFO2(data->data, data->length, &e, &sz); 836 if (ret) 837 goto out; 838 if (e.len == 0) 839 goto out; 840 for (j = 0; j < asreq->req_body.etype.len; j++) { 841 for (i = 0; i < e.len; i++) { 842 if (asreq->req_body.etype.val[j] == e.val[i].etype) { 843 krb5_salt salt; 844 if (e.val[i].salt == NULL) 845 ret = krb5_get_pw_salt(context, client, &salt); 846 else { 847 salt.saltvalue.data = *e.val[i].salt; 848 salt.saltvalue.length = strlen(*e.val[i].salt); 849 ret = 0; 850 } 851 if (ret == 0) 852 ret = set_paid(paid, context, e.val[i].etype, 853 KRB5_PW_SALT, 854 salt.saltvalue.data, 855 salt.saltvalue.length, 856 e.val[i].s2kparams); 857 if (e.val[i].salt == NULL) 858 krb5_free_salt(context, salt); 859 if (ret == 0) { 860 free_ETYPE_INFO2(&e); 861 return paid; 862 } 863 } 864 } 865 } 866 out: 867 free_ETYPE_INFO2(&e); 868 return NULL; 869} 870 871static struct pa_info_data * 872pa_etype_info(krb5_context context, 873 const krb5_principal client, 874 const AS_REQ *asreq, 875 struct pa_info_data *paid, 876 heim_octet_string *data) 877{ 878 krb5_error_code ret; 879 ETYPE_INFO e; 880 size_t sz; 881 size_t i, j; 882 883 memset(&e, 0, sizeof(e)); 884 ret = decode_ETYPE_INFO(data->data, data->length, &e, &sz); 885 if (ret) 886 goto out; 887 if (e.len == 0) 888 goto out; 889 for (j = 0; j < asreq->req_body.etype.len; j++) { 890 for (i = 0; i < e.len; i++) { 891 if (asreq->req_body.etype.val[j] == e.val[i].etype) { 892 krb5_salt salt; 893 salt.salttype = KRB5_PW_SALT; 894 if (e.val[i].salt == NULL) 895 ret = krb5_get_pw_salt(context, client, &salt); 896 else { 897 salt.saltvalue = *e.val[i].salt; 898 ret = 0; 899 } 900 if (e.val[i].salttype) 901 salt.salttype = *e.val[i].salttype; 902 if (ret == 0) { 903 ret = set_paid(paid, context, e.val[i].etype, 904 salt.salttype, 905 salt.saltvalue.data, 906 salt.saltvalue.length, 907 NULL); 908 if (e.val[i].salt == NULL) 909 krb5_free_salt(context, salt); 910 } 911 if (ret == 0) { 912 free_ETYPE_INFO(&e); 913 return paid; 914 } 915 } 916 } 917 } 918 out: 919 free_ETYPE_INFO(&e); 920 return NULL; 921} 922 923static struct pa_info_data * 924pa_pw_or_afs3_salt(krb5_context context, 925 const krb5_principal client, 926 const AS_REQ *asreq, 927 struct pa_info_data *paid, 928 heim_octet_string *data) 929{ 930 krb5_error_code ret; 931 if (paid->etype == KRB5_ENCTYPE_NULL) 932 return NULL; 933 ret = set_paid(paid, context, 934 paid->etype, 935 paid->salt.salttype, 936 data->data, 937 data->length, 938 NULL); 939 if (ret) 940 return NULL; 941 return paid; 942} 943 944 945struct pa_info { 946 krb5_preauthtype type; 947 struct pa_info_data *(*salt_info)(krb5_context, 948 const krb5_principal, 949 const AS_REQ *, 950 struct pa_info_data *, 951 heim_octet_string *); 952}; 953 954static struct pa_info pa_prefs[] = { 955 { KRB5_PADATA_ETYPE_INFO2, pa_etype_info2 }, 956 { KRB5_PADATA_ETYPE_INFO, pa_etype_info }, 957 { KRB5_PADATA_PW_SALT, pa_pw_or_afs3_salt }, 958 { KRB5_PADATA_AFS3_SALT, pa_pw_or_afs3_salt } 959}; 960 961static PA_DATA * 962find_pa_data(const METHOD_DATA *md, unsigned type) 963{ 964 size_t i; 965 if (md == NULL) 966 return NULL; 967 for (i = 0; i < md->len; i++) 968 if (md->val[i].padata_type == type) 969 return &md->val[i]; 970 return NULL; 971} 972 973static struct pa_info_data * 974process_pa_info(krb5_context context, 975 const krb5_principal client, 976 const AS_REQ *asreq, 977 struct pa_info_data *paid, 978 METHOD_DATA *md) 979{ 980 struct pa_info_data *p = NULL; 981 size_t i; 982 983 for (i = 0; p == NULL && i < sizeof(pa_prefs)/sizeof(pa_prefs[0]); i++) { 984 PA_DATA *pa = find_pa_data(md, pa_prefs[i].type); 985 if (pa == NULL) 986 continue; 987 paid->salt.salttype = (krb5_salttype)pa_prefs[i].type; 988 p = (*pa_prefs[i].salt_info)(context, client, asreq, 989 paid, &pa->padata_value); 990 } 991 return p; 992} 993 994static krb5_error_code 995make_pa_enc_timestamp(krb5_context context, METHOD_DATA *md, 996 krb5_enctype etype, krb5_keyblock *key) 997{ 998 PA_ENC_TS_ENC p; 999 unsigned char *buf; 1000 size_t buf_size; 1001 size_t len = 0; 1002 EncryptedData encdata; 1003 krb5_error_code ret; 1004 int32_t usec; 1005 int usec2; 1006 krb5_crypto crypto; 1007 1008 krb5_us_timeofday (context, &p.patimestamp, &usec); 1009 usec2 = usec; 1010 p.pausec = &usec2; 1011 1012 ASN1_MALLOC_ENCODE(PA_ENC_TS_ENC, buf, buf_size, &p, &len, ret); 1013 if (ret) 1014 return ret; 1015 if(buf_size != len) 1016 krb5_abortx(context, "internal error in ASN.1 encoder"); 1017 1018 ret = krb5_crypto_init(context, key, 0, &crypto); 1019 if (ret) { 1020 free(buf); 1021 return ret; 1022 } 1023 ret = krb5_encrypt_EncryptedData(context, 1024 crypto, 1025 KRB5_KU_PA_ENC_TIMESTAMP, 1026 buf, 1027 len, 1028 0, 1029 &encdata); 1030 free(buf); 1031 krb5_crypto_destroy(context, crypto); 1032 if (ret) 1033 return ret; 1034 1035 ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_size, &encdata, &len, ret); 1036 free_EncryptedData(&encdata); 1037 if (ret) 1038 return ret; 1039 if(buf_size != len) 1040 krb5_abortx(context, "internal error in ASN.1 encoder"); 1041 1042 ret = krb5_padata_add(context, md, KRB5_PADATA_ENC_TIMESTAMP, buf, len); 1043 if (ret) 1044 free(buf); 1045 return ret; 1046} 1047 1048static krb5_error_code 1049add_enc_ts_padata(krb5_context context, 1050 METHOD_DATA *md, 1051 krb5_principal client, 1052 krb5_s2k_proc keyproc, 1053 krb5_const_pointer keyseed, 1054 krb5_enctype *enctypes, 1055 unsigned netypes, 1056 krb5_salt *salt, 1057 krb5_data *s2kparams) 1058{ 1059 krb5_error_code ret; 1060 krb5_salt salt2; 1061 krb5_enctype *ep; 1062 size_t i; 1063 1064 memset(&salt2, 0, sizeof(salt2)); 1065 1066 if(salt == NULL) { 1067 /* default to standard salt */ 1068 ret = krb5_get_pw_salt (context, client, &salt2); 1069 if (ret) 1070 return ret; 1071 salt = &salt2; 1072 } 1073 if (!enctypes) { 1074 enctypes = context->etypes; 1075 netypes = 0; 1076 for (ep = enctypes; *ep != ETYPE_NULL; ep++) 1077 netypes++; 1078 } 1079 1080 for (i = 0; i < netypes; ++i) { 1081 krb5_keyblock *key; 1082 1083 _krb5_debugx(context, 5, "krb5_get_init_creds: using ENC-TS with enctype %d", enctypes[i]); 1084 1085 ret = (*keyproc)(context, enctypes[i], keyseed, 1086 *salt, s2kparams, &key); 1087 if (ret) 1088 continue; 1089 ret = make_pa_enc_timestamp (context, md, enctypes[i], key); 1090 krb5_free_keyblock (context, key); 1091 if (ret) 1092 return ret; 1093 } 1094 if(salt == &salt2) 1095 krb5_free_salt(context, salt2); 1096 return 0; 1097} 1098 1099static krb5_error_code 1100pa_data_to_md_ts_enc(krb5_context context, 1101 const AS_REQ *a, 1102 const krb5_principal client, 1103 krb5_init_creds_context ctx, 1104 struct pa_info_data *ppaid, 1105 METHOD_DATA *md) 1106{ 1107 if (ctx->keyproc == NULL || ctx->keyseed == NULL) 1108 return 0; 1109 1110 if (ppaid) { 1111 add_enc_ts_padata(context, md, client, 1112 ctx->keyproc, ctx->keyseed, 1113 &ppaid->etype, 1, 1114 &ppaid->salt, ppaid->s2kparams); 1115 } else { 1116 krb5_salt salt; 1117 1118 _krb5_debugx(context, 5, "krb5_get_init_creds: pa-info not found, guessing salt"); 1119 1120 /* make a v5 salted pa-data */ 1121 add_enc_ts_padata(context, md, client, 1122 ctx->keyproc, ctx->keyseed, 1123 a->req_body.etype.val, a->req_body.etype.len, 1124 NULL, NULL); 1125 1126 /* make a v4 salted pa-data */ 1127 salt.salttype = KRB5_PW_SALT; 1128 krb5_data_zero(&salt.saltvalue); 1129 add_enc_ts_padata(context, md, client, 1130 ctx->keyproc, ctx->keyseed, 1131 a->req_body.etype.val, a->req_body.etype.len, 1132 &salt, NULL); 1133 } 1134 return 0; 1135} 1136 1137static krb5_error_code 1138pa_data_to_key_plain(krb5_context context, 1139 const krb5_principal client, 1140 krb5_init_creds_context ctx, 1141 krb5_salt salt, 1142 krb5_data *s2kparams, 1143 krb5_enctype etype, 1144 krb5_keyblock **key) 1145{ 1146 krb5_error_code ret; 1147 1148 ret = (*ctx->keyproc)(context, etype, ctx->keyseed, 1149 salt, s2kparams, key); 1150 return ret; 1151} 1152 1153 1154static krb5_error_code 1155pa_data_to_md_pkinit(krb5_context context, 1156 const AS_REQ *a, 1157 const krb5_principal client, 1158 int win2k, 1159 krb5_init_creds_context ctx, 1160 METHOD_DATA *md) 1161{ 1162 if (ctx->pk_init_ctx == NULL) 1163 return 0; 1164#ifdef PKINIT 1165 return _krb5_pk_mk_padata(context, 1166 ctx->pk_init_ctx, 1167 ctx->ic_flags, 1168 win2k, 1169 &a->req_body, 1170 ctx->pk_nonce, 1171 md); 1172#else 1173 krb5_set_error_message(context, EINVAL, 1174 N_("no support for PKINIT compiled in", "")); 1175 return EINVAL; 1176#endif 1177} 1178 1179static krb5_error_code 1180pa_data_add_pac_request(krb5_context context, 1181 krb5_init_creds_context ctx, 1182 METHOD_DATA *md) 1183{ 1184 size_t len = 0, length; 1185 krb5_error_code ret; 1186 PA_PAC_REQUEST req; 1187 void *buf; 1188 1189 switch (ctx->req_pac) { 1190 case KRB5_INIT_CREDS_TRISTATE_UNSET: 1191 return 0; /* don't bother */ 1192 case KRB5_INIT_CREDS_TRISTATE_TRUE: 1193 req.include_pac = 1; 1194 break; 1195 case KRB5_INIT_CREDS_TRISTATE_FALSE: 1196 req.include_pac = 0; 1197 } 1198 1199 ASN1_MALLOC_ENCODE(PA_PAC_REQUEST, buf, length, 1200 &req, &len, ret); 1201 if (ret) 1202 return ret; 1203 if(len != length) 1204 krb5_abortx(context, "internal error in ASN.1 encoder"); 1205 1206 ret = krb5_padata_add(context, md, KRB5_PADATA_PA_PAC_REQUEST, buf, len); 1207 if (ret) 1208 free(buf); 1209 1210 return 0; 1211} 1212 1213/* 1214 * Assumes caller always will free `out_md', even on error. 1215 */ 1216 1217static krb5_error_code 1218process_pa_data_to_md(krb5_context context, 1219 const krb5_creds *creds, 1220 const AS_REQ *a, 1221 krb5_init_creds_context ctx, 1222 METHOD_DATA *in_md, 1223 METHOD_DATA **out_md, 1224 krb5_prompter_fct prompter, 1225 void *prompter_data) 1226{ 1227 krb5_error_code ret; 1228 1229 ALLOC(*out_md, 1); 1230 if (*out_md == NULL) { 1231 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 1232 return ENOMEM; 1233 } 1234 (*out_md)->len = 0; 1235 (*out_md)->val = NULL; 1236 1237 if (_krb5_have_debug(context, 5)) { 1238 unsigned i; 1239 _krb5_debugx(context, 5, "KDC send %d patypes", in_md->len); 1240 for (i = 0; i < in_md->len; i++) 1241 _krb5_debugx(context, 5, "KDC send PA-DATA type: %d", in_md->val[i].padata_type); 1242 } 1243 1244 /* 1245 * Make sure we don't sent both ENC-TS and PK-INIT pa data, no 1246 * need to expose our password protecting our PKCS12 key. 1247 */ 1248 1249 if (ctx->pk_init_ctx) { 1250 1251 _krb5_debugx(context, 5, "krb5_get_init_creds: prepareing PKINIT padata (%s)", 1252 (ctx->used_pa_types & USED_PKINIT_W2K) ? "win2k" : "ietf"); 1253 1254 if (ctx->used_pa_types & USED_PKINIT_W2K) { 1255 krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP, 1256 "Already tried pkinit, looping"); 1257 return KRB5_GET_IN_TKT_LOOP; 1258 } 1259 1260 ret = pa_data_to_md_pkinit(context, a, creds->client, (ctx->used_pa_types & USED_PKINIT), ctx, *out_md); 1261 if (ret) 1262 return ret; 1263 1264 if (ctx->used_pa_types & USED_PKINIT) 1265 ctx->used_pa_types |= USED_PKINIT_W2K; 1266 else 1267 ctx->used_pa_types |= USED_PKINIT; 1268 1269 } else if (in_md->len != 0) { 1270 struct pa_info_data paid, *ppaid; 1271 const char *state; 1272 unsigned flag; 1273 1274 memset(&paid, 0, sizeof(paid)); 1275 1276 paid.etype = KRB5_ENCTYPE_NULL; 1277 ppaid = process_pa_info(context, creds->client, a, &paid, in_md); 1278 1279 /* 1280 * We have to allow the KDC to re-negotiate the PA-TS data 1281 * once, this is since the in the case of a windows read only 1282 * KDC that doesn't have the keys simply guesses what the 1283 * master is supposed to support. In the case where this 1284 * breaks in when the RO-KDC is a newer version the the RW-KDC 1285 * and the RO-KDC announced a enctype that the older doesn't 1286 * support. 1287 */ 1288 if (ppaid) { 1289 if (ctx->used_pa_types & USED_ENC_TS_INFO) { 1290 flag = USED_ENC_TS_RENEG; 1291 state = "reneg"; 1292 } else { 1293 flag = USED_ENC_TS_INFO; 1294 state = "info"; 1295 } 1296 } else { 1297 flag = USED_ENC_TS_GUESS; 1298 state = "guess"; 1299 } 1300 1301 if (ctx->used_pa_types & flag) { 1302 free_paid(context, &paid); 1303 krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP, 1304 "Already tried ENC-TS-%s, looping", state); 1305 return KRB5_GET_IN_TKT_LOOP; 1306 } 1307 1308 if (ppaid) { 1309 free_paid(context, &ctx->paid); 1310 ctx->paid = *ppaid; 1311 } else { 1312 free_paid(context, &paid); 1313 } 1314 1315 pa_data_to_md_ts_enc(context, a, creds->client, ctx, ppaid, *out_md); 1316 1317 ctx->used_pa_types |= flag; 1318 } 1319 1320#ifdef PKINIT 1321 if (ctx->pku2u_assertion) { 1322 krb5_data data; 1323 ret = krb5_data_copy(&data, 1324 ctx->pku2u_assertion->data, 1325 ctx->pku2u_assertion->length); 1326 if (ret) 1327 return ret; 1328 ret = krb5_padata_add(context, *out_md, KRB5_PADATA_PKU2U_NAME, 1329 data.data, data.length); 1330 if (ret) { 1331 krb5_data_free(&data); 1332 return ret; 1333 } 1334 } 1335#endif 1336 1337 pa_data_add_pac_request(context, ctx, *out_md); 1338 1339 if ((ctx->fast_state.flags & KRB5_FAST_DISABLED) == 0) { 1340 ctx->fast_state.flags |= KRB5_FAST_REQUIRE_ENC_PA; 1341 1342 ret = krb5_padata_add(context, *out_md, KRB5_PADATA_REQ_ENC_PA_REP, NULL, 0); 1343 if (ret) 1344 return ret; 1345 } 1346 1347 if ((*out_md)->len == 0) { 1348 free(*out_md); 1349 *out_md = NULL; 1350 } 1351 1352 return 0; 1353} 1354 1355static krb5_error_code 1356process_pa_data_to_key(krb5_context context, 1357 krb5_init_creds_context ctx, 1358 krb5_creds *creds, 1359 AS_REQ *a, 1360 AS_REP *rep, 1361 const krb5_krbhst_info *hi, 1362 krb5_keyblock **key) 1363{ 1364 struct pa_info_data paid, *ppaid = NULL; 1365 krb5_error_code ret; 1366 krb5_enctype etype; 1367 PA_DATA *pa; 1368 1369 memset(&paid, 0, sizeof(paid)); 1370 1371 etype = rep->enc_part.etype; 1372 1373 if (rep->padata) { 1374 paid.etype = etype; 1375 ppaid = process_pa_info(context, creds->client, a, &paid, 1376 rep->padata); 1377 } 1378 if (ppaid == NULL) { 1379 if ((ctx->used_pa_types & USED_ENC_TS_INFO) == 0) { 1380 ctx->paid.etype = etype; 1381 ctx->paid.s2kparams = NULL; 1382 ret = krb5_get_pw_salt (context, creds->client, &ctx->paid.salt); 1383 if (ret) 1384 return ret; 1385 } 1386 ppaid = &ctx->paid; 1387 } 1388 1389 pa = NULL; 1390 if (rep->padata) { 1391 int idx = 0; 1392 pa = krb5_find_padata(rep->padata->val, 1393 rep->padata->len, 1394 KRB5_PADATA_PK_AS_REP, 1395 &idx); 1396 if (pa == NULL) { 1397 idx = 0; 1398 pa = krb5_find_padata(rep->padata->val, 1399 rep->padata->len, 1400 KRB5_PADATA_PK_AS_REP_19, 1401 &idx); 1402 } 1403 } 1404 if (pa && ctx->pk_init_ctx) { 1405#ifdef PKINIT 1406 _krb5_debugx(context, 5, "krb5_get_init_creds: using PKINIT"); 1407 1408 ret = _krb5_pk_rd_pa_reply(context, 1409 a->req_body.realm, 1410 ctx->pk_init_ctx, 1411 etype, 1412 hi, 1413 ctx->pk_nonce, 1414 &ctx->req_buffer, 1415 pa, 1416 key); 1417#else 1418 ret = EINVAL; 1419 krb5_set_error_message(context, ret, N_("no support for PKINIT compiled in", "")); 1420#endif 1421 } else if (ctx->keyseed) { 1422 _krb5_debugx(context, 5, "krb5_get_init_creds: using keyproc"); 1423 1424 ret = pa_data_to_key_plain(context, creds->client, ctx, 1425 ppaid->salt, ppaid->s2kparams, etype, key); 1426 } else { 1427 ret = EINVAL; 1428 krb5_set_error_message(context, ret, N_("No usable pa data type", "")); 1429 } 1430 1431 free_paid(context, &paid); 1432 return ret; 1433} 1434 1435/* 1436 * 1437 */ 1438 1439static krb5_error_code 1440capture_lkdc_domain(krb5_context context, 1441 krb5_init_creds_context ctx) 1442{ 1443 size_t len; 1444 1445 len = strlen(_krb5_wellknown_lkdc); 1446 1447 if (ctx->kdc_hostname != NULL || 1448 strncmp(ctx->cred.client->realm, _krb5_wellknown_lkdc, len) != 0 || 1449 ctx->cred.client->realm[len] != ':') 1450 return 0; 1451 1452 ctx->kdc_hostname = strdup(&ctx->cred.client->realm[len + 1]); 1453 1454 _krb5_debugx(context, 5, "krb5_get_init_creds: setting LKDC hostname to: %s", 1455 ctx->kdc_hostname); 1456 return 0; 1457} 1458 1459/** 1460 * Start a new context to get a new initial credential. 1461 * 1462 * @param context A Kerberos 5 context. 1463 * @param client The Kerberos principal to get the credential for, if 1464 * NULL is given, the default principal is used as determined by 1465 * krb5_get_default_principal(). 1466 * @param prompter 1467 * @param prompter_data 1468 * @param start_time the time the ticket should start to be valid or 0 for now. 1469 * @param options a options structure, can be NULL for default options. 1470 * @param rctx A new allocated free with krb5_init_creds_free(). 1471 * 1472 * @return 0 for success or an Kerberos 5 error code, see krb5_get_error_message(). 1473 * 1474 * @ingroup krb5_credential 1475 */ 1476 1477KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1478krb5_init_creds_init(krb5_context context, 1479 krb5_principal client, 1480 krb5_prompter_fct prompter, 1481 void *prompter_data, 1482 krb5_deltat start_time, 1483 krb5_get_init_creds_opt *options, 1484 krb5_init_creds_context *rctx) 1485{ 1486 krb5_init_creds_context ctx; 1487 krb5_error_code ret; 1488 1489 *rctx = NULL; 1490 1491 ctx = calloc(1, sizeof(*ctx)); 1492 if (ctx == NULL) { 1493 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 1494 return ENOMEM; 1495 } 1496 1497 ret = get_init_creds_common(context, client, start_time, options, ctx); 1498 if (ret) { 1499 free(ctx); 1500 return ret; 1501 } 1502 1503 /* Set a new nonce. */ 1504 krb5_generate_random_block (&ctx->nonce, sizeof(ctx->nonce)); 1505 ctx->nonce &= 0x7fffffff; 1506 /* XXX these just needs to be the same when using Windows PK-INIT */ 1507 ctx->pk_nonce = ctx->nonce; 1508 1509 ctx->prompter = prompter; 1510 ctx->prompter_data = prompter_data; 1511 1512 /* pick up hostname from LKDC realm name */ 1513 ret = capture_lkdc_domain(context, ctx); 1514 if (ret) { 1515 free_init_creds_ctx(context, ctx); 1516 return ret; 1517 } 1518 1519 *rctx = ctx; 1520 1521 return ret; 1522} 1523 1524/** 1525 * The set KDC hostname for the initial request, it will not be 1526 * considered in referrals to another KDC. 1527 * 1528 * @param context a Kerberos 5 context. 1529 * @param ctx a krb5_init_creds_context context. 1530 * @param hostname the hostname for the KDC of realm 1531 * 1532 * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message(). 1533 * @ingroup krb5_credential 1534 */ 1535 1536krb5_error_code KRB5_LIB_FUNCTION 1537krb5_init_creds_set_kdc_hostname(krb5_context context, 1538 krb5_init_creds_context ctx, 1539 const char *hostname) 1540{ 1541 if (ctx->kdc_hostname) 1542 free(ctx->kdc_hostname); 1543 ctx->kdc_hostname = strdup(hostname); 1544 if (ctx->kdc_hostname == NULL) 1545 return ENOMEM; 1546 return 0; 1547} 1548 1549/** 1550 * Sets the service that the is requested. This call is only neede for 1551 * special initial tickets, by default the a krbtgt is fetched in the default realm. 1552 * 1553 * @param context a Kerberos 5 context. 1554 * @param ctx a krb5_init_creds_context context. 1555 * @param service the service given as a string, for example 1556 * "kadmind/admin". If NULL, the default krbtgt in the clients 1557 * realm is set. 1558 * 1559 * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message(). 1560 * @ingroup krb5_credential 1561 */ 1562 1563KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1564krb5_init_creds_set_service(krb5_context context, 1565 krb5_init_creds_context ctx, 1566 const char *service) 1567{ 1568 krb5_const_realm client_realm; 1569 krb5_principal principal; 1570 krb5_error_code ret; 1571 1572 client_realm = krb5_principal_get_realm (context, ctx->cred.client); 1573 1574 if (service) { 1575 ret = krb5_parse_name (context, service, &principal); 1576 if (ret) 1577 return ret; 1578 krb5_principal_set_realm (context, principal, client_realm); 1579 } else { 1580 ret = krb5_make_principal(context, &principal, 1581 client_realm, KRB5_TGS_NAME, client_realm, 1582 NULL); 1583 if (ret) 1584 return ret; 1585 } 1586 1587 /* 1588 * This is for Windows RODC that are picky about what name type 1589 * the server principal have, and the really strange part is that 1590 * they are picky about the AS-REQ name type and not the TGS-REQ 1591 * later. Oh well. 1592 */ 1593 1594 if (krb5_principal_is_krbtgt(context, principal)) 1595 krb5_principal_set_type(context, principal, KRB5_NT_SRV_INST); 1596 1597 krb5_free_principal(context, ctx->cred.server); 1598 ctx->cred.server = principal; 1599 1600 return 0; 1601} 1602 1603/** 1604 * Sets the password that will use for the request. 1605 * 1606 * @param context a Kerberos 5 context. 1607 * @param ctx a krb5_init_creds_context context. 1608 * @param cert client cert 1609 * 1610 * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message(). 1611 * @ingroup krb5_credential 1612 */ 1613 1614krb5_error_code KRB5_LIB_FUNCTION 1615krb5_init_creds_set_pkinit_client_cert(krb5_context context, 1616 krb5_init_creds_context ctx, 1617 struct hx509_cert_data *cert) 1618{ 1619#ifdef PKINIT 1620 if (ctx->client_cert) 1621 hx509_cert_free(ctx->client_cert); 1622 ctx->client_cert = hx509_cert_ref(cert); 1623 return 0; 1624#else 1625 return EINVAL; 1626#endif 1627} 1628 1629/** 1630 * Sets the password that will use for the request. 1631 * 1632 * @param context a Kerberos 5 context. 1633 * @param ctx krb5_init_creds_context context. 1634 * @param password the password to use. 1635 * 1636 * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message(). 1637 * @ingroup krb5_credential 1638 */ 1639 1640KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1641krb5_init_creds_set_password(krb5_context context, 1642 krb5_init_creds_context ctx, 1643 const char *password) 1644{ 1645 if (ctx->password) { 1646 memset(ctx->password, 0, strlen(ctx->password)); 1647 free(ctx->password); 1648 } 1649 if (password) { 1650 ctx->password = strdup(password); 1651 if (ctx->password == NULL) { 1652 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 1653 return ENOMEM; 1654 } 1655 ctx->keyseed = (void *) ctx->password; 1656 } else { 1657 ctx->keyseed = NULL; 1658 ctx->password = NULL; 1659 } 1660 1661 return 0; 1662} 1663 1664static krb5_error_code KRB5_CALLCONV 1665keytab_key_proc(krb5_context context, krb5_enctype enctype, 1666 krb5_const_pointer keyseed, 1667 krb5_salt salt, krb5_data *s2kparms, 1668 krb5_keyblock **key) 1669{ 1670 krb5_keytab_key_proc_args *args = rk_UNCONST(keyseed); 1671 krb5_keytab keytab = args->keytab; 1672 krb5_principal principal = args->principal; 1673 krb5_error_code ret; 1674 krb5_keytab real_keytab; 1675 krb5_keytab_entry entry; 1676 1677 if (keytab == NULL) { 1678 ret = krb5_kt_default(context, &real_keytab); 1679 if (ret) 1680 return ret; 1681 } else 1682 real_keytab = keytab; 1683 1684 ret = krb5_kt_get_entry (context, real_keytab, principal, 1685 0, enctype, &entry); 1686 1687 if (keytab == NULL) 1688 krb5_kt_close (context, real_keytab); 1689 1690 if (ret) 1691 return ret; 1692 1693 ret = krb5_copy_keyblock (context, &entry.keyblock, key); 1694 krb5_kt_free_entry(context, &entry); 1695 return ret; 1696} 1697 1698 1699/** 1700 * Set the keytab to use for authentication. 1701 * 1702 * @param context a Kerberos 5 context. 1703 * @param ctx ctx krb5_init_creds_context context. 1704 * @param keytab the keytab to read the key from. 1705 * 1706 * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message(). 1707 * @ingroup krb5_credential 1708 */ 1709 1710KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1711krb5_init_creds_set_keytab(krb5_context context, 1712 krb5_init_creds_context ctx, 1713 krb5_keytab keytab) 1714{ 1715 krb5_keytab_key_proc_args *a; 1716 krb5_keytab_entry entry; 1717 krb5_kt_cursor cursor; 1718 krb5_enctype *etypes = NULL; 1719 krb5_error_code ret; 1720 size_t netypes = 0; 1721 int kvno = 0, found = 0; 1722 1723 a = malloc(sizeof(*a)); 1724 if (a == NULL) { 1725 krb5_set_error_message(context, ENOMEM, 1726 N_("malloc: out of memory", "")); 1727 return ENOMEM; 1728 } 1729 1730 a->principal = ctx->cred.client; 1731 a->keytab = keytab; 1732 1733 ctx->keytab_data = a; 1734 ctx->keyseed = (void *)a; 1735 ctx->keyproc = keytab_key_proc; 1736 1737 /* 1738 * We need to the KDC what enctypes we support for this keytab, 1739 * esp if the keytab is really a password based entry, then the 1740 * KDC might have more enctypes in the database then what we have 1741 * in the keytab. 1742 */ 1743 1744 ret = krb5_kt_start_seq_get(context, keytab, &cursor); 1745 if(ret) 1746 goto out; 1747 1748 while(krb5_kt_next_entry(context, keytab, &entry, &cursor) == 0){ 1749 void *ptr; 1750 1751 if (!krb5_principal_compare(context, entry.principal, ctx->cred.client)) 1752 goto next; 1753 1754 found = 1; 1755 1756 /* check if we ahve this kvno already */ 1757 if (entry.vno > kvno) { 1758 /* remove old list of etype */ 1759 if (etypes) 1760 free(etypes); 1761 etypes = NULL; 1762 netypes = 0; 1763 kvno = entry.vno; 1764 } else if (entry.vno != kvno) 1765 goto next; 1766 1767 /* check if enctype is supported */ 1768 if (krb5_enctype_valid(context, entry.keyblock.keytype) != 0) 1769 goto next; 1770 1771 /* add enctype to supported list */ 1772 ptr = realloc(etypes, sizeof(etypes[0]) * (netypes + 2)); 1773 if (ptr == NULL) { 1774 free(etypes); 1775 ret = krb5_enomem(context); 1776 goto out; 1777 } 1778 1779 etypes = ptr; 1780 etypes[netypes] = entry.keyblock.keytype; 1781 etypes[netypes + 1] = ETYPE_NULL; 1782 netypes++; 1783 next: 1784 krb5_kt_free_entry(context, &entry); 1785 } 1786 krb5_kt_end_seq_get(context, keytab, &cursor); 1787 1788 if (etypes) { 1789 if (ctx->etypes) 1790 free(ctx->etypes); 1791 ctx->etypes = etypes; 1792 } 1793 1794 out: 1795 if (!found) { 1796 if (ret == 0) 1797 ret = KRB5_KT_NOTFOUND; 1798 _krb5_kt_principal_not_found(context, ret, keytab, ctx->cred.client, 0, 0); 1799 } 1800 1801 return ret; 1802} 1803 1804krb5_error_code KRB5_LIB_FUNCTION 1805_krb5_init_creds_set_pku2u(krb5_context context, 1806 krb5_init_creds_context ctx, 1807 krb5_data *data) 1808{ 1809#ifdef PKINIT 1810 krb5_error_code ret; 1811 1812 ctx->ic_flags |= KRB5_INIT_CREDS_PKU2U; 1813 ctx->flags = int2KDCOptions(0); 1814 1815 if (ctx->pku2u_assertion) 1816 krb5_free_data(context, ctx->pku2u_assertion); 1817 1818 if (data) { 1819 ret = krb5_copy_data(context, data, &ctx->pku2u_assertion); 1820 if (ret) 1821 return ret; 1822 } else { 1823 ctx->pku2u_assertion = NULL; 1824 } 1825 1826 return 0; 1827#else 1828 return EINVAL; 1829#endif 1830} 1831 1832 1833static krb5_error_code KRB5_CALLCONV 1834keyblock_key_proc(krb5_context context, krb5_enctype enctype, 1835 krb5_const_pointer keyseed, 1836 krb5_salt salt, krb5_data *s2kparms, 1837 krb5_keyblock **key) 1838{ 1839 return krb5_copy_keyblock (context, keyseed, key); 1840} 1841 1842KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1843krb5_init_creds_set_keyblock(krb5_context context, 1844 krb5_init_creds_context ctx, 1845 krb5_keyblock *keyblock) 1846{ 1847 ctx->keyseed = (void *)keyblock; 1848 ctx->keyproc = keyblock_key_proc; 1849 1850 return 0; 1851} 1852 1853KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1854krb5_init_creds_set_fast_ccache(krb5_context context, 1855 krb5_init_creds_context ctx, 1856 krb5_ccache fast_ccache) 1857{ 1858 ctx->fast_state.armor_ccache = fast_ccache; 1859 ctx->fast_state.flags |= KRB5_FAST_REQUIRED; 1860 return 0; 1861} 1862 1863/* 1864 * FAST 1865 */ 1866 1867static krb5_error_code 1868check_fast(krb5_context context, struct fast_state *state) 1869{ 1870 if (state->flags & KRB5_FAST_EXPECTED) { 1871 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, 1872 "Expected FAST, but no FAST " 1873 "was in the response from the KDC"); 1874 return KRB5KRB_AP_ERR_MODIFIED; 1875 } 1876 return 0; 1877} 1878 1879 1880static krb5_error_code 1881fast_unwrap_as_rep(krb5_context context, int32_t nonce, 1882 krb5_data *chksumdata, 1883 struct fast_state *state, AS_REP *rep) 1884{ 1885 PA_FX_FAST_REPLY fxfastrep; 1886 KrbFastResponse fastrep; 1887 krb5_error_code ret; 1888 PA_DATA *pa = NULL; 1889 int idx = 0; 1890 1891 if (state->armor_crypto == NULL || rep->padata == NULL) 1892 return check_fast(context, state); 1893 1894 /* find PA_FX_FAST_REPLY */ 1895 1896 pa = krb5_find_padata(rep->padata->val, rep->padata->len, 1897 KRB5_PADATA_FX_FAST, &idx); 1898 if (pa == NULL) 1899 return check_fast(context, state); 1900 1901 memset(&fxfastrep, 0, sizeof(fxfastrep)); 1902 memset(&fastrep, 0, sizeof(fastrep)); 1903 1904 ret = decode_PA_FX_FAST_REPLY(pa->padata_value.data, pa->padata_value.length, &fxfastrep, NULL); 1905 if (ret) 1906 return ret; 1907 1908 if (fxfastrep.element == choice_PA_FX_FAST_REPLY_armored_data) { 1909 krb5_data data; 1910 ret = krb5_decrypt_EncryptedData(context, 1911 state->armor_crypto, 1912 KRB5_KU_FAST_REP, 1913 &fxfastrep.u.armored_data.enc_fast_rep, 1914 &data); 1915 if (ret) 1916 goto out; 1917 1918 ret = decode_KrbFastResponse(data.data, data.length, &fastrep, NULL); 1919 krb5_data_free(&data); 1920 if (ret) 1921 goto out; 1922 1923 } else { 1924 ret = KRB5KDC_ERR_PREAUTH_FAILED; 1925 goto out; 1926 } 1927 1928 free_METHOD_DATA(rep->padata); 1929 ret = copy_METHOD_DATA(&fastrep.padata, rep->padata); 1930 if (ret) 1931 goto out; 1932 1933 if (fastrep.strengthen_key) { 1934 krb5_keyblock result; 1935 1936 ret = _krb5_fast_cf2(context, 1937 fastrep.strengthen_key, 1938 "strengthenkey", 1939 state->reply_key, 1940 "replykey", 1941 &result, 1942 NULL); 1943 if (ret) 1944 goto out; 1945 1946 krb5_free_keyblock_contents(context, state->reply_key); 1947 *state->reply_key = result; 1948 } 1949 1950 if (nonce != fastrep.nonce) { 1951 ret = KRB5KDC_ERR_PREAUTH_FAILED; 1952 goto out; 1953 } 1954 if (fastrep.finished) { 1955 PrincipalName cname; 1956 krb5_realm crealm = NULL; 1957 1958 if (chksumdata == NULL) { 1959 ret = KRB5KDC_ERR_PREAUTH_FAILED; 1960 goto out; 1961 } 1962 1963 ret = krb5_verify_checksum(context, state->armor_crypto, 1964 KRB5_KU_FAST_FINISHED, 1965 chksumdata->data, chksumdata->length, 1966 &fastrep.finished->ticket_checksum); 1967 if (ret) 1968 goto out; 1969 1970 /* update */ 1971 ret = copy_Realm(&fastrep.finished->crealm, &crealm); 1972 if (ret) 1973 goto out; 1974 free_Realm(&rep->crealm); 1975 rep->crealm = crealm; 1976 1977 ret = copy_PrincipalName(&fastrep.finished->cname, &cname); 1978 if (ret) 1979 goto out; 1980 free_PrincipalName(&rep->cname); 1981 rep->cname = cname; 1982 1983#if 0 /* store authenticated checksum as kdc-offset */ 1984 fastrep->finished.timestamp; 1985 fastrep->finished.usec = 0; 1986#endif 1987 1988 } else if (chksumdata) { 1989 /* expected fastrep.finish but didn't get it */ 1990 ret = KRB5KDC_ERR_PREAUTH_FAILED; 1991 } 1992 1993 out: 1994 free_PA_FX_FAST_REPLY(&fxfastrep); 1995 1996 return ret; 1997} 1998 1999static krb5_error_code 2000fast_unwrap_error(krb5_context context, struct fast_state *state, KRB_ERROR *error) 2001{ 2002 if (state->armor_crypto == NULL) 2003 return check_fast(context, state); 2004 2005 return 0; 2006} 2007 2008static krb5_error_code 2009make_fast_ap_fxarmor(krb5_context context, 2010 struct fast_state *state, 2011 KrbFastArmor **armor) 2012{ 2013 KrbFastArmor *fxarmor = NULL; 2014 krb5_auth_context auth_context = NULL; 2015 krb5_creds cred, *credp = NULL; 2016 krb5_error_code ret; 2017 2018 ALLOC(fxarmor, 1); 2019 if (fxarmor == NULL) { 2020 ret = ENOMEM; 2021 goto out; 2022 } 2023 2024 fxarmor->armor_type = 1; 2025 2026 memset(&cred, 0, sizeof(cred)); 2027 2028 ret = krb5_auth_con_init (context, &auth_context); 2029 if (ret) 2030 goto out; 2031 2032 ret = krb5_cc_get_principal(context, state->armor_ccache, &cred.client); 2033 if (ret) 2034 goto out; 2035 2036 ret = krb5_make_principal(context, &cred.server, 2037 cred.client->realm, 2038 KRB5_TGS_NAME, 2039 cred.client->realm, 2040 NULL); 2041 if (ret) { 2042 krb5_free_principal(context, cred.client); 2043 goto out; 2044 } 2045 2046 ret = krb5_get_credentials(context, 0, state->armor_ccache, &cred, &credp); 2047 krb5_free_principal(context, cred.server); 2048 krb5_free_principal(context, cred.client); 2049 if (ret) 2050 goto out; 2051 2052 ret = krb5_mk_req_extended(context, 2053 &auth_context, 2054 AP_OPTS_USE_SUBKEY, 2055 NULL, 2056 credp, 2057 &fxarmor->armor_value); 2058 krb5_free_creds(context, credp); 2059 if (ret) 2060 goto out; 2061 2062 if (state->armor_crypto) 2063 krb5_crypto_destroy(context, state->armor_crypto); 2064 krb5_free_keyblock_contents(context, &state->armor_key); 2065 2066 ret = _krb5_fast_armor_key(context, 2067 auth_context->local_subkey, 2068 auth_context->keyblock, 2069 &state->armor_key, 2070 &state->armor_crypto); 2071 if (ret) 2072 goto out; 2073 2074 *armor = fxarmor; 2075 fxarmor = NULL; 2076 out: 2077 if (fxarmor) 2078 free_KrbFastArmor(fxarmor); 2079 return ret; 2080} 2081 2082 2083static krb5_error_code 2084fast_wrap_req(krb5_context context, struct fast_state *state, KDC_REQ *req) 2085{ 2086 KrbFastArmor *fxarmor = NULL; 2087 PA_FX_FAST_REQUEST fxreq; 2088 krb5_error_code ret; 2089 KrbFastReq fastreq; 2090 krb5_data data; 2091 size_t size; 2092 2093 if (state->flags & KRB5_FAST_DISABLED) { 2094 _krb5_debugx(context, 10, "fast disabled, not doing any fast wrapping"); 2095 return 0; 2096 } 2097 2098 memset(&fxreq, 0, sizeof(fxreq)); 2099 memset(&fastreq, 0, sizeof(fastreq)); 2100 krb5_data_zero(&data); 2101 2102 if (state->armor_crypto == NULL) { 2103 if (state->armor_ccache) { 2104 /* 2105 * Instead of keeping state in FX_COOKIE in the KDC, we 2106 * rebuild a new armor key for every request, because this 2107 * is what the MIT KDC expect and RFC6113 is vage about 2108 * what the behavior should be. 2109 */ 2110 state->type = choice_PA_FX_FAST_REQUEST_armored_data; 2111 } else { 2112 return check_fast(context, state); 2113 } 2114 } 2115 2116 state->flags |= KRB5_FAST_EXPECTED; 2117 2118 fastreq.fast_options.hide_client_names = 1; 2119 2120 ret = copy_KDC_REQ_BODY(&req->req_body, &fastreq.req_body); 2121 if (ret) 2122 goto out; 2123 free_KDC_REQ_BODY(&req->req_body); 2124 2125 req->req_body.realm = strdup(KRB5_ANON_REALM); 2126 ALLOC(req->req_body.cname, 1); 2127 req->req_body.cname->name_type = KRB5_NT_PRINCIPAL; 2128 ALLOC(req->req_body.cname->name_string.val, 2); 2129 req->req_body.cname->name_string.len = 2; 2130 req->req_body.cname->name_string.val[0] = strdup(KRB5_WELLKNOWN_NAME); 2131 req->req_body.cname->name_string.val[1] = strdup(KRB5_ANON_NAME); 2132 2133 if (req->padata) { 2134 ret = copy_METHOD_DATA(req->padata, &fastreq.padata); 2135 free_METHOD_DATA(req->padata); 2136 } else { 2137 ALLOC(req->padata, 1); 2138 } 2139 2140 2141 ASN1_MALLOC_ENCODE(KrbFastReq, data.data, data.length, &fastreq, &size, ret); 2142 if (ret) 2143 goto out; 2144 heim_assert(data.length == size, "ASN.1 internal error"); 2145 2146 fxreq.element = state->type; 2147 2148 if (state->type == choice_PA_FX_FAST_REQUEST_armored_data) { 2149 size_t len; 2150 void *buf; 2151 2152 ret = make_fast_ap_fxarmor(context, state, &fxreq.u.armored_data.armor); 2153 if (ret) 2154 goto out; 2155 2156 heim_assert(state->armor_crypto != NULL, "FAST armor key missing when FAST started"); 2157 2158 ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, len, &req->req_body, &size, ret); 2159 if (ret) 2160 goto out; 2161 heim_assert(len == size, "ASN.1 internal error"); 2162 2163 ret = krb5_create_checksum(context, state->armor_crypto, 2164 KRB5_KU_FAST_REQ_CHKSUM, 0, 2165 buf, len, 2166 &fxreq.u.armored_data.req_checksum); 2167 free(buf); 2168 if (ret) 2169 goto out; 2170 2171 ret = krb5_encrypt_EncryptedData(context, state->armor_crypto, 2172 KRB5_KU_FAST_ENC, 2173 data.data, 2174 data.length, 2175 0, 2176 &fxreq.u.armored_data.enc_fast_req); 2177 krb5_data_free(&data); 2178 2179 } else { 2180 krb5_data_free(&data); 2181 heim_assert(false, "unknown FAST type, internal error"); 2182 } 2183 2184 ASN1_MALLOC_ENCODE(PA_FX_FAST_REQUEST, data.data, data.length, &fxreq, &size, ret); 2185 if (ret) 2186 goto out; 2187 heim_assert(data.length == size, "ASN.1 internal error"); 2188 2189 2190 ret = krb5_padata_add(context, req->padata, KRB5_PADATA_FX_FAST, data.data, data.length); 2191 if (ret) 2192 goto out; 2193 krb5_data_zero(&data); 2194 2195 out: 2196 free_PA_FX_FAST_REQUEST(&fxreq); 2197 if (fxarmor) { 2198 free_KrbFastArmor(fxarmor); 2199 free(fxarmor); 2200 } 2201 krb5_data_free(&data); 2202 2203 return ret; 2204} 2205 2206 2207/** 2208 * The core loop if krb5_get_init_creds() function family. Create the 2209 * packets and have the caller send them off to the KDC. 2210 * 2211 * If the caller want all work been done for them, use 2212 * krb5_init_creds_get() instead. 2213 * 2214 * @param context a Kerberos 5 context. 2215 * @param ctx ctx krb5_init_creds_context context. 2216 * @param in input data from KDC, first round it should be reset by krb5_data_zer(). 2217 * @param out reply to KDC. 2218 * @param hostinfo KDC address info, first round it can be NULL. 2219 * @param realm realm is a pointer the realm to send the packet, it have the 2220 * lifetime the next call to krb5_init_creds_step() or krb5_init_creds_free(). 2221 * @param flags status of the round, if 2222 * KRB5_INIT_CREDS_STEP_FLAG_CONTINUE is set, continue one more round. 2223 * 2224 * @return 0 for success, or an Kerberos 5 error code, see 2225 * krb5_get_error_message(). 2226 * 2227 * @ingroup krb5_credential 2228 */ 2229 2230KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2231krb5_init_creds_step(krb5_context context, 2232 krb5_init_creds_context ctx, 2233 krb5_data *in, 2234 krb5_data *out, 2235 krb5_krbhst_info *hostinfo, 2236 krb5_realm *realm, 2237 unsigned int *flags) 2238{ 2239 struct timeval start_time, end_time; 2240 krb5_error_code ret; 2241 size_t len = 0; 2242 size_t size; 2243 AS_REQ req2; 2244 2245 gettimeofday(&start_time, NULL); 2246 2247 krb5_data_zero(out); 2248 2249 if (realm) 2250 *realm = NULL; 2251 2252 if (ctx->as_req.req_body.cname == NULL) { 2253 2254#ifdef PKINIT 2255 if (ctx->pk_init_ctx && ctx->client_cert) 2256 _krb5_pk_set_user_id(context, ctx->pk_init_ctx, ctx->client_cert); 2257#endif 2258 2259 ret = init_as_req(context, ctx->flags, &ctx->cred, 2260 ctx->addrs, ctx->etypes, &ctx->as_req); 2261 if (ret) { 2262 free_init_creds_ctx(context, ctx); 2263 return ret; 2264 } 2265 if (ctx->fast_state.armor_ccache == NULL) 2266 ctx->fast_state.flags |= KRB5_FAST_DISABLED; 2267 } 2268 2269#define MAX_PA_COUNTER 10 2270 if (ctx->pa_counter > MAX_PA_COUNTER) { 2271 krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP, 2272 N_("Looping %d times while getting " 2273 "initial credentials", ""), 2274 ctx->pa_counter); 2275 return KRB5_GET_IN_TKT_LOOP; 2276 } 2277 ctx->pa_counter++; 2278 2279 _krb5_debugx(context, 5, "krb5_get_init_creds: loop %d", ctx->pa_counter); 2280 2281 /* Lets process the input packet */ 2282 if (in && in->length) { 2283 krb5_kdc_rep rep; 2284 2285 memset(&rep, 0, sizeof(rep)); 2286 2287 _krb5_debugx(context, 5, "krb5_get_init_creds: processing input"); 2288 2289 ret = decode_AS_REP(in->data, in->length, &rep.kdc_rep, &size); 2290 if (ret == 0) { 2291 unsigned eflags = EXTRACT_TICKET_AS_REQ | EXTRACT_TICKET_TIMESYNC; 2292 krb5_data data; 2293 2294 /* 2295 * Unwrap AS-REP 2296 */ 2297 ASN1_MALLOC_ENCODE(Ticket, data.data, data.length, 2298 &rep.kdc_rep.ticket, &size, ret); 2299 if (ret) 2300 goto out; 2301 heim_assert(data.length == size, "ASN.1 internal error"); 2302 2303 ret = fast_unwrap_as_rep(context, ctx->nonce, &data, 2304 &ctx->fast_state, &rep.kdc_rep); 2305 krb5_data_free(&data); 2306 if (ret) 2307 goto out; 2308 2309 /* 2310 * Now check and extract the ticket 2311 */ 2312 2313 if (ctx->flags.canonicalize) { 2314 eflags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH; 2315 eflags |= EXTRACT_TICKET_MATCH_REALM; 2316 } 2317 if (ctx->ic_flags & KRB5_INIT_CREDS_NO_C_CANON_CHECK) 2318 eflags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH; 2319 2320 ret = process_pa_data_to_key(context, ctx, &ctx->cred, 2321 &ctx->as_req, &rep.kdc_rep, 2322 hostinfo, &ctx->fast_state.reply_key); 2323 if (ret) { 2324 free_AS_REP(&rep.kdc_rep); 2325 goto out; 2326 } 2327 2328 _krb5_debugx(context, 5, "krb5_get_init_creds: extracting ticket"); 2329 2330 ret = _krb5_extract_ticket(context, 2331 &rep, 2332 &ctx->cred, 2333 ctx->fast_state.reply_key, 2334 KRB5_KU_AS_REP_ENC_PART, 2335 NULL, 2336 ctx->nonce, 2337 eflags, 2338 &ctx->req_buffer, 2339 NULL, 2340 NULL); 2341 2342 if (ret == 0) 2343 ret = copy_EncKDCRepPart(&rep.enc_part, &ctx->enc_part); 2344 2345 krb5_free_keyblock(context, ctx->fast_state.reply_key); 2346 ctx->fast_state.reply_key = NULL; 2347 ctx->ic_flags |= KRB5_INIT_CREDS_DONE; 2348 *flags = 0; 2349 2350 free_AS_REP(&rep.kdc_rep); 2351 free_EncASRepPart(&rep.enc_part); 2352 2353 gettimeofday(&end_time, NULL); 2354 timevalsub(&end_time, &start_time); 2355 timevaladd(&ctx->stats.run_time, &end_time); 2356 2357 _krb5_debugx(context, 1, "krb5_get_init_creds: wc: %ld.%06d", 2358 ctx->stats.run_time.tv_sec, ctx->stats.run_time.tv_usec); 2359 return ret; 2360 2361 } else { 2362 /* let's try to parse it as a KRB-ERROR */ 2363 2364 _krb5_debugx(context, 5, "krb5_get_init_creds: got an KRB-ERROR from KDC"); 2365 2366 free_KRB_ERROR(&ctx->error); 2367 2368 ret = krb5_rd_error(context, in, &ctx->error); 2369 if(ret && in->length && ((char*)in->data)[0] == 4) 2370 ret = KRB5KRB_AP_ERR_V4_REPLY; 2371 if (ret) { 2372 _krb5_debugx(context, 5, "krb5_get_init_creds: failed to read error"); 2373 goto out; 2374 } 2375 2376 /* 2377 * Unwrap KRB-ERROR 2378 */ 2379 ret = fast_unwrap_error(context, &ctx->fast_state, &ctx->error); 2380 if (ret) 2381 goto out; 2382 2383 /* 2384 * 2385 */ 2386 2387 ret = krb5_error_from_rd_error(context, &ctx->error, &ctx->cred); 2388 2389 /* log the failure */ 2390 if (_krb5_have_debug(context, 5)) { 2391 const char *str = krb5_get_error_message(context, ret); 2392 _krb5_debugx(context, 5, "krb5_get_init_creds: KRB-ERROR %d/%s", ret, str); 2393 krb5_free_error_message(context, str); 2394 } 2395 2396 /* 2397 * If no preauth was set and KDC requires it, give it one 2398 * more try. 2399 */ 2400 2401 if (ret == KRB5KDC_ERR_PREAUTH_REQUIRED) { 2402 2403 free_METHOD_DATA(&ctx->md); 2404 memset(&ctx->md, 0, sizeof(ctx->md)); 2405 2406 if (ctx->error.e_data) { 2407 ret = decode_METHOD_DATA(ctx->error.e_data->data, 2408 ctx->error.e_data->length, 2409 &ctx->md, 2410 NULL); 2411 if (ret) { 2412 krb5_set_error_message(context, ret, 2413 N_("Failed to decode METHOD-DATA", "")); 2414 goto out; 2415 } 2416 } else { 2417 krb5_set_error_message(context, ret, 2418 N_("Preauth required but no preauth " 2419 "options send by KDC", "")); 2420 goto out; 2421 } 2422 } else if (ret == KRB5KRB_AP_ERR_SKEW && context->kdc_sec_offset == 0) { 2423 /* 2424 * Try adapt to timeskrew when we are using pre-auth, and 2425 * if there was a time skew, try again. 2426 */ 2427 krb5_set_real_time(context, ctx->error.stime, -1); 2428 if (context->kdc_sec_offset) 2429 ret = 0; 2430 2431 _krb5_debugx(context, 10, "init_creds: err skew updateing kdc offset to %d", 2432 context->kdc_sec_offset); 2433 if (ret) 2434 goto out; 2435 2436 ctx->used_pa_types = 0; 2437 2438 } else if (ret == KRB5_KDC_ERR_WRONG_REALM && ctx->flags.canonicalize) { 2439 /* client referal to a new realm */ 2440 char *ref_realm; 2441 2442 if (ctx->error.crealm == NULL) { 2443 krb5_set_error_message(context, ret, 2444 N_("Got a client referral, not but no realm", "")); 2445 goto out; 2446 } 2447 ref_realm = *ctx->error.crealm; 2448 2449 _krb5_debugx(context, 5, "krb5_get_init_creds: referral to realm %s", 2450 ref_realm); 2451 2452 /* 2453 * If its a krbtgt, lets updat the requested krbtgt too 2454 */ 2455 if (krb5_principal_is_krbtgt(context, ctx->cred.server)) { 2456 2457 free(ctx->cred.server->name.name_string.val[1]); 2458 ctx->cred.server->name.name_string.val[1] = strdup(ref_realm); 2459 if (ctx->cred.server->name.name_string.val[1] == NULL) { 2460 ret = ENOMEM; 2461 goto out; 2462 } 2463 2464 free_PrincipalName(ctx->as_req.req_body.sname); 2465 ret = _krb5_principal2principalname(ctx->as_req.req_body.sname, ctx->cred.server); 2466 if (ret) 2467 goto out; 2468 } 2469 2470 free(ctx->as_req.req_body.realm); 2471 ret = copy_Realm(&ref_realm, &ctx->as_req.req_body.realm); 2472 if (ret) 2473 goto out; 2474 2475 ret = krb5_principal_set_realm(context, 2476 ctx->cred.client, 2477 *ctx->error.crealm); 2478 if (ret) 2479 goto out; 2480 2481 ret = krb5_unparse_name(context, ctx->cred.client, &ref_realm); 2482 if (ret == 0) { 2483 _krb5_debugx(context, 5, "krb5_get_init_creds: got referal to %s", ref_realm); 2484 krb5_xfree(ref_realm); 2485 } 2486 2487 ctx->used_pa_types = 0; 2488 } else if (ret == KRB5KDC_ERR_KEY_EXP && ctx->change_password == 0 && ctx->prompter) { 2489 char buf2[1024]; 2490 2491 ctx->change_password = 1; 2492 2493 ctx->prompter(context, ctx->prompter_data, NULL, N_("Password has expired", ""), 0, NULL); 2494 2495 2496 /* try to avoid recursion */ 2497 if (ctx->in_tkt_service != NULL && strcmp(ctx->in_tkt_service, "kadmin/changepw") == 0) 2498 goto out; 2499 2500 /* don't include prompter in runtime */ 2501 gettimeofday(&end_time, NULL); 2502 timevalsub(&end_time, &start_time); 2503 timevaladd(&ctx->stats.run_time, &end_time); 2504 2505 ret = change_password(context, 2506 ctx->cred.client, 2507 ctx->password, 2508 buf2, 2509 sizeof(buf2), 2510 ctx->prompter, 2511 ctx->prompter_data, 2512 NULL); 2513 if (ret) 2514 goto out; 2515 2516 gettimeofday(&start_time, NULL); 2517 2518 krb5_init_creds_set_password(context, ctx, buf2); 2519 2520 ctx->used_pa_types = 0; 2521 2522 } else if (ret == KRB5KDC_ERR_PREAUTH_FAILED) { 2523 2524 if (ctx->fast_state.flags & KRB5_FAST_DISABLED) { 2525 _krb5_debugx(context, 10, "FAST disabled and got preauth failed"); 2526 goto out; 2527 } 2528 2529 if ((ctx->fast_state.flags & KRB5_FAST_OPTIMISTIC) == 0) { 2530 _krb5_debugx(context, 10, "Preauth failed"); 2531 goto out; 2532 } 2533 2534 _krb5_debugx(context, 10, "preauth failed with Optimistic FAST, trying w/o FAST"); 2535 2536 ctx->fast_state.flags &= ~KRB5_FAST_OPTIMISTIC; 2537 ctx->fast_state.flags |= KRB5_FAST_DISABLED; 2538 ctx->used_pa_types = 0; 2539 2540 } else { 2541 if (ctx->fast_state.flags & KRB5_FAST_OPTIMISTIC) { 2542 _krb5_debugx(context, 10, 2543 "Some other error %d failed with Optimistic FAST, trying w/o FAST", ret); 2544 2545 ctx->fast_state.flags &= ~KRB5_FAST_OPTIMISTIC; 2546 ctx->fast_state.flags |= KRB5_FAST_DISABLED; 2547 ctx->used_pa_types = 0; 2548 } else { 2549 /* some other error code from the KDC, lets return it to the user */ 2550 goto out; 2551 } 2552 } 2553 } 2554 } 2555 2556 if (ctx->as_req.padata) { 2557 free_METHOD_DATA(ctx->as_req.padata); 2558 free(ctx->as_req.padata); 2559 ctx->as_req.padata = NULL; 2560 } 2561 2562 /* Set a new nonce. */ 2563 ctx->as_req.req_body.nonce = ctx->nonce; 2564 2565 /* fill_in_md_data */ 2566 ret = process_pa_data_to_md(context, &ctx->cred, &ctx->as_req, ctx, 2567 &ctx->md, &ctx->as_req.padata, 2568 ctx->prompter, ctx->prompter_data); 2569 if (ret) 2570 goto out; 2571 2572 /* 2573 * Wrap with FAST 2574 */ 2575 copy_AS_REQ(&ctx->as_req, &req2); 2576 2577 ret = fast_wrap_req(context, &ctx->fast_state, &req2); 2578 if (ret) { 2579 free_AS_REQ(&req2); 2580 goto out; 2581 } 2582 2583 krb5_data_free(&ctx->req_buffer); 2584 2585 ASN1_MALLOC_ENCODE(AS_REQ, 2586 ctx->req_buffer.data, ctx->req_buffer.length, 2587 &req2, &len, ret); 2588 free_AS_REQ(&req2); 2589 if (ret) 2590 goto out; 2591 if(len != ctx->req_buffer.length) 2592 krb5_abortx(context, "internal error in ASN.1 encoder"); 2593 2594 out->data = ctx->req_buffer.data; 2595 out->length = ctx->req_buffer.length; 2596 2597 *flags = KRB5_INIT_CREDS_STEP_FLAG_CONTINUE; 2598 2599 if (realm) 2600 *realm = ctx->cred.client->realm; 2601 2602 2603 gettimeofday(&end_time, NULL); 2604 timevalsub(&end_time, &start_time); 2605 timevaladd(&ctx->stats.run_time, &end_time); 2606 2607 return 0; 2608 out: 2609 return ret; 2610} 2611 2612/** 2613 * Extract the newly acquired credentials from krb5_init_creds_context 2614 * context. 2615 * 2616 * @param context A Kerberos 5 context. 2617 * @param ctx 2618 * @param cred credentials, free with krb5_free_cred_contents(). 2619 * 2620 * @return 0 for sucess or An Kerberos error code, see krb5_get_error_message(). 2621 */ 2622 2623KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2624krb5_init_creds_get_creds(krb5_context context, 2625 krb5_init_creds_context ctx, 2626 krb5_creds *cred) 2627{ 2628 return krb5_copy_creds_contents(context, &ctx->cred, cred); 2629} 2630 2631KRB5_LIB_FUNCTION krb5_timestamp KRB5_LIB_CALL 2632_krb5_init_creds_get_cred_endtime(krb5_context context, krb5_init_creds_context ctx) 2633{ 2634 return ctx->cred.times.endtime; 2635} 2636 2637KRB5_LIB_FUNCTION krb5_principal KRB5_LIB_CALL 2638_krb5_init_creds_get_cred_client(krb5_context context, krb5_init_creds_context ctx) 2639{ 2640 return ctx->cred.client; 2641} 2642 2643 2644 2645/** 2646 * Get the last error from the transaction. 2647 * 2648 * @return Returns 0 or an error code 2649 * 2650 * @ingroup krb5_credential 2651 */ 2652 2653KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2654krb5_init_creds_get_error(krb5_context context, 2655 krb5_init_creds_context ctx, 2656 KRB_ERROR *error) 2657{ 2658 krb5_error_code ret; 2659 2660 ret = copy_KRB_ERROR(&ctx->error, error); 2661 if (ret) 2662 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 2663 2664 return ret; 2665} 2666 2667/** 2668 * Store config 2669 * 2670 * @param context A Kerberos 5 context. 2671 * @param ctx The krb5_init_creds_context to free. 2672 * @param id store 2673 * 2674 * @return Returns 0 or an error code 2675 * 2676 * @ingroup krb5_credential 2677 */ 2678 2679krb5_error_code KRB5_LIB_FUNCTION 2680krb5_init_creds_store_config(krb5_context context, 2681 krb5_init_creds_context ctx, 2682 krb5_ccache id) 2683{ 2684 krb5_error_code ret; 2685 2686 if (ctx->kdc_hostname) { 2687 krb5_data data; 2688 data.length = strlen(ctx->kdc_hostname); 2689 data.data = ctx->kdc_hostname; 2690 2691 ret = krb5_cc_set_config(context, id, NULL, "lkdc-hostname", &data); 2692 if (ret) 2693 return ret; 2694 } 2695 return 0; 2696} 2697 2698 2699krb5_error_code 2700krb5_init_creds_store(krb5_context context, 2701 krb5_init_creds_context ctx, 2702 krb5_ccache id) 2703{ 2704 krb5_error_code ret; 2705 2706 if (ctx->cred.client == NULL) { 2707 ret = KRB5KDC_ERR_PREAUTH_REQUIRED; 2708 krb5_set_error_message(context, ret, "init creds not completed yet"); 2709 return ret; 2710 } 2711 2712 ret = krb5_cc_initialize(context, id, ctx->cred.client); 2713 if (ret) 2714 return ret; 2715 2716 ret = krb5_cc_store_cred(context, id, &ctx->cred); 2717 if (ret) 2718 return ret; 2719 2720 if (ctx->cred.flags.b.enc_pa_rep) { 2721 krb5_data data = { 3, rk_UNCONST("yes") }; 2722 ret = krb5_cc_set_config(context, id, ctx->cred.server, 2723 "fast_avail", &data); 2724 if (ret) 2725 return ret; 2726 } 2727 2728 return 0; 2729} 2730 2731/** 2732 * Free the krb5_init_creds_context allocated by krb5_init_creds_init(). 2733 * 2734 * @param context A Kerberos 5 context. 2735 * @param ctx The krb5_init_creds_context to free. 2736 * 2737 * @ingroup krb5_credential 2738 */ 2739 2740KRB5_LIB_FUNCTION void KRB5_LIB_CALL 2741krb5_init_creds_free(krb5_context context, 2742 krb5_init_creds_context ctx) 2743{ 2744 free_init_creds_ctx(context, ctx); 2745 free(ctx); 2746} 2747 2748/** 2749 * Get new credentials as setup by the krb5_init_creds_context. 2750 * 2751 * @param context A Kerberos 5 context. 2752 * @param ctx The krb5_init_creds_context to process. 2753 * 2754 * @ingroup krb5_credential 2755 */ 2756 2757KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2758krb5_init_creds_get(krb5_context context, krb5_init_creds_context ctx) 2759{ 2760 krb5_sendto_ctx stctx = NULL; 2761 krb5_krbhst_info *hostinfo = NULL; 2762 krb5_error_code ret; 2763 krb5_data in, out; 2764 unsigned int flags = 0; 2765 2766 krb5_data_zero(&in); 2767 krb5_data_zero(&out); 2768 2769 ret = krb5_sendto_ctx_alloc(context, &stctx); 2770 if (ret) 2771 goto out; 2772 krb5_sendto_ctx_set_func(stctx, _krb5_kdc_retry, NULL); 2773 2774 if (ctx->kdc_hostname) 2775 krb5_sendto_set_hostname(context, stctx, ctx->kdc_hostname); 2776 2777 while (1) { 2778 krb5_realm realm = NULL; 2779 struct timeval nstart, nend; 2780 2781 flags = 0; 2782 ret = krb5_init_creds_step(context, ctx, &in, &out, hostinfo, &realm, &flags); 2783 krb5_data_free(&in); 2784 if (ret) 2785 goto out; 2786 2787 if ((flags & KRB5_INIT_CREDS_STEP_FLAG_CONTINUE) == 0) 2788 break; 2789 2790 gettimeofday(&nstart, NULL); 2791 2792 ret = krb5_sendto_context (context, stctx, &out, realm, &in); 2793 if (ret) 2794 goto out; 2795 2796 gettimeofday(&nend, NULL); 2797 timevalsub(&nend, &nstart); 2798 timevaladd(&ctx->stats.run_time, &nend); 2799 } 2800 2801 out: 2802 if (stctx) 2803 krb5_sendto_ctx_free(context, stctx); 2804 2805 return ret; 2806} 2807 2808/** 2809 * Get new credentials using password. 2810 * 2811 * @ingroup krb5_credential 2812 */ 2813 2814 2815KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2816krb5_get_init_creds_password(krb5_context context, 2817 krb5_creds *creds, 2818 krb5_principal client, 2819 const char *password, 2820 krb5_prompter_fct prompter, 2821 void *data, 2822 krb5_deltat start_time, 2823 const char *in_tkt_service, 2824 krb5_get_init_creds_opt *options) 2825{ 2826 krb5_init_creds_context ctx; 2827 char buf[BUFSIZ]; 2828 krb5_error_code ret; 2829 int chpw = 0; 2830 2831 again: 2832 ret = krb5_init_creds_init(context, client, prompter, data, start_time, options, &ctx); 2833 if (ret) 2834 goto out; 2835 2836 ret = krb5_init_creds_set_service(context, ctx, in_tkt_service); 2837 if (ret) 2838 goto out; 2839 2840 if (prompter != NULL && ctx->password == NULL && password == NULL) { 2841 krb5_prompt prompt; 2842 krb5_data password_data; 2843 char *p, *q; 2844 2845 krb5_unparse_name (context, client, &p); 2846 asprintf (&q, "%s's Password: ", p); 2847 free (p); 2848 prompt.prompt = q; 2849 password_data.data = buf; 2850 password_data.length = sizeof(buf); 2851 prompt.hidden = 1; 2852 prompt.reply = &password_data; 2853 prompt.type = KRB5_PROMPT_TYPE_PASSWORD; 2854 2855 ret = (*prompter) (context, data, NULL, NULL, 1, &prompt); 2856 free (q); 2857 if (ret) { 2858 memset (buf, 0, sizeof(buf)); 2859 ret = KRB5_LIBOS_PWDINTR; 2860 krb5_clear_error_message (context); 2861 goto out; 2862 } 2863 password = password_data.data; 2864 } 2865 2866 if (password) { 2867 ret = krb5_init_creds_set_password(context, ctx, password); 2868 if (ret) 2869 goto out; 2870 } 2871 2872 ret = krb5_init_creds_get(context, ctx); 2873 2874 if (ret == 0) 2875 krb5_process_last_request(context, options, ctx); 2876 2877 if (ret == KRB5KDC_ERR_KEY_EXPIRED && chpw == 0) { 2878 char buf2[1024]; 2879 2880 /* try to avoid recursion */ 2881 if (in_tkt_service != NULL && strcmp(in_tkt_service, "kadmin/changepw") == 0) 2882 goto out; 2883 2884 /* don't try to change password where then where none */ 2885 if (prompter == NULL) 2886 goto out; 2887 2888 ret = change_password (context, 2889 client, 2890 ctx->password, 2891 buf2, 2892 sizeof(buf2), 2893 prompter, 2894 data, 2895 options); 2896 if (ret) 2897 goto out; 2898 chpw = 1; 2899 krb5_init_creds_free(context, ctx); 2900 2901 goto again; 2902 } 2903 2904 out: 2905 if (ret == 0) 2906 krb5_init_creds_get_creds(context, ctx, creds); 2907 2908 if (ctx) 2909 krb5_init_creds_free(context, ctx); 2910 2911 memset(buf, 0, sizeof(buf)); 2912 return ret; 2913} 2914 2915/** 2916 * Get new credentials using keyblock. 2917 * 2918 * @ingroup krb5_credential 2919 */ 2920 2921KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2922krb5_get_init_creds_keyblock(krb5_context context, 2923 krb5_creds *creds, 2924 krb5_principal client, 2925 krb5_keyblock *keyblock, 2926 krb5_deltat start_time, 2927 const char *in_tkt_service, 2928 krb5_get_init_creds_opt *options) 2929{ 2930 krb5_init_creds_context ctx; 2931 krb5_error_code ret; 2932 2933 memset(creds, 0, sizeof(*creds)); 2934 2935 ret = krb5_init_creds_init(context, client, NULL, NULL, start_time, options, &ctx); 2936 if (ret) 2937 goto out; 2938 2939 ret = krb5_init_creds_set_service(context, ctx, in_tkt_service); 2940 if (ret) 2941 goto out; 2942 2943 ret = krb5_init_creds_set_keyblock(context, ctx, keyblock); 2944 if (ret) 2945 goto out; 2946 2947 ret = krb5_init_creds_get(context, ctx); 2948 2949 if (ret == 0) 2950 krb5_process_last_request(context, options, ctx); 2951 2952 out: 2953 if (ret == 0) 2954 krb5_init_creds_get_creds(context, ctx, creds); 2955 2956 if (ctx) 2957 krb5_init_creds_free(context, ctx); 2958 2959 return ret; 2960} 2961 2962/** 2963 * Get new credentials using keytab. 2964 * 2965 * @ingroup krb5_credential 2966 */ 2967 2968KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2969krb5_get_init_creds_keytab(krb5_context context, 2970 krb5_creds *creds, 2971 krb5_principal client, 2972 krb5_keytab keytab, 2973 krb5_deltat start_time, 2974 const char *in_tkt_service, 2975 krb5_get_init_creds_opt *options) 2976{ 2977 krb5_init_creds_context ctx; 2978 krb5_error_code ret; 2979 2980 memset(creds, 0, sizeof(*creds)); 2981 2982 ret = krb5_init_creds_init(context, client, NULL, NULL, start_time, options, &ctx); 2983 if (ret) 2984 goto out; 2985 2986 ret = krb5_init_creds_set_service(context, ctx, in_tkt_service); 2987 if (ret) 2988 goto out; 2989 2990 ret = krb5_init_creds_set_keytab(context, ctx, keytab); 2991 if (ret) 2992 goto out; 2993 2994 ret = krb5_init_creds_get(context, ctx); 2995 if (ret == 0) 2996 krb5_process_last_request(context, options, ctx); 2997 2998 out: 2999 if (ret == 0) 3000 krb5_init_creds_get_creds(context, ctx, creds); 3001 3002 if (ctx) 3003 krb5_init_creds_free(context, ctx); 3004 3005 return ret; 3006} 3007