1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* clients/kinit/kinit.c - Initialize a credential cache */ 3 /* 4 * Copyright 1990, 2008 by the Massachusetts Institute of Technology. 5 * All Rights Reserved. 6 * 7 * Export of this software from the United States of America may 8 * require a specific license from the United States Government. 9 * It is the responsibility of any person or organization contemplating 10 * export to obtain such a license before exporting. 11 * 12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 13 * distribute this software and its documentation for any purpose and 14 * without fee is hereby granted, provided that the above copyright 15 * notice appear in all copies and that both that copyright notice and 16 * this permission notice appear in supporting documentation, and that 17 * the name of M.I.T. not be used in advertising or publicity pertaining 18 * to distribution of the software without specific, written prior 19 * permission. Furthermore if you modify this software you must label 20 * your software as modified software and not distribute it in such a 21 * fashion that it might be confused with the original M.I.T. software. 22 * M.I.T. makes no representations about the suitability of 23 * this software for any purpose. It is provided "as is" without express 24 * or implied warranty. 25 */ 26 27 #include "autoconf.h" 28 #include <k5-int.h> 29 #include "k5-platform.h" /* For asprintf and getopt */ 30 #include <krb5.h> 31 #include "extern.h" 32 #include <locale.h> 33 #include <string.h> 34 #include <stdio.h> 35 #include <time.h> 36 #include <errno.h> 37 #include <com_err.h> 38 39 #ifndef _WIN32 40 #define GET_PROGNAME(x) (strrchr((x), '/') ? strrchr((x), '/') + 1 : (x)) 41 #else 42 #define GET_PROGNAME(x) max(max(strrchr((x), '/'), strrchr((x), '\\')) + 1,(x)) 43 #endif 44 45 #ifdef HAVE_PWD_H 46 #include <pwd.h> 47 static char * 48 get_name_from_os(void) 49 { 50 struct passwd *pw; 51 52 pw = getpwuid(getuid()); 53 return (pw != NULL) ? pw->pw_name : NULL; 54 } 55 #else /* HAVE_PWD_H */ 56 #ifdef _WIN32 57 static char * 58 get_name_from_os(void) 59 { 60 static char name[1024]; 61 DWORD name_size = sizeof(name); 62 63 if (GetUserName(name, &name_size)) { 64 name[sizeof(name) - 1] = '\0'; /* Just to be extra safe */ 65 return name; 66 } else { 67 return NULL; 68 } 69 } 70 #else /* _WIN32 */ 71 static char * 72 get_name_from_os(void) 73 { 74 return NULL; 75 } 76 #endif /* _WIN32 */ 77 #endif /* HAVE_PWD_H */ 78 79 static char *progname; 80 81 typedef enum { INIT_PW, INIT_KT, RENEW, VALIDATE } action_type; 82 83 struct k_opts 84 { 85 /* In seconds */ 86 krb5_deltat starttime; 87 krb5_deltat lifetime; 88 krb5_deltat rlife; 89 90 int forwardable; 91 int proxiable; 92 int request_pac; 93 int anonymous; 94 int addresses; 95 96 int not_forwardable; 97 int not_proxiable; 98 int not_request_pac; 99 int no_addresses; 100 101 int verbose; 102 103 char *principal_name; 104 char *service_name; 105 char *keytab_name; 106 char *k5_in_cache_name; 107 char *k5_out_cache_name; 108 char *armor_ccache; 109 110 action_type action; 111 int use_client_keytab; 112 113 int num_pa_opts; 114 krb5_gic_opt_pa_data *pa_opts; 115 116 int canonicalize; 117 int enterprise; 118 }; 119 120 struct k5_data 121 { 122 krb5_context ctx; 123 krb5_ccache in_cc, out_cc; 124 krb5_principal me; 125 char *name; 126 krb5_boolean switch_to_cache; 127 }; 128 129 /* 130 * If struct[2] == NULL, then long_getopt acts as if the short flag struct[3] 131 * were specified. If struct[2] != NULL, then struct[3] is stored in 132 * *(struct[2]), the array index which was specified is stored in *index, and 133 * long_getopt() returns 0. 134 */ 135 const char *shopts = "r:fpFPn54aAVl:s:c:kit:T:RS:vX:CEI:"; 136 137 #define USAGE_BREAK "\n\t" 138 139 static void 140 usage(void) 141 { 142 fprintf(stderr, 143 _("Usage: %s [-V] [-l lifetime] [-s start_time] " 144 "[-r renewable_life]\n" 145 "\t[-f | -F] [-p | -P] [-n] [-a | -A] [-C] [-E]\n" 146 "\t[--request-pac | --no-request-pac]\n" 147 "\t[-v] [-R] [-k [-i|-t keytab_file]] [-c cachename]\n" 148 "\t[-S service_name] [-I input_ccache] [-T ticket_armor_cache]\n" 149 "\t[-X <attribute>[=<value>]] [principal]\n" 150 "\n"), progname); 151 152 fprintf(stderr, " options:\n"); 153 fprintf(stderr, _("\t-V verbose\n")); 154 fprintf(stderr, _("\t-l lifetime\n")); 155 fprintf(stderr, _("\t-s start time\n")); 156 fprintf(stderr, _("\t-r renewable lifetime\n")); 157 fprintf(stderr, _("\t-f forwardable\n")); 158 fprintf(stderr, _("\t-F not forwardable\n")); 159 fprintf(stderr, _("\t-p proxiable\n")); 160 fprintf(stderr, _("\t-P not proxiable\n")); 161 fprintf(stderr, _("\t-n anonymous\n")); 162 fprintf(stderr, _("\t-a include addresses\n")); 163 fprintf(stderr, _("\t-A do not include addresses\n")); 164 fprintf(stderr, _("\t-v validate\n")); 165 fprintf(stderr, _("\t-R renew\n")); 166 fprintf(stderr, _("\t-C canonicalize\n")); 167 fprintf(stderr, _("\t-E client is enterprise principal name\n")); 168 fprintf(stderr, _("\t-k use keytab\n")); 169 fprintf(stderr, _("\t-i use default client keytab (with -k)\n")); 170 fprintf(stderr, _("\t-t filename of keytab to use\n")); 171 fprintf(stderr, _("\t-c Kerberos 5 cache name\n")); 172 fprintf(stderr, _("\t-S service\n")); 173 fprintf(stderr, _("\t-I input credential cache\n")); 174 fprintf(stderr, _("\t-T armor credential cache\n")); 175 fprintf(stderr, _("\t-X <attribute>[=<value>]\n")); 176 fprintf(stderr, 177 _("\t--{,no}-request-pac request KDC include/exclude a PAC\n")); 178 exit(2); 179 } 180 181 static krb5_context errctx; 182 static void 183 extended_com_err_fn(const char *myprog, errcode_t code, const char *fmt, 184 va_list args) 185 { 186 const char *emsg; 187 188 emsg = krb5_get_error_message(errctx, code); 189 fprintf(stderr, "%s: %s ", myprog, emsg); 190 krb5_free_error_message(errctx, emsg); 191 vfprintf(stderr, fmt, args); 192 fprintf(stderr, "\n"); 193 } 194 195 static int 196 add_preauth_opt(struct k_opts *opts, char *av) 197 { 198 char *sep, *v; 199 krb5_gic_opt_pa_data *p, *x; 200 size_t newsize = (opts->num_pa_opts + 1) * sizeof(*opts->pa_opts); 201 202 x = realloc(opts->pa_opts, newsize); 203 if (x == NULL) 204 return ENOMEM; 205 opts->pa_opts = x; 206 207 p = &opts->pa_opts[opts->num_pa_opts]; 208 sep = strchr(av, '='); 209 if (sep) { 210 *sep = '\0'; 211 v = ++sep; 212 p->value = v; 213 } else { 214 p->value = "yes"; 215 } 216 p->attr = av; 217 opts->num_pa_opts++; 218 return 0; 219 } 220 221 static char * 222 parse_options(int argc, char **argv, struct k_opts *opts) 223 { 224 struct option long_options[] = { 225 { "noforwardable", 0, NULL, 'F' }, 226 { "noproxiable", 0, NULL, 'P' }, 227 { "addresses", 0, NULL, 'a'}, 228 { "forwardable", 0, NULL, 'f' }, 229 { "proxiable", 0, NULL, 'p' }, 230 { "noaddresses", 0, NULL, 'A' }, 231 { "canonicalize", 0, NULL, 'C' }, 232 { "enterprise", 0, NULL, 'E' }, 233 { "request-pac", 0, &opts->request_pac, 1 }, 234 { "no-request-pac", 0, &opts->not_request_pac, 1 }, 235 { NULL, 0, NULL, 0 } 236 }; 237 krb5_error_code ret; 238 int errflg = 0; 239 int i; 240 241 while ((i = getopt_long(argc, argv, shopts, long_options, 0)) != -1) { 242 switch (i) { 243 case 'V': 244 opts->verbose = 1; 245 break; 246 case 'l': 247 /* Lifetime */ 248 ret = krb5_string_to_deltat(optarg, &opts->lifetime); 249 if (ret || opts->lifetime == 0) { 250 fprintf(stderr, _("Bad lifetime value %s\n"), optarg); 251 errflg++; 252 } 253 break; 254 case 'r': 255 /* Renewable Time */ 256 ret = krb5_string_to_deltat(optarg, &opts->rlife); 257 if (ret || opts->rlife == 0) { 258 fprintf(stderr, _("Bad lifetime value %s\n"), optarg); 259 errflg++; 260 } 261 break; 262 case 'f': 263 opts->forwardable = 1; 264 break; 265 case 'F': 266 opts->not_forwardable = 1; 267 break; 268 case 'p': 269 opts->proxiable = 1; 270 break; 271 case 'P': 272 opts->not_proxiable = 1; 273 break; 274 case 'n': 275 opts->anonymous = 1; 276 break; 277 case 'a': 278 opts->addresses = 1; 279 break; 280 case 'A': 281 opts->no_addresses = 1; 282 break; 283 case 's': 284 ret = krb5_string_to_deltat(optarg, &opts->starttime); 285 if (ret || opts->starttime == 0) { 286 /* Parse as an absolute time; intentionally undocumented 287 * but left for backwards compatibility. */ 288 krb5_timestamp abs_starttime; 289 290 ret = krb5_string_to_timestamp(optarg, &abs_starttime); 291 if (ret || abs_starttime == 0) { 292 fprintf(stderr, _("Bad start time value %s\n"), optarg); 293 errflg++; 294 } else { 295 opts->starttime = ts_delta(abs_starttime, time(NULL)); 296 } 297 } 298 break; 299 case 'S': 300 opts->service_name = optarg; 301 break; 302 case 'k': 303 opts->action = INIT_KT; 304 break; 305 case 'i': 306 opts->use_client_keytab = 1; 307 break; 308 case 't': 309 if (opts->keytab_name != NULL) { 310 fprintf(stderr, _("Only one -t option allowed.\n")); 311 errflg++; 312 } else { 313 opts->keytab_name = optarg; 314 } 315 break; 316 case 'T': 317 if (opts->armor_ccache != NULL) { 318 fprintf(stderr, _("Only one armor_ccache\n")); 319 errflg++; 320 } else { 321 opts->armor_ccache = optarg; 322 } 323 break; 324 case 'R': 325 opts->action = RENEW; 326 break; 327 case 'v': 328 opts->action = VALIDATE; 329 break; 330 case 'c': 331 if (opts->k5_out_cache_name != NULL) { 332 fprintf(stderr, _("Only one -c option allowed\n")); 333 errflg++; 334 } else { 335 opts->k5_out_cache_name = optarg; 336 } 337 break; 338 case 'I': 339 if (opts->k5_in_cache_name != NULL) { 340 fprintf(stderr, _("Only one -I option allowed\n")); 341 errflg++; 342 } else { 343 opts->k5_in_cache_name = optarg; 344 } 345 break; 346 case 'X': 347 ret = add_preauth_opt(opts, optarg); 348 if (ret) { 349 com_err(progname, ret, _("while adding preauth option")); 350 errflg++; 351 } 352 break; 353 case 'C': 354 opts->canonicalize = 1; 355 break; 356 case 'E': 357 opts->enterprise = 1; 358 break; 359 case '4': 360 fprintf(stderr, _("Kerberos 4 is no longer supported\n")); 361 exit(3); 362 break; 363 case '5': 364 break; 365 case 0: 366 /* If this option set a flag, do nothing else now. */ 367 break; 368 default: 369 errflg++; 370 break; 371 } 372 } 373 374 if (opts->forwardable && opts->not_forwardable) { 375 fprintf(stderr, _("Only one of -f and -F allowed\n")); 376 errflg++; 377 } 378 if (opts->proxiable && opts->not_proxiable) { 379 fprintf(stderr, _("Only one of -p and -P allowed\n")); 380 errflg++; 381 } 382 if (opts->request_pac && opts->not_request_pac) { 383 fprintf(stderr, _("Only one of --request-pac and --no-request-pac " 384 "allowed\n")); 385 errflg++; 386 } 387 if (opts->addresses && opts->no_addresses) { 388 fprintf(stderr, _("Only one of -a and -A allowed\n")); 389 errflg++; 390 } 391 if (opts->keytab_name != NULL && opts->use_client_keytab == 1) { 392 fprintf(stderr, _("Only one of -t and -i allowed\n")); 393 errflg++; 394 } 395 if ((opts->keytab_name != NULL || opts->use_client_keytab == 1) && 396 opts->action != INIT_KT) { 397 opts->action = INIT_KT; 398 fprintf(stderr, _("keytab specified, forcing -k\n")); 399 } 400 if (argc - optind > 1) { 401 fprintf(stderr, _("Extra arguments (starting with \"%s\").\n"), 402 argv[optind + 1]); 403 errflg++; 404 } 405 406 if (errflg) 407 usage(); 408 409 opts->principal_name = (optind == argc - 1) ? argv[optind] : 0; 410 return opts->principal_name; 411 } 412 413 static int 414 k5_begin(struct k_opts *opts, struct k5_data *k5) 415 { 416 krb5_error_code ret; 417 int success = 0; 418 int flags = opts->enterprise ? KRB5_PRINCIPAL_PARSE_ENTERPRISE : 0; 419 krb5_ccache defcache = NULL; 420 krb5_principal defcache_princ = NULL, princ; 421 krb5_keytab keytab; 422 const char *deftype = NULL; 423 char *defrealm, *name; 424 425 ret = krb5_init_context(&k5->ctx); 426 if (ret) { 427 com_err(progname, ret, _("while initializing Kerberos 5 library")); 428 return 0; 429 } 430 errctx = k5->ctx; 431 432 if (opts->k5_out_cache_name) { 433 ret = krb5_cc_resolve(k5->ctx, opts->k5_out_cache_name, &k5->out_cc); 434 if (ret) { 435 com_err(progname, ret, _("resolving ccache %s"), 436 opts->k5_out_cache_name); 437 goto cleanup; 438 } 439 if (opts->verbose) { 440 fprintf(stderr, _("Using specified cache: %s\n"), 441 opts->k5_out_cache_name); 442 } 443 } else { 444 /* Resolve the default ccache and get its type and default principal 445 * (if it is initialized). */ 446 ret = krb5_cc_default(k5->ctx, &defcache); 447 if (ret) { 448 com_err(progname, ret, _("while getting default ccache")); 449 goto cleanup; 450 } 451 deftype = krb5_cc_get_type(k5->ctx, defcache); 452 if (krb5_cc_get_principal(k5->ctx, defcache, &defcache_princ) != 0) 453 defcache_princ = NULL; 454 } 455 456 /* Choose a client principal name. */ 457 if (opts->principal_name != NULL) { 458 /* Use the specified principal name. */ 459 ret = krb5_parse_name_flags(k5->ctx, opts->principal_name, flags, 460 &k5->me); 461 if (ret) { 462 com_err(progname, ret, _("when parsing name %s"), 463 opts->principal_name); 464 goto cleanup; 465 } 466 } else if (opts->anonymous) { 467 /* Use the anonymous principal for the local realm. */ 468 ret = krb5_get_default_realm(k5->ctx, &defrealm); 469 if (ret) { 470 com_err(progname, ret, _("while getting default realm")); 471 goto cleanup; 472 } 473 ret = krb5_build_principal_ext(k5->ctx, &k5->me, 474 strlen(defrealm), defrealm, 475 strlen(KRB5_WELLKNOWN_NAMESTR), 476 KRB5_WELLKNOWN_NAMESTR, 477 strlen(KRB5_ANONYMOUS_PRINCSTR), 478 KRB5_ANONYMOUS_PRINCSTR, 0); 479 krb5_free_default_realm(k5->ctx, defrealm); 480 if (ret) { 481 com_err(progname, ret, _("while building principal")); 482 goto cleanup; 483 } 484 } else if (opts->action == INIT_KT && opts->use_client_keytab) { 485 /* Use the first entry from the client keytab. */ 486 ret = krb5_kt_client_default(k5->ctx, &keytab); 487 if (ret) { 488 com_err(progname, ret, 489 _("When resolving the default client keytab")); 490 goto cleanup; 491 } 492 ret = k5_kt_get_principal(k5->ctx, keytab, &k5->me); 493 krb5_kt_close(k5->ctx, keytab); 494 if (ret) { 495 com_err(progname, ret, 496 _("When determining client principal name from keytab")); 497 goto cleanup; 498 } 499 } else if (opts->action == INIT_KT) { 500 /* Use the default host/service name. */ 501 ret = krb5_sname_to_principal(k5->ctx, NULL, NULL, KRB5_NT_SRV_HST, 502 &k5->me); 503 if (ret) { 504 com_err(progname, ret, 505 _("when creating default server principal name")); 506 goto cleanup; 507 } 508 } else if (k5->out_cc != NULL) { 509 /* If the output ccache is initialized, use its principal. */ 510 if (krb5_cc_get_principal(k5->ctx, k5->out_cc, &princ) == 0) 511 k5->me = princ; 512 } else if (defcache_princ != NULL) { 513 /* Use the default cache's principal, and use the default cache as the 514 * output cache. */ 515 k5->out_cc = defcache; 516 defcache = NULL; 517 k5->me = defcache_princ; 518 defcache_princ = NULL; 519 } 520 521 /* If we still haven't chosen, use the local username. */ 522 if (k5->me == NULL) { 523 name = get_name_from_os(); 524 if (name == NULL) { 525 fprintf(stderr, _("Unable to identify user\n")); 526 goto cleanup; 527 } 528 ret = krb5_parse_name_flags(k5->ctx, name, flags, &k5->me); 529 if (ret) { 530 com_err(progname, ret, _("when parsing name %s"), name); 531 goto cleanup; 532 } 533 } 534 535 if (k5->out_cc == NULL && krb5_cc_support_switch(k5->ctx, deftype)) { 536 /* Use an existing cache for the client principal if we can. */ 537 ret = krb5_cc_cache_match(k5->ctx, k5->me, &k5->out_cc); 538 if (ret && ret != KRB5_CC_NOTFOUND) { 539 com_err(progname, ret, _("while searching for ccache for %s"), 540 opts->principal_name); 541 goto cleanup; 542 } 543 if (!ret) { 544 if (opts->verbose) { 545 fprintf(stderr, _("Using existing cache: %s\n"), 546 krb5_cc_get_name(k5->ctx, k5->out_cc)); 547 } 548 k5->switch_to_cache = 1; 549 } else if (defcache_princ != NULL) { 550 /* Create a new cache to avoid overwriting the initialized default 551 * cache. */ 552 ret = krb5_cc_new_unique(k5->ctx, deftype, NULL, &k5->out_cc); 553 if (ret) { 554 com_err(progname, ret, _("while generating new ccache")); 555 goto cleanup; 556 } 557 if (opts->verbose) { 558 fprintf(stderr, _("Using new cache: %s\n"), 559 krb5_cc_get_name(k5->ctx, k5->out_cc)); 560 } 561 k5->switch_to_cache = 1; 562 } 563 } 564 565 /* Use the default cache if we haven't picked one yet. */ 566 if (k5->out_cc == NULL) { 567 k5->out_cc = defcache; 568 defcache = NULL; 569 if (opts->verbose) { 570 fprintf(stderr, _("Using default cache: %s\n"), 571 krb5_cc_get_name(k5->ctx, k5->out_cc)); 572 } 573 } 574 575 if (opts->k5_in_cache_name) { 576 ret = krb5_cc_resolve(k5->ctx, opts->k5_in_cache_name, &k5->in_cc); 577 if (ret) { 578 com_err(progname, ret, _("resolving ccache %s"), 579 opts->k5_in_cache_name); 580 goto cleanup; 581 } 582 if (opts->verbose) { 583 fprintf(stderr, _("Using specified input cache: %s\n"), 584 opts->k5_in_cache_name); 585 } 586 } 587 588 ret = krb5_unparse_name(k5->ctx, k5->me, &k5->name); 589 if (ret) { 590 com_err(progname, ret, _("when unparsing name")); 591 goto cleanup; 592 } 593 if (opts->verbose) 594 fprintf(stderr, _("Using principal: %s\n"), k5->name); 595 596 opts->principal_name = k5->name; 597 598 success = 1; 599 600 cleanup: 601 if (defcache != NULL) 602 krb5_cc_close(k5->ctx, defcache); 603 krb5_free_principal(k5->ctx, defcache_princ); 604 return success; 605 } 606 607 static void 608 k5_end(struct k5_data *k5) 609 { 610 krb5_free_unparsed_name(k5->ctx, k5->name); 611 krb5_free_principal(k5->ctx, k5->me); 612 if (k5->in_cc != NULL) 613 krb5_cc_close(k5->ctx, k5->in_cc); 614 if (k5->out_cc != NULL) 615 krb5_cc_close(k5->ctx, k5->out_cc); 616 krb5_free_context(k5->ctx); 617 errctx = NULL; 618 memset(k5, 0, sizeof(*k5)); 619 } 620 621 static krb5_error_code KRB5_CALLCONV 622 kinit_prompter(krb5_context ctx, void *data, const char *name, 623 const char *banner, int num_prompts, krb5_prompt prompts[]) 624 { 625 krb5_boolean *pwprompt = data; 626 krb5_prompt_type *ptypes; 627 int i; 628 629 /* Make a note if we receive a password prompt. */ 630 ptypes = krb5_get_prompt_types(ctx); 631 for (i = 0; i < num_prompts; i++) { 632 if (ptypes != NULL && ptypes[i] == KRB5_PROMPT_TYPE_PASSWORD) 633 *pwprompt = TRUE; 634 } 635 return krb5_prompter_posix(ctx, data, name, banner, num_prompts, prompts); 636 } 637 638 static int 639 k5_kinit(struct k_opts *opts, struct k5_data *k5) 640 { 641 int notix = 1; 642 krb5_keytab keytab = 0; 643 krb5_creds my_creds; 644 krb5_error_code ret; 645 krb5_get_init_creds_opt *options = NULL; 646 krb5_boolean pwprompt = FALSE; 647 krb5_address **addresses = NULL; 648 krb5_principal cprinc; 649 krb5_ccache mcc = NULL; 650 int i; 651 652 memset(&my_creds, 0, sizeof(my_creds)); 653 654 ret = krb5_get_init_creds_opt_alloc(k5->ctx, &options); 655 if (ret) 656 goto cleanup; 657 658 if (opts->lifetime) 659 krb5_get_init_creds_opt_set_tkt_life(options, opts->lifetime); 660 if (opts->rlife) 661 krb5_get_init_creds_opt_set_renew_life(options, opts->rlife); 662 if (opts->forwardable) 663 krb5_get_init_creds_opt_set_forwardable(options, 1); 664 if (opts->not_forwardable) 665 krb5_get_init_creds_opt_set_forwardable(options, 0); 666 if (opts->proxiable) 667 krb5_get_init_creds_opt_set_proxiable(options, 1); 668 if (opts->not_proxiable) 669 krb5_get_init_creds_opt_set_proxiable(options, 0); 670 if (opts->canonicalize) 671 krb5_get_init_creds_opt_set_canonicalize(options, 1); 672 if (opts->anonymous) 673 krb5_get_init_creds_opt_set_anonymous(options, 1); 674 if (opts->addresses) { 675 ret = krb5_os_localaddr(k5->ctx, &addresses); 676 if (ret) { 677 com_err(progname, ret, _("getting local addresses")); 678 goto cleanup; 679 } 680 krb5_get_init_creds_opt_set_address_list(options, addresses); 681 } 682 if (opts->no_addresses) 683 krb5_get_init_creds_opt_set_address_list(options, NULL); 684 if (opts->armor_ccache != NULL) { 685 krb5_get_init_creds_opt_set_fast_ccache_name(k5->ctx, options, 686 opts->armor_ccache); 687 } 688 if (opts->request_pac) 689 krb5_get_init_creds_opt_set_pac_request(k5->ctx, options, TRUE); 690 if (opts->not_request_pac) 691 krb5_get_init_creds_opt_set_pac_request(k5->ctx, options, FALSE); 692 693 694 if (opts->action == INIT_KT && opts->keytab_name != NULL) { 695 #ifndef _WIN32 696 if (strncmp(opts->keytab_name, "KDB:", 4) == 0) { 697 ret = kinit_kdb_init(&k5->ctx, k5->me->realm.data); 698 errctx = k5->ctx; 699 if (ret) { 700 com_err(progname, ret, 701 _("while setting up KDB keytab for realm %s"), 702 k5->me->realm.data); 703 goto cleanup; 704 } 705 } 706 #endif 707 708 ret = krb5_kt_resolve(k5->ctx, opts->keytab_name, &keytab); 709 if (ret) { 710 com_err(progname, ret, _("resolving keytab %s"), 711 opts->keytab_name); 712 goto cleanup; 713 } 714 if (opts->verbose) 715 fprintf(stderr, _("Using keytab: %s\n"), opts->keytab_name); 716 } else if (opts->action == INIT_KT && opts->use_client_keytab) { 717 ret = krb5_kt_client_default(k5->ctx, &keytab); 718 if (ret) { 719 com_err(progname, ret, _("resolving default client keytab")); 720 goto cleanup; 721 } 722 } 723 724 for (i = 0; i < opts->num_pa_opts; i++) { 725 ret = krb5_get_init_creds_opt_set_pa(k5->ctx, options, 726 opts->pa_opts[i].attr, 727 opts->pa_opts[i].value); 728 if (ret) { 729 com_err(progname, ret, _("while setting '%s'='%s'"), 730 opts->pa_opts[i].attr, opts->pa_opts[i].value); 731 goto cleanup; 732 } 733 if (opts->verbose) { 734 fprintf(stderr, _("PA Option %s = %s\n"), opts->pa_opts[i].attr, 735 opts->pa_opts[i].value); 736 } 737 } 738 if (k5->in_cc) { 739 ret = krb5_get_init_creds_opt_set_in_ccache(k5->ctx, options, 740 k5->in_cc); 741 if (ret) 742 goto cleanup; 743 } 744 ret = krb5_get_init_creds_opt_set_out_ccache(k5->ctx, options, k5->out_cc); 745 if (ret) 746 goto cleanup; 747 748 switch (opts->action) { 749 case INIT_PW: 750 ret = krb5_get_init_creds_password(k5->ctx, &my_creds, k5->me, 0, 751 kinit_prompter, &pwprompt, 752 opts->starttime, opts->service_name, 753 options); 754 break; 755 case INIT_KT: 756 ret = krb5_get_init_creds_keytab(k5->ctx, &my_creds, k5->me, keytab, 757 opts->starttime, opts->service_name, 758 options); 759 break; 760 case VALIDATE: 761 ret = krb5_get_validated_creds(k5->ctx, &my_creds, k5->me, k5->out_cc, 762 opts->service_name); 763 break; 764 case RENEW: 765 ret = krb5_get_renewed_creds(k5->ctx, &my_creds, k5->me, k5->out_cc, 766 opts->service_name); 767 break; 768 } 769 770 if (ret) { 771 char *doing = NULL; 772 switch (opts->action) { 773 case INIT_PW: 774 case INIT_KT: 775 doing = _("getting initial credentials"); 776 break; 777 case VALIDATE: 778 doing = _("validating credentials"); 779 break; 780 case RENEW: 781 doing = _("renewing credentials"); 782 break; 783 } 784 785 /* If reply decryption failed, or if pre-authentication failed and we 786 * were prompted for a password, assume the password was wrong. */ 787 if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY || 788 (pwprompt && ret == KRB5KDC_ERR_PREAUTH_FAILED)) { 789 fprintf(stderr, _("%s: Password incorrect while %s\n"), progname, 790 doing); 791 } else { 792 com_err(progname, ret, _("while %s"), doing); 793 } 794 goto cleanup; 795 } 796 797 if (opts->action != INIT_PW && opts->action != INIT_KT) { 798 cprinc = opts->canonicalize ? my_creds.client : k5->me; 799 ret = krb5_cc_new_unique(k5->ctx, "MEMORY", NULL, &mcc); 800 if (!ret) 801 ret = krb5_cc_initialize(k5->ctx, mcc, cprinc); 802 if (ret) { 803 com_err(progname, ret, _("when creating temporary cache")); 804 goto cleanup; 805 } 806 if (opts->verbose) 807 fprintf(stderr, _("Initialized cache\n")); 808 809 ret = k5_cc_store_primary_cred(k5->ctx, mcc, &my_creds); 810 if (ret) { 811 com_err(progname, ret, _("while storing credentials")); 812 goto cleanup; 813 } 814 ret = krb5_cc_move(k5->ctx, mcc, k5->out_cc); 815 if (ret) { 816 com_err(progname, ret, _("while saving to cache %s"), 817 opts->k5_out_cache_name ? opts->k5_out_cache_name : ""); 818 goto cleanup; 819 } 820 mcc = NULL; 821 if (opts->verbose) 822 fprintf(stderr, _("Stored credentials\n")); 823 } 824 notix = 0; 825 if (k5->switch_to_cache) { 826 ret = krb5_cc_switch(k5->ctx, k5->out_cc); 827 if (ret) { 828 com_err(progname, ret, _("while switching to new ccache")); 829 goto cleanup; 830 } 831 } 832 833 cleanup: 834 #ifndef _WIN32 835 kinit_kdb_fini(); 836 #endif 837 if (mcc != NULL) 838 krb5_cc_destroy(k5->ctx, mcc); 839 if (options) 840 krb5_get_init_creds_opt_free(k5->ctx, options); 841 if (my_creds.client == k5->me) 842 my_creds.client = 0; 843 if (opts->pa_opts) { 844 free(opts->pa_opts); 845 opts->pa_opts = NULL; 846 opts->num_pa_opts = 0; 847 } 848 krb5_free_cred_contents(k5->ctx, &my_creds); 849 if (keytab != NULL) 850 krb5_kt_close(k5->ctx, keytab); 851 return notix ? 0 : 1; 852 } 853 854 int 855 main(int argc, char *argv[]) 856 { 857 struct k_opts opts; 858 struct k5_data k5; 859 int authed_k5 = 0; 860 861 setlocale(LC_ALL, ""); 862 progname = GET_PROGNAME(argv[0]); 863 864 /* Ensure we can be driven from a pipe */ 865 if (!isatty(fileno(stdin))) 866 setvbuf(stdin, 0, _IONBF, 0); 867 if (!isatty(fileno(stdout))) 868 setvbuf(stdout, 0, _IONBF, 0); 869 if (!isatty(fileno(stderr))) 870 setvbuf(stderr, 0, _IONBF, 0); 871 872 memset(&opts, 0, sizeof(opts)); 873 opts.action = INIT_PW; 874 875 memset(&k5, 0, sizeof(k5)); 876 877 set_com_err_hook(extended_com_err_fn); 878 879 parse_options(argc, argv, &opts); 880 881 if (k5_begin(&opts, &k5)) 882 authed_k5 = k5_kinit(&opts, &k5); 883 884 if (authed_k5 && opts.verbose) 885 fprintf(stderr, _("Authenticated to Kerberos v5\n")); 886 887 k5_end(&k5); 888 889 if (!authed_k5) 890 exit(1); 891 return 0; 892 } 893