xref: /freebsd/crypto/heimdal/kuser/klist.c (revision 77a0943ded95b9e6438f7db70c4a28e4d93946d4)
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 
36 RCSID("$Id: klist.c,v 1.53 2000/02/06 08:15:40 assar Exp $");
37 
38 static char*
39 printable_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 
47 static char*
48 printable_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 
56 static void
57 print_cred(krb5_context context, krb5_creds *cred)
58 {
59     char *str;
60     krb5_error_code ret;
61     krb5_timestamp 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 
81 static void
82 print_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     krb5_timestamp 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 
174 static void
175 print_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 
248 static int
249 check_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 
284 static void
285 display_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 
337 static int version_flag = 0;
338 static int help_flag	= 0;
339 static int do_verbose	= 0;
340 static int do_test	= 0;
341 #ifdef KRB4
342 static int do_tokens	= 0;
343 #endif
344 static char *cred_cache;
345 
346 static 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 
363 static void
364 usage (int ret)
365 {
366     arg_printusage (args,
367 		    sizeof(args)/sizeof(*args),
368 		    NULL,
369 		    "");
370     exit (ret);
371 }
372 
373 int
374 main (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