Home | History | Annotate | Download | only in klist
      1 /*
      2  * Copyright 2007 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[256];
    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 	snprintf(buf, sizeof(buf), gettext("unsupported encryption type %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