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 36#ifndef HEIMDAL_SMALLER 37#include "krb5-v4compat.h" 38#endif 39 40struct krb5_dh_moduli; 41struct AlgorithmIdentifier; 42struct _krb5_krb_auth_data; 43#include <krb5-private.h> 44 45#ifndef NO_NTLM 46#include "heimntlm.h" 47#endif 48 49int forwardable_flag = -1; 50int proxiable_flag = -1; 51int renewable_flag = -1; 52int renew_flag = 0; 53int pac_flag = -1; 54int validate_flag = 0; 55int version_flag = 0; 56int help_flag = 0; 57int addrs_flag = -1; 58struct getarg_strings extra_addresses; 59int anonymous_flag = 0; 60char *lifetime = NULL; 61char *renew_life = NULL; 62char *server_str = NULL; 63char *cred_cache = NULL; 64char *start_str = NULL; 65static int switch_cache_flags = 1; 66struct getarg_strings etype_str; 67int use_keytab = 0; 68char *keytab_str = NULL; 69int do_afslog = -1; 70#ifndef HEIMDAL_SMALLER 71int get_v4_tgt = -1; 72int convert_524 = 0; 73static char *krb4_cc_name; 74#endif 75int fcache_version; 76char *password_file = NULL; 77char *pk_user_id = NULL; 78int pk_enterprise_flag = 0; 79char *pk_x509_anchors = NULL; 80int pk_use_enckey = 0; 81static int canonicalize_flag = 0; 82static int enterprise_flag = 0; 83static int ok_as_delegate_flag = 0; 84static int use_referrals_flag = 0; 85static int windows_flag = 0; 86#ifndef NO_NTLM 87static char *ntlm_domain; 88#endif 89 90 91static struct getargs args[] = { 92 /* 93 * used by MIT 94 * a: ~A 95 * V: verbose 96 * F: ~f 97 * P: ~p 98 * C: v4 cache name? 99 * 5: 100 */ 101#ifndef HEIMDAL_SMALLER 102 { "524init", '4', arg_flag, &get_v4_tgt, 103 NP_("obtain version 4 TGT", "") }, 104 105 { "524convert", '9', arg_flag, &convert_524, 106 NP_("only convert ticket to version 4", "") }, 107#endif 108 { "afslog", 0 , arg_flag, &do_afslog, 109 NP_("obtain afs tokens", "") }, 110 111 { "cache", 'c', arg_string, &cred_cache, 112 NP_("credentials cache", ""), "cachename" }, 113 114 { "forwardable", 'f', arg_flag, &forwardable_flag, 115 NP_("get forwardable tickets", "")}, 116 117 { "keytab", 't', arg_string, &keytab_str, 118 NP_("keytab to use", ""), "keytabname" }, 119 120 { "lifetime", 'l', arg_string, &lifetime, 121 NP_("lifetime of tickets", ""), "time"}, 122 123 { "proxiable", 'p', arg_flag, &proxiable_flag, 124 NP_("get proxiable tickets", "") }, 125 126 { "renew", 'R', arg_flag, &renew_flag, 127 NP_("renew TGT", "") }, 128 129 { "renewable", 0, arg_flag, &renewable_flag, 130 NP_("get renewable tickets", "") }, 131 132 { "renewable-life", 'r', arg_string, &renew_life, 133 NP_("renewable lifetime of tickets", ""), "time" }, 134 135 { "server", 'S', arg_string, &server_str, 136 NP_("server to get ticket for", ""), "principal" }, 137 138 { "start-time", 's', arg_string, &start_str, 139 NP_("when ticket gets valid", ""), "time" }, 140 141 { "use-keytab", 'k', arg_flag, &use_keytab, 142 NP_("get key from keytab", "") }, 143 144 { "validate", 'v', arg_flag, &validate_flag, 145 NP_("validate TGT", "") }, 146 147 { "enctypes", 'e', arg_strings, &etype_str, 148 NP_("encryption types to use", ""), "enctypes" }, 149 150 { "fcache-version", 0, arg_integer, &fcache_version, 151 NP_("file cache version to create", "") }, 152 153 { "addresses", 'A', arg_negative_flag, &addrs_flag, 154 NP_("request a ticket with no addresses", "") }, 155 156 { "extra-addresses",'a', arg_strings, &extra_addresses, 157 NP_("include these extra addresses", ""), "addresses" }, 158 159 { "anonymous", 0, arg_flag, &anonymous_flag, 160 NP_("request an anonymous ticket", "") }, 161 162 { "request-pac", 0, arg_flag, &pac_flag, 163 NP_("request a Windows PAC", "") }, 164 165 { "password-file", 0, arg_string, &password_file, 166 NP_("read the password from a file", "") }, 167 168 { "canonicalize",0, arg_flag, &canonicalize_flag, 169 NP_("canonicalize client principal", "") }, 170 171 { "enterprise",0, arg_flag, &enterprise_flag, 172 NP_("parse principal as a KRB5-NT-ENTERPRISE name", "") }, 173#ifdef PKINIT 174 { "pk-enterprise", 0, arg_flag, &pk_enterprise_flag, 175 NP_("use enterprise name from certificate", "") }, 176 177 { "pk-user", 'C', arg_string, &pk_user_id, 178 NP_("principal's public/private/certificate identifier", ""), "id" }, 179 180 { "x509-anchors", 'D', arg_string, &pk_x509_anchors, 181 NP_("directory with CA certificates", ""), "directory" }, 182 183 { "pk-use-enckey", 0, arg_flag, &pk_use_enckey, 184 NP_("Use RSA encrypted reply (instead of DH)", "") }, 185#endif 186#ifndef NO_NTLM 187 { "ntlm-domain", 0, arg_string, &ntlm_domain, 188 NP_("NTLM domain", ""), "domain" }, 189#endif 190 191 { "change-default", 0, arg_negative_flag, &switch_cache_flags, 192 NP_("switch the default cache to the new credentials cache", "") }, 193 194 { "ok-as-delegate", 0, arg_flag, &ok_as_delegate_flag, 195 NP_("honor ok-as-delegate on tickets", "") }, 196 197 { "use-referrals", 0, arg_flag, &use_referrals_flag, 198 NP_("only use referrals, no dns canalisation", "") }, 199 200 { "windows", 0, arg_flag, &windows_flag, 201 NP_("get windows behavior", "") }, 202 203 { "version", 0, arg_flag, &version_flag }, 204 { "help", 0, arg_flag, &help_flag } 205}; 206 207static void 208usage (int ret) 209{ 210 arg_printusage_i18n (args, 211 sizeof(args)/sizeof(*args), 212 N_("Usage: ", ""), 213 NULL, 214 "[principal [command]]", 215 getarg_i18n); 216 exit (ret); 217} 218 219static krb5_error_code 220get_server(krb5_context context, 221 krb5_principal client, 222 const char *server, 223 krb5_principal *princ) 224{ 225 krb5_const_realm realm; 226 if(server) 227 return krb5_parse_name(context, server, princ); 228 229 realm = krb5_principal_get_realm(context, client); 230 return krb5_make_principal(context, princ, realm, 231 KRB5_TGS_NAME, realm, NULL); 232} 233 234#ifndef HEIMDAL_SMALLER 235 236static krb5_error_code 237do_524init(krb5_context context, krb5_ccache ccache, 238 krb5_creds *creds, const char *server) 239{ 240 krb5_error_code ret; 241 242 struct credentials c; 243 krb5_creds in_creds, *real_creds; 244 245 if(creds != NULL) 246 real_creds = creds; 247 else { 248 krb5_principal client; 249 krb5_cc_get_principal(context, ccache, &client); 250 memset(&in_creds, 0, sizeof(in_creds)); 251 ret = get_server(context, client, server, &in_creds.server); 252 if(ret) { 253 krb5_free_principal(context, client); 254 return ret; 255 } 256 in_creds.client = client; 257 ret = krb5_get_credentials(context, 0, ccache, &in_creds, &real_creds); 258 krb5_free_principal(context, client); 259 krb5_free_principal(context, in_creds.server); 260 if(ret) 261 return ret; 262 } 263 ret = krb524_convert_creds_kdc_ccache(context, ccache, real_creds, &c); 264 if(ret) 265 krb5_warn(context, ret, "converting creds"); 266 else { 267 krb5_error_code tret = _krb5_krb_tf_setup(context, &c, NULL, 0); 268 if(tret) 269 krb5_warn(context, tret, "saving v4 creds"); 270 } 271 272 if(creds == NULL) 273 krb5_free_creds(context, real_creds); 274 memset(&c, 0, sizeof(c)); 275 276 return ret; 277} 278 279#endif 280 281static int 282renew_validate(krb5_context context, 283 int renew, 284 int validate, 285 krb5_ccache cache, 286 const char *server, 287 krb5_deltat life) 288{ 289 krb5_error_code ret; 290 krb5_creds in, *out = NULL; 291 krb5_kdc_flags flags; 292 293 memset(&in, 0, sizeof(in)); 294 295 ret = krb5_cc_get_principal(context, cache, &in.client); 296 if(ret) { 297 krb5_warn(context, ret, "krb5_cc_get_principal"); 298 return ret; 299 } 300 ret = get_server(context, in.client, server, &in.server); 301 if(ret) { 302 krb5_warn(context, ret, "get_server"); 303 goto out; 304 } 305 306 if (renew) { 307 /* 308 * no need to check the error here, it's only to be 309 * friendly to the user 310 */ 311 krb5_get_credentials(context, KRB5_GC_CACHED, cache, &in, &out); 312 } 313 314 flags.i = 0; 315 flags.b.renewable = flags.b.renew = renew; 316 flags.b.validate = validate; 317 318 if (forwardable_flag != -1) 319 flags.b.forwardable = forwardable_flag; 320 else if (out) 321 flags.b.forwardable = out->flags.b.forwardable; 322 323 if (proxiable_flag != -1) 324 flags.b.proxiable = proxiable_flag; 325 else if (out) 326 flags.b.proxiable = out->flags.b.proxiable; 327 328 if (anonymous_flag) 329 flags.b.request_anonymous = anonymous_flag; 330 if(life) 331 in.times.endtime = time(NULL) + life; 332 333 if (out) { 334 krb5_free_creds (context, out); 335 out = NULL; 336 } 337 338 339 ret = krb5_get_kdc_cred(context, 340 cache, 341 flags, 342 NULL, 343 NULL, 344 &in, 345 &out); 346 if(ret) { 347 krb5_warn(context, ret, "krb5_get_kdc_cred"); 348 goto out; 349 } 350 ret = krb5_cc_initialize(context, cache, in.client); 351 if(ret) { 352 krb5_free_creds (context, out); 353 krb5_warn(context, ret, "krb5_cc_initialize"); 354 goto out; 355 } 356 ret = krb5_cc_store_cred(context, cache, out); 357 358 if(ret == 0 && server == NULL) { 359 /* only do this if it's a general renew-my-tgt request */ 360#ifndef HEIMDAL_SMALLER 361 if(get_v4_tgt) 362 do_524init(context, cache, out, NULL); 363#endif 364#ifndef NO_AFS 365 if(do_afslog && k_hasafs()) 366 krb5_afslog(context, cache, NULL, NULL); 367#endif 368 } 369 370 krb5_free_creds (context, out); 371 if(ret) { 372 krb5_warn(context, ret, "krb5_cc_store_cred"); 373 goto out; 374 } 375out: 376 krb5_free_cred_contents(context, &in); 377 return ret; 378} 379 380#ifndef NO_NTLM 381 382static krb5_error_code 383store_ntlmkey(krb5_context context, krb5_ccache id, 384 const char *domain, struct ntlm_buf *buf) 385{ 386 krb5_error_code ret; 387 krb5_data data; 388 char *name; 389 390 asprintf(&name, "ntlm-key-%s", domain); 391 if (name == NULL) { 392 krb5_clear_error_message(context); 393 return ENOMEM; 394 } 395 396 data.length = buf->length; 397 data.data = buf->data; 398 399 ret = krb5_cc_set_config(context, id, NULL, name, &data); 400 free(name); 401 return ret; 402} 403#endif 404 405static krb5_error_code 406get_new_tickets(krb5_context context, 407 krb5_principal principal, 408 krb5_ccache ccache, 409 krb5_deltat ticket_life, 410 int interactive) 411{ 412 krb5_error_code ret; 413 krb5_get_init_creds_opt *opt; 414 krb5_creds cred; 415 char passwd[256]; 416 krb5_deltat start_time = 0; 417 krb5_deltat renew = 0; 418 char *renewstr = NULL; 419 krb5_enctype *enctype = NULL; 420 krb5_ccache tempccache; 421#ifndef NO_NTLM 422 struct ntlm_buf ntlmkey; 423 memset(&ntlmkey, 0, sizeof(ntlmkey)); 424#endif 425 passwd[0] = '\0'; 426 427 if (password_file) { 428 FILE *f; 429 430 if (strcasecmp("STDIN", password_file) == 0) 431 f = stdin; 432 else 433 f = fopen(password_file, "r"); 434 if (f == NULL) 435 krb5_errx(context, 1, "Failed to open the password file %s", 436 password_file); 437 438 if (fgets(passwd, sizeof(passwd), f) == NULL) 439 krb5_errx(context, 1, 440 N_("Failed to read password from file %s", ""), 441 password_file); 442 if (f != stdin) 443 fclose(f); 444 passwd[strcspn(passwd, "\n")] = '\0'; 445 } 446 447 448 memset(&cred, 0, sizeof(cred)); 449 450 ret = krb5_get_init_creds_opt_alloc (context, &opt); 451 if (ret) 452 krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc"); 453 454 krb5_get_init_creds_opt_set_default_flags(context, "kinit", 455 krb5_principal_get_realm(context, principal), opt); 456 457 if(forwardable_flag != -1) 458 krb5_get_init_creds_opt_set_forwardable (opt, forwardable_flag); 459 if(proxiable_flag != -1) 460 krb5_get_init_creds_opt_set_proxiable (opt, proxiable_flag); 461 if(anonymous_flag) 462 krb5_get_init_creds_opt_set_anonymous (opt, anonymous_flag); 463 if (pac_flag != -1) 464 krb5_get_init_creds_opt_set_pac_request(context, opt, 465 pac_flag ? TRUE : FALSE); 466 if (canonicalize_flag) 467 krb5_get_init_creds_opt_set_canonicalize(context, opt, TRUE); 468 if (pk_enterprise_flag && windows_flag) 469 krb5_get_init_creds_opt_set_win2k(context, opt, TRUE); 470 if (pk_user_id || anonymous_flag) { 471 ret = krb5_get_init_creds_opt_set_pkinit(context, opt, 472 principal, 473 pk_user_id, 474 pk_x509_anchors, 475 NULL, 476 NULL, 477 pk_use_enckey ? 2 : 0 | 478 anonymous_flag ? 4 : 0, 479 krb5_prompter_posix, 480 NULL, 481 passwd); 482 if (ret) 483 krb5_err(context, 1, ret, "krb5_get_init_creds_opt_set_pkinit"); 484 } 485 486 if (addrs_flag != -1) 487 krb5_get_init_creds_opt_set_addressless(context, opt, 488 addrs_flag ? FALSE : TRUE); 489 490 if (renew_life == NULL && renewable_flag) 491 renewstr = "1 month"; 492 if (renew_life) 493 renewstr = renew_life; 494 if (renewstr) { 495 renew = parse_time (renewstr, "s"); 496 if (renew < 0) 497 errx (1, "unparsable time: %s", renewstr); 498 499 krb5_get_init_creds_opt_set_renew_life (opt, renew); 500 } 501 502 if(ticket_life != 0) 503 krb5_get_init_creds_opt_set_tkt_life (opt, ticket_life); 504 505 if(start_str) { 506 int tmp = parse_time (start_str, "s"); 507 if (tmp < 0) 508 errx (1, N_("unparsable time: %s", ""), start_str); 509 510 start_time = tmp; 511 } 512 513 if(etype_str.num_strings) { 514 int i; 515 516 enctype = malloc(etype_str.num_strings * sizeof(*enctype)); 517 if(enctype == NULL) 518 errx(1, "out of memory"); 519 for(i = 0; i < etype_str.num_strings; i++) { 520 ret = krb5_string_to_enctype(context, 521 etype_str.strings[i], 522 &enctype[i]); 523 if(ret) 524 errx(1, "unrecognized enctype: %s", etype_str.strings[i]); 525 } 526 krb5_get_init_creds_opt_set_etype_list(opt, enctype, 527 etype_str.num_strings); 528 } 529 530 if(use_keytab || keytab_str) { 531 krb5_keytab kt; 532 if(keytab_str) 533 ret = krb5_kt_resolve(context, keytab_str, &kt); 534 else 535 ret = krb5_kt_default(context, &kt); 536 if (ret) 537 krb5_err (context, 1, ret, "resolving keytab"); 538 ret = krb5_get_init_creds_keytab (context, 539 &cred, 540 principal, 541 kt, 542 start_time, 543 server_str, 544 opt); 545 krb5_kt_close(context, kt); 546 } else if (pk_user_id || anonymous_flag) { 547 ret = krb5_get_init_creds_password (context, 548 &cred, 549 principal, 550 passwd, 551 krb5_prompter_posix, 552 NULL, 553 start_time, 554 server_str, 555 opt); 556 } else if (!interactive) { 557 krb5_warnx(context, "Not interactive, failed to get initial ticket"); 558 krb5_get_init_creds_opt_free(context, opt); 559 return 0; 560 } else { 561 562 if (passwd[0] == '\0') { 563 char *p, *prompt; 564 565 krb5_unparse_name (context, principal, &p); 566 asprintf (&prompt, N_("%s's Password: ", ""), p); 567 free (p); 568 569 if (UI_UTIL_read_pw_string(passwd, sizeof(passwd)-1, prompt, 0)){ 570 memset(passwd, 0, sizeof(passwd)); 571 exit(1); 572 } 573 free (prompt); 574 } 575 576 577 ret = krb5_get_init_creds_password (context, 578 &cred, 579 principal, 580 passwd, 581 krb5_prompter_posix, 582 NULL, 583 start_time, 584 server_str, 585 opt); 586 } 587 krb5_get_init_creds_opt_free(context, opt); 588#ifndef NO_NTLM 589 if (ntlm_domain && passwd[0]) 590 heim_ntlm_nt_key(passwd, &ntlmkey); 591#endif 592 memset(passwd, 0, sizeof(passwd)); 593 594 switch(ret){ 595 case 0: 596 break; 597 case KRB5_LIBOS_PWDINTR: /* don't print anything if it was just C-c:ed */ 598 exit(1); 599 case KRB5KRB_AP_ERR_BAD_INTEGRITY: 600 case KRB5KRB_AP_ERR_MODIFIED: 601 case KRB5KDC_ERR_PREAUTH_FAILED: 602 krb5_errx(context, 1, N_("Password incorrect", "")); 603 break; 604 case KRB5KRB_AP_ERR_V4_REPLY: 605 krb5_errx(context, 1, N_("Looks like a Kerberos 4 reply", "")); 606 break; 607 default: 608 krb5_err(context, 1, ret, "krb5_get_init_creds"); 609 } 610 611 if(ticket_life != 0) { 612 if(abs(cred.times.endtime - cred.times.starttime - ticket_life) > 30) { 613 char life[64]; 614 unparse_time_approx(cred.times.endtime - cred.times.starttime, 615 life, sizeof(life)); 616 krb5_warnx(context, N_("NOTICE: ticket lifetime is %s", ""), life); 617 } 618 } 619 if(renew_life) { 620 if(abs(cred.times.renew_till - cred.times.starttime - renew) > 30) { 621 char life[64]; 622 unparse_time_approx(cred.times.renew_till - cred.times.starttime, 623 life, sizeof(life)); 624 krb5_warnx(context, 625 N_("NOTICE: ticket renewable lifetime is %s", ""), 626 life); 627 } 628 } 629 630 ret = krb5_cc_new_unique(context, krb5_cc_get_type(context, ccache), 631 NULL, &tempccache); 632 if (ret) 633 krb5_err (context, 1, ret, "krb5_cc_new_unique"); 634 635 ret = krb5_cc_initialize (context, tempccache, cred.client); 636 if (ret) 637 krb5_err (context, 1, ret, "krb5_cc_initialize"); 638 639 ret = krb5_cc_store_cred (context, tempccache, &cred); 640 if (ret) 641 krb5_err (context, 1, ret, "krb5_cc_store_cred"); 642 643 krb5_free_cred_contents (context, &cred); 644 645 ret = krb5_cc_move(context, tempccache, ccache); 646 if (ret) 647 krb5_err (context, 1, ret, "krb5_cc_move"); 648 649 if (switch_cache_flags) 650 krb5_cc_switch(context, ccache); 651 652#ifndef NO_NTLM 653 if (ntlm_domain && ntlmkey.data) 654 store_ntlmkey(context, ccache, ntlm_domain, &ntlmkey); 655#endif 656 657 if (ok_as_delegate_flag || windows_flag || use_referrals_flag) { 658 unsigned char d = 0; 659 krb5_data data; 660 661 if (ok_as_delegate_flag || windows_flag) 662 d |= 1; 663 if (use_referrals_flag || windows_flag) 664 d |= 2; 665 666 data.length = 1; 667 data.data = &d; 668 669 krb5_cc_set_config(context, ccache, NULL, "realm-config", &data); 670 } 671 672 673 if (enctype) 674 free(enctype); 675 676 return 0; 677} 678 679static time_t 680ticket_lifetime(krb5_context context, krb5_ccache cache, 681 krb5_principal client, const char *server) 682{ 683 krb5_creds in_cred, *cred; 684 krb5_error_code ret; 685 time_t timeout; 686 687 memset(&in_cred, 0, sizeof(in_cred)); 688 689 ret = krb5_cc_get_principal(context, cache, &in_cred.client); 690 if(ret) { 691 krb5_warn(context, ret, "krb5_cc_get_principal"); 692 return 0; 693 } 694 ret = get_server(context, in_cred.client, server, &in_cred.server); 695 if(ret) { 696 krb5_free_principal(context, in_cred.client); 697 krb5_warn(context, ret, "get_server"); 698 return 0; 699 } 700 701 ret = krb5_get_credentials(context, KRB5_GC_CACHED, 702 cache, &in_cred, &cred); 703 krb5_free_principal(context, in_cred.client); 704 krb5_free_principal(context, in_cred.server); 705 if(ret) { 706 krb5_warn(context, ret, "krb5_get_credentials"); 707 return 0; 708 } 709 timeout = cred->times.endtime - cred->times.starttime; 710 if (timeout < 0) 711 timeout = 0; 712 krb5_free_creds(context, cred); 713 return timeout; 714} 715 716struct renew_ctx { 717 krb5_context context; 718 krb5_ccache ccache; 719 krb5_principal principal; 720 krb5_deltat ticket_life; 721}; 722 723static time_t 724renew_func(void *ptr) 725{ 726 struct renew_ctx *ctx = ptr; 727 krb5_error_code ret; 728 time_t expire; 729 int new_tickets = 0; 730 731 if (renewable_flag) { 732 ret = renew_validate(ctx->context, renewable_flag, validate_flag, 733 ctx->ccache, server_str, ctx->ticket_life); 734 if (ret) 735 new_tickets = 1; 736 } else 737 new_tickets = 1; 738 739 if (new_tickets) 740 get_new_tickets(ctx->context, ctx->principal, 741 ctx->ccache, ctx->ticket_life, 0); 742 743#ifndef HEIMDAL_SMALLER 744 if(get_v4_tgt || convert_524) 745 do_524init(ctx->context, ctx->ccache, NULL, server_str); 746#endif 747#ifndef NO_AFS 748 if(do_afslog && k_hasafs()) 749 krb5_afslog(ctx->context, ctx->ccache, NULL, NULL); 750#endif 751 752 expire = ticket_lifetime(ctx->context, ctx->ccache, ctx->principal, 753 server_str) / 2; 754 return expire + 1; 755} 756 757int 758main (int argc, char **argv) 759{ 760 krb5_error_code ret; 761 krb5_context context; 762 krb5_ccache ccache; 763 krb5_principal principal; 764 int optidx = 0; 765 krb5_deltat ticket_life = 0; 766 int parseflags = 0; 767 768 setprogname (argv[0]); 769 770 setlocale (LC_ALL, ""); 771 bindtextdomain ("heimdal_kuser", HEIMDAL_LOCALEDIR); 772 textdomain("heimdal_kuser"); 773 774 ret = krb5_init_context (&context); 775 if (ret == KRB5_CONFIG_BADFORMAT) 776 errx (1, "krb5_init_context failed to parse configuration file"); 777 else if (ret) 778 errx(1, "krb5_init_context failed: %d", ret); 779 780 if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) 781 usage(1); 782 783 if (help_flag) 784 usage (0); 785 786 if(version_flag) { 787 print_version(NULL); 788 exit(0); 789 } 790 791 argc -= optidx; 792 argv += optidx; 793 794 if (canonicalize_flag || enterprise_flag) 795 parseflags |= KRB5_PRINCIPAL_PARSE_ENTERPRISE; 796 797 if (pk_enterprise_flag) { 798 ret = _krb5_pk_enterprise_cert(context, pk_user_id, 799 argv[0], &principal); 800 if (ret) 801 krb5_err(context, 1, ret, "krb5_pk_enterprise_certs"); 802 803 } else if (anonymous_flag) { 804 805 ret = krb5_make_principal(context, &principal, argv[0], 806 KRB5_WELLKNOWN_NAME, KRB5_ANON_NAME, 807 NULL); 808 if (ret) 809 krb5_err(context, 1, ret, "krb5_build_principal"); 810 krb5_principal_set_type(context, principal, KRB5_NT_WELLKNOWN); 811 812 } else { 813 if (argv[0]) { 814 ret = krb5_parse_name_flags (context, argv[0], parseflags, 815 &principal); 816 if (ret) 817 krb5_err (context, 1, ret, "krb5_parse_name"); 818 } else { 819 ret = krb5_get_default_principal (context, &principal); 820 if (ret) 821 krb5_err (context, 1, ret, "krb5_get_default_principal"); 822 } 823 } 824 825 if(fcache_version) 826 krb5_set_fcache_version(context, fcache_version); 827 828 if(renewable_flag == -1) 829 /* this seems somewhat pointless, but whatever */ 830 krb5_appdefault_boolean(context, "kinit", 831 krb5_principal_get_realm(context, principal), 832 "renewable", FALSE, &renewable_flag); 833#ifndef HEIMDAL_SMALLER 834 if(get_v4_tgt == -1) 835 krb5_appdefault_boolean(context, "kinit", 836 krb5_principal_get_realm(context, principal), 837 "krb4_get_tickets", FALSE, &get_v4_tgt); 838#endif 839 if(do_afslog == -1) 840 krb5_appdefault_boolean(context, "kinit", 841 krb5_principal_get_realm(context, principal), 842 "afslog", TRUE, &do_afslog); 843 844 if(cred_cache) 845 ret = krb5_cc_resolve(context, cred_cache, &ccache); 846 else { 847 if(argc > 1) { 848 char s[1024]; 849 ret = krb5_cc_new_unique(context, NULL, NULL, &ccache); 850 if(ret) 851 krb5_err(context, 1, ret, "creating cred cache"); 852 snprintf(s, sizeof(s), "%s:%s", 853 krb5_cc_get_type(context, ccache), 854 krb5_cc_get_name(context, ccache)); 855 setenv("KRB5CCNAME", s, 1); 856#ifndef HEIMDAL_SMALLER 857 if (get_v4_tgt) { 858 int fd; 859 if (asprintf(&krb4_cc_name, "%s_XXXXXX", TKT_ROOT) < 0) 860 krb5_errx(context, 1, "out of memory"); 861 if((fd = mkstemp(krb4_cc_name)) >= 0) { 862 close(fd); 863 setenv("KRBTKFILE", krb4_cc_name, 1); 864 } else { 865 free(krb4_cc_name); 866 krb4_cc_name = NULL; 867 } 868 } 869#endif 870 } else { 871 ret = krb5_cc_cache_match(context, principal, &ccache); 872 if (ret) 873 ret = krb5_cc_default (context, &ccache); 874 } 875 } 876 if (ret) 877 krb5_err (context, 1, ret, N_("resolving credentials cache", "")); 878 879#ifndef NO_AFS 880 if(argc > 1 && k_hasafs ()) 881 k_setpag(); 882#endif 883 884 if (lifetime) { 885 int tmp = parse_time (lifetime, "s"); 886 if (tmp < 0) 887 errx (1, N_("unparsable time: %s", ""), lifetime); 888 889 ticket_life = tmp; 890 } 891 892 if(addrs_flag == 0 && extra_addresses.num_strings > 0) 893 krb5_errx(context, 1, 894 N_("specifying both extra addresses and " 895 "no addresses makes no sense", "")); 896 { 897 int i; 898 krb5_addresses addresses; 899 memset(&addresses, 0, sizeof(addresses)); 900 for(i = 0; i < extra_addresses.num_strings; i++) { 901 ret = krb5_parse_address(context, extra_addresses.strings[i], 902 &addresses); 903 if (ret == 0) { 904 krb5_add_extra_addresses(context, &addresses); 905 krb5_free_addresses(context, &addresses); 906 } 907 } 908 free_getarg_strings(&extra_addresses); 909 } 910 911 if(renew_flag || validate_flag) { 912 ret = renew_validate(context, renew_flag, validate_flag, 913 ccache, server_str, ticket_life); 914 exit(ret != 0); 915 } 916 917#ifndef HEIMDAL_SMALLER 918 if(!convert_524) 919#endif 920 get_new_tickets(context, principal, ccache, ticket_life, 1); 921 922#ifndef HEIMDAL_SMALLER 923 if(get_v4_tgt || convert_524) 924 do_524init(context, ccache, NULL, server_str); 925#endif 926#ifndef NO_AFS 927 if(do_afslog && k_hasafs()) 928 krb5_afslog(context, ccache, NULL, NULL); 929#endif 930 if(argc > 1) { 931 struct renew_ctx ctx; 932 time_t timeout; 933 934 timeout = ticket_lifetime(context, ccache, principal, server_str) / 2; 935 936 ctx.context = context; 937 ctx.ccache = ccache; 938 ctx.principal = principal; 939 ctx.ticket_life = ticket_life; 940 941 ret = simple_execvp_timed(argv[1], argv+1, 942 renew_func, &ctx, timeout); 943#define EX_NOEXEC 126 944#define EX_NOTFOUND 127 945 if(ret == EX_NOEXEC) 946 krb5_warnx(context, N_("permission denied: %s", ""), argv[1]); 947 else if(ret == EX_NOTFOUND) 948 krb5_warnx(context, N_("command not found: %s", ""), argv[1]); 949 950 krb5_cc_destroy(context, ccache); 951#ifndef HEIMDAL_SMALLER 952 _krb5_krb_dest_tkt(context, krb4_cc_name); 953#endif 954#ifndef NO_AFS 955 if(k_hasafs()) 956 k_unlog(); 957#endif 958 } else { 959 krb5_cc_close (context, ccache); 960 ret = 0; 961 } 962 krb5_free_principal(context, principal); 963 krb5_free_context (context); 964 return ret; 965} 966