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