1 /* 2 * Copyright (c) 1997-2003 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 #include "rtbl.h" 36 37 RCSID("$Id: klist.c,v 1.68.2.2 2003/10/13 15:13:39 joda Exp $"); 38 39 static char* 40 printable_time(time_t t) 41 { 42 static char s[128]; 43 strcpy(s, ctime(&t)+ 4); 44 s[15] = 0; 45 return s; 46 } 47 48 static char* 49 printable_time_long(time_t t) 50 { 51 static char s[128]; 52 strcpy(s, ctime(&t)+ 4); 53 s[20] = 0; 54 return s; 55 } 56 57 #define COL_ISSUED " Issued" 58 #define COL_EXPIRES " Expires" 59 #define COL_FLAGS "Flags" 60 #define COL_PRINCIPAL " Principal" 61 #define COL_PRINCIPAL_KVNO " Principal (kvno)" 62 63 static void 64 print_cred(krb5_context context, krb5_creds *cred, rtbl_t ct, int do_flags) 65 { 66 char *str; 67 krb5_error_code ret; 68 krb5_timestamp sec; 69 70 krb5_timeofday (context, &sec); 71 72 73 if(cred->times.starttime) 74 rtbl_add_column_entry(ct, COL_ISSUED, 75 printable_time(cred->times.starttime)); 76 else 77 rtbl_add_column_entry(ct, COL_ISSUED, 78 printable_time(cred->times.authtime)); 79 80 if(cred->times.endtime > sec) 81 rtbl_add_column_entry(ct, COL_EXPIRES, 82 printable_time(cred->times.endtime)); 83 else 84 rtbl_add_column_entry(ct, COL_EXPIRES, ">>>Expired<<<"); 85 ret = krb5_unparse_name (context, cred->server, &str); 86 if (ret) 87 krb5_err(context, 1, ret, "krb5_unparse_name"); 88 rtbl_add_column_entry(ct, COL_PRINCIPAL, str); 89 if(do_flags) { 90 char s[16], *sp = s; 91 if(cred->flags.b.forwardable) 92 *sp++ = 'F'; 93 if(cred->flags.b.forwarded) 94 *sp++ = 'f'; 95 if(cred->flags.b.proxiable) 96 *sp++ = 'P'; 97 if(cred->flags.b.proxy) 98 *sp++ = 'p'; 99 if(cred->flags.b.may_postdate) 100 *sp++ = 'D'; 101 if(cred->flags.b.postdated) 102 *sp++ = 'd'; 103 if(cred->flags.b.renewable) 104 *sp++ = 'R'; 105 if(cred->flags.b.initial) 106 *sp++ = 'I'; 107 if(cred->flags.b.invalid) 108 *sp++ = 'i'; 109 if(cred->flags.b.pre_authent) 110 *sp++ = 'A'; 111 if(cred->flags.b.hw_authent) 112 *sp++ = 'H'; 113 *sp++ = '\0'; 114 rtbl_add_column_entry(ct, COL_FLAGS, s); 115 } 116 free(str); 117 } 118 119 static void 120 print_cred_verbose(krb5_context context, krb5_creds *cred) 121 { 122 int j; 123 char *str; 124 krb5_error_code ret; 125 int first_flag; 126 krb5_timestamp sec; 127 128 krb5_timeofday (context, &sec); 129 130 ret = krb5_unparse_name(context, cred->server, &str); 131 if(ret) 132 exit(1); 133 printf("Server: %s\n", str); 134 free (str); 135 { 136 Ticket t; 137 size_t len; 138 char *s; 139 140 decode_Ticket(cred->ticket.data, cred->ticket.length, &t, &len); 141 ret = krb5_enctype_to_string(context, t.enc_part.etype, &s); 142 printf("Ticket etype: "); 143 if (ret == 0) { 144 printf("%s", s); 145 free(s); 146 } else { 147 printf("unknown(%d)", t.enc_part.etype); 148 } 149 if(t.enc_part.kvno) 150 printf(", kvno %d", *t.enc_part.kvno); 151 printf("\n"); 152 if(cred->session.keytype != t.enc_part.etype) { 153 ret = krb5_keytype_to_string(context, cred->session.keytype, &str); 154 if(ret == KRB5_PROG_KEYTYPE_NOSUPP) 155 ret = krb5_enctype_to_string(context, cred->session.keytype, 156 &str); 157 if(ret) 158 krb5_warn(context, ret, "session keytype"); 159 else { 160 printf("Session key: %s\n", str); 161 free(str); 162 } 163 } 164 free_Ticket(&t); 165 } 166 printf("Auth time: %s\n", printable_time_long(cred->times.authtime)); 167 if(cred->times.authtime != cred->times.starttime) 168 printf("Start time: %s\n", printable_time_long(cred->times.starttime)); 169 printf("End time: %s", printable_time_long(cred->times.endtime)); 170 if(sec > cred->times.endtime) 171 printf(" (expired)"); 172 printf("\n"); 173 if(cred->flags.b.renewable) 174 printf("Renew till: %s\n", 175 printable_time_long(cred->times.renew_till)); 176 printf("Ticket flags: "); 177 #define PRINT_FLAG2(f, s) if(cred->flags.b.f) { if(!first_flag) printf(", "); printf("%s", #s); first_flag = 0; } 178 #define PRINT_FLAG(f) PRINT_FLAG2(f, f) 179 first_flag = 1; 180 PRINT_FLAG(forwardable); 181 PRINT_FLAG(forwarded); 182 PRINT_FLAG(proxiable); 183 PRINT_FLAG(proxy); 184 PRINT_FLAG2(may_postdate, may-postdate); 185 PRINT_FLAG(postdated); 186 PRINT_FLAG(invalid); 187 PRINT_FLAG(renewable); 188 PRINT_FLAG(initial); 189 PRINT_FLAG2(pre_authent, pre-authenticated); 190 PRINT_FLAG2(hw_authent, hw-authenticated); 191 PRINT_FLAG2(transited_policy_checked, transited-policy-checked); 192 PRINT_FLAG2(ok_as_delegate, ok-as-delegate); 193 PRINT_FLAG(anonymous); 194 printf("\n"); 195 printf("Addresses: "); 196 for(j = 0; j < cred->addresses.len; j++){ 197 char buf[128]; 198 size_t len; 199 if(j) printf(", "); 200 ret = krb5_print_address(&cred->addresses.val[j], 201 buf, sizeof(buf), &len); 202 203 if(ret == 0) 204 printf("%s", buf); 205 } 206 printf("\n\n"); 207 } 208 209 /* 210 * Print all tickets in `ccache' on stdout, verbosily iff do_verbose. 211 */ 212 213 static void 214 print_tickets (krb5_context context, 215 krb5_ccache ccache, 216 krb5_principal principal, 217 int do_verbose, 218 int do_flags) 219 { 220 krb5_error_code ret; 221 char *str; 222 krb5_cc_cursor cursor; 223 krb5_creds creds; 224 225 rtbl_t ct = NULL; 226 227 ret = krb5_unparse_name (context, principal, &str); 228 if (ret) 229 krb5_err (context, 1, ret, "krb5_unparse_name"); 230 231 printf ("%17s: %s:%s\n", 232 "Credentials cache", 233 krb5_cc_get_type(context, ccache), 234 krb5_cc_get_name(context, ccache)); 235 printf ("%17s: %s\n", "Principal", str); 236 free (str); 237 238 if(do_verbose) 239 printf ("%17s: %d\n", "Cache version", 240 krb5_cc_get_version(context, ccache)); 241 242 if (do_verbose && context->kdc_sec_offset) { 243 char buf[BUFSIZ]; 244 int val; 245 int sig; 246 247 val = context->kdc_sec_offset; 248 sig = 1; 249 if (val < 0) { 250 sig = -1; 251 val = -val; 252 } 253 254 unparse_time (val, buf, sizeof(buf)); 255 256 printf ("%17s: %s%s\n", "KDC time offset", 257 sig == -1 ? "-" : "", buf); 258 } 259 260 printf("\n"); 261 262 ret = krb5_cc_start_seq_get (context, ccache, &cursor); 263 if (ret) 264 krb5_err(context, 1, ret, "krb5_cc_start_seq_get"); 265 266 if(!do_verbose) { 267 ct = rtbl_create(); 268 rtbl_add_column(ct, COL_ISSUED, 0); 269 rtbl_add_column(ct, COL_EXPIRES, 0); 270 if(do_flags) 271 rtbl_add_column(ct, COL_FLAGS, 0); 272 rtbl_add_column(ct, COL_PRINCIPAL, 0); 273 rtbl_set_prefix(ct, " "); 274 rtbl_set_column_prefix(ct, COL_ISSUED, ""); 275 } 276 while ((ret = krb5_cc_next_cred (context, 277 ccache, 278 &cursor, 279 &creds)) == 0) { 280 if(do_verbose){ 281 print_cred_verbose(context, &creds); 282 }else{ 283 print_cred(context, &creds, ct, do_flags); 284 } 285 krb5_free_creds_contents (context, &creds); 286 } 287 if(ret != KRB5_CC_END) 288 krb5_err(context, 1, ret, "krb5_cc_get_next"); 289 ret = krb5_cc_end_seq_get (context, ccache, &cursor); 290 if (ret) 291 krb5_err (context, 1, ret, "krb5_cc_end_seq_get"); 292 if(!do_verbose) { 293 rtbl_format(ct, stdout); 294 rtbl_destroy(ct); 295 } 296 } 297 298 /* 299 * Check if there's a tgt for the realm of `principal' and ccache and 300 * if so return 0, else 1 301 */ 302 303 static int 304 check_for_tgt (krb5_context context, 305 krb5_ccache ccache, 306 krb5_principal principal) 307 { 308 krb5_error_code ret; 309 krb5_creds pattern; 310 krb5_creds creds; 311 krb5_realm *client_realm; 312 int expired; 313 314 client_realm = krb5_princ_realm (context, principal); 315 316 ret = krb5_make_principal (context, &pattern.server, 317 *client_realm, KRB5_TGS_NAME, *client_realm, 318 NULL); 319 if (ret) 320 krb5_err (context, 1, ret, "krb5_make_principal"); 321 322 ret = krb5_cc_retrieve_cred (context, ccache, 0, &pattern, &creds); 323 expired = time(NULL) > creds.times.endtime; 324 krb5_free_principal (context, pattern.server); 325 krb5_free_creds_contents (context, &creds); 326 if (ret) { 327 if (ret == KRB5_CC_END) 328 return 1; 329 krb5_err (context, 1, ret, "krb5_cc_retrieve_cred"); 330 } 331 return expired; 332 } 333 334 #ifdef KRB4 335 /* prints the approximate kdc time differential as something human 336 readable */ 337 338 static void 339 print_time_diff(int do_verbose) 340 { 341 int d = abs(krb_get_kdc_time_diff()); 342 char buf[80]; 343 344 if ((do_verbose && d > 0) || d > 60) { 345 unparse_time_approx (d, buf, sizeof(buf)); 346 printf ("Time diff:\t%s\n", buf); 347 } 348 } 349 350 /* 351 * return a short representation of `dp' in string form. 352 */ 353 354 static char * 355 short_date(int32_t dp) 356 { 357 char *cp; 358 time_t t = (time_t)dp; 359 360 if (t == (time_t)(-1L)) return "*** Never *** "; 361 cp = ctime(&t) + 4; 362 cp[15] = '\0'; 363 return (cp); 364 } 365 366 /* 367 * Print a list of all the v4 tickets 368 */ 369 370 static int 371 display_v4_tickets (int do_verbose) 372 { 373 char *file; 374 int ret; 375 krb_principal princ; 376 CREDENTIALS cred; 377 int found = 0; 378 379 rtbl_t ct; 380 381 file = getenv ("KRBTKFILE"); 382 if (file == NULL) 383 file = TKT_FILE; 384 385 printf("%17s: %s\n", "V4-ticket file", file); 386 387 ret = krb_get_tf_realm (file, princ.realm); 388 if (ret) { 389 warnx ("%s", krb_get_err_text(ret)); 390 return 1; 391 } 392 393 ret = tf_init (file, R_TKT_FIL); 394 if (ret) { 395 warnx ("tf_init: %s", krb_get_err_text(ret)); 396 return 1; 397 } 398 ret = tf_get_pname (princ.name); 399 if (ret) { 400 tf_close (); 401 warnx ("tf_get_pname: %s", krb_get_err_text(ret)); 402 return 1; 403 } 404 ret = tf_get_pinst (princ.instance); 405 if (ret) { 406 tf_close (); 407 warnx ("tf_get_pname: %s", krb_get_err_text(ret)); 408 return 1; 409 } 410 411 printf ("%17s: %s\n", "Principal", krb_unparse_name(&princ)); 412 print_time_diff(do_verbose); 413 printf("\n"); 414 415 ct = rtbl_create(); 416 rtbl_add_column(ct, COL_ISSUED, 0); 417 rtbl_add_column(ct, COL_EXPIRES, 0); 418 if (do_verbose) 419 rtbl_add_column(ct, COL_PRINCIPAL_KVNO, 0); 420 else 421 rtbl_add_column(ct, COL_PRINCIPAL, 0); 422 rtbl_set_prefix(ct, " "); 423 rtbl_set_column_prefix(ct, COL_ISSUED, ""); 424 425 while ((ret = tf_get_cred(&cred)) == KSUCCESS) { 426 struct timeval tv; 427 char buf1[20], buf2[20]; 428 const char *pp; 429 430 found++; 431 432 strlcpy(buf1, 433 short_date(cred.issue_date), 434 sizeof(buf1)); 435 cred.issue_date = krb_life_to_time(cred.issue_date, cred.lifetime); 436 krb_kdctimeofday(&tv); 437 if (do_verbose || tv.tv_sec < (unsigned long) cred.issue_date) 438 strlcpy(buf2, 439 short_date(cred.issue_date), 440 sizeof(buf2)); 441 else 442 strlcpy(buf2, 443 ">>> Expired <<<", 444 sizeof(buf2)); 445 rtbl_add_column_entry(ct, COL_ISSUED, buf1); 446 rtbl_add_column_entry(ct, COL_EXPIRES, buf2); 447 pp = krb_unparse_name_long(cred.service, 448 cred.instance, 449 cred.realm); 450 if (do_verbose) { 451 char *tmp; 452 453 asprintf(&tmp, "%s (%d)", pp, cred.kvno); 454 rtbl_add_column_entry(ct, COL_PRINCIPAL_KVNO, tmp); 455 free(tmp); 456 } else { 457 rtbl_add_column_entry(ct, COL_PRINCIPAL, pp); 458 } 459 } 460 rtbl_format(ct, stdout); 461 rtbl_destroy(ct); 462 if (!found && ret == EOF) 463 printf("No tickets in file.\n"); 464 tf_close(); 465 466 /* 467 * should do NAT stuff here 468 */ 469 return 0; 470 } 471 #endif /* KRB4 */ 472 473 /* 474 * Print a list of all AFS tokens 475 */ 476 477 static void 478 display_tokens(int do_verbose) 479 { 480 u_int32_t i; 481 unsigned char t[4096]; 482 struct ViceIoctl parms; 483 484 parms.in = (void *)&i; 485 parms.in_size = sizeof(i); 486 parms.out = (void *)t; 487 parms.out_size = sizeof(t); 488 489 for (i = 0;; i++) { 490 int32_t size_secret_tok, size_public_tok; 491 unsigned char *cell; 492 struct ClearToken ct; 493 unsigned char *r = t; 494 struct timeval tv; 495 char buf1[20], buf2[20]; 496 497 if(k_pioctl(NULL, VIOCGETTOK, &parms, 0) < 0) { 498 if(errno == EDOM) 499 break; 500 continue; 501 } 502 if(parms.out_size > sizeof(t)) 503 continue; 504 if(parms.out_size < sizeof(size_secret_tok)) 505 continue; 506 t[min(parms.out_size,sizeof(t)-1)] = 0; 507 memcpy(&size_secret_tok, r, sizeof(size_secret_tok)); 508 /* dont bother about the secret token */ 509 r += size_secret_tok + sizeof(size_secret_tok); 510 if (parms.out_size < (r - t) + sizeof(size_public_tok)) 511 continue; 512 memcpy(&size_public_tok, r, sizeof(size_public_tok)); 513 r += sizeof(size_public_tok); 514 if (parms.out_size < (r - t) + size_public_tok + sizeof(int32_t)) 515 continue; 516 memcpy(&ct, r, size_public_tok); 517 r += size_public_tok; 518 /* there is a int32_t with length of cellname, but we dont read it */ 519 r += sizeof(int32_t); 520 cell = r; 521 522 gettimeofday (&tv, NULL); 523 strlcpy (buf1, printable_time(ct.BeginTimestamp), 524 sizeof(buf1)); 525 if (do_verbose || tv.tv_sec < ct.EndTimestamp) 526 strlcpy (buf2, printable_time(ct.EndTimestamp), 527 sizeof(buf2)); 528 else 529 strlcpy (buf2, ">>> Expired <<<", sizeof(buf2)); 530 531 printf("%s %s ", buf1, buf2); 532 533 if ((ct.EndTimestamp - ct.BeginTimestamp) & 1) 534 printf("User's (AFS ID %d) tokens for %s", ct.ViceId, cell); 535 else 536 printf("Tokens for %s", cell); 537 if (do_verbose) 538 printf(" (%d)", ct.AuthHandle); 539 putchar('\n'); 540 } 541 } 542 543 /* 544 * display the ccache in `cred_cache' 545 */ 546 547 static int 548 display_v5_ccache (const char *cred_cache, int do_test, int do_verbose, 549 int do_flags) 550 { 551 krb5_error_code ret; 552 krb5_context context; 553 krb5_ccache ccache; 554 krb5_principal principal; 555 int exit_status = 0; 556 557 ret = krb5_init_context (&context); 558 if (ret) 559 errx (1, "krb5_init_context failed: %d", ret); 560 561 if(cred_cache) { 562 ret = krb5_cc_resolve(context, cred_cache, &ccache); 563 if (ret) 564 krb5_err (context, 1, ret, "%s", cred_cache); 565 } else { 566 ret = krb5_cc_default (context, &ccache); 567 if (ret) 568 krb5_err (context, 1, ret, "krb5_cc_resolve"); 569 } 570 571 ret = krb5_cc_get_principal (context, ccache, &principal); 572 if (ret) { 573 if(ret == ENOENT) { 574 if (!do_test) 575 krb5_warnx(context, "No ticket file: %s", 576 krb5_cc_get_name(context, ccache)); 577 return 1; 578 } else 579 krb5_err (context, 1, ret, "krb5_cc_get_principal"); 580 } 581 if (do_test) 582 exit_status = check_for_tgt (context, ccache, principal); 583 else 584 print_tickets (context, ccache, principal, do_verbose, do_flags); 585 586 ret = krb5_cc_close (context, ccache); 587 if (ret) 588 krb5_err (context, 1, ret, "krb5_cc_close"); 589 590 krb5_free_principal (context, principal); 591 krb5_free_context (context); 592 return exit_status; 593 } 594 595 static int version_flag = 0; 596 static int help_flag = 0; 597 static int do_verbose = 0; 598 static int do_test = 0; 599 #ifdef KRB4 600 static int do_v4 = 1; 601 #endif 602 static int do_tokens = 0; 603 static int do_v5 = 1; 604 static char *cred_cache; 605 static int do_flags = 0; 606 607 static struct getargs args[] = { 608 { NULL, 'f', arg_flag, &do_flags }, 609 { "cache", 'c', arg_string, &cred_cache, 610 "credentials cache to list", "cache" }, 611 { "test", 't', arg_flag, &do_test, 612 "test for having tickets", NULL }, 613 { NULL, 's', arg_flag, &do_test }, 614 #ifdef KRB4 615 { "v4", '4', arg_flag, &do_v4, 616 "display v4 tickets", NULL }, 617 #endif 618 { "tokens", 'T', arg_flag, &do_tokens, 619 "display AFS tokens", NULL }, 620 { "v5", '5', arg_flag, &do_v5, 621 "display v5 cred cache", NULL}, 622 { "verbose", 'v', arg_flag, &do_verbose, 623 "verbose output", NULL }, 624 { NULL, 'a', arg_flag, &do_verbose }, 625 { NULL, 'n', arg_flag, &do_verbose }, 626 { "version", 0, arg_flag, &version_flag, 627 "print version", NULL }, 628 { "help", 0, arg_flag, &help_flag, 629 NULL, NULL} 630 }; 631 632 static void 633 usage (int ret) 634 { 635 arg_printusage (args, 636 sizeof(args)/sizeof(*args), 637 NULL, 638 ""); 639 exit (ret); 640 } 641 642 int 643 main (int argc, char **argv) 644 { 645 int optind = 0; 646 int exit_status = 0; 647 648 setprogname (argv[0]); 649 650 if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optind)) 651 usage(1); 652 653 if (help_flag) 654 usage (0); 655 656 if(version_flag){ 657 print_version(NULL); 658 exit(0); 659 } 660 661 argc -= optind; 662 argv += optind; 663 664 if (argc != 0) 665 usage (1); 666 667 if (do_v5) 668 exit_status = display_v5_ccache (cred_cache, do_test, 669 do_verbose, do_flags); 670 671 if (!do_test) { 672 #ifdef KRB4 673 if (do_v4) { 674 if (do_v5) 675 printf ("\n"); 676 display_v4_tickets (do_verbose); 677 } 678 #endif 679 if (do_tokens && k_hasafs ()) { 680 if (do_v5) 681 printf ("\n"); 682 #ifdef KRB4 683 else if (do_v4) 684 printf ("\n"); 685 #endif 686 display_tokens (do_verbose); 687 } 688 } 689 690 return exit_status; 691 } 692