2 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
7 * clients/klist/klist.c
9 * Copyright 1990 by the Massachusetts Institute of Technology.
10 * All Rights Reserved.
12 * Export of this software from the United States of America may
13 * require a specific license from the United States Government.
14 * It is the responsibility of any person or organization contemplating
15 * export to obtain such a license before exporting.
17 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
18 * distribute this software and its documentation for any purpose and
19 * without fee is hereby granted, provided that the above copyright
20 * notice appear in all copies and that both that copyright notice and
21 * this permission notice appear in supporting documentation, and that
22 * the name of M.I.T. not be used in advertising or publicity pertaining
23 * to distribution of the software without specific, written prior
24 * permission. Furthermore if you modify this software you must label
25 * your software as modified software and not distribute it in such a
26 * fashion that it might be confused with the original M.I.T. software.
27 * M.I.T. makes no representations about the suitability of
28 * this software for any purpose. It is provided "as is" without express
29 * or implied warranty.
32 * List out the contents of your credential cache or keytab.
38 #ifdef KRB5_KRB4_COMPAT
39 #include <kerberosIV/krb.h>
40 #endif /* KRB5_KRB4_COMPAT */
48 #include <netinet/in.h>
49 #if defined(HAVE_ARPA_INET_H)
50 #include <arpa/inet.h>
56 #define GET_PROGNAME(x) (strrchr((x), '/') ? strrchr((x), '/')+1 : (x))
58 #define GET_PROGNAME(x) max(max(strrchr((x), '/'), strrchr((x), '\\')) + 1,(x))
62 #include <sys/socket.h>
68 int show_flags
= 0, show_time
= 0, status_only
= 0, show_keys
= 0;
69 int show_etype
= 0, show_addresses
= 0, no_resolve
= 0;
73 size_t timestamp_width
;
75 krb5_context kcontext
;
77 char * etype_string (krb5_enctype
);
78 void show_credential (krb5_creds
*);
80 void do_ccache (char *);
81 void do_keytab (char *);
82 void printtime (time_t);
83 void one_addr (krb5_address
*);
84 void fillit (FILE *, unsigned int, int);
85 void show_addr(krb5_address
*a
);
87 #ifdef KRB5_KRB4_COMPAT
88 void do_v4_ccache (char *);
89 #endif /* KRB5_KRB4_COMPAT */
96 * The reason we start out with got_k4 and got_k5 as zero (false) is
97 * so that we can easily add dynamic loading support for determining
98 * whether Kerberos 4 and Keberos 5 libraries are available
101 static int got_k5
= 0;
102 static int got_k4
= 0;
104 static int default_k5
= 1;
105 #ifdef KRB5_KRB4_COMPAT
106 static int default_k4
= 1;
107 #else /* KRB5_KRB4_COMPAT */
108 static int default_k4
= 0;
109 #endif /* KRB5_KRB4_COMPAT */
113 #define KRB_AVAIL_STRING(x) ((x)?gettext("available"):gettext("not available"))
115 fprintf(stderr
, gettext("Usage: %s [-5] [-4] [-e]"
116 " [[-c] [-f] [-s] [-a [-n]]] "
117 "[-k [-t] [-K]] [name]\n"), progname
);
118 fprintf(stderr
, "\t-5 Kerberos 5 (%s)\n", KRB_AVAIL_STRING(got_k5
));
119 fprintf(stderr
, "\t-4 Kerberos 4 (%s)\n", KRB_AVAIL_STRING(got_k4
));
120 fprintf(stderr
, gettext("\t (Default is %s%s%s%s)\n"),
121 default_k5
?"Kerberos 5":"",
122 (default_k5
&& default_k4
)?gettext(" and "):"",
123 default_k4
?"Kerberos 4":"",
124 (!default_k5
&& !default_k4
)?gettext("neither"):"");
125 fprintf(stderr
, gettext("\t-c specifies credentials cache\n"));
126 fprintf(stderr
, gettext("\t-k specifies keytab\n"));
127 fprintf(stderr
, gettext("\t (Default is credentials cache)\n"));
128 fprintf(stderr
, gettext("\t-e shows the encryption type\n"));
129 fprintf(stderr
, gettext("\toptions for credential caches:\n"));
130 fprintf(stderr
, gettext("\t\t-f shows credentials flags\n"));
131 fprintf(stderr
, gettext("\t\t-s sets exit status based on valid tgt existence\n"));
132 fprintf(stderr
, gettext("\t\t-a displays the address list\n"));
133 fprintf(stderr
, gettext("\t\t-n do not reverse-resolve\n"));
134 fprintf(stderr
, gettext("\toptions for keytabs:\n"));
135 fprintf(stderr
, gettext("\t\t-t shows keytab entry timestamps\n"));
136 fprintf(stderr
, gettext("\t\t-K shows keytab entry DES keys\n"));
149 int use_k5
= 0, use_k4
= 0;
152 #ifdef KRB5_KRB4_COMPAT
154 #endif /* KRB5_KRB4_COMPAT */
156 (void) setlocale(LC_ALL
, "");
158 #if !defined(TEXT_DOMAIN)
159 #define TEXT_DOMAIN "SYS_TEST"
160 #endif /* !TEXT_DOMAIN */
162 (void) textdomain(TEXT_DOMAIN
);
164 progname
= GET_PROGNAME(argv
[0]);
168 while ((c
= getopt(argc
, argv
, "fetKsnack45")) != -1) {
192 if (mode
!= DEFAULT
) usage();
196 if (mode
!= DEFAULT
) usage();
202 #ifdef KRB5_KRB4_COMPAT
203 fprintf(stderr
, "Kerberos 4 support could not be loaded\n");
204 #else /* KRB5_KRB4_COMPAT */
205 fprintf(stderr
, gettext("This was not built with Kerberos 4 support\n"));
206 #endif /* KRB5_KRB4_COMPAT */
214 fprintf(stderr
, gettext("Kerberos 5 support could not be loaded\n"));
225 if (no_resolve
&& !show_addresses
) {
229 if (mode
== DEFAULT
|| mode
== CCACHE
) {
230 if (show_time
|| show_keys
)
233 if (show_flags
|| status_only
|| show_addresses
)
237 if (argc
- optind
> 1) {
239 gettext("Extra arguments (starting with \"%s\").\n"),
244 name
= (optind
== argc
-1) ? argv
[optind
] : 0;
246 if (!use_k5
&& !use_k4
)
261 if (!krb5_timestamp_to_sfstring(now
, tmp
, 20, (char *) NULL
) ||
262 !krb5_timestamp_to_sfstring(now
, tmp
, sizeof(tmp
),
264 timestamp_width
= (int) strlen(tmp
);
266 timestamp_width
= 15;
271 krb5_error_code retval
;
272 retval
= krb5_init_context(&kcontext
);
274 com_err(progname
, retval
, gettext("while initializing krb5"));
278 if (mode
== DEFAULT
|| mode
== CCACHE
)
283 #ifdef KRB5_KRB4_COMPAT
284 if (mode
== DEFAULT
|| mode
== CCACHE
)
287 /* We may want to add v4 srvtab support */
289 "%s: srvtab option not supported for Kerberos 4\n",
293 #endif /* KRB4_KRB5_COMPAT */
303 krb5_keytab_entry entry
;
304 krb5_kt_cursor cursor
;
305 char buf
[BUFSIZ
]; /* hopefully large enough for any type */
310 if ((code
= krb5_kt_default(kcontext
, &kt
))) {
311 com_err(progname
, code
,
312 gettext("while getting default keytab"));
316 if ((code
= krb5_kt_resolve(kcontext
, name
, &kt
))) {
317 com_err(progname
, code
,
318 gettext("while resolving keytab %s"),
324 if ((code
= krb5_kt_get_name(kcontext
, kt
, buf
, BUFSIZ
))) {
325 com_err(progname
, code
,
326 gettext("while getting keytab name"));
330 printf(gettext("Keytab name: %s\n"), buf
);
332 if ((code
= krb5_kt_start_seq_get(kcontext
, kt
, &cursor
))) {
333 com_err(progname
, code
,
334 gettext("while starting keytab scan"));
339 printf(gettext("KVNO Timestamp"));
340 fillit(stdout
, timestamp_width
-
341 sizeof (gettext("Timestamp")) + 2, (int)' ');
342 printf(gettext("Principal\n"));
344 fillit(stdout
, timestamp_width
, (int) '-');
346 fillit(stdout
, 78 - timestamp_width
-
347 sizeof (gettext("KVNO")), (int)'-');
350 printf(gettext("KVNO Principal\n"));
351 printf("---- ------------------------------"
352 "--------------------------------------"
356 while ((code
= krb5_kt_next_entry(kcontext
, kt
, &entry
, &cursor
)) == 0) {
357 if ((code
= krb5_unparse_name(kcontext
, entry
.principal
, &pname
))) {
358 com_err(progname
, code
,
359 gettext("while unparsing principal name"));
362 printf("%4d ", entry
.vno
);
364 printtime(entry
.timestamp
);
369 printf(" (%s) " , etype_string(entry
.key
.enctype
));
374 for (i
= 0; i
< entry
.key
.length
; i
++)
375 printf("%02x", entry
.key
.contents
[i
]);
380 krb5_free_unparsed_name(kcontext
, pname
);
382 if (code
&& code
!= KRB5_KT_END
) {
383 com_err(progname
, code
,
384 gettext("while scanning keytab"));
387 if ((code
= krb5_kt_end_seq_get(kcontext
, kt
, &cursor
))) {
388 com_err(progname
, code
,
389 gettext("while ending keytab scan"));
397 krb5_ccache cache
= NULL
;
400 krb5_principal princ
;
402 krb5_error_code code
;
406 /* exit_status is set back to 0 if a valid tgt is found */
410 if ((code
= krb5_cc_default(kcontext
, &cache
))) {
412 com_err(progname
, code
,
413 gettext("while getting default "
418 if ((code
= krb5_cc_resolve(kcontext
, name
, &cache
))) {
420 com_err(progname
, code
,
421 gettext("while resolving ccache %s"),
427 flags
= 0; /* turns off OPENCLOSE mode */
428 if ((code
= krb5_cc_set_flags(kcontext
, cache
, flags
))) {
429 if (code
== KRB5_FCC_NOFILE
) {
431 com_err(progname
, code
, gettext("(ticket cache %s:%s)"),
432 krb5_cc_get_type(kcontext
, cache
),
433 krb5_cc_get_name(kcontext
, cache
));
434 #ifdef KRB5_KRB4_COMPAT
437 #endif /* KRB5_KRB4_COMPAT */
441 com_err(progname
, code
,
442 gettext("while setting cache "
443 "flags(ticket cache %s:%s)"),
444 krb5_cc_get_type(kcontext
, cache
),
445 krb5_cc_get_name(kcontext
, cache
));
449 if ((code
= krb5_cc_get_principal(kcontext
, cache
, &princ
))) {
451 com_err(progname
, code
,
452 gettext("while retrieving principal name"));
455 if ((code
= krb5_unparse_name(kcontext
, princ
, &defname
))) {
457 com_err(progname
, code
,
458 gettext("while unparsing principal name"));
462 printf(gettext("Ticket cache: %s:%s\nDefault principal: "
464 krb5_cc_get_type(kcontext
, cache
),
465 krb5_cc_get_name(kcontext
, cache
), defname
);
466 fputs(gettext("Valid starting"), stdout
);
467 fillit(stdout
, timestamp_width
-
468 sizeof (gettext("Valid starting")) + 3, (int)' ');
469 fputs(gettext("Expires"), stdout
);
470 fillit(stdout
, timestamp_width
-
471 sizeof (gettext("Expires")) + 3, (int)' ');
472 fputs(gettext("Service principal\n"), stdout
);
474 if ((code
= krb5_cc_start_seq_get(kcontext
, cache
, &cur
))) {
476 com_err(progname
, code
,
477 gettext("while starting to retrieve tickets"));
480 while (!(code
= krb5_cc_next_cred(kcontext
, cache
, &cur
, &creds
))) {
482 if (exit_status
&& creds
.server
->length
== 2 &&
483 strcmp(creds
.server
->realm
.data
,
484 princ
->realm
.data
) == 0 &&
485 strcmp((char *)creds
.server
->data
[0].data
,
487 strcmp((char *)creds
.server
->data
[1].data
,
488 princ
->realm
.data
) == 0 &&
489 creds
.times
.endtime
> now
)
492 show_credential(&creds
);
494 krb5_free_cred_contents(kcontext
, &creds
);
496 if (code
== KRB5_CC_END
) {
497 if ((code
= krb5_cc_end_seq_get(kcontext
, cache
, &cur
))) {
499 com_err(progname
, code
,
500 gettext("while finishing ticket "
504 flags
= KRB5_TC_OPENCLOSE
; /* turns on OPENCLOSE mode */
505 if ((code
= krb5_cc_set_flags(kcontext
, cache
, flags
))) {
507 com_err(progname
, code
,
508 gettext("while closing ccache"));
511 #ifdef KRB5_KRB4_COMPAT
512 if (name
== NULL
&& !status_only
)
514 #endif /* KRB5_KRB4_COMPAT */
518 com_err(progname
, code
,
519 gettext("while retrieving a ticket"));
525 etype_string(enctype
)
526 krb5_enctype enctype
;
528 static char buf
[256];
529 krb5_error_code retval
;
531 if ((retval
= krb5_enctype_to_string(enctype
, buf
, sizeof(buf
)))) {
532 /* XXX if there's an error != EINVAL, I should probably report it */
533 snprintf(buf
, sizeof(buf
), gettext("unsupported encryption type %d"), enctype
);
541 register krb5_creds
*cred
;
546 if (cred
->ticket_flags
& TKT_FLG_FORWARDABLE
)
548 if (cred
->ticket_flags
& TKT_FLG_FORWARDED
)
550 if (cred
->ticket_flags
& TKT_FLG_PROXIABLE
)
552 if (cred
->ticket_flags
& TKT_FLG_PROXY
)
554 if (cred
->ticket_flags
& TKT_FLG_MAY_POSTDATE
)
556 if (cred
->ticket_flags
& TKT_FLG_POSTDATED
)
558 if (cred
->ticket_flags
& TKT_FLG_INVALID
)
560 if (cred
->ticket_flags
& TKT_FLG_RENEWABLE
)
562 if (cred
->ticket_flags
& TKT_FLG_INITIAL
)
564 if (cred
->ticket_flags
& TKT_FLG_HW_AUTH
)
566 if (cred
->ticket_flags
& TKT_FLG_PRE_AUTH
)
568 if (cred
->ticket_flags
& TKT_FLG_TRANSIT_POLICY_CHECKED
)
570 if (cred
->ticket_flags
& TKT_FLG_OK_AS_DELEGATE
)
571 buf
[i
++] = 'O'; /* D/d are taken. Use short strings? */
572 if (cred
->ticket_flags
& TKT_FLG_ANONYMOUS
)
582 char timestring
[BUFSIZ
];
586 if (!krb5_timestamp_to_sfstring((krb5_timestamp
) tv
, timestring
,
587 timestamp_width
+1, &fill
)) {
593 show_credential(cred
)
594 register krb5_creds
* cred
;
596 krb5_error_code retval
;
598 char *name
, *sname
, *flags
;
601 retval
= krb5_unparse_name(kcontext
, cred
->client
, &name
);
603 com_err(progname
, retval
,
604 gettext("while unparsing client name"));
607 retval
= krb5_unparse_name(kcontext
, cred
->server
, &sname
);
609 com_err(progname
, retval
,
610 gettext("while unparsing server name"));
611 krb5_free_unparsed_name(kcontext
, name
);
614 if (!cred
->times
.starttime
)
615 cred
->times
.starttime
= cred
->times
.authtime
;
617 printtime(cred
->times
.starttime
);
618 putchar(' '); putchar(' ');
619 printtime(cred
->times
.endtime
);
620 putchar(' '); putchar(' ');
622 printf("%s\n", sname
);
624 if (strcmp(name
, defname
)) {
625 printf(gettext("\tfor client %s"), name
);
629 if (cred
->times
.renew_till
) {
634 fputs(gettext("renew until "), stdout
);
635 printtime(cred
->times
.renew_till
);
639 if (extra_field
> 3) {
645 flags
= flags_string(cred
);
646 if (flags
&& *flags
) {
651 printf(gettext("Flags: %s"), flags
);
656 if (extra_field
> 2) {
662 retval
= decode_krb5_ticket(&cred
->ticket
, &tkt
);
670 printf(gettext("Etype(skey, tkt): %s, "),
671 etype_string(cred
->keyblock
.enctype
));
673 etype_string(tkt
->enc_part
.enctype
));
678 krb5_free_ticket(kcontext
, tkt
);
681 /* if any additional info was printed, extra_field is non-zero */
686 if (show_addresses
) {
687 if (!cred
->addresses
|| !cred
->addresses
[0]) {
688 printf(gettext("\tAddresses: (none)\n"));
692 printf(gettext("\tAddresses: "));
693 one_addr(cred
->addresses
[0]);
695 for (i
=1; cred
->addresses
[i
]; i
++) {
697 one_addr(cred
->addresses
[i
]);
704 krb5_free_unparsed_name(kcontext
, name
);
705 krb5_free_unparsed_name(kcontext
, sname
);
708 #include "port-sockets.h"
709 #include "socket-utils.h" /* for ss2sin etc */
710 #include <fake-addrinfo.h>
715 struct sockaddr_storage ss
;
717 char namebuf
[NI_MAXHOST
];
719 memset (&ss
, 0, sizeof (ss
));
721 switch (a
->addrtype
) {
723 if (a
->length
!= IPV4_ADDR_LEN
) {
725 printf ("broken address (type %d length %d)",
726 a
->addrtype
, a
->length
);
730 struct sockaddr_in
*sinp
= ss2sin (&ss
);
731 sinp
->sin_family
= AF_INET
;
733 sinp
->sin_len
= sizeof (struct sockaddr_in
);
735 memcpy (&sinp
->sin_addr
, a
->contents
, IPV4_ADDR_LEN
);
738 #ifdef KRB5_USE_INET6
740 if (a
->length
!= IPV6_ADDR_LEN
)
743 struct sockaddr_in6
*sin6p
= ss2sin6 (&ss
);
744 sin6p
->sin6_family
= AF_INET6
;
746 sin6p
->sin6_len
= sizeof (struct sockaddr_in6
);
748 memcpy (&sin6p
->sin6_addr
, a
->contents
, IPV6_ADDR_LEN
);
753 printf(gettext("unknown addr type %d"), a
->addrtype
);
758 err
= getnameinfo (ss2sa (&ss
), socklen (ss2sa (&ss
)),
759 namebuf
, sizeof (namebuf
), 0, 0,
760 no_resolve
? NI_NUMERICHOST
: 0U);
762 printf (gettext("unprintable address (type %d, error %d %s)"), a
->addrtype
, err
,
766 printf ("%s", namebuf
);
777 for (i
=0; i
<num
; i
++)
781 #ifdef KRB5_KRB4_COMPAT
786 char pname
[ANAME_SZ
];
788 char prealm
[REALM_SZ
];
797 file
= name
?name
:tkt_string();
801 "%s: exit status option not supported for Kerberos 4\n",
809 printf("Kerberos 4 ticket cache: %s\n", file
);
812 * Since krb_get_tf_realm will return a ticket_file error,
813 * we will call tf_init and tf_close first to filter out
814 * things like no ticket file. Otherwise, the error that
815 * the user would see would be
816 * klist: can't find realm of ticket file: No ticket file (tf_util)
818 * klist: No ticket file (tf_util)
821 /* Open ticket file */
822 k_errno
= tf_init(file
, R_TKT_FIL
);
824 fprintf(stderr
, "%s: %s\n", progname
, krb_get_err_text (k_errno
));
827 /* Close ticket file */
831 * We must find the realm of the ticket file here before calling
832 * tf_init because since the realm of the ticket file is not
833 * really stored in the principal section of the file, the
834 * routine we use must itself call tf_init and tf_close.
836 if ((k_errno
= krb_get_tf_realm(file
, prealm
)) != KSUCCESS
) {
837 fprintf(stderr
, "%s: can't find realm of ticket file: %s\n",
838 progname
, krb_get_err_text (k_errno
));
842 /* Open ticket file */
843 if ((k_errno
= tf_init(file
, R_TKT_FIL
))) {
844 fprintf(stderr
, "%s: %s\n", progname
, krb_get_err_text (k_errno
));
847 /* Get principal name and instance */
848 if ((k_errno
= tf_get_pname(pname
)) ||
849 (k_errno
= tf_get_pinst(pinst
))) {
850 fprintf(stderr
, "%s: %s\n", progname
, krb_get_err_text (k_errno
));
855 * You may think that this is the obvious place to get the
856 * realm of the ticket file, but it can't be done here as the
857 * routine to do this must open the ticket file. This is why
858 * it was done before tf_init.
861 printf("Principal: %s%s%s%s%s\n\n", pname
,
862 (pinst
[0] ? "." : ""), pinst
,
863 (prealm
[0] ? "@" : ""), prealm
);
864 while ((k_errno
= tf_get_cred(&c
)) == KSUCCESS
) {
866 printf("%-18s %-18s %s\n",
867 " Issued", " Expires", " Principal");
870 printtime(c
.issue_date
);
872 printtime(krb_life_to_time(c
.issue_date
, c
.lifetime
));
873 printf(" %s%s%s%s%s\n",
874 c
.service
, (c
.instance
[0] ? "." : ""), c
.instance
,
875 (c
.realm
[0] ? "@" : ""), c
.realm
);
877 if (header
&& k_errno
== EOF
) {
878 printf("No tickets in file.\n");
881 #endif /* KRB4_KRB5_COMPAT */