klist.c revision 55682
1/*
2 * Copyright (c) 1997-1999 Kungliga Tekniska H�gskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the Institute nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include "kuser_locl.h"
35
36RCSID("$Id: klist.c,v 1.52 1999/12/02 17:05:01 joda Exp $");
37
38static char*
39printable_time(time_t t)
40{
41    static char s[128];
42    strcpy(s, ctime(&t)+ 4);
43    s[15] = 0;
44    return s;
45}
46
47static char*
48printable_time_long(time_t t)
49{
50    static char s[128];
51    strcpy(s, ctime(&t)+ 4);
52    s[20] = 0;
53    return s;
54}
55
56static void
57print_cred(krb5_context context, krb5_creds *cred)
58{
59    char *str;
60    krb5_error_code ret;
61    int32_t sec;
62
63    krb5_timeofday (context, &sec);
64
65    if(cred->times.starttime)
66	printf ("%s  ", printable_time(cred->times.starttime));
67    else
68	printf ("%s  ", printable_time(cred->times.authtime));
69
70    if(cred->times.endtime > sec)
71	printf ("%s  ", printable_time(cred->times.endtime));
72    else
73	printf ("%-15s  ", ">>>Expired<<<");
74    ret = krb5_unparse_name (context, cred->server, &str);
75    if (ret)
76	krb5_err(context, 1, ret, "krb5_unparse_name");
77    printf ("%s\n", str);
78    free (str);
79}
80
81static void
82print_cred_verbose(krb5_context context, krb5_creds *cred)
83{
84    int j;
85    char *str;
86    krb5_error_code ret;
87    int first_flag;
88    int32_t sec;
89
90    krb5_timeofday (context, &sec);
91
92    ret = krb5_unparse_name(context, cred->server, &str);
93    if(ret)
94	exit(1);
95    printf("Server: %s\n", str);
96    free (str);
97    {
98	Ticket t;
99	size_t len;
100	char *s;
101
102	decode_Ticket(cred->ticket.data, cred->ticket.length, &t, &len);
103	ret = krb5_enctype_to_string(context, t.enc_part.etype, &s);
104	if (ret == 0) {
105	    printf("Ticket etype: %s", s);
106	    free(s);
107	} else {
108	    printf("Unknown etype: %d", t.enc_part.etype);
109	}
110	if(t.enc_part.kvno)
111	    printf(", kvno %d", *t.enc_part.kvno);
112	printf("\n");
113	if(cred->session.keytype != t.enc_part.etype) {
114	    ret = krb5_keytype_to_string(context, cred->session.keytype, &str);
115	    if(ret == KRB5_PROG_KEYTYPE_NOSUPP)
116		ret = krb5_enctype_to_string(context, cred->session.keytype,
117					     &str);
118	    if(ret)
119		krb5_warn(context, ret, "session keytype");
120	    else {
121		printf("Session key: %s\n", str);
122		free(str);
123	    }
124	}
125	free_Ticket(&t);
126    }
127    printf("Auth time:  %s\n", printable_time_long(cred->times.authtime));
128    if(cred->times.authtime != cred->times.starttime)
129	printf("Start time: %s\n", printable_time_long(cred->times.starttime));
130    printf("End time:   %s", printable_time_long(cred->times.endtime));
131    if(sec > cred->times.endtime)
132	printf(" (expired)");
133    printf("\n");
134    if(cred->flags.b.renewable)
135	printf("Renew till: %s\n",
136	       printable_time_long(cred->times.renew_till));
137    printf("Ticket flags: ");
138#define PRINT_FLAG2(f, s) if(cred->flags.b.f) { if(!first_flag) printf(", "); printf("%s", #s); first_flag = 0; }
139#define PRINT_FLAG(f) PRINT_FLAG2(f, f)
140    first_flag = 1;
141    PRINT_FLAG(forwardable);
142    PRINT_FLAG(forwarded);
143    PRINT_FLAG(proxiable);
144    PRINT_FLAG(proxy);
145    PRINT_FLAG2(may_postdate, may-postdate);
146    PRINT_FLAG(postdated);
147    PRINT_FLAG(invalid);
148    PRINT_FLAG(renewable);
149    PRINT_FLAG(initial);
150    PRINT_FLAG2(pre_authent, pre-authenticated);
151    PRINT_FLAG2(hw_authent, hw-authenticated);
152    PRINT_FLAG2(transited_policy_checked, transited-policy-checked);
153    PRINT_FLAG2(ok_as_delegate, ok-as-delegate);
154    PRINT_FLAG(anonymous);
155    printf("\n");
156    printf("Addresses: ");
157    for(j = 0; j < cred->addresses.len; j++){
158	char buf[128];
159	size_t len;
160	if(j) printf(", ");
161	ret = krb5_print_address(&cred->addresses.val[j],
162				 buf, sizeof(buf), &len);
163
164	if(ret == 0)
165	    printf("%s", buf);
166    }
167    printf("\n\n");
168}
169
170/*
171 * Print all tickets in `ccache' on stdout, verbosily iff do_verbose.
172 */
173
174static void
175print_tickets (krb5_context context,
176	       krb5_ccache ccache,
177	       krb5_principal principal,
178	       int do_verbose)
179{
180    krb5_error_code ret;
181    char *str;
182    krb5_cc_cursor cursor;
183    krb5_creds creds;
184
185    ret = krb5_unparse_name (context, principal, &str);
186    if (ret)
187	krb5_err (context, 1, ret, "krb5_unparse_name");
188
189    printf ("%17s: %s:%s\n",
190	    "Credentials cache",
191	    krb5_cc_get_type(context, ccache),
192	    krb5_cc_get_name(context, ccache));
193    printf ("%17s: %s\n", "Principal", str);
194    free (str);
195
196    if(do_verbose)
197	printf ("%17s: %d\n", "Cache version",
198		krb5_cc_get_version(context, ccache));
199
200    if (do_verbose && context->kdc_sec_offset) {
201	char buf[BUFSIZ];
202	int val;
203	int sig;
204
205	val = context->kdc_sec_offset;
206	sig = 1;
207	if (val < 0) {
208	    sig = -1;
209	    val = -val;
210	}
211
212	unparse_time (val, buf, sizeof(buf));
213
214	printf ("%17s: %s%s\n", "KDC time offset",
215		sig == -1 ? "-" : "", buf);
216    }
217
218    printf("\n");
219
220    ret = krb5_cc_start_seq_get (context, ccache, &cursor);
221    if (ret)
222	krb5_err(context, 1, ret, "krb5_cc_start_seq_get");
223
224    if(!do_verbose)
225	printf("  %-15s  %-15s  %s\n", "Issued", "Expires", "Principal");
226
227    while (krb5_cc_next_cred (context,
228			      ccache,
229			      &creds,
230			      &cursor) == 0) {
231	if(do_verbose){
232	    print_cred_verbose(context, &creds);
233	}else{
234	    print_cred(context, &creds);
235	}
236	krb5_free_creds_contents (context, &creds);
237    }
238    ret = krb5_cc_end_seq_get (context, ccache, &cursor);
239    if (ret)
240	krb5_err (context, 1, ret, "krb5_cc_end_seq_get");
241}
242
243/*
244 * Check if there's a tgt for the realm of `principal' and ccache and
245 * if so return 0, else 1
246 */
247
248static int
249check_for_tgt (krb5_context context,
250	       krb5_ccache ccache,
251	       krb5_principal principal)
252{
253    krb5_error_code ret;
254    krb5_creds pattern;
255    krb5_creds creds;
256    krb5_realm *client_realm;
257    int expired;
258
259    client_realm = krb5_princ_realm (context, principal);
260
261    ret = krb5_make_principal (context, &pattern.server,
262			       *client_realm, KRB5_TGS_NAME, *client_realm,
263			       NULL);
264    if (ret)
265	krb5_err (context, 1, ret, "krb5_make_principal");
266
267    ret = krb5_cc_retrieve_cred (context, ccache, 0, &pattern, &creds);
268    expired = time(NULL) > creds.times.endtime;
269    krb5_free_principal (context, pattern.server);
270    krb5_free_creds_contents (context, &creds);
271    if (ret) {
272	if (ret == KRB5_CC_END)
273	    return 1;
274	krb5_err (context, 1, ret, "krb5_cc_retrieve_cred");
275    }
276    return expired;
277}
278
279#ifdef KRB4
280/*
281 * Print a list of all AFS tokens
282 */
283
284static void
285display_tokens(int do_verbose)
286{
287    u_int32_t i;
288    unsigned char t[128];
289    struct ViceIoctl parms;
290
291    parms.in = (void *)&i;
292    parms.in_size = sizeof(i);
293    parms.out = (void *)t;
294    parms.out_size = sizeof(t);
295
296    for (i = 0; k_pioctl(NULL, VIOCGETTOK, &parms, 0) == 0; i++) {
297        int32_t size_secret_tok, size_public_tok;
298        unsigned char *cell;
299	struct ClearToken ct;
300	unsigned char *r = t;
301	struct timeval tv;
302	char buf1[20], buf2[20];
303
304	memcpy(&size_secret_tok, r, sizeof(size_secret_tok));
305	/* dont bother about the secret token */
306	r += size_secret_tok + sizeof(size_secret_tok);
307	memcpy(&size_public_tok, r, sizeof(size_public_tok));
308	r += sizeof(size_public_tok);
309	memcpy(&ct, r, size_public_tok);
310	r += size_public_tok;
311	/* there is a int32_t with length of cellname, but we dont read it */
312	r += sizeof(int32_t);
313	cell = r;
314
315	gettimeofday (&tv, NULL);
316	strlcpy (buf1, printable_time(ct.BeginTimestamp),
317			 sizeof(buf1));
318	if (do_verbose || tv.tv_sec < ct.EndTimestamp)
319	    strlcpy (buf2, printable_time(ct.EndTimestamp),
320			     sizeof(buf2));
321	else
322	    strlcpy (buf2, ">>> Expired <<<", sizeof(buf2));
323
324	printf("%s  %s  ", buf1, buf2);
325
326	if ((ct.EndTimestamp - ct.BeginTimestamp) & 1)
327	  printf("User's (AFS ID %d) tokens for %s", ct.ViceId, cell);
328	else
329	  printf("Tokens for %s", cell);
330	if (do_verbose)
331	    printf(" (%d)", ct.AuthHandle);
332	putchar('\n');
333    }
334}
335#endif
336
337static int version_flag = 0;
338static int help_flag	= 0;
339static int do_verbose	= 0;
340static int do_test	= 0;
341#ifdef KRB4
342static int do_tokens	= 0;
343#endif
344static char *cred_cache;
345
346static struct getargs args[] = {
347    { "cache",			'c', arg_string, &cred_cache,
348      "credentials cache to list", "cache" },
349    { "test",			't', arg_flag, &do_test,
350      "test for having tickets", NULL },
351#ifdef KRB4
352    { "tokens",			'T',   arg_flag, &do_tokens,
353      "display AFS tokens", NULL },
354#endif
355    { "verbose",		'v', arg_flag, &do_verbose,
356      "Verbose output", NULL },
357    { "version", 		0,   arg_flag, &version_flag,
358      "print version", NULL },
359    { "help",			0,   arg_flag, &help_flag,
360      NULL, NULL}
361};
362
363static void
364usage (int ret)
365{
366    arg_printusage (args,
367		    sizeof(args)/sizeof(*args),
368		    NULL,
369		    "");
370    exit (ret);
371}
372
373int
374main (int argc, char **argv)
375{
376    krb5_error_code ret;
377    krb5_context context;
378    krb5_ccache ccache;
379    krb5_principal principal;
380    int optind = 0;
381    int exit_status = 0;
382
383    set_progname (argv[0]);
384
385    if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optind))
386	usage(1);
387
388    if (help_flag)
389	usage (0);
390
391    if(version_flag){
392	print_version(NULL);
393	exit(0);
394    }
395
396    argc -= optind;
397    argv += optind;
398
399    if (argc != 0)
400	usage (1);
401
402    ret = krb5_init_context (&context);
403    if (ret)
404	krb5_err(context, 1, ret, "krb5_init_context");
405
406    if(cred_cache) {
407	ret = krb5_cc_resolve(context, cred_cache, &ccache);
408	if (ret)
409	    krb5_err (context, 1, ret, "%s", cred_cache);
410    } else {
411	ret = krb5_cc_default (context, &ccache);
412	if (ret)
413	    krb5_err (context, 1, ret, "krb5_cc_resolve");
414    }
415
416    ret = krb5_cc_get_principal (context, ccache, &principal);
417    if (ret) {
418	if(ret == ENOENT) {
419	    if (do_test)
420		return 1;
421	    else
422		krb5_errx(context, 1, "No ticket file: %s",
423			  krb5_cc_get_name(context, ccache));
424	} else
425	    krb5_err (context, 1, ret, "krb5_cc_get_principal");
426    }
427    if (do_test)
428	exit_status = check_for_tgt (context, ccache, principal);
429    else
430	print_tickets (context, ccache, principal, do_verbose);
431
432    ret = krb5_cc_close (context, ccache);
433    if (ret)
434	krb5_err (context, 1, ret, "krb5_cc_close");
435
436    krb5_free_principal (context, principal);
437    krb5_free_context (context);
438
439#ifdef KRB4
440    if (!do_test && do_tokens && k_hasafs ())
441	display_tokens (do_verbose);
442#endif
443
444    return exit_status;
445}
446