xref: /titanic_41/usr/src/cmd/krb5/klist/klist.c (revision 1eca9c5f1f5a027ee89ec25e5d9f722e9087ba69)
1 /*
2  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 #pragma ident	"%Z%%M%	%I%	%E% SMI"
6 
7 /*
8  * clients/klist/klist.c
9  *
10  * Copyright 1990 by the Massachusetts Institute of Technology.
11  * All Rights Reserved.
12  *
13  * Export of this software from the United States of America may
14  *   require a specific license from the United States Government.
15  *   It is the responsibility of any person or organization contemplating
16  *   export to obtain such a license before exporting.
17  *
18  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
19  * distribute this software and its documentation for any purpose and
20  * without fee is hereby granted, provided that the above copyright
21  * notice appear in all copies and that both that copyright notice and
22  * this permission notice appear in supporting documentation, and that
23  * the name of M.I.T. not be used in advertising or publicity pertaining
24  * to distribution of the software without specific, written prior
25  * permission.  Furthermore if you modify this software you must label
26  * your software as modified software and not distribute it in such a
27  * fashion that it might be confused with the original M.I.T. software.
28  * M.I.T. makes no representations about the suitability of
29  * this software for any purpose.  It is provided "as is" without express
30  * or implied warranty.
31  *
32  *
33  * List out the contents of your credential cache or keytab.
34  */
35 
36 #include <k5-int.h>
37 #include "com_err.h"
38 #include <krb5.h>
39 #ifdef KRB5_KRB4_COMPAT
40 #include <kerberosIV/krb.h>
41 #endif /* KRB5_KRB4_COMPAT */
42 
43 #include <stdlib.h>
44 #include <string.h>
45 #include <stdio.h>
46 #include <time.h>
47 #include <libintl.h>
48 #include <locale.h>
49 #include <netinet/in.h>
50 #if defined(HAVE_ARPA_INET_H)
51 #include <arpa/inet.h>
52 #endif
53 #include <inet/ip.h>
54 #include <inet/ip6.h>
55 
56 #ifndef _WIN32
57 #define GET_PROGNAME(x) (strrchr((x), '/') ? strrchr((x), '/')+1 : (x))
58 #else
59 #define GET_PROGNAME(x) max(max(strrchr((x), '/'), strrchr((x), '\\')) + 1,(x))
60 #endif /* _WIN32 */
61 
62 #ifndef _WIN32
63 #include <sys/socket.h>
64 #include <netdb.h>
65 #endif
66 
67 extern int optind;
68 
69 int show_flags = 0, show_time = 0, status_only = 0, show_keys = 0;
70 int show_etype = 0, show_addresses = 0, no_resolve = 0;
71 char *defname;
72 char *progname;
73 krb5_int32 now;
74 size_t timestamp_width;
75 
76 krb5_context kcontext;
77 
78 char * etype_string (krb5_enctype );
79 void show_credential (krb5_creds *);
80 
81 void do_ccache (char *);
82 void do_keytab (char *);
83 void printtime (time_t);
84 void one_addr (krb5_address *);
85 void fillit (FILE *, unsigned int, int);
86 void show_addr(krb5_address *a);
87 
88 #ifdef KRB5_KRB4_COMPAT
89 void do_v4_ccache (char *);
90 #endif /* KRB5_KRB4_COMPAT */
91 
92 #define DEFAULT 0
93 #define CCACHE 1
94 #define KEYTAB 2
95 
96 /*
97  * The reason we start out with got_k4 and got_k5 as zero (false) is
98  * so that we can easily add dynamic loading support for determining
99  * whether Kerberos 4 and Keberos 5 libraries are available
100  */
101 
102 static int got_k5 = 0;
103 static int got_k4 = 0;
104 
105 static int default_k5 = 1;
106 #ifdef KRB5_KRB4_COMPAT
107 static int default_k4 = 1;
108 #else  /* KRB5_KRB4_COMPAT */
109 static int default_k4 = 0;
110 #endif /* KRB5_KRB4_COMPAT */
111 
112 static void usage()
113 {
114 #define KRB_AVAIL_STRING(x) ((x)?gettext("available"):gettext("not available"))
115 
116     fprintf(stderr, gettext("Usage: %s [-5] [-4] [-e]"
117                     " [[-c] [-f] [-s] [-a [-n]]] "
118 	            "[-k [-t] [-K]] [name]\n"), progname);
119     fprintf(stderr, "\t-5 Kerberos 5 (%s)\n", KRB_AVAIL_STRING(got_k5));
120     fprintf(stderr, "\t-4 Kerberos 4 (%s)\n", KRB_AVAIL_STRING(got_k4));
121     fprintf(stderr, gettext("\t   (Default is %s%s%s%s)\n"),
122 	    default_k5?"Kerberos 5":"",
123 	    (default_k5 && default_k4)?gettext(" and "):"",
124 	    default_k4?"Kerberos 4":"",
125 	    (!default_k5 && !default_k4)?gettext("neither"):"");
126     fprintf(stderr, gettext("\t-c specifies credentials cache\n"));
127     fprintf(stderr, gettext("\t-k specifies keytab\n"));
128     fprintf(stderr, gettext("\t   (Default is credentials cache)\n"));
129     fprintf(stderr, gettext("\t-e shows the encryption type\n"));
130     fprintf(stderr, gettext("\toptions for credential caches:\n"));
131     fprintf(stderr, gettext("\t\t-f shows credentials flags\n"));
132     fprintf(stderr, gettext("\t\t-s sets exit status based on valid tgt existence\n"));
133     fprintf(stderr, gettext("\t\t-a displays the address list\n"));
134     fprintf(stderr, gettext("\t\t-n do not reverse-resolve\n"));
135     fprintf(stderr, gettext("\toptions for keytabs:\n"));
136     fprintf(stderr, gettext("\t\t-t shows keytab entry timestamps\n"));
137     fprintf(stderr, gettext("\t\t-K shows keytab entry DES keys\n"));
138     exit(1);
139 }
140 
141 
142 int
143 main(argc, argv)
144     int argc;
145     char **argv;
146 {
147     int c;
148     char *name;
149     int mode;
150     int use_k5 = 0, use_k4 = 0;
151 
152     got_k5 = 1;
153 #ifdef KRB5_KRB4_COMPAT
154     got_k4 = 1;
155 #endif /* KRB5_KRB4_COMPAT */
156 
157     (void) setlocale(LC_ALL, "");
158 
159 #if !defined(TEXT_DOMAIN)
160 #define	TEXT_DOMAIN "SYS_TEST"
161 #endif /* !TEXT_DOMAIN */
162 
163     (void) textdomain(TEXT_DOMAIN);
164 
165     progname = GET_PROGNAME(argv[0]);
166 
167     name = NULL;
168     mode = DEFAULT;
169     while ((c = getopt(argc, argv, "fetKsnack45")) != -1) {
170 	switch (c) {
171 	case 'f':
172 	    show_flags = 1;
173 	    break;
174 	case 'e':
175 	    show_etype = 1;
176 	    break;
177 	case 't':
178 	    show_time = 1;
179 	    break;
180 	case 'K':
181 	    show_keys = 1;
182 	    break;
183 	case 's':
184 	    status_only = 1;
185 	    break;
186 	case 'n':
187 	    no_resolve = 1;
188 	    break;
189 	case 'a':
190 	    show_addresses = 1;
191 	    break;
192 	case 'c':
193 	    if (mode != DEFAULT) usage();
194 	    mode = CCACHE;
195 	    break;
196 	case 'k':
197 	    if (mode != DEFAULT) usage();
198 	    mode = KEYTAB;
199 	    break;
200 	case '4':
201 	    if (!got_k4)
202 	    {
203 #ifdef KRB5_KRB4_COMPAT
204 		fprintf(stderr, "Kerberos 4 support could not be loaded\n");
205 #else  /* KRB5_KRB4_COMPAT */
206 		fprintf(stderr, gettext("This was not built with Kerberos 4 support\n"));
207 #endif /* KRB5_KRB4_COMPAT */
208 		exit(3);
209 	    }
210 	    use_k4 = 1;
211 	    break;
212 	case '5':
213 	    if (!got_k5)
214 	    {
215 		fprintf(stderr, gettext("Kerberos 5 support could not be loaded\n"));
216 		exit(3);
217 	    }
218 	    use_k5 = 1;
219 	    break;
220 	default:
221 	    usage();
222 	    break;
223 	}
224     }
225 
226     if (no_resolve && !show_addresses) {
227 	usage();
228     }
229 
230     if (mode == DEFAULT || mode == CCACHE) {
231 	if (show_time || show_keys)
232 	    usage();
233     } else {
234 	if (show_flags || status_only || show_addresses)
235 	    usage();
236     }
237 
238     if (argc - optind > 1) {
239 		fprintf(stderr,
240 			gettext("Extra arguments (starting with \"%s\").\n"),
241 		argv[optind+1]);
242 	usage();
243     }
244 
245     name = (optind == argc-1) ? argv[optind] : 0;
246 
247     if (!use_k5 && !use_k4)
248     {
249 	use_k5 = default_k5;
250 	use_k4 = default_k4;
251     }
252 
253     if (!use_k5)
254 	got_k5 = 0;
255     if (!use_k4)
256 	got_k4 = 0;
257 
258     now = time(0);
259     {
260 	char tmp[BUFSIZ];
261 
262 	if (!krb5_timestamp_to_sfstring(now, tmp, 20, (char *) NULL) ||
263 	    !krb5_timestamp_to_sfstring(now, tmp, sizeof(tmp),
264 					(char *) NULL))
265 	    timestamp_width = (int) strlen(tmp);
266 	else
267 	    timestamp_width = 15;
268     }
269 
270     if (got_k5)
271     {
272 	krb5_error_code retval;
273 	retval = krb5_init_context(&kcontext);
274 	if (retval) {
275 	    com_err(progname, retval, gettext("while initializing krb5"));
276 	    exit(1);
277 	}
278 
279 	if (mode == DEFAULT || mode == CCACHE)
280 	    do_ccache(name);
281 	else
282 	    do_keytab(name);
283     } else {
284 #ifdef KRB5_KRB4_COMPAT
285 	if (mode == DEFAULT || mode == CCACHE)
286 	    do_v4_ccache(name);
287 	else {
288 	    /* We may want to add v4 srvtab support */
289 	    fprintf(stderr,
290 		    "%s: srvtab option not supported for Kerberos 4\n",
291 		    progname);
292 	    exit(1);
293 	}
294 #endif /* KRB4_KRB5_COMPAT */
295     }
296 
297     return 0;
298 }
299 
300 void do_keytab(name)
301    char *name;
302 {
303      krb5_keytab kt;
304      krb5_keytab_entry entry;
305      krb5_kt_cursor cursor;
306      char buf[BUFSIZ]; /* hopefully large enough for any type */
307      char *pname;
308      int code;
309 
310      if (name == NULL) {
311 	  if ((code = krb5_kt_default(kcontext, &kt))) {
312 			com_err(progname, code,
313 				gettext("while getting default keytab"));
314 	       exit(1);
315 	  }
316      } else {
317 	  if ((code = krb5_kt_resolve(kcontext, name, &kt))) {
318 			com_err(progname, code,
319 				gettext("while resolving keytab %s"),
320 		       name);
321 	       exit(1);
322 	  }
323      }
324 
325      if ((code = krb5_kt_get_name(kcontext, kt, buf, BUFSIZ))) {
326 	  com_err(progname, code,
327 			gettext("while getting keytab name"));
328 	  exit(1);
329      }
330 
331      printf(gettext("Keytab name: %s\n"), buf);
332 
333      if ((code = krb5_kt_start_seq_get(kcontext, kt, &cursor))) {
334 	  com_err(progname, code,
335 			gettext("while starting keytab scan"));
336 	  exit(1);
337      }
338 
339      if (show_time) {
340 	  printf(gettext("KVNO Timestamp"));
341 	  fillit(stdout, timestamp_width -
342 	    sizeof (gettext("Timestamp")) + 2, (int)' ');
343 	  printf(gettext("Principal\n"));
344 	  printf("---- ");
345 	  fillit(stdout, timestamp_width, (int) '-');
346 	  printf(" ");
347 	  fillit(stdout, 78 - timestamp_width -
348 		    sizeof (gettext("KVNO")), (int)'-');
349 	  printf("\n");
350      } else {
351 	  printf(gettext("KVNO Principal\n"));
352 	  printf("---- ------------------------------"
353 			    "--------------------------------------"
354 			    "------\n");
355      }
356 
357      while ((code = krb5_kt_next_entry(kcontext, kt, &entry, &cursor)) == 0) {
358 	  if ((code = krb5_unparse_name(kcontext, entry.principal, &pname))) {
359 	       com_err(progname, code,
360 				gettext("while unparsing principal name"));
361 	       exit(1);
362 	  }
363 	  printf("%4d ", entry.vno);
364 	  if (show_time) {
365 	       printtime(entry.timestamp);
366 	       printf(" ");
367 	  }
368 	  printf("%s", pname);
369 	  if (show_etype)
370 	      printf(" (%s) " , etype_string(entry.key.enctype));
371 	  if (show_keys) {
372 	       printf(" (0x");
373 	       {
374 		    int i;
375 		    for (i = 0; i < entry.key.length; i++)
376 			 printf("%02x", entry.key.contents[i]);
377 	       }
378 	       printf(")");
379 	  }
380 	  printf("\n");
381 	  krb5_free_unparsed_name(kcontext, pname);
382      }
383      if (code && code != KRB5_KT_END) {
384 		com_err(progname, code,
385 			gettext("while scanning keytab"));
386 	  exit(1);
387      }
388      if ((code = krb5_kt_end_seq_get(kcontext, kt, &cursor))) {
389 		com_err(progname, code,
390 			gettext("while ending keytab scan"));
391 	  exit(1);
392      }
393      exit(0);
394 }
395 void do_ccache(name)
396    char *name;
397 {
398     krb5_ccache cache = NULL;
399     krb5_cc_cursor cur;
400     krb5_creds creds;
401     krb5_principal princ;
402     krb5_flags flags;
403     krb5_error_code code;
404     int	exit_status = 0;
405 
406     if (status_only)
407 	/* exit_status is set back to 0 if a valid tgt is found */
408 	exit_status = 1;
409 
410     if (name == NULL) {
411 	if ((code = krb5_cc_default(kcontext, &cache))) {
412 	    if (!status_only)
413 				com_err(progname, code,
414 					gettext("while getting default "
415 						"ccache"));
416 	    exit(1);
417 	    }
418     } else {
419 	if ((code = krb5_cc_resolve(kcontext, name, &cache))) {
420 	    if (!status_only)
421 				com_err(progname, code,
422 					gettext("while resolving ccache %s"),
423 			name);
424 	    exit(1);
425 	}
426     }
427 
428     flags = 0;				/* turns off OPENCLOSE mode */
429     if ((code = krb5_cc_set_flags(kcontext, cache, flags))) {
430 	if (code == KRB5_FCC_NOFILE) {
431 	    if (!status_only) {
432 		com_err(progname, code, gettext("(ticket cache %s:%s)"),
433 			krb5_cc_get_type(kcontext, cache),
434 			krb5_cc_get_name(kcontext, cache));
435 #ifdef KRB5_KRB4_COMPAT
436 		if (name == NULL)
437 		    do_v4_ccache(0);
438 #endif /* KRB5_KRB4_COMPAT */
439 	    }
440 	} else {
441 	    if (!status_only)
442 		com_err(progname, code,
443 			gettext("while setting cache "
444 				"flags(ticket cache %s:%s)"),
445 			krb5_cc_get_type(kcontext, cache),
446 			krb5_cc_get_name(kcontext, cache));
447 	}
448 	exit(1);
449     }
450     if ((code = krb5_cc_get_principal(kcontext, cache, &princ))) {
451 	if (!status_only)
452 			com_err(progname, code,
453 				gettext("while retrieving principal name"));
454 	exit(1);
455     }
456     if ((code = krb5_unparse_name(kcontext, princ, &defname))) {
457 	if (!status_only)
458 			com_err(progname, code,
459 				gettext("while unparsing principal name"));
460 	exit(1);
461     }
462     if (!status_only) {
463 		printf(gettext("Ticket cache: %s:%s\nDefault principal: "
464 			    "%s\n\n"),
465 	       krb5_cc_get_type(kcontext, cache),
466 	       krb5_cc_get_name(kcontext, cache), defname);
467 		fputs(gettext("Valid starting"), stdout);
468 		fillit(stdout, timestamp_width -
469 		    sizeof (gettext("Valid starting")) + 3, (int)' ');
470 		fputs(gettext("Expires"), stdout);
471 		fillit(stdout, timestamp_width -
472 		    sizeof (gettext("Expires")) + 3, (int)' ');
473 		fputs(gettext("Service principal\n"), stdout);
474     }
475     if ((code = krb5_cc_start_seq_get(kcontext, cache, &cur))) {
476 	if (!status_only)
477 			com_err(progname, code,
478 				gettext("while starting to retrieve tickets"));
479 	exit(1);
480     }
481     while (!(code = krb5_cc_next_cred(kcontext, cache, &cur, &creds))) {
482 	if (status_only) {
483 	    if (exit_status && creds.server->length == 2 &&
484 			    strcmp(creds.server->realm.data,
485 				princ->realm.data) == 0 &&
486 			    strcmp((char *)creds.server->data[0].data,
487 				"krbtgt") == 0 &&
488 		strcmp((char *)creds.server->data[1].data,
489 		       princ->realm.data) == 0 &&
490 		creds.times.endtime > now)
491 		exit_status = 0;
492 	} else {
493 	    show_credential(&creds);
494 	}
495 	krb5_free_cred_contents(kcontext, &creds);
496     }
497     if (code == KRB5_CC_END) {
498 	if ((code = krb5_cc_end_seq_get(kcontext, cache, &cur))) {
499 	    if (!status_only)
500 				com_err(progname, code,
501 					gettext("while finishing ticket "
502 						"retrieval"));
503 	    exit(1);
504 	}
505 	flags = KRB5_TC_OPENCLOSE;	/* turns on OPENCLOSE mode */
506 	if ((code = krb5_cc_set_flags(kcontext, cache, flags))) {
507 	    if (!status_only)
508 				com_err(progname, code,
509 					gettext("while closing ccache"));
510 	    exit(1);
511 	}
512 #ifdef KRB5_KRB4_COMPAT
513 	if (name == NULL && !status_only)
514 	    do_v4_ccache(0);
515 #endif /* KRB5_KRB4_COMPAT */
516 	exit(exit_status);
517     } else {
518 	if (!status_only)
519 			com_err(progname, code,
520 				gettext("while retrieving a ticket"));
521 	exit(1);
522     }
523 }
524 
525 char *
526 etype_string(enctype)
527     krb5_enctype enctype;
528 {
529     static char buf[100];
530     krb5_error_code retval;
531 
532     if ((retval = krb5_enctype_to_string(enctype, buf, sizeof(buf)))) {
533 	/* XXX if there's an error != EINVAL, I should probably report it */
534 	sprintf(buf, gettext("etype %d"), enctype);
535     }
536 
537     return buf;
538 }
539 
540 static char *
541 flags_string(cred)
542     register krb5_creds *cred;
543 {
544     static char buf[32];
545     int i = 0;
546 
547     if (cred->ticket_flags & TKT_FLG_FORWARDABLE)
548 	buf[i++] = 'F';
549     if (cred->ticket_flags & TKT_FLG_FORWARDED)
550 	buf[i++] = 'f';
551     if (cred->ticket_flags & TKT_FLG_PROXIABLE)
552 	buf[i++] = 'P';
553     if (cred->ticket_flags & TKT_FLG_PROXY)
554 	buf[i++] = 'p';
555     if (cred->ticket_flags & TKT_FLG_MAY_POSTDATE)
556 	buf[i++] = 'D';
557     if (cred->ticket_flags & TKT_FLG_POSTDATED)
558 	buf[i++] = 'd';
559     if (cred->ticket_flags & TKT_FLG_INVALID)
560 	buf[i++] = 'i';
561     if (cred->ticket_flags & TKT_FLG_RENEWABLE)
562 	buf[i++] = 'R';
563     if (cred->ticket_flags & TKT_FLG_INITIAL)
564 	buf[i++] = 'I';
565     if (cred->ticket_flags & TKT_FLG_HW_AUTH)
566 	buf[i++] = 'H';
567     if (cred->ticket_flags & TKT_FLG_PRE_AUTH)
568 	buf[i++] = 'A';
569     if (cred->ticket_flags & TKT_FLG_TRANSIT_POLICY_CHECKED)
570 	buf[i++] = 'T';
571     if (cred->ticket_flags & TKT_FLG_OK_AS_DELEGATE)
572 	buf[i++] = 'O';		/* D/d are taken.  Use short strings?  */
573     if (cred->ticket_flags & TKT_FLG_ANONYMOUS)
574 	buf[i++] = 'a';
575     buf[i] = '\0';
576     return(buf);
577 }
578 
579 void
580 printtime(tv)
581     time_t tv;
582 {
583     char timestring[BUFSIZ];
584     char fill;
585 
586     fill = ' ';
587 	if (!krb5_timestamp_to_sfstring((krb5_timestamp) tv, timestring,
588 					timestamp_width+1, &fill)) {
589 	printf(timestring);
590     }
591 }
592 
593 void
594 show_credential(cred)
595     register krb5_creds * cred;
596 {
597     krb5_error_code retval;
598     krb5_ticket *tkt;
599     char *name, *sname, *flags;
600     int	extra_field = 0;
601 
602     retval = krb5_unparse_name(kcontext, cred->client, &name);
603     if (retval) {
604 		com_err(progname, retval,
605 			gettext("while unparsing client name"));
606 	return;
607     }
608     retval = krb5_unparse_name(kcontext, cred->server, &sname);
609     if (retval) {
610 		com_err(progname, retval,
611 			gettext("while unparsing server name"));
612 		krb5_free_unparsed_name(kcontext, name);
613 	return;
614     }
615     if (!cred->times.starttime)
616 	cred->times.starttime = cred->times.authtime;
617 
618     printtime(cred->times.starttime);
619     putchar(' '); putchar(' ');
620     printtime(cred->times.endtime);
621     putchar(' '); putchar(' ');
622 
623     printf("%s\n", sname);
624 
625     if (strcmp(name, defname)) {
626 		printf(gettext("\tfor client %s"), name);
627 	    extra_field++;
628     }
629 
630     if (cred->times.renew_till) {
631 	if (!extra_field)
632 		fputs("\t",stdout);
633 	else
634 		fputs(", ",stdout);
635 		fputs(gettext("renew until "), stdout);
636 	printtime(cred->times.renew_till);
637 	extra_field += 2;
638     }
639 
640     if (extra_field > 3) {
641 	fputs("\n", stdout);
642 	extra_field = 0;
643     }
644 
645     if (show_flags) {
646 	flags = flags_string(cred);
647 	if (flags && *flags) {
648 	    if (!extra_field)
649 		fputs("\t",stdout);
650 	    else
651 		fputs(", ",stdout);
652 			printf(gettext("Flags: %s"), flags);
653 	    extra_field++;
654 	}
655     }
656 
657     if (extra_field > 2) {
658 	fputs("\n", stdout);
659 	extra_field = 0;
660     }
661 
662     if (show_etype) {
663 	retval = decode_krb5_ticket(&cred->ticket, &tkt);
664 	if (retval)
665 	    goto err_tkt;
666 
667 	if (!extra_field)
668 	    fputs("\t",stdout);
669 	else
670 	    fputs(", ",stdout);
671 	printf(gettext("Etype(skey, tkt): %s, "),
672 	       etype_string(cred->keyblock.enctype));
673 	printf("%s ",
674 	       etype_string(tkt->enc_part.enctype));
675 	extra_field++;
676 
677     err_tkt:
678 	if (tkt != NULL)
679 	    krb5_free_ticket(kcontext, tkt);
680     }
681 
682     /* if any additional info was printed, extra_field is non-zero */
683     if (extra_field)
684 	putchar('\n');
685 
686 
687     if (show_addresses) {
688 	if (!cred->addresses || !cred->addresses[0]) {
689 	    printf(gettext("\tAddresses: (none)\n"));
690 	} else {
691 	    int i;
692 
693 	    printf(gettext("\tAddresses: "));
694 	    one_addr(cred->addresses[0]);
695 
696 	    for (i=1; cred->addresses[i]; i++) {
697 		printf(", ");
698 		one_addr(cred->addresses[i]);
699 	    }
700 
701 	    printf("\n");
702 	}
703     }
704 
705     krb5_free_unparsed_name(kcontext, name);
706     krb5_free_unparsed_name(kcontext, sname);
707 }
708 
709 #include "port-sockets.h"
710 #include "socket-utils.h" /* for ss2sin etc */
711 #include <fake-addrinfo.h>
712 
713 void one_addr(a)
714     krb5_address *a;
715 {
716     struct sockaddr_storage ss;
717     int err;
718     char namebuf[NI_MAXHOST];
719 
720     memset (&ss, 0, sizeof (ss));
721 
722     switch (a->addrtype) {
723     case ADDRTYPE_INET:
724 	if (a->length != IPV4_ADDR_LEN) {
725 	broken:
726 	    printf ("broken address (type %d length %d)",
727 		    a->addrtype, a->length);
728 	    return;
729 	}
730 	{
731 	    struct sockaddr_in *sinp = ss2sin (&ss);
732 	    sinp->sin_family = AF_INET;
733 #ifdef HAVE_SA_LEN
734 	    sinp->sin_len = sizeof (struct sockaddr_in);
735 #endif
736 	    memcpy (&sinp->sin_addr, a->contents, IPV4_ADDR_LEN);
737 	}
738 	break;
739 #ifdef KRB5_USE_INET6
740     case ADDRTYPE_INET6:
741 	if (a->length != IPV6_ADDR_LEN)
742 	    goto broken;
743 	{
744 	    struct sockaddr_in6 *sin6p = ss2sin6 (&ss);
745 	    sin6p->sin6_family = AF_INET6;
746 #ifdef HAVE_SA_LEN
747 	    sin6p->sin6_len = sizeof (struct sockaddr_in6);
748 #endif
749 	    memcpy (&sin6p->sin6_addr, a->contents, IPV6_ADDR_LEN);
750 	}
751 	break;
752 #endif
753     default:
754 	printf(gettext("unknown addr type %d"), a->addrtype);
755 	return;
756     }
757 
758     namebuf[0] = 0;
759     err = getnameinfo (ss2sa (&ss), socklen (ss2sa (&ss)),
760 		       namebuf, sizeof (namebuf), 0, 0,
761 		       no_resolve ? NI_NUMERICHOST : 0U);
762     if (err) {
763 	printf (gettext("unprintable address (type %d, error %d %s)"), a->addrtype, err,
764 		gai_strerror (err));
765 	return;
766     }
767     printf ("%s", namebuf);
768 }
769 
770 void
771 fillit(f, num, c)
772     FILE		*f;
773     unsigned int	num;
774     int			c;
775 {
776     int i;
777 
778     for (i=0; i<num; i++)
779 	fputc(c, f);
780 }
781 
782 #ifdef KRB5_KRB4_COMPAT
783 void
784 do_v4_ccache(name)
785     char * name;
786 {
787     char    pname[ANAME_SZ];
788     char    pinst[INST_SZ];
789     char    prealm[REALM_SZ];
790     char    *file;
791     int     k_errno;
792     CREDENTIALS c;
793     int     header = 1;
794 
795     if (!got_k4)
796 	return;
797 
798     file = name?name:tkt_string();
799 
800     if (status_only) {
801 	fprintf(stderr,
802 		"%s: exit status option not supported for Kerberos 4\n",
803 		progname);
804 	exit(1);
805     }
806 
807     if (got_k5)
808 	printf("\n\n");
809 
810     printf("Kerberos 4 ticket cache: %s\n", file);
811 
812     /*
813      * Since krb_get_tf_realm will return a ticket_file error,
814      * we will call tf_init and tf_close first to filter out
815      * things like no ticket file.  Otherwise, the error that
816      * the user would see would be
817      * klist: can't find realm of ticket file: No ticket file (tf_util)
818      * instead of
819      * klist: No ticket file (tf_util)
820      */
821 
822     /* Open ticket file */
823     k_errno = tf_init(file, R_TKT_FIL);
824     if (k_errno) {
825 	fprintf(stderr, "%s: %s\n", progname, krb_get_err_text (k_errno));
826 	exit(1);
827     }
828     /* Close ticket file */
829     (void) tf_close();
830 
831     /*
832      * We must find the realm of the ticket file here before calling
833      * tf_init because since the realm of the ticket file is not
834      * really stored in the principal section of the file, the
835      * routine we use must itself call tf_init and tf_close.
836      */
837     if ((k_errno = krb_get_tf_realm(file, prealm)) != KSUCCESS) {
838 	fprintf(stderr, "%s: can't find realm of ticket file: %s\n",
839 		progname, krb_get_err_text (k_errno));
840 	exit(1);
841     }
842 
843     /* Open ticket file */
844     if ((k_errno = tf_init(file, R_TKT_FIL))) {
845 	fprintf(stderr, "%s: %s\n", progname, krb_get_err_text (k_errno));
846 	exit(1);
847     }
848     /* Get principal name and instance */
849     if ((k_errno = tf_get_pname(pname)) ||
850 	(k_errno = tf_get_pinst(pinst))) {
851 	fprintf(stderr, "%s: %s\n", progname, krb_get_err_text (k_errno));
852 	exit(1);
853     }
854 
855     /*
856      * You may think that this is the obvious place to get the
857      * realm of the ticket file, but it can't be done here as the
858      * routine to do this must open the ticket file.  This is why
859      * it was done before tf_init.
860      */
861 
862     printf("Principal: %s%s%s%s%s\n\n", pname,
863 	   (pinst[0] ? "." : ""), pinst,
864 	   (prealm[0] ? "@" : ""), prealm);
865     while ((k_errno = tf_get_cred(&c)) == KSUCCESS) {
866 	if (header) {
867 	    printf("%-18s  %-18s  %s\n",
868 		   "  Issued", "  Expires", "  Principal");
869 	    header = 0;
870 	}
871 	printtime(c.issue_date);
872 	fputs("  ", stdout);
873 	printtime(krb_life_to_time(c.issue_date, c.lifetime));
874 	printf("  %s%s%s%s%s\n",
875 	       c.service, (c.instance[0] ? "." : ""), c.instance,
876 	       (c.realm[0] ? "@" : ""), c.realm);
877     }
878     if (header && k_errno == EOF) {
879 	printf("No tickets in file.\n");
880     }
881 }
882 #endif /* KRB4_KRB5_COMPAT */
883