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