1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* clients/klist/klist.c - List contents of credential cache or keytab */ 3 /* 4 * Copyright 1990 by the Massachusetts Institute of Technology. 5 * All Rights Reserved. 6 * 7 * Export of this software from the United States of America may 8 * require a specific license from the United States Government. 9 * It is the responsibility of any person or organization contemplating 10 * export to obtain such a license before exporting. 11 * 12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 13 * distribute this software and its documentation for any purpose and 14 * without fee is hereby granted, provided that the above copyright 15 * notice appear in all copies and that both that copyright notice and 16 * this permission notice appear in supporting documentation, and that 17 * the name of M.I.T. not be used in advertising or publicity pertaining 18 * to distribution of the software without specific, written prior 19 * permission. Furthermore if you modify this software you must label 20 * your software as modified software and not distribute it in such a 21 * fashion that it might be confused with the original M.I.T. software. 22 * M.I.T. makes no representations about the suitability of 23 * this software for any purpose. It is provided "as is" without express 24 * or implied warranty. 25 */ 26 27 #include "k5-int.h" 28 #include <krb5.h> 29 #include <com_err.h> 30 #include <locale.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <stdio.h> 34 #include <time.h> 35 36 /* Need definition of INET6 before network headers, for IRIX. */ 37 #if defined(HAVE_ARPA_INET_H) 38 #include <arpa/inet.h> 39 #endif 40 41 #ifndef _WIN32 42 #define GET_PROGNAME(x) (strrchr((x), '/') ? strrchr((x), '/') + 1 : (x)) 43 #else 44 #define GET_PROGNAME(x) max(max(strrchr((x), '/'), strrchr((x), '\\')) + 1,(x)) 45 #endif 46 47 #ifndef _WIN32 48 #include <sys/socket.h> 49 #include <netdb.h> 50 #endif 51 52 int show_flags = 0, show_time = 0, status_only = 0, show_keys = 0; 53 int show_etype = 0, show_addresses = 0, no_resolve = 0, print_version = 0; 54 int show_adtype = 0, show_all = 0, list_all = 0, use_client_keytab = 0; 55 int show_config = 0; 56 char *progname; 57 krb5_timestamp now; 58 unsigned int timestamp_width; 59 60 krb5_context context; 61 62 static krb5_boolean is_local_tgt(krb5_principal princ, krb5_data *realm); 63 static char *etype_string(krb5_enctype ); 64 static void show_credential(krb5_creds *, const char *); 65 66 static void list_all_ccaches(void); 67 static int list_ccache(krb5_ccache); 68 static void show_all_ccaches(void); 69 static void do_ccache(void); 70 static int show_ccache(krb5_ccache); 71 static int check_ccache(krb5_ccache); 72 static void do_keytab(const char *); 73 static void printtime(krb5_timestamp); 74 static void one_addr(krb5_address *); 75 static void fillit(FILE *, unsigned int, int); 76 77 #define DEFAULT 0 78 #define CCACHE 1 79 #define KEYTAB 2 80 81 static void 82 usage(void) 83 { 84 fprintf(stderr, _("Usage: %s [-e] [-V] [[-c] [-l] [-A] [-d] [-f] [-s] " 85 "[-a [-n]]] [-k [-i] [-t] [-K]] [-C] [name]\n"), 86 progname); 87 fprintf(stderr, _("\t-c specifies credentials cache\n")); 88 fprintf(stderr, _("\t-k specifies keytab\n")); 89 fprintf(stderr, _("\t (Default is credentials cache)\n")); 90 fprintf(stderr, _("\t-i uses default client keytab if no name given\n")); 91 fprintf(stderr, _("\t-l lists credential caches in collection\n")); 92 fprintf(stderr, _("\t-A shows content of all credential caches\n")); 93 fprintf(stderr, _("\t-e shows the encryption type\n")); 94 fprintf(stderr, _("\t-V shows the Kerberos version and exits\n")); 95 fprintf(stderr, _("\toptions for credential caches:\n")); 96 fprintf(stderr, _("\t\t-d shows the submitted authorization data " 97 "types\n")); 98 fprintf(stderr, _("\t\t-f shows credentials flags\n")); 99 fprintf(stderr, _("\t\t-s sets exit status based on valid tgt " 100 "existence\n")); 101 fprintf(stderr, _("\t\t-a displays the address list\n")); 102 fprintf(stderr, _("\t\t\t-n do not reverse-resolve\n")); 103 fprintf(stderr, _("\toptions for keytabs:\n")); 104 fprintf(stderr, _("\t\t-t shows keytab entry timestamps\n")); 105 fprintf(stderr, _("\t\t-K shows keytab entry keys\n")); 106 fprintf(stderr, _("\t\t-C includes configuration data entries\n")); 107 exit(1); 108 } 109 110 static void 111 extended_com_err_fn(const char *prog, errcode_t code, const char *fmt, 112 va_list args) 113 { 114 const char *msg; 115 116 msg = krb5_get_error_message(context, code); 117 fprintf(stderr, "%s: %s%s", prog, msg, (*fmt == '\0') ? "" : " "); 118 krb5_free_error_message(context, msg); 119 vfprintf(stderr, fmt, args); 120 fprintf(stderr, "\n"); 121 } 122 123 int 124 main(int argc, char *argv[]) 125 { 126 krb5_error_code ret; 127 char *name, tmp[BUFSIZ]; 128 int c, mode; 129 130 setlocale(LC_ALL, ""); 131 progname = GET_PROGNAME(argv[0]); 132 set_com_err_hook(extended_com_err_fn); 133 134 name = NULL; 135 mode = DEFAULT; 136 /* V = version so v can be used for verbose later if desired. */ 137 while ((c = getopt(argc, argv, "dfetKsnacki45lAVC")) != -1) { 138 switch (c) { 139 case 'd': 140 show_adtype = 1; 141 break; 142 case 'f': 143 show_flags = 1; 144 break; 145 case 'e': 146 show_etype = 1; 147 break; 148 case 't': 149 show_time = 1; 150 break; 151 case 'K': 152 show_keys = 1; 153 break; 154 case 's': 155 status_only = 1; 156 break; 157 case 'n': 158 no_resolve = 1; 159 break; 160 case 'a': 161 show_addresses = 1; 162 break; 163 case 'c': 164 if (mode != DEFAULT) 165 usage(); 166 mode = CCACHE; 167 break; 168 case 'k': 169 if (mode != DEFAULT) 170 usage(); 171 mode = KEYTAB; 172 break; 173 case 'i': 174 use_client_keytab = 1; 175 break; 176 case '4': 177 fprintf(stderr, _("Kerberos 4 is no longer supported\n")); 178 exit(3); 179 break; 180 case '5': 181 break; 182 case 'l': 183 list_all = 1; 184 break; 185 case 'A': 186 show_all = 1; 187 break; 188 case 'C': 189 show_config = 1; 190 break; 191 case 'V': 192 print_version = 1; 193 break; 194 default: 195 usage(); 196 break; 197 } 198 } 199 200 if (no_resolve && !show_addresses) 201 usage(); 202 203 if (mode == DEFAULT || mode == CCACHE) { 204 if (show_time || show_keys) 205 usage(); 206 if ((show_all && list_all) || (status_only && list_all)) 207 usage(); 208 } else { 209 if (show_flags || status_only || show_addresses || 210 show_all || list_all) 211 usage(); 212 } 213 214 if (argc - optind > 1) { 215 fprintf(stderr, _("Extra arguments (starting with \"%s\").\n"), 216 argv[optind + 1]); 217 usage(); 218 } 219 220 if (print_version) { 221 #ifdef _WIN32 /* No access to autoconf vars; fix somehow. */ 222 printf("Kerberos for Windows\n"); 223 #else 224 printf(_("%s version %s\n"), PACKAGE_NAME, PACKAGE_VERSION); 225 #endif 226 exit(0); 227 } 228 229 name = (optind == argc - 1) ? argv[optind] : NULL; 230 now = time(0); 231 232 if (!krb5_timestamp_to_sfstring(now, tmp, 20, NULL) || 233 !krb5_timestamp_to_sfstring(now, tmp, sizeof(tmp), NULL)) 234 timestamp_width = (int)strlen(tmp); 235 else 236 timestamp_width = 15; 237 238 ret = krb5_init_context(&context); 239 if (ret) { 240 com_err(progname, ret, _("while initializing krb5")); 241 exit(1); 242 } 243 244 if (name != NULL && mode != KEYTAB) { 245 ret = krb5_cc_set_default_name(context, name); 246 if (ret) { 247 com_err(progname, ret, _("while setting default cache name")); 248 exit(1); 249 } 250 } 251 252 if (list_all) 253 list_all_ccaches(); 254 else if (show_all) 255 show_all_ccaches(); 256 else if (mode == DEFAULT || mode == CCACHE) 257 do_ccache(); 258 else 259 do_keytab(name); 260 return 0; 261 } 262 263 static void 264 do_keytab(const char *name) 265 { 266 krb5_error_code ret; 267 krb5_keytab kt; 268 krb5_keytab_entry entry; 269 krb5_kt_cursor cursor; 270 unsigned int i; 271 char buf[BUFSIZ]; /* Hopefully large enough for any type */ 272 char *pname; 273 274 if (name == NULL && use_client_keytab) { 275 ret = krb5_kt_client_default(context, &kt); 276 if (ret) { 277 com_err(progname, ret, _("while getting default client keytab")); 278 exit(1); 279 } 280 } else if (name == NULL) { 281 ret = krb5_kt_default(context, &kt); 282 if (ret) { 283 com_err(progname, ret, _("while getting default keytab")); 284 exit(1); 285 } 286 } else { 287 ret = krb5_kt_resolve(context, name, &kt); 288 if (ret) { 289 com_err(progname, ret, _("while resolving keytab %s"), name); 290 exit(1); 291 } 292 } 293 294 ret = krb5_kt_get_name(context, kt, buf, BUFSIZ); 295 if (ret) { 296 com_err(progname, ret, _("while getting keytab name")); 297 exit(1); 298 } 299 300 printf("Keytab name: %s\n", buf); 301 302 ret = krb5_kt_start_seq_get(context, kt, &cursor); 303 if (ret) { 304 com_err(progname, ret, _("while starting keytab scan")); 305 exit(1); 306 } 307 308 /* XXX Translating would disturb table alignment; skip for now. */ 309 if (show_time) { 310 printf("KVNO Timestamp"); 311 fillit(stdout, timestamp_width - sizeof("Timestamp") + 2, (int) ' '); 312 printf("Principal\n"); 313 printf("---- "); 314 fillit(stdout, timestamp_width, (int) '-'); 315 printf(" "); 316 fillit(stdout, 78 - timestamp_width - sizeof("KVNO"), (int) '-'); 317 printf("\n"); 318 } else { 319 printf("KVNO Principal\n"); 320 printf("---- ------------------------------------------------" 321 "--------------------------\n"); 322 } 323 324 while ((ret = krb5_kt_next_entry(context, kt, &entry, &cursor)) == 0) { 325 ret = krb5_unparse_name(context, entry.principal, &pname); 326 if (ret) { 327 com_err(progname, ret, _("while unparsing principal name")); 328 exit(1); 329 } 330 printf("%4d ", entry.vno); 331 if (show_time) { 332 printtime(entry.timestamp); 333 printf(" "); 334 } 335 printf("%s", pname); 336 if (show_etype) 337 printf(" (%s) " , etype_string(entry.key.enctype)); 338 if (show_keys) { 339 printf(" (0x"); 340 for (i = 0; i < entry.key.length; i++) 341 printf("%02x", entry.key.contents[i]); 342 printf(")"); 343 } 344 printf("\n"); 345 krb5_free_unparsed_name(context, pname); 346 krb5_free_keytab_entry_contents(context, &entry); 347 } 348 if (ret && ret != KRB5_KT_END) { 349 com_err(progname, ret, _("while scanning keytab")); 350 exit(1); 351 } 352 ret = krb5_kt_end_seq_get(context, kt, &cursor); 353 if (ret) { 354 com_err(progname, ret, _("while ending keytab scan")); 355 exit(1); 356 } 357 exit(0); 358 } 359 360 static void 361 list_all_ccaches(void) 362 { 363 krb5_error_code ret; 364 krb5_ccache cache; 365 krb5_cccol_cursor cursor; 366 int exit_status; 367 368 ret = krb5_cccol_cursor_new(context, &cursor); 369 if (ret) { 370 if (!status_only) 371 com_err(progname, ret, _("while listing ccache collection")); 372 exit(1); 373 } 374 375 /* XXX Translating would disturb table alignment; skip for now. */ 376 printf("%-30s %s\n", "Principal name", "Cache name"); 377 printf("%-30s %s\n", "--------------", "----------"); 378 exit_status = 1; 379 while ((ret = krb5_cccol_cursor_next(context, cursor, &cache)) == 0 && 380 cache != NULL) { 381 exit_status = list_ccache(cache) && exit_status; 382 krb5_cc_close(context, cache); 383 } 384 krb5_cccol_cursor_free(context, &cursor); 385 exit(exit_status); 386 } 387 388 static int 389 list_ccache(krb5_ccache cache) 390 { 391 krb5_error_code ret; 392 krb5_principal princ = NULL; 393 char *princname = NULL, *ccname = NULL; 394 int expired, status = 1; 395 396 ret = krb5_cc_get_principal(context, cache, &princ); 397 if (ret) /* Uninitialized cache file, probably. */ 398 goto cleanup; 399 ret = krb5_unparse_name(context, princ, &princname); 400 if (ret) 401 goto cleanup; 402 ret = krb5_cc_get_full_name(context, cache, &ccname); 403 if (ret) 404 goto cleanup; 405 406 expired = check_ccache(cache); 407 408 printf("%-30.30s %s", princname, ccname); 409 if (expired) 410 printf(" %s", _("(Expired)")); 411 printf("\n"); 412 413 status = 0; 414 415 cleanup: 416 krb5_free_principal(context, princ); 417 krb5_free_unparsed_name(context, princname); 418 krb5_free_string(context, ccname); 419 return status; 420 } 421 422 static void 423 show_all_ccaches(void) 424 { 425 krb5_error_code ret; 426 krb5_ccache cache; 427 krb5_cccol_cursor cursor; 428 krb5_boolean first; 429 int exit_status, st; 430 431 ret = krb5_cccol_cursor_new(context, &cursor); 432 if (ret) { 433 if (!status_only) 434 com_err(progname, ret, _("while listing ccache collection")); 435 exit(1); 436 } 437 exit_status = 1; 438 first = TRUE; 439 while ((ret = krb5_cccol_cursor_next(context, cursor, &cache)) == 0 && 440 cache != NULL) { 441 if (!status_only && !first) 442 printf("\n"); 443 first = FALSE; 444 st = status_only ? check_ccache(cache) : show_ccache(cache); 445 exit_status = st && exit_status; 446 krb5_cc_close(context, cache); 447 } 448 krb5_cccol_cursor_free(context, &cursor); 449 exit(exit_status); 450 } 451 452 static void 453 do_ccache(void) 454 { 455 krb5_error_code ret; 456 krb5_ccache cache; 457 458 ret = krb5_cc_default(context, &cache); 459 if (ret) { 460 if (!status_only) 461 com_err(progname, ret, _("while resolving ccache")); 462 exit(1); 463 } 464 exit(status_only ? check_ccache(cache) : show_ccache(cache)); 465 } 466 467 /* Display the contents of cache. */ 468 static int 469 show_ccache(krb5_ccache cache) 470 { 471 krb5_cc_cursor cur = NULL; 472 krb5_creds creds; 473 krb5_principal princ = NULL; 474 krb5_error_code ret; 475 char *defname = NULL; 476 int status = 1; 477 478 ret = krb5_cc_get_principal(context, cache, &princ); 479 if (ret) { 480 com_err(progname, ret, ""); 481 goto cleanup; 482 } 483 ret = krb5_unparse_name(context, princ, &defname); 484 if (ret) { 485 com_err(progname, ret, _("while unparsing principal name")); 486 goto cleanup; 487 } 488 489 printf(_("Ticket cache: %s:%s\nDefault principal: %s\n\n"), 490 krb5_cc_get_type(context, cache), krb5_cc_get_name(context, cache), 491 defname); 492 /* XXX Translating would disturb table alignment; skip for now. */ 493 fputs("Valid starting", stdout); 494 fillit(stdout, timestamp_width - sizeof("Valid starting") + 3, (int) ' '); 495 fputs("Expires", stdout); 496 fillit(stdout, timestamp_width - sizeof("Expires") + 3, (int) ' '); 497 fputs("Service principal\n", stdout); 498 499 ret = krb5_cc_start_seq_get(context, cache, &cur); 500 if (ret) { 501 com_err(progname, ret, _("while starting to retrieve tickets")); 502 goto cleanup; 503 } 504 while ((ret = krb5_cc_next_cred(context, cache, &cur, &creds)) == 0) { 505 if (show_config || !krb5_is_config_principal(context, creds.server)) 506 show_credential(&creds, defname); 507 krb5_free_cred_contents(context, &creds); 508 } 509 if (ret == KRB5_CC_END) { 510 ret = krb5_cc_end_seq_get(context, cache, &cur); 511 cur = NULL; 512 if (ret) { 513 com_err(progname, ret, _("while finishing ticket retrieval")); 514 goto cleanup; 515 } 516 } else { 517 com_err(progname, ret, _("while retrieving a ticket")); 518 goto cleanup; 519 } 520 521 status = 0; 522 523 cleanup: 524 if (cur != NULL) 525 (void)krb5_cc_end_seq_get(context, cache, &cur); 526 krb5_free_principal(context, princ); 527 krb5_free_unparsed_name(context, defname); 528 return status; 529 } 530 531 /* Return 0 if cache is accessible, present, and unexpired; return 1 if not. */ 532 static int 533 check_ccache(krb5_ccache cache) 534 { 535 krb5_error_code ret; 536 krb5_cc_cursor cur = NULL; 537 krb5_creds creds; 538 krb5_principal princ = NULL; 539 krb5_boolean found_tgt = FALSE, found_current_tgt = FALSE; 540 krb5_boolean found_current_cred = FALSE; 541 542 ret = krb5_cc_get_principal(context, cache, &princ); 543 if (ret) 544 goto cleanup; 545 ret = krb5_cc_start_seq_get(context, cache, &cur); 546 if (ret) 547 goto cleanup; 548 found_tgt = found_current_tgt = found_current_cred = FALSE; 549 while ((ret = krb5_cc_next_cred(context, cache, &cur, &creds)) == 0) { 550 if (is_local_tgt(creds.server, &princ->realm)) { 551 found_tgt = TRUE; 552 if (ts_after(creds.times.endtime, now)) 553 found_current_tgt = TRUE; 554 } else if (!krb5_is_config_principal(context, creds.server) && 555 ts_after(creds.times.endtime, now)) { 556 found_current_cred = TRUE; 557 } 558 krb5_free_cred_contents(context, &creds); 559 } 560 if (ret != KRB5_CC_END) 561 goto cleanup; 562 ret = krb5_cc_end_seq_get(context, cache, &cur); 563 cur = NULL; 564 565 cleanup: 566 if (cur != NULL) 567 (void)krb5_cc_end_seq_get(context, cache, &cur); 568 krb5_free_principal(context, princ); 569 if (ret) 570 return 1; 571 /* If the cache contains at least one local TGT, require that it be 572 * current. Otherwise accept any current cred. */ 573 if (found_tgt) 574 return found_current_tgt ? 0 : 1; 575 return found_current_cred ? 0 : 1; 576 } 577 578 /* Return true if princ is the local krbtgt principal for local_realm. */ 579 static krb5_boolean 580 is_local_tgt(krb5_principal princ, krb5_data *realm) 581 { 582 return princ->length == 2 && data_eq(princ->realm, *realm) && 583 data_eq_string(princ->data[0], KRB5_TGS_NAME) && 584 data_eq(princ->data[1], *realm); 585 } 586 587 static char * 588 etype_string(krb5_enctype enctype) 589 { 590 static char buf[100]; 591 char *bp = buf; 592 size_t deplen, buflen = sizeof(buf); 593 594 if (krb5int_c_deprecated_enctype(enctype)) { 595 deplen = strlcpy(bp, "DEPRECATED:", buflen); 596 buflen -= deplen; 597 bp += deplen; 598 } 599 600 if (krb5_enctype_to_name(enctype, FALSE, bp, buflen)) 601 snprintf(bp, buflen, "etype %d", enctype); 602 return buf; 603 } 604 605 static char * 606 flags_string(krb5_creds *cred) 607 { 608 static char buf[32]; 609 int i = 0; 610 611 if (cred->ticket_flags & TKT_FLG_FORWARDABLE) 612 buf[i++] = 'F'; 613 if (cred->ticket_flags & TKT_FLG_FORWARDED) 614 buf[i++] = 'f'; 615 if (cred->ticket_flags & TKT_FLG_PROXIABLE) 616 buf[i++] = 'P'; 617 if (cred->ticket_flags & TKT_FLG_PROXY) 618 buf[i++] = 'p'; 619 if (cred->ticket_flags & TKT_FLG_MAY_POSTDATE) 620 buf[i++] = 'D'; 621 if (cred->ticket_flags & TKT_FLG_POSTDATED) 622 buf[i++] = 'd'; 623 if (cred->ticket_flags & TKT_FLG_INVALID) 624 buf[i++] = 'i'; 625 if (cred->ticket_flags & TKT_FLG_RENEWABLE) 626 buf[i++] = 'R'; 627 if (cred->ticket_flags & TKT_FLG_INITIAL) 628 buf[i++] = 'I'; 629 if (cred->ticket_flags & TKT_FLG_HW_AUTH) 630 buf[i++] = 'H'; 631 if (cred->ticket_flags & TKT_FLG_PRE_AUTH) 632 buf[i++] = 'A'; 633 if (cred->ticket_flags & TKT_FLG_TRANSIT_POLICY_CHECKED) 634 buf[i++] = 'T'; 635 if (cred->ticket_flags & TKT_FLG_OK_AS_DELEGATE) 636 buf[i++] = 'O'; /* D/d are taken. Use short strings? */ 637 if (cred->ticket_flags & TKT_FLG_ANONYMOUS) 638 buf[i++] = 'a'; 639 buf[i] = '\0'; 640 return buf; 641 } 642 643 static void 644 printtime(krb5_timestamp ts) 645 { 646 char timestring[BUFSIZ], fill = ' '; 647 648 if (!krb5_timestamp_to_sfstring(ts, timestring, timestamp_width + 1, 649 &fill)) 650 printf("%s", timestring); 651 } 652 653 static void 654 print_config_data(int col, krb5_data *data) 655 { 656 unsigned int i; 657 658 for (i = 0; i < data->length; i++) { 659 while (col < 8) { 660 putchar(' '); 661 col++; 662 } 663 if (data->data[i] > 0x20 && data->data[i] < 0x7f) { 664 putchar(data->data[i]); 665 col++; 666 } else { 667 col += printf("\\%03o", (unsigned char)data->data[i]); 668 } 669 if (col > 72) { 670 putchar('\n'); 671 col = 0; 672 } 673 } 674 if (col > 0) 675 putchar('\n'); 676 } 677 678 static void 679 show_credential(krb5_creds *cred, const char *defname) 680 { 681 krb5_error_code ret; 682 krb5_ticket *tkt = NULL; 683 char *name = NULL, *sname = NULL, *tktsname, *flags; 684 int extra_field = 0, ccol = 0, i, r; 685 krb5_boolean is_config = krb5_is_config_principal(context, cred->server); 686 687 ret = krb5_unparse_name(context, cred->client, &name); 688 if (ret) { 689 com_err(progname, ret, _("while unparsing client name")); 690 goto cleanup; 691 } 692 ret = krb5_unparse_name(context, cred->server, &sname); 693 if (ret) { 694 com_err(progname, ret, _("while unparsing server name")); 695 goto cleanup; 696 } 697 if (!is_config) 698 (void)krb5_decode_ticket(&cred->ticket, &tkt); 699 if (!cred->times.starttime) 700 cred->times.starttime = cred->times.authtime; 701 702 if (!is_config) { 703 printtime(cred->times.starttime); 704 putchar(' '); 705 putchar(' '); 706 printtime(cred->times.endtime); 707 putchar(' '); 708 putchar(' '); 709 printf("%s\n", sname); 710 } else { 711 fputs("config: ", stdout); 712 ccol = 8; 713 for (i = 1; i < cred->server->length; i++) { 714 r = printf("%s%.*s%s", i > 1 ? "(" : "", 715 (int)cred->server->data[i].length, 716 cred->server->data[i].data, i > 1 ? ")" : ""); 717 if (r >= 0) 718 ccol += r; 719 } 720 fputs(" = ", stdout); 721 ccol += 3; 722 } 723 724 if (strcmp(name, defname)) { 725 printf(_("\tfor client %s"), name); 726 extra_field++; 727 } 728 729 if (is_config) 730 print_config_data(ccol, &cred->ticket); 731 732 if (cred->times.renew_till) { 733 if (!extra_field) 734 fputs("\t",stdout); 735 else 736 fputs(", ",stdout); 737 fputs(_("renew until "), stdout); 738 printtime(cred->times.renew_till); 739 extra_field += 2; 740 } 741 742 if (show_flags) { 743 flags = flags_string(cred); 744 if (flags && *flags) { 745 if (!extra_field) 746 fputs("\t",stdout); 747 else 748 fputs(", ",stdout); 749 printf(_("Flags: %s"), flags); 750 extra_field++; 751 } 752 } 753 754 if (extra_field > 2) { 755 fputs("\n", stdout); 756 extra_field = 0; 757 } 758 759 if (show_etype && tkt != NULL) { 760 if (!extra_field) 761 fputs("\t",stdout); 762 else 763 fputs(", ",stdout); 764 printf(_("Etype (skey, tkt): %s, "), 765 etype_string(cred->keyblock.enctype)); 766 printf("%s ", etype_string(tkt->enc_part.enctype)); 767 extra_field++; 768 } 769 770 if (show_adtype) { 771 if (cred->authdata != NULL) { 772 if (!extra_field) 773 fputs("\t",stdout); 774 else 775 fputs(", ",stdout); 776 printf(_("AD types: ")); 777 for (i = 0; cred->authdata[i] != NULL; i++) { 778 if (i) 779 printf(", "); 780 printf("%d", cred->authdata[i]->ad_type); 781 } 782 extra_field++; 783 } 784 } 785 786 /* If any additional info was printed, extra_field is non-zero. */ 787 if (extra_field) 788 putchar('\n'); 789 790 if (show_addresses) { 791 if (cred->addresses == NULL || cred->addresses[0] == NULL) { 792 printf(_("\tAddresses: (none)\n")); 793 } else { 794 printf(_("\tAddresses: ")); 795 one_addr(cred->addresses[0]); 796 797 for (i = 1; cred->addresses[i] != NULL; i++) { 798 printf(", "); 799 one_addr(cred->addresses[i]); 800 } 801 802 printf("\n"); 803 } 804 } 805 806 /* Display the ticket server if it is different from the server name the 807 * entry was cached under (most commonly for referrals). */ 808 if (tkt != NULL && 809 !krb5_principal_compare(context, cred->server, tkt->server)) { 810 ret = krb5_unparse_name(context, tkt->server, &tktsname); 811 if (ret) { 812 com_err(progname, ret, _("while unparsing ticket server name")); 813 goto cleanup; 814 } 815 printf(_("\tTicket server: %s\n"), tktsname); 816 krb5_free_unparsed_name(context, tktsname); 817 } 818 819 cleanup: 820 krb5_free_unparsed_name(context, name); 821 krb5_free_unparsed_name(context, sname); 822 krb5_free_ticket(context, tkt); 823 } 824 825 #include "port-sockets.h" 826 #include "socket-utils.h" /* For ss2sin etc. */ 827 #include "fake-addrinfo.h" 828 829 static void 830 one_addr(krb5_address *a) 831 { 832 struct sockaddr_storage ss; 833 struct sockaddr_in *sinp; 834 struct sockaddr_in6 *sin6p; 835 int err, i; 836 char namebuf[NI_MAXHOST]; 837 const uint8_t *p; 838 839 memset(&ss, 0, sizeof(ss)); 840 841 switch (a->addrtype) { 842 case ADDRTYPE_INET: 843 if (a->length != 4) { 844 printf(_("broken address (type %d length %d)"), 845 a->addrtype, a->length); 846 return; 847 } 848 sinp = ss2sin(&ss); 849 sinp->sin_family = AF_INET; 850 memcpy(&sinp->sin_addr, a->contents, 4); 851 break; 852 case ADDRTYPE_INET6: 853 if (a->length != 16) { 854 printf(_("broken address (type %d length %d)"), 855 a->addrtype, a->length); 856 return; 857 } 858 sin6p = ss2sin6(&ss); 859 sin6p->sin6_family = AF_INET6; 860 memcpy(&sin6p->sin6_addr, a->contents, 16); 861 break; 862 case ADDRTYPE_NETBIOS: 863 if (a->length != 16) { 864 printf(_("broken address (type %d length %d)"), 865 a->addrtype, a->length); 866 return; 867 } 868 p = a->contents; 869 for (i = 0; i < 15 && p[i] != '\0' && p[i] != ' '; i++) 870 putchar(p[i]); 871 return; 872 default: 873 printf(_("unknown addrtype %d"), a->addrtype); 874 return; 875 } 876 877 namebuf[0] = 0; 878 err = getnameinfo(ss2sa(&ss), sa_socklen(ss2sa(&ss)), namebuf, 879 sizeof(namebuf), 0, 0, 880 no_resolve ? NI_NUMERICHOST : 0U); 881 if (err) { 882 printf(_("unprintable address (type %d, error %d %s)"), a->addrtype, 883 err, gai_strerror(err)); 884 return; 885 } 886 printf("%s", namebuf); 887 } 888 889 static void 890 fillit(FILE *f, unsigned int num, int c) 891 { 892 unsigned int i; 893 894 for (i = 0; i < num; i++) 895 fputc(c, f); 896 } 897