1 /* 2 * Copyright (c) 1997-2001 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.64 2001/05/11 19:55:13 assar 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 (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 ret = krb5_cc_end_seq_get (context, ccache, &cursor); 288 if (ret) 289 krb5_err (context, 1, ret, "krb5_cc_end_seq_get"); 290 if(!do_verbose) { 291 rtbl_format(ct, stdout); 292 rtbl_destroy(ct); 293 } 294 } 295 296 /* 297 * Check if there's a tgt for the realm of `principal' and ccache and 298 * if so return 0, else 1 299 */ 300 301 static int 302 check_for_tgt (krb5_context context, 303 krb5_ccache ccache, 304 krb5_principal principal) 305 { 306 krb5_error_code ret; 307 krb5_creds pattern; 308 krb5_creds creds; 309 krb5_realm *client_realm; 310 int expired; 311 312 client_realm = krb5_princ_realm (context, principal); 313 314 ret = krb5_make_principal (context, &pattern.server, 315 *client_realm, KRB5_TGS_NAME, *client_realm, 316 NULL); 317 if (ret) 318 krb5_err (context, 1, ret, "krb5_make_principal"); 319 320 ret = krb5_cc_retrieve_cred (context, ccache, 0, &pattern, &creds); 321 expired = time(NULL) > creds.times.endtime; 322 krb5_free_principal (context, pattern.server); 323 krb5_free_creds_contents (context, &creds); 324 if (ret) { 325 if (ret == KRB5_CC_END) 326 return 1; 327 krb5_err (context, 1, ret, "krb5_cc_retrieve_cred"); 328 } 329 return expired; 330 } 331 332 #ifdef KRB4 333 /* prints the approximate kdc time differential as something human 334 readable */ 335 336 static void 337 print_time_diff(int do_verbose) 338 { 339 int d = abs(krb_get_kdc_time_diff()); 340 char buf[80]; 341 342 if ((do_verbose && d > 0) || d > 60) { 343 unparse_time_approx (d, buf, sizeof(buf)); 344 printf ("Time diff:\t%s\n", buf); 345 } 346 } 347 348 /* 349 * return a short representation of `dp' in string form. 350 */ 351 352 static char * 353 short_date(int32_t dp) 354 { 355 char *cp; 356 time_t t = (time_t)dp; 357 358 if (t == (time_t)(-1L)) return "*** Never *** "; 359 cp = ctime(&t) + 4; 360 cp[15] = '\0'; 361 return (cp); 362 } 363 364 /* 365 * Print a list of all the v4 tickets 366 */ 367 368 static int 369 display_v4_tickets (int do_verbose) 370 { 371 char *file; 372 int ret; 373 krb_principal princ; 374 CREDENTIALS cred; 375 int found = 0; 376 377 rtbl_t ct; 378 379 file = getenv ("KRBTKFILE"); 380 if (file == NULL) 381 file = TKT_FILE; 382 383 printf("v4-ticket file: %s\n", file); 384 385 ret = krb_get_tf_realm (file, princ.realm); 386 if (ret) { 387 warnx ("%s", krb_get_err_text(ret)); 388 return 1; 389 } 390 391 ret = tf_init (file, R_TKT_FIL); 392 if (ret) { 393 warnx ("tf_init: %s", krb_get_err_text(ret)); 394 return 1; 395 } 396 ret = tf_get_pname (princ.name); 397 if (ret) { 398 tf_close (); 399 warnx ("tf_get_pname: %s", krb_get_err_text(ret)); 400 return 1; 401 } 402 ret = tf_get_pinst (princ.instance); 403 if (ret) { 404 tf_close (); 405 warnx ("tf_get_pname: %s", krb_get_err_text(ret)); 406 return 1; 407 } 408 409 printf("Principal:\t%s\n", krb_unparse_name (&princ)); 410 print_time_diff(do_verbose); 411 printf("\n"); 412 413 ct = rtbl_create(); 414 rtbl_add_column(ct, COL_ISSUED, 0); 415 rtbl_add_column(ct, COL_EXPIRES, 0); 416 if (do_verbose) 417 rtbl_add_column(ct, COL_PRINCIPAL_KVNO, 0); 418 else 419 rtbl_add_column(ct, COL_PRINCIPAL, 0); 420 rtbl_set_prefix(ct, " "); 421 rtbl_set_column_prefix(ct, COL_ISSUED, ""); 422 423 while ((ret = tf_get_cred(&cred)) == KSUCCESS) { 424 struct timeval tv; 425 char buf1[20], buf2[20]; 426 const char *pp; 427 428 found++; 429 430 strlcpy(buf1, 431 short_date(cred.issue_date), 432 sizeof(buf1)); 433 cred.issue_date = krb_life_to_time(cred.issue_date, cred.lifetime); 434 krb_kdctimeofday(&tv); 435 if (do_verbose || tv.tv_sec < (unsigned long) cred.issue_date) 436 strlcpy(buf2, 437 short_date(cred.issue_date), 438 sizeof(buf2)); 439 else 440 strlcpy(buf2, 441 ">>> Expired <<<", 442 sizeof(buf2)); 443 rtbl_add_column_entry(ct, COL_ISSUED, buf1); 444 rtbl_add_column_entry(ct, COL_EXPIRES, buf2); 445 pp = krb_unparse_name_long(cred.service, 446 cred.instance, 447 cred.realm); 448 if (do_verbose) { 449 char *tmp; 450 451 asprintf(&tmp, "%s (%d)", pp, cred.kvno); 452 rtbl_add_column_entry(ct, COL_PRINCIPAL_KVNO, tmp); 453 free(tmp); 454 } else { 455 rtbl_add_column_entry(ct, COL_PRINCIPAL, pp); 456 } 457 } 458 rtbl_format(ct, stdout); 459 rtbl_destroy(ct); 460 if (!found && ret == EOF) 461 printf("No tickets in file.\n"); 462 tf_close(); 463 464 /* 465 * should do NAT stuff here 466 */ 467 return 0; 468 } 469 470 /* 471 * Print a list of all AFS tokens 472 */ 473 474 static void 475 display_tokens(int do_verbose) 476 { 477 u_int32_t i; 478 unsigned char t[128]; 479 struct ViceIoctl parms; 480 481 parms.in = (void *)&i; 482 parms.in_size = sizeof(i); 483 parms.out = (void *)t; 484 parms.out_size = sizeof(t); 485 486 for (i = 0; k_pioctl(NULL, VIOCGETTOK, &parms, 0) == 0; i++) { 487 int32_t size_secret_tok, size_public_tok; 488 unsigned char *cell; 489 struct ClearToken ct; 490 unsigned char *r = t; 491 struct timeval tv; 492 char buf1[20], buf2[20]; 493 494 memcpy(&size_secret_tok, r, sizeof(size_secret_tok)); 495 /* dont bother about the secret token */ 496 r += size_secret_tok + sizeof(size_secret_tok); 497 memcpy(&size_public_tok, r, sizeof(size_public_tok)); 498 r += sizeof(size_public_tok); 499 memcpy(&ct, r, size_public_tok); 500 r += size_public_tok; 501 /* there is a int32_t with length of cellname, but we dont read it */ 502 r += sizeof(int32_t); 503 cell = r; 504 505 gettimeofday (&tv, NULL); 506 strlcpy (buf1, printable_time(ct.BeginTimestamp), 507 sizeof(buf1)); 508 if (do_verbose || tv.tv_sec < ct.EndTimestamp) 509 strlcpy (buf2, printable_time(ct.EndTimestamp), 510 sizeof(buf2)); 511 else 512 strlcpy (buf2, ">>> Expired <<<", sizeof(buf2)); 513 514 printf("%s %s ", buf1, buf2); 515 516 if ((ct.EndTimestamp - ct.BeginTimestamp) & 1) 517 printf("User's (AFS ID %d) tokens for %s", ct.ViceId, cell); 518 else 519 printf("Tokens for %s", cell); 520 if (do_verbose) 521 printf(" (%d)", ct.AuthHandle); 522 putchar('\n'); 523 } 524 } 525 #endif /* KRB4 */ 526 527 /* 528 * display the ccache in `cred_cache' 529 */ 530 531 static int 532 display_v5_ccache (const char *cred_cache, int do_test, int do_verbose, 533 int do_flags) 534 { 535 krb5_error_code ret; 536 krb5_context context; 537 krb5_ccache ccache; 538 krb5_principal principal; 539 int exit_status = 0; 540 541 ret = krb5_init_context (&context); 542 if (ret) 543 errx (1, "krb5_init_context failed: %d", ret); 544 545 if(cred_cache) { 546 ret = krb5_cc_resolve(context, cred_cache, &ccache); 547 if (ret) 548 krb5_err (context, 1, ret, "%s", cred_cache); 549 } else { 550 ret = krb5_cc_default (context, &ccache); 551 if (ret) 552 krb5_err (context, 1, ret, "krb5_cc_resolve"); 553 } 554 555 ret = krb5_cc_get_principal (context, ccache, &principal); 556 if (ret) { 557 if(ret == ENOENT) { 558 if (!do_test) 559 krb5_warnx(context, "No ticket file: %s", 560 krb5_cc_get_name(context, ccache)); 561 return 1; 562 } else 563 krb5_err (context, 1, ret, "krb5_cc_get_principal"); 564 } 565 if (do_test) 566 exit_status = check_for_tgt (context, ccache, principal); 567 else 568 print_tickets (context, ccache, principal, do_verbose, do_flags); 569 570 ret = krb5_cc_close (context, ccache); 571 if (ret) 572 krb5_err (context, 1, ret, "krb5_cc_close"); 573 574 krb5_free_principal (context, principal); 575 krb5_free_context (context); 576 return exit_status; 577 } 578 579 static int version_flag = 0; 580 static int help_flag = 0; 581 static int do_verbose = 0; 582 static int do_test = 0; 583 #ifdef KRB4 584 static int do_v4 = 1; 585 static int do_tokens = 0; 586 #endif 587 static int do_v5 = 1; 588 static char *cred_cache; 589 static int do_flags = 0; 590 591 static struct getargs args[] = { 592 { NULL, 'f', arg_flag, &do_flags }, 593 { "cache", 'c', arg_string, &cred_cache, 594 "credentials cache to list", "cache" }, 595 { "test", 't', arg_flag, &do_test, 596 "test for having tickets", NULL }, 597 { NULL, 's', arg_flag, &do_test }, 598 #ifdef KRB4 599 { "v4", '4', arg_flag, &do_v4, 600 "display v4 tickets", NULL }, 601 { "tokens", 'T', arg_flag, &do_tokens, 602 "display AFS tokens", NULL }, 603 #endif 604 { "v5", '5', arg_flag, &do_v5, 605 "display v5 cred cache", NULL}, 606 { "verbose", 'v', arg_flag, &do_verbose, 607 "verbose output", NULL }, 608 { NULL, 'a', arg_flag, &do_verbose }, 609 { NULL, 'n', arg_flag, &do_verbose }, 610 { "version", 0, arg_flag, &version_flag, 611 "print version", NULL }, 612 { "help", 0, arg_flag, &help_flag, 613 NULL, NULL} 614 }; 615 616 static void 617 usage (int ret) 618 { 619 arg_printusage (args, 620 sizeof(args)/sizeof(*args), 621 NULL, 622 ""); 623 exit (ret); 624 } 625 626 int 627 main (int argc, char **argv) 628 { 629 int optind = 0; 630 int exit_status = 0; 631 632 setprogname (argv[0]); 633 634 if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optind)) 635 usage(1); 636 637 if (help_flag) 638 usage (0); 639 640 if(version_flag){ 641 print_version(NULL); 642 exit(0); 643 } 644 645 argc -= optind; 646 argv += optind; 647 648 if (argc != 0) 649 usage (1); 650 651 if (do_v5) 652 exit_status = display_v5_ccache (cred_cache, do_test, 653 do_verbose, do_flags); 654 655 #ifdef KRB4 656 if (!do_test) { 657 if (do_v4) { 658 if (do_v5) 659 printf ("\n"); 660 display_v4_tickets (do_verbose); 661 } 662 if (do_tokens && k_hasafs ()) { 663 if (do_v4 || do_v5) 664 printf ("\n"); 665 display_tokens (do_verbose); 666 } 667 } 668 #endif 669 670 return exit_status; 671 } 672