1 /* 2 * Copyright (c) 1997-2007 Kungliga Tekniska H�gskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include "kuser_locl.h" 35 RCSID("$Id: kinit.c 22116 2007-12-03 21:22:58Z lha $"); 36 37 #include "krb5-v4compat.h" 38 39 #include "heimntlm.h" 40 41 int forwardable_flag = -1; 42 int proxiable_flag = -1; 43 int renewable_flag = -1; 44 int renew_flag = 0; 45 int pac_flag = -1; 46 int validate_flag = 0; 47 int version_flag = 0; 48 int help_flag = 0; 49 int addrs_flag = -1; 50 struct getarg_strings extra_addresses; 51 int anonymous_flag = 0; 52 char *lifetime = NULL; 53 char *renew_life = NULL; 54 char *server_str = NULL; 55 char *cred_cache = NULL; 56 char *start_str = NULL; 57 struct getarg_strings etype_str; 58 int use_keytab = 0; 59 char *keytab_str = NULL; 60 int do_afslog = -1; 61 int get_v4_tgt = -1; 62 int convert_524 = 0; 63 int fcache_version; 64 char *password_file = NULL; 65 char *pk_user_id = NULL; 66 char *pk_x509_anchors = NULL; 67 int pk_use_enckey = 0; 68 static int canonicalize_flag = 0; 69 static char *ntlm_domain; 70 71 static char *krb4_cc_name; 72 73 static struct getargs args[] = { 74 /* 75 * used by MIT 76 * a: ~A 77 * V: verbose 78 * F: ~f 79 * P: ~p 80 * C: v4 cache name? 81 * 5: 82 */ 83 { "524init", '4', arg_flag, &get_v4_tgt, 84 "obtain version 4 TGT" }, 85 86 { "524convert", '9', arg_flag, &convert_524, 87 "only convert ticket to version 4" }, 88 89 { "afslog", 0 , arg_flag, &do_afslog, 90 "obtain afs tokens" }, 91 92 { "cache", 'c', arg_string, &cred_cache, 93 "credentials cache", "cachename" }, 94 95 { "forwardable", 'f', arg_flag, &forwardable_flag, 96 "get forwardable tickets"}, 97 98 { "keytab", 't', arg_string, &keytab_str, 99 "keytab to use", "keytabname" }, 100 101 { "lifetime", 'l', arg_string, &lifetime, 102 "lifetime of tickets", "time"}, 103 104 { "proxiable", 'p', arg_flag, &proxiable_flag, 105 "get proxiable tickets" }, 106 107 { "renew", 'R', arg_flag, &renew_flag, 108 "renew TGT" }, 109 110 { "renewable", 0, arg_flag, &renewable_flag, 111 "get renewable tickets" }, 112 113 { "renewable-life", 'r', arg_string, &renew_life, 114 "renewable lifetime of tickets", "time" }, 115 116 { "server", 'S', arg_string, &server_str, 117 "server to get ticket for", "principal" }, 118 119 { "start-time", 's', arg_string, &start_str, 120 "when ticket gets valid", "time" }, 121 122 { "use-keytab", 'k', arg_flag, &use_keytab, 123 "get key from keytab" }, 124 125 { "validate", 'v', arg_flag, &validate_flag, 126 "validate TGT" }, 127 128 { "enctypes", 'e', arg_strings, &etype_str, 129 "encryption types to use", "enctypes" }, 130 131 { "fcache-version", 0, arg_integer, &fcache_version, 132 "file cache version to create" }, 133 134 { "addresses", 'A', arg_negative_flag, &addrs_flag, 135 "request a ticket with no addresses" }, 136 137 { "extra-addresses",'a', arg_strings, &extra_addresses, 138 "include these extra addresses", "addresses" }, 139 140 { "anonymous", 0, arg_flag, &anonymous_flag, 141 "request an anonymous ticket" }, 142 143 { "request-pac", 0, arg_flag, &pac_flag, 144 "request a Windows PAC" }, 145 146 { "password-file", 0, arg_string, &password_file, 147 "read the password from a file" }, 148 149 { "canonicalize",0, arg_flag, &canonicalize_flag, 150 "canonicalize client principal" }, 151 #ifdef PKINIT 152 { "pk-user", 'C', arg_string, &pk_user_id, 153 "principal's public/private/certificate identifier", "id" }, 154 155 { "x509-anchors", 'D', arg_string, &pk_x509_anchors, 156 "directory with CA certificates", "directory" }, 157 158 { "pk-use-enckey", 0, arg_flag, &pk_use_enckey, 159 "Use RSA encrypted reply (instead of DH)" }, 160 #endif 161 { "ntlm-domain", 0, arg_string, &ntlm_domain, 162 "NTLM domain", "domain" }, 163 164 { "version", 0, arg_flag, &version_flag }, 165 { "help", 0, arg_flag, &help_flag } 166 }; 167 168 static void 169 usage (int ret) 170 { 171 arg_printusage (args, 172 sizeof(args)/sizeof(*args), 173 NULL, 174 "[principal [command]]"); 175 exit (ret); 176 } 177 178 static krb5_error_code 179 get_server(krb5_context context, 180 krb5_principal client, 181 const char *server, 182 krb5_principal *princ) 183 { 184 krb5_realm *client_realm; 185 if(server) 186 return krb5_parse_name(context, server, princ); 187 188 client_realm = krb5_princ_realm (context, client); 189 return krb5_make_principal(context, princ, *client_realm, 190 KRB5_TGS_NAME, *client_realm, NULL); 191 } 192 193 static krb5_error_code 194 do_524init(krb5_context context, krb5_ccache ccache, 195 krb5_creds *creds, const char *server) 196 { 197 krb5_error_code ret; 198 199 struct credentials c; 200 krb5_creds in_creds, *real_creds; 201 202 if(creds != NULL) 203 real_creds = creds; 204 else { 205 krb5_principal client; 206 krb5_cc_get_principal(context, ccache, &client); 207 memset(&in_creds, 0, sizeof(in_creds)); 208 ret = get_server(context, client, server, &in_creds.server); 209 if(ret) { 210 krb5_free_principal(context, client); 211 return ret; 212 } 213 in_creds.client = client; 214 ret = krb5_get_credentials(context, 0, ccache, &in_creds, &real_creds); 215 krb5_free_principal(context, client); 216 krb5_free_principal(context, in_creds.server); 217 if(ret) 218 return ret; 219 } 220 ret = krb524_convert_creds_kdc_ccache(context, ccache, real_creds, &c); 221 if(ret) 222 krb5_warn(context, ret, "converting creds"); 223 else { 224 krb5_error_code tret = _krb5_krb_tf_setup(context, &c, NULL, 0); 225 if(tret) 226 krb5_warn(context, tret, "saving v4 creds"); 227 } 228 229 if(creds == NULL) 230 krb5_free_creds(context, real_creds); 231 memset(&c, 0, sizeof(c)); 232 233 return ret; 234 } 235 236 static int 237 renew_validate(krb5_context context, 238 int renew, 239 int validate, 240 krb5_ccache cache, 241 const char *server, 242 krb5_deltat life) 243 { 244 krb5_error_code ret; 245 krb5_creds in, *out = NULL; 246 krb5_kdc_flags flags; 247 248 memset(&in, 0, sizeof(in)); 249 250 ret = krb5_cc_get_principal(context, cache, &in.client); 251 if(ret) { 252 krb5_warn(context, ret, "krb5_cc_get_principal"); 253 return ret; 254 } 255 ret = get_server(context, in.client, server, &in.server); 256 if(ret) { 257 krb5_warn(context, ret, "get_server"); 258 goto out; 259 } 260 261 if (renew) { 262 /* 263 * no need to check the error here, it's only to be 264 * friendly to the user 265 */ 266 krb5_get_credentials(context, KRB5_GC_CACHED, cache, &in, &out); 267 } 268 269 flags.i = 0; 270 flags.b.renewable = flags.b.renew = renew; 271 flags.b.validate = validate; 272 273 if (forwardable_flag != -1) 274 flags.b.forwardable = forwardable_flag; 275 else if (out) 276 flags.b.forwardable = out->flags.b.forwardable; 277 278 if (proxiable_flag != -1) 279 flags.b.proxiable = proxiable_flag; 280 else if (out) 281 flags.b.proxiable = out->flags.b.proxiable; 282 283 if (anonymous_flag != -1) 284 flags.b.request_anonymous = anonymous_flag; 285 if(life) 286 in.times.endtime = time(NULL) + life; 287 288 if (out) { 289 krb5_free_creds (context, out); 290 out = NULL; 291 } 292 293 294 ret = krb5_get_kdc_cred(context, 295 cache, 296 flags, 297 NULL, 298 NULL, 299 &in, 300 &out); 301 if(ret) { 302 krb5_warn(context, ret, "krb5_get_kdc_cred"); 303 goto out; 304 } 305 ret = krb5_cc_initialize(context, cache, in.client); 306 if(ret) { 307 krb5_free_creds (context, out); 308 krb5_warn(context, ret, "krb5_cc_initialize"); 309 goto out; 310 } 311 ret = krb5_cc_store_cred(context, cache, out); 312 313 if(ret == 0 && server == NULL) { 314 /* only do this if it's a general renew-my-tgt request */ 315 if(get_v4_tgt) 316 do_524init(context, cache, out, NULL); 317 if(do_afslog && k_hasafs()) 318 krb5_afslog(context, cache, NULL, NULL); 319 } 320 321 krb5_free_creds (context, out); 322 if(ret) { 323 krb5_warn(context, ret, "krb5_cc_store_cred"); 324 goto out; 325 } 326 out: 327 krb5_free_cred_contents(context, &in); 328 return ret; 329 } 330 331 static krb5_error_code 332 store_ntlmkey(krb5_context context, krb5_ccache id, 333 const char *domain, krb5_const_principal client, 334 struct ntlm_buf *buf) 335 { 336 krb5_error_code ret; 337 krb5_creds cred; 338 339 memset(&cred, 0, sizeof(cred)); 340 341 ret = krb5_make_principal(context, &cred.server, 342 krb5_principal_get_realm(context, client), 343 "@ntlm-key", domain, NULL); 344 if (ret) 345 goto out; 346 ret = krb5_copy_principal(context, client, &cred.client); 347 if (ret) 348 goto out; 349 350 cred.times.authtime = time(NULL); 351 cred.times.endtime = time(NULL) + 3600 * 24 * 30; /* XXX */ 352 cred.session.keytype = ENCTYPE_ARCFOUR_HMAC_MD5; 353 ret = krb5_data_copy(&cred.session.keyvalue, buf->data, buf->length); 354 if (ret) 355 goto out; 356 357 ret = krb5_cc_store_cred(context, id, &cred); 358 359 out: 360 krb5_free_cred_contents (context, &cred); 361 return 0; 362 } 363 364 static krb5_error_code 365 get_new_tickets(krb5_context context, 366 krb5_principal principal, 367 krb5_ccache ccache, 368 krb5_deltat ticket_life, 369 int interactive) 370 { 371 krb5_error_code ret; 372 krb5_get_init_creds_opt *opt; 373 krb5_creds cred; 374 char passwd[256]; 375 krb5_deltat start_time = 0; 376 krb5_deltat renew = 0; 377 char *renewstr = NULL; 378 krb5_enctype *enctype = NULL; 379 struct ntlm_buf ntlmkey; 380 krb5_ccache tempccache; 381 382 memset(&ntlmkey, 0, sizeof(ntlmkey)); 383 passwd[0] = '\0'; 384 385 if (password_file) { 386 FILE *f; 387 388 if (strcasecmp("STDIN", password_file) == 0) 389 f = stdin; 390 else 391 f = fopen(password_file, "r"); 392 if (f == NULL) 393 krb5_errx(context, 1, "Failed to open the password file %s", 394 password_file); 395 396 if (fgets(passwd, sizeof(passwd), f) == NULL) 397 krb5_errx(context, 1, 398 "Failed to read password from file %s", password_file); 399 if (f != stdin) 400 fclose(f); 401 passwd[strcspn(passwd, "\n")] = '\0'; 402 } 403 404 405 memset(&cred, 0, sizeof(cred)); 406 407 ret = krb5_get_init_creds_opt_alloc (context, &opt); 408 if (ret) 409 krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc"); 410 411 krb5_get_init_creds_opt_set_default_flags(context, "kinit", 412 krb5_principal_get_realm(context, principal), opt); 413 414 if(forwardable_flag != -1) 415 krb5_get_init_creds_opt_set_forwardable (opt, forwardable_flag); 416 if(proxiable_flag != -1) 417 krb5_get_init_creds_opt_set_proxiable (opt, proxiable_flag); 418 if(anonymous_flag != -1) 419 krb5_get_init_creds_opt_set_anonymous (opt, anonymous_flag); 420 if (pac_flag != -1) 421 krb5_get_init_creds_opt_set_pac_request(context, opt, 422 pac_flag ? TRUE : FALSE); 423 if (canonicalize_flag) 424 krb5_get_init_creds_opt_set_canonicalize(context, opt, TRUE); 425 if (pk_user_id) { 426 ret = krb5_get_init_creds_opt_set_pkinit(context, opt, 427 principal, 428 pk_user_id, 429 pk_x509_anchors, 430 NULL, 431 NULL, 432 pk_use_enckey ? 2 : 0, 433 krb5_prompter_posix, 434 NULL, 435 passwd); 436 if (ret) 437 krb5_err(context, 1, ret, "krb5_get_init_creds_opt_set_pkinit"); 438 } 439 440 if (addrs_flag != -1) 441 krb5_get_init_creds_opt_set_addressless(context, opt, 442 addrs_flag ? FALSE : TRUE); 443 444 if (renew_life == NULL && renewable_flag) 445 renewstr = "1 month"; 446 if (renew_life) 447 renewstr = renew_life; 448 if (renewstr) { 449 renew = parse_time (renewstr, "s"); 450 if (renew < 0) 451 errx (1, "unparsable time: %s", renewstr); 452 453 krb5_get_init_creds_opt_set_renew_life (opt, renew); 454 } 455 456 if(ticket_life != 0) 457 krb5_get_init_creds_opt_set_tkt_life (opt, ticket_life); 458 459 if(start_str) { 460 int tmp = parse_time (start_str, "s"); 461 if (tmp < 0) 462 errx (1, "unparsable time: %s", start_str); 463 464 start_time = tmp; 465 } 466 467 if(etype_str.num_strings) { 468 int i; 469 470 enctype = malloc(etype_str.num_strings * sizeof(*enctype)); 471 if(enctype == NULL) 472 errx(1, "out of memory"); 473 for(i = 0; i < etype_str.num_strings; i++) { 474 ret = krb5_string_to_enctype(context, 475 etype_str.strings[i], 476 &enctype[i]); 477 if(ret) 478 errx(1, "unrecognized enctype: %s", etype_str.strings[i]); 479 } 480 krb5_get_init_creds_opt_set_etype_list(opt, enctype, 481 etype_str.num_strings); 482 } 483 484 if(use_keytab || keytab_str) { 485 krb5_keytab kt; 486 if(keytab_str) 487 ret = krb5_kt_resolve(context, keytab_str, &kt); 488 else 489 ret = krb5_kt_default(context, &kt); 490 if (ret) 491 krb5_err (context, 1, ret, "resolving keytab"); 492 ret = krb5_get_init_creds_keytab (context, 493 &cred, 494 principal, 495 kt, 496 start_time, 497 server_str, 498 opt); 499 krb5_kt_close(context, kt); 500 } else if (pk_user_id) { 501 ret = krb5_get_init_creds_password (context, 502 &cred, 503 principal, 504 passwd, 505 krb5_prompter_posix, 506 NULL, 507 start_time, 508 server_str, 509 opt); 510 } else if (!interactive) { 511 krb5_warnx(context, "Not interactive, failed to get initial ticket"); 512 krb5_get_init_creds_opt_free(context, opt); 513 return 0; 514 } else { 515 516 if (passwd[0] == '\0') { 517 char *p, *prompt; 518 519 krb5_unparse_name (context, principal, &p); 520 asprintf (&prompt, "%s's Password: ", p); 521 free (p); 522 523 if (UI_UTIL_read_pw_string(passwd, sizeof(passwd)-1, prompt, 0)){ 524 memset(passwd, 0, sizeof(passwd)); 525 exit(1); 526 } 527 free (prompt); 528 } 529 530 531 ret = krb5_get_init_creds_password (context, 532 &cred, 533 principal, 534 passwd, 535 krb5_prompter_posix, 536 NULL, 537 start_time, 538 server_str, 539 opt); 540 } 541 krb5_get_init_creds_opt_free(context, opt); 542 if (ntlm_domain && passwd[0]) 543 heim_ntlm_nt_key(passwd, &ntlmkey); 544 memset(passwd, 0, sizeof(passwd)); 545 546 switch(ret){ 547 case 0: 548 break; 549 case KRB5_LIBOS_PWDINTR: /* don't print anything if it was just C-c:ed */ 550 exit(1); 551 case KRB5KRB_AP_ERR_BAD_INTEGRITY: 552 case KRB5KRB_AP_ERR_MODIFIED: 553 case KRB5KDC_ERR_PREAUTH_FAILED: 554 krb5_errx(context, 1, "Password incorrect"); 555 break; 556 case KRB5KRB_AP_ERR_V4_REPLY: 557 krb5_errx(context, 1, "Looks like a Kerberos 4 reply"); 558 break; 559 default: 560 krb5_err(context, 1, ret, "krb5_get_init_creds"); 561 } 562 563 if(ticket_life != 0) { 564 if(abs(cred.times.endtime - cred.times.starttime - ticket_life) > 30) { 565 char life[64]; 566 unparse_time_approx(cred.times.endtime - cred.times.starttime, 567 life, sizeof(life)); 568 krb5_warnx(context, "NOTICE: ticket lifetime is %s", life); 569 } 570 } 571 if(renew_life) { 572 if(abs(cred.times.renew_till - cred.times.starttime - renew) > 30) { 573 char life[64]; 574 unparse_time_approx(cred.times.renew_till - cred.times.starttime, 575 life, sizeof(life)); 576 krb5_warnx(context, "NOTICE: ticket renewable lifetime is %s", 577 life); 578 } 579 } 580 581 ret = krb5_cc_new_unique(context, krb5_cc_get_type(context, ccache), 582 NULL, &tempccache); 583 if (ret) 584 krb5_err (context, 1, ret, "krb5_cc_new_unique"); 585 586 ret = krb5_cc_initialize (context, tempccache, cred.client); 587 if (ret) 588 krb5_err (context, 1, ret, "krb5_cc_initialize"); 589 590 ret = krb5_cc_store_cred (context, tempccache, &cred); 591 if (ret) 592 krb5_err (context, 1, ret, "krb5_cc_store_cred"); 593 594 krb5_free_cred_contents (context, &cred); 595 596 ret = krb5_cc_move(context, tempccache, ccache); 597 if (ret) 598 krb5_err (context, 1, ret, "krb5_cc_move"); 599 600 if (ntlm_domain && ntlmkey.data) 601 store_ntlmkey(context, ccache, ntlm_domain, principal, &ntlmkey); 602 603 if (enctype) 604 free(enctype); 605 606 return 0; 607 } 608 609 static time_t 610 ticket_lifetime(krb5_context context, krb5_ccache cache, 611 krb5_principal client, const char *server) 612 { 613 krb5_creds in_cred, *cred; 614 krb5_error_code ret; 615 time_t timeout; 616 617 memset(&in_cred, 0, sizeof(in_cred)); 618 619 ret = krb5_cc_get_principal(context, cache, &in_cred.client); 620 if(ret) { 621 krb5_warn(context, ret, "krb5_cc_get_principal"); 622 return 0; 623 } 624 ret = get_server(context, in_cred.client, server, &in_cred.server); 625 if(ret) { 626 krb5_free_principal(context, in_cred.client); 627 krb5_warn(context, ret, "get_server"); 628 return 0; 629 } 630 631 ret = krb5_get_credentials(context, KRB5_GC_CACHED, 632 cache, &in_cred, &cred); 633 krb5_free_principal(context, in_cred.client); 634 krb5_free_principal(context, in_cred.server); 635 if(ret) { 636 krb5_warn(context, ret, "krb5_get_credentials"); 637 return 0; 638 } 639 timeout = cred->times.endtime - cred->times.starttime; 640 if (timeout < 0) 641 timeout = 0; 642 krb5_free_creds(context, cred); 643 return timeout; 644 } 645 646 struct renew_ctx { 647 krb5_context context; 648 krb5_ccache ccache; 649 krb5_principal principal; 650 krb5_deltat ticket_life; 651 }; 652 653 static time_t 654 renew_func(void *ptr) 655 { 656 struct renew_ctx *ctx = ptr; 657 krb5_error_code ret; 658 time_t expire; 659 int new_tickets = 0; 660 661 if (renewable_flag) { 662 ret = renew_validate(ctx->context, renewable_flag, validate_flag, 663 ctx->ccache, server_str, ctx->ticket_life); 664 if (ret) 665 new_tickets = 1; 666 } else 667 new_tickets = 1; 668 669 if (new_tickets) 670 get_new_tickets(ctx->context, ctx->principal, 671 ctx->ccache, ctx->ticket_life, 0); 672 673 if(get_v4_tgt || convert_524) 674 do_524init(ctx->context, ctx->ccache, NULL, server_str); 675 if(do_afslog && k_hasafs()) 676 krb5_afslog(ctx->context, ctx->ccache, NULL, NULL); 677 678 expire = ticket_lifetime(ctx->context, ctx->ccache, ctx->principal, 679 server_str) / 2; 680 return expire + 1; 681 } 682 683 int 684 main (int argc, char **argv) 685 { 686 krb5_error_code ret; 687 krb5_context context; 688 krb5_ccache ccache; 689 krb5_principal principal; 690 int optidx = 0; 691 krb5_deltat ticket_life = 0; 692 int parseflags = 0; 693 694 setprogname (argv[0]); 695 696 ret = krb5_init_context (&context); 697 if (ret == KRB5_CONFIG_BADFORMAT) 698 errx (1, "krb5_init_context failed to parse configuration file"); 699 else if (ret) 700 errx(1, "krb5_init_context failed: %d", ret); 701 702 if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) 703 usage(1); 704 705 if (help_flag) 706 usage (0); 707 708 if(version_flag) { 709 print_version(NULL); 710 exit(0); 711 } 712 713 argc -= optidx; 714 argv += optidx; 715 716 if (canonicalize_flag) 717 parseflags |= KRB5_PRINCIPAL_PARSE_ENTERPRISE; 718 719 if (argv[0]) { 720 ret = krb5_parse_name_flags (context, argv[0], parseflags, &principal); 721 if (ret) 722 krb5_err (context, 1, ret, "krb5_parse_name"); 723 } else { 724 ret = krb5_get_default_principal (context, &principal); 725 if (ret) 726 krb5_err (context, 1, ret, "krb5_get_default_principal"); 727 } 728 729 if(fcache_version) 730 krb5_set_fcache_version(context, fcache_version); 731 732 if(renewable_flag == -1) 733 /* this seems somewhat pointless, but whatever */ 734 krb5_appdefault_boolean(context, "kinit", 735 krb5_principal_get_realm(context, principal), 736 "renewable", FALSE, &renewable_flag); 737 if(get_v4_tgt == -1) 738 krb5_appdefault_boolean(context, "kinit", 739 krb5_principal_get_realm(context, principal), 740 "krb4_get_tickets", FALSE, &get_v4_tgt); 741 if(do_afslog == -1) 742 krb5_appdefault_boolean(context, "kinit", 743 krb5_principal_get_realm(context, principal), 744 "afslog", TRUE, &do_afslog); 745 746 if(cred_cache) 747 ret = krb5_cc_resolve(context, cred_cache, &ccache); 748 else { 749 if(argc > 1) { 750 char s[1024]; 751 ret = krb5_cc_gen_new(context, &krb5_fcc_ops, &ccache); 752 if(ret) 753 krb5_err(context, 1, ret, "creating cred cache"); 754 snprintf(s, sizeof(s), "%s:%s", 755 krb5_cc_get_type(context, ccache), 756 krb5_cc_get_name(context, ccache)); 757 setenv("KRB5CCNAME", s, 1); 758 if (get_v4_tgt) { 759 int fd; 760 if (asprintf(&krb4_cc_name, "%s_XXXXXX", TKT_ROOT) < 0) 761 krb5_errx(context, 1, "out of memory"); 762 if((fd = mkstemp(krb4_cc_name)) >= 0) { 763 close(fd); 764 setenv("KRBTKFILE", krb4_cc_name, 1); 765 } else { 766 free(krb4_cc_name); 767 krb4_cc_name = NULL; 768 } 769 } 770 } else { 771 ret = krb5_cc_cache_match(context, principal, NULL, &ccache); 772 if (ret) 773 ret = krb5_cc_default (context, &ccache); 774 } 775 } 776 if (ret) 777 krb5_err (context, 1, ret, "resolving credentials cache"); 778 779 if(argc > 1 && k_hasafs ()) 780 k_setpag(); 781 782 if (lifetime) { 783 int tmp = parse_time (lifetime, "s"); 784 if (tmp < 0) 785 errx (1, "unparsable time: %s", lifetime); 786 787 ticket_life = tmp; 788 } 789 790 if(addrs_flag == 0 && extra_addresses.num_strings > 0) 791 krb5_errx(context, 1, "specifying both extra addresses and " 792 "no addresses makes no sense"); 793 { 794 int i; 795 krb5_addresses addresses; 796 memset(&addresses, 0, sizeof(addresses)); 797 for(i = 0; i < extra_addresses.num_strings; i++) { 798 ret = krb5_parse_address(context, extra_addresses.strings[i], 799 &addresses); 800 if (ret == 0) { 801 krb5_add_extra_addresses(context, &addresses); 802 krb5_free_addresses(context, &addresses); 803 } 804 } 805 free_getarg_strings(&extra_addresses); 806 } 807 808 if(renew_flag || validate_flag) { 809 ret = renew_validate(context, renew_flag, validate_flag, 810 ccache, server_str, ticket_life); 811 exit(ret != 0); 812 } 813 814 if(!convert_524) 815 get_new_tickets(context, principal, ccache, ticket_life, 1); 816 817 if(get_v4_tgt || convert_524) 818 do_524init(context, ccache, NULL, server_str); 819 if(do_afslog && k_hasafs()) 820 krb5_afslog(context, ccache, NULL, NULL); 821 if(argc > 1) { 822 struct renew_ctx ctx; 823 time_t timeout; 824 825 timeout = ticket_lifetime(context, ccache, principal, server_str) / 2; 826 827 ctx.context = context; 828 ctx.ccache = ccache; 829 ctx.principal = principal; 830 ctx.ticket_life = ticket_life; 831 832 ret = simple_execvp_timed(argv[1], argv+1, 833 renew_func, &ctx, timeout); 834 #define EX_NOEXEC 126 835 #define EX_NOTFOUND 127 836 if(ret == EX_NOEXEC) 837 krb5_warnx(context, "permission denied: %s", argv[1]); 838 else if(ret == EX_NOTFOUND) 839 krb5_warnx(context, "command not found: %s", argv[1]); 840 841 krb5_cc_destroy(context, ccache); 842 _krb5_krb_dest_tkt(context, krb4_cc_name); 843 if(k_hasafs()) 844 k_unlog(); 845 } else { 846 krb5_cc_close (context, ccache); 847 ret = 0; 848 } 849 krb5_free_principal(context, principal); 850 krb5_free_context (context); 851 return ret; 852 } 853