2 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
5 #pragma ident "%Z%%M% %I% %E% SMI"
8 * clients/klist/klist.c
10 * Copyright 1990 by the Massachusetts Institute of Technology.
11 * All Rights Reserved.
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.
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.
33 * List out the contents of your credential cache or keytab.
39 #ifdef KRB5_KRB4_COMPAT
40 #include <kerberosIV/krb.h>
41 #endif /* KRB5_KRB4_COMPAT */
49 #include <netinet/in.h>
50 #if defined(HAVE_ARPA_INET_H)
51 #include <arpa/inet.h>
57 #define GET_PROGNAME(x) (strrchr((x), '/') ? strrchr((x), '/')+1 : (x))
59 #define GET_PROGNAME(x) max(max(strrchr((x), '/'), strrchr((x), '\\')) + 1,(x))
63 #include <sys/socket.h>
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;
74 size_t timestamp_width
;
76 krb5_context kcontext
;
78 char * etype_string (krb5_enctype
);
79 void show_credential (krb5_creds
*);
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
);
88 #ifdef KRB5_KRB4_COMPAT
89 void do_v4_ccache (char *);
90 #endif /* KRB5_KRB4_COMPAT */
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
102 static int got_k5
= 0;
103 static int got_k4
= 0;
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 */
114 #define KRB_AVAIL_STRING(x) ((x)?gettext("available"):gettext("not available"))
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"));
150 int use_k5
= 0, use_k4
= 0;
153 #ifdef KRB5_KRB4_COMPAT
155 #endif /* KRB5_KRB4_COMPAT */
157 (void) setlocale(LC_ALL
, "");
159 #if !defined(TEXT_DOMAIN)
160 #define TEXT_DOMAIN "SYS_TEST"
161 #endif /* !TEXT_DOMAIN */
163 (void) textdomain(TEXT_DOMAIN
);
165 progname
= GET_PROGNAME(argv
[0]);
169 while ((c
= getopt(argc
, argv
, "fetKsnack45")) != -1) {
193 if (mode
!= DEFAULT
) usage();
197 if (mode
!= DEFAULT
) usage();
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 */
215 fprintf(stderr
, gettext("Kerberos 5 support could not be loaded\n"));
226 if (no_resolve
&& !show_addresses
) {
230 if (mode
== DEFAULT
|| mode
== CCACHE
) {
231 if (show_time
|| show_keys
)
234 if (show_flags
|| status_only
|| show_addresses
)
238 if (argc
- optind
> 1) {
240 gettext("Extra arguments (starting with \"%s\").\n"),
245 name
= (optind
== argc
-1) ? argv
[optind
] : 0;
247 if (!use_k5
&& !use_k4
)
262 if (!krb5_timestamp_to_sfstring(now
, tmp
, 20, (char *) NULL
) ||
263 !krb5_timestamp_to_sfstring(now
, tmp
, sizeof(tmp
),
265 timestamp_width
= (int) strlen(tmp
);
267 timestamp_width
= 15;
272 krb5_error_code retval
;
273 retval
= krb5_init_context(&kcontext
);
275 com_err(progname
, retval
, gettext("while initializing krb5"));
279 if (mode
== DEFAULT
|| mode
== CCACHE
)
284 #ifdef KRB5_KRB4_COMPAT
285 if (mode
== DEFAULT
|| mode
== CCACHE
)
288 /* We may want to add v4 srvtab support */
290 "%s: srvtab option not supported for Kerberos 4\n",
294 #endif /* KRB4_KRB5_COMPAT */
304 krb5_keytab_entry entry
;
305 krb5_kt_cursor cursor
;
306 char buf
[BUFSIZ
]; /* hopefully large enough for any type */
311 if ((code
= krb5_kt_default(kcontext
, &kt
))) {
312 com_err(progname
, code
,
313 gettext("while getting default keytab"));
317 if ((code
= krb5_kt_resolve(kcontext
, name
, &kt
))) {
318 com_err(progname
, code
,
319 gettext("while resolving keytab %s"),
325 if ((code
= krb5_kt_get_name(kcontext
, kt
, buf
, BUFSIZ
))) {
326 com_err(progname
, code
,
327 gettext("while getting keytab name"));
331 printf(gettext("Keytab name: %s\n"), buf
);
333 if ((code
= krb5_kt_start_seq_get(kcontext
, kt
, &cursor
))) {
334 com_err(progname
, code
,
335 gettext("while starting keytab scan"));
340 printf(gettext("KVNO Timestamp"));
341 fillit(stdout
, timestamp_width
-
342 sizeof (gettext("Timestamp")) + 2, (int)' ');
343 printf(gettext("Principal\n"));
345 fillit(stdout
, timestamp_width
, (int) '-');
347 fillit(stdout
, 78 - timestamp_width
-
348 sizeof (gettext("KVNO")), (int)'-');
351 printf(gettext("KVNO Principal\n"));
352 printf("---- ------------------------------"
353 "--------------------------------------"
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"));
363 printf("%4d ", entry
.vno
);
365 printtime(entry
.timestamp
);
370 printf(" (%s) " , etype_string(entry
.key
.enctype
));
375 for (i
= 0; i
< entry
.key
.length
; i
++)
376 printf("%02x", entry
.key
.contents
[i
]);
381 krb5_free_unparsed_name(kcontext
, pname
);
383 if (code
&& code
!= KRB5_KT_END
) {
384 com_err(progname
, code
,
385 gettext("while scanning keytab"));
388 if ((code
= krb5_kt_end_seq_get(kcontext
, kt
, &cursor
))) {
389 com_err(progname
, code
,
390 gettext("while ending keytab scan"));
398 krb5_ccache cache
= NULL
;
401 krb5_principal princ
;
403 krb5_error_code code
;
407 /* exit_status is set back to 0 if a valid tgt is found */
411 if ((code
= krb5_cc_default(kcontext
, &cache
))) {
413 com_err(progname
, code
,
414 gettext("while getting default "
419 if ((code
= krb5_cc_resolve(kcontext
, name
, &cache
))) {
421 com_err(progname
, code
,
422 gettext("while resolving ccache %s"),
428 flags
= 0; /* turns off OPENCLOSE mode */
429 if ((code
= krb5_cc_set_flags(kcontext
, cache
, flags
))) {
430 if (code
== KRB5_FCC_NOFILE
) {
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
438 #endif /* KRB5_KRB4_COMPAT */
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
));
450 if ((code
= krb5_cc_get_principal(kcontext
, cache
, &princ
))) {
452 com_err(progname
, code
,
453 gettext("while retrieving principal name"));
456 if ((code
= krb5_unparse_name(kcontext
, princ
, &defname
))) {
458 com_err(progname
, code
,
459 gettext("while unparsing principal name"));
463 printf(gettext("Ticket cache: %s:%s\nDefault principal: "
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
);
475 if ((code
= krb5_cc_start_seq_get(kcontext
, cache
, &cur
))) {
477 com_err(progname
, code
,
478 gettext("while starting to retrieve tickets"));
481 while (!(code
= krb5_cc_next_cred(kcontext
, cache
, &cur
, &creds
))) {
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
,
488 strcmp((char *)creds
.server
->data
[1].data
,
489 princ
->realm
.data
) == 0 &&
490 creds
.times
.endtime
> now
)
493 show_credential(&creds
);
495 krb5_free_cred_contents(kcontext
, &creds
);
497 if (code
== KRB5_CC_END
) {
498 if ((code
= krb5_cc_end_seq_get(kcontext
, cache
, &cur
))) {
500 com_err(progname
, code
,
501 gettext("while finishing ticket "
505 flags
= KRB5_TC_OPENCLOSE
; /* turns on OPENCLOSE mode */
506 if ((code
= krb5_cc_set_flags(kcontext
, cache
, flags
))) {
508 com_err(progname
, code
,
509 gettext("while closing ccache"));
512 #ifdef KRB5_KRB4_COMPAT
513 if (name
== NULL
&& !status_only
)
515 #endif /* KRB5_KRB4_COMPAT */
519 com_err(progname
, code
,
520 gettext("while retrieving a ticket"));
526 etype_string(enctype
)
527 krb5_enctype enctype
;
529 static char buf
[256];
530 krb5_error_code retval
;
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
);
542 register krb5_creds
*cred
;
547 if (cred
->ticket_flags
& TKT_FLG_FORWARDABLE
)
549 if (cred
->ticket_flags
& TKT_FLG_FORWARDED
)
551 if (cred
->ticket_flags
& TKT_FLG_PROXIABLE
)
553 if (cred
->ticket_flags
& TKT_FLG_PROXY
)
555 if (cred
->ticket_flags
& TKT_FLG_MAY_POSTDATE
)
557 if (cred
->ticket_flags
& TKT_FLG_POSTDATED
)
559 if (cred
->ticket_flags
& TKT_FLG_INVALID
)
561 if (cred
->ticket_flags
& TKT_FLG_RENEWABLE
)
563 if (cred
->ticket_flags
& TKT_FLG_INITIAL
)
565 if (cred
->ticket_flags
& TKT_FLG_HW_AUTH
)
567 if (cred
->ticket_flags
& TKT_FLG_PRE_AUTH
)
569 if (cred
->ticket_flags
& TKT_FLG_TRANSIT_POLICY_CHECKED
)
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
)
583 char timestring
[BUFSIZ
];
587 if (!krb5_timestamp_to_sfstring((krb5_timestamp
) tv
, timestring
,
588 timestamp_width
+1, &fill
)) {
594 show_credential(cred
)
595 register krb5_creds
* cred
;
597 krb5_error_code retval
;
599 char *name
, *sname
, *flags
;
602 retval
= krb5_unparse_name(kcontext
, cred
->client
, &name
);
604 com_err(progname
, retval
,
605 gettext("while unparsing client name"));
608 retval
= krb5_unparse_name(kcontext
, cred
->server
, &sname
);
610 com_err(progname
, retval
,
611 gettext("while unparsing server name"));
612 krb5_free_unparsed_name(kcontext
, name
);
615 if (!cred
->times
.starttime
)
616 cred
->times
.starttime
= cred
->times
.authtime
;
618 printtime(cred
->times
.starttime
);
619 putchar(' '); putchar(' ');
620 printtime(cred
->times
.endtime
);
621 putchar(' '); putchar(' ');
623 printf("%s\n", sname
);
625 if (strcmp(name
, defname
)) {
626 printf(gettext("\tfor client %s"), name
);
630 if (cred
->times
.renew_till
) {
635 fputs(gettext("renew until "), stdout
);
636 printtime(cred
->times
.renew_till
);
640 if (extra_field
> 3) {
646 flags
= flags_string(cred
);
647 if (flags
&& *flags
) {
652 printf(gettext("Flags: %s"), flags
);
657 if (extra_field
> 2) {
663 retval
= decode_krb5_ticket(&cred
->ticket
, &tkt
);
671 printf(gettext("Etype(skey, tkt): %s, "),
672 etype_string(cred
->keyblock
.enctype
));
674 etype_string(tkt
->enc_part
.enctype
));
679 krb5_free_ticket(kcontext
, tkt
);
682 /* if any additional info was printed, extra_field is non-zero */
687 if (show_addresses
) {
688 if (!cred
->addresses
|| !cred
->addresses
[0]) {
689 printf(gettext("\tAddresses: (none)\n"));
693 printf(gettext("\tAddresses: "));
694 one_addr(cred
->addresses
[0]);
696 for (i
=1; cred
->addresses
[i
]; i
++) {
698 one_addr(cred
->addresses
[i
]);
705 krb5_free_unparsed_name(kcontext
, name
);
706 krb5_free_unparsed_name(kcontext
, sname
);
709 #include "port-sockets.h"
710 #include "socket-utils.h" /* for ss2sin etc */
711 #include <fake-addrinfo.h>
716 struct sockaddr_storage ss
;
718 char namebuf
[NI_MAXHOST
];
720 memset (&ss
, 0, sizeof (ss
));
722 switch (a
->addrtype
) {
724 if (a
->length
!= IPV4_ADDR_LEN
) {
726 printf ("broken address (type %d length %d)",
727 a
->addrtype
, a
->length
);
731 struct sockaddr_in
*sinp
= ss2sin (&ss
);
732 sinp
->sin_family
= AF_INET
;
734 sinp
->sin_len
= sizeof (struct sockaddr_in
);
736 memcpy (&sinp
->sin_addr
, a
->contents
, IPV4_ADDR_LEN
);
739 #ifdef KRB5_USE_INET6
741 if (a
->length
!= IPV6_ADDR_LEN
)
744 struct sockaddr_in6
*sin6p
= ss2sin6 (&ss
);
745 sin6p
->sin6_family
= AF_INET6
;
747 sin6p
->sin6_len
= sizeof (struct sockaddr_in6
);
749 memcpy (&sin6p
->sin6_addr
, a
->contents
, IPV6_ADDR_LEN
);
754 printf(gettext("unknown addr type %d"), a
->addrtype
);
759 err
= getnameinfo (ss2sa (&ss
), socklen (ss2sa (&ss
)),
760 namebuf
, sizeof (namebuf
), 0, 0,
761 no_resolve
? NI_NUMERICHOST
: 0U);
763 printf (gettext("unprintable address (type %d, error %d %s)"), a
->addrtype
, err
,
767 printf ("%s", namebuf
);
778 for (i
=0; i
<num
; i
++)
782 #ifdef KRB5_KRB4_COMPAT
787 char pname
[ANAME_SZ
];
789 char prealm
[REALM_SZ
];
798 file
= name
?name
:tkt_string();
802 "%s: exit status option not supported for Kerberos 4\n",
810 printf("Kerberos 4 ticket cache: %s\n", file
);
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)
819 * klist: No ticket file (tf_util)
822 /* Open ticket file */
823 k_errno
= tf_init(file
, R_TKT_FIL
);
825 fprintf(stderr
, "%s: %s\n", progname
, krb_get_err_text (k_errno
));
828 /* Close ticket file */
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.
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
));
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
));
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
));
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.
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
) {
867 printf("%-18s %-18s %s\n",
868 " Issued", " Expires", " Principal");
871 printtime(c
.issue_date
);
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
);
878 if (header
&& k_errno
== EOF
) {
879 printf("No tickets in file.\n");
882 #endif /* KRB4_KRB5_COMPAT */