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
usage(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
extended_com_err_fn(const char * prog,errcode_t code,const char * fmt,va_list args)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
main(int argc,char * argv[])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
do_keytab(const char * name)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
list_all_ccaches(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
list_ccache(krb5_ccache cache)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
show_all_ccaches(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
do_ccache(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
show_ccache(krb5_ccache cache)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
check_ccache(krb5_ccache cache)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
is_local_tgt(krb5_principal princ,krb5_data * realm)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 *
etype_string(krb5_enctype enctype)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 *
flags_string(krb5_creds * cred)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
printtime(krb5_timestamp ts)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
print_config_data(int col,krb5_data * data)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
show_credential(krb5_creds * cred,const char * defname)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
one_addr(krb5_address * a)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
fillit(FILE * f,unsigned int num,int c)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