Use symbolic names for the encryption types.
[krb5.git] / src / clients / klist / klist.c
1 /*
2  * clients/klist/klist.c
3  *
4  * Copyright 1990 by the Massachusetts Institute of Technology.
5  * All Rights Reserved.
6  *
7  * Export of this software from the United States of America may
8  *   require a specific license from the United States Government.
9  *   It is the responsibility of any person or organization contemplating
10  *   export to obtain such a license before exporting.
11  * 
12  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13  * distribute this software and its documentation for any purpose and
14  * without fee is hereby granted, provided that the above copyright
15  * notice appear in all copies and that both that copyright notice and
16  * this permission notice appear in supporting documentation, and that
17  * the name of M.I.T. not be used in advertising or publicity pertaining
18  * to distribution of the software without specific, written prior
19  * permission.  M.I.T. makes no representations about the suitability of
20  * this software for any purpose.  It is provided "as is" without express
21  * or implied warranty.
22  * 
23  *
24  * List out the contents of your credential cache or keytab.
25  */
26
27 #include "k5-int.h"
28 #include "com_err.h"
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stdio.h>
32 #include <time.h>
33
34 extern int optind;
35 extern char *optarg;
36 int show_flags = 0, show_time = 0, status_only = 0, show_keys = 0;
37 int show_etype = 0;
38 char *defname;
39 char *progname;
40 krb5_int32 now;
41 int timestamp_width;
42
43 krb5_context kcontext;
44
45 void show_credential KRB5_PROTOTYPE((char *,
46                                 krb5_context,
47                                 krb5_creds *));
48         
49 void do_ccache KRB5_PROTOTYPE((char *));
50 void do_keytab KRB5_PROTOTYPE((char *));
51 void printtime KRB5_PROTOTYPE((time_t));
52 void fillit KRB5_PROTOTYPE((FILE *, int, int));
53         
54 #define DEFAULT 0
55 #define CCACHE 1
56 #define KEYTAB 2
57
58 void usage()
59 {
60      fprintf(stderr, "Usage: %s [[-c] [-f] [-e] [-s]] [-k [-t] [-K]] [name]\n",
61              progname); 
62      fprintf(stderr, "\t-c specifies credentials cache, -k specifies keytab");
63      fprintf(stderr, ", -c is default\n");
64      fprintf(stderr, "\toptions for credential caches:\n");
65      fprintf(stderr, "\t\t-f shows credentials flags\n");
66      fprintf(stderr, "\t\t-e shows the encryption type\n");
67      fprintf(stderr, "\t\t-s sets exit status based on valid tgt existence\n");
68      fprintf(stderr, "\toptions for keytabs:\n");
69      fprintf(stderr, "\t\t-t shows keytab entry timestamps\n");
70      fprintf(stderr, "\t\t-K shows keytab entry DES keys\n");
71      exit(1);
72 }
73  
74
75 void
76 main(argc, argv)
77     int argc;
78     char **argv;
79 {
80     int code;
81     char *name;
82     int mode;
83
84     krb5_init_context(&kcontext);
85     krb5_init_ets(kcontext);
86
87     progname = (strrchr(*argv, '/') ? strrchr(*argv, '/')+1 : argv[0]);
88
89     argv++;
90     name = NULL;
91     mode = DEFAULT;
92     while (*argv) {
93         if ((*argv)[0] != '-') {
94             if (name) usage();
95             name = *argv;
96         } else switch ((*argv)[1]) {
97         case 'f':
98             show_flags = 1;
99             break;
100         case 'e':
101             show_etype = 1;
102             break;
103         case 't':
104             show_time = 1;
105             break;
106         case 'K':
107             show_keys = 1;
108             break;
109         case 's':
110             status_only = 1;
111             break;
112         case 'c':
113             if (mode != DEFAULT) usage();
114             mode = CCACHE;
115             break;
116         case 'k':
117             if (mode != DEFAULT) usage();
118             mode = KEYTAB;
119             break;
120         default:
121             usage();
122             break;
123         }
124         argv++;
125     }
126
127     if (mode == DEFAULT || mode == CCACHE) {
128          if (show_time || show_keys)
129               usage();
130     } else {
131          if (show_flags || status_only)
132               usage();
133     }
134
135     if ((code = krb5_timeofday(kcontext, &now))) {
136          if (!status_only)
137               com_err(progname, code, "while getting time of day.");
138          exit(1);
139     }
140     else {
141         char tmp[BUFSIZ];
142
143         if (!krb5_timestamp_to_sfstring(now, tmp, 20, (char *) NULL) ||
144             !krb5_timestamp_to_sfstring(now, tmp, sizeof(tmp), (char *) NULL))
145             timestamp_width = (int) strlen(tmp);
146         else
147             timestamp_width = 15;
148     }
149
150     if (mode == DEFAULT || mode == CCACHE)
151          do_ccache(name);
152     else
153          do_keytab(name);
154 }    
155
156 void do_keytab(name)
157    char *name;
158 {
159      krb5_keytab kt;
160      krb5_keytab_entry entry;
161      krb5_kt_cursor cursor;
162      char buf[BUFSIZ]; /* hopefully large enough for any type */
163      char *pname;
164      int code;
165      
166      if (name == NULL) {
167           if ((code = krb5_kt_default(kcontext, &kt))) {
168                com_err(progname, code, "while getting default keytab");
169                exit(1);
170           }
171      } else {
172           if ((code = krb5_kt_resolve(kcontext, name, &kt))) {
173                com_err(progname, code, "while resolving keytab %s",
174                        name);
175                exit(1);
176           }
177      }
178
179      if ((code = krb5_kt_get_name(kcontext, kt, buf, BUFSIZ))) {
180           com_err(progname, code, "while getting keytab name");
181           exit(1);
182      }
183
184      printf("Keytab name: %s\n", buf);
185      
186      if ((code = krb5_kt_start_seq_get(kcontext, kt, &cursor))) {
187           com_err(progname, code, "while starting keytab scan");
188           exit(1);
189      }
190
191      if (show_time) {
192           printf("KVNO Timestamp");
193           fillit(stdout, timestamp_width - sizeof("Timestamp") + 2, (int) ' ');
194           printf("Principal\n");
195           printf("---- ");
196           fillit(stdout, timestamp_width, (int) '-');
197           printf(" ");
198           fillit(stdout, 78 - timestamp_width - sizeof("KVNO"), (int) '-');
199           printf("\n");
200      } else {
201           printf("KVNO Principal\n");
202           printf("---- --------------------------------------------------------------------------\n");
203      }
204      
205      while ((code = krb5_kt_next_entry(kcontext, kt, &entry, &cursor)) == 0) {
206           if ((code = krb5_unparse_name(kcontext, entry.principal, &pname))) {
207                com_err(progname, code, "while unparsing principal name");
208                exit(1);
209           }
210           printf("%4d ", entry.vno);
211           if (show_time) {
212                printtime(entry.timestamp);
213                printf(" ");
214           }
215           printf("%s", pname);
216           if (show_keys) {
217                printf(" (0x");
218                {
219                     int i;
220                     for (i = 0; i < entry.key.length; i++)
221                          printf("%02x", entry.key.contents[i]);
222                }
223                printf(")");
224           }
225           printf("\n");
226           free(pname);
227      }
228      if (code && code != KRB5_KT_END) {
229           com_err(progname, code, "while scanning keytab");
230           exit(1);
231      }
232      if ((code = krb5_kt_end_seq_get(kcontext, kt, &cursor))) {
233           com_err(progname, code, "while ending keytab scan");
234           exit(1);
235      }
236      exit(0);
237 }
238 void do_ccache(name)
239    char *name;
240 {
241     krb5_ccache cache = NULL;
242     krb5_cc_cursor cur;
243     krb5_creds creds;
244     krb5_principal princ;
245     krb5_flags flags;
246     krb5_error_code code;
247     int exit_status = 0;
248             
249     if (status_only)
250         /* exit_status is set back to 0 if a valid tgt is found */
251         exit_status = 1;
252
253     if (name == NULL) {
254         if ((code = krb5_cc_default(kcontext, &cache))) {
255             if (!status_only)
256                 com_err(progname, code, "while getting default ccache");
257             exit(1);
258             }
259     } else {
260         if ((code = krb5_cc_resolve(kcontext, name, &cache))) {
261             if (!status_only)
262                 com_err(progname, code, "while resolving ccache %s",
263                         name);
264             exit(1);
265         }
266     }
267  
268     flags = 0;                          /* turns off OPENCLOSE mode */
269     if ((code = krb5_cc_set_flags(kcontext, cache, flags))) {
270         if (code == ENOENT) {
271             if (!status_only)
272                 com_err(progname, code, "(ticket cache %s)",
273                         krb5_cc_get_name(kcontext, cache));
274         } else {
275             if (!status_only)
276                 com_err(progname, code,
277                         "while setting cache flags (ticket cache %s)",
278                         krb5_cc_get_name(kcontext, cache));
279         }
280         exit(1);
281     }
282     if ((code = krb5_cc_get_principal(kcontext, cache, &princ))) {
283         if (!status_only)
284             com_err(progname, code, "while retrieving principal name");
285         exit(1);
286     }
287     if ((code = krb5_unparse_name(kcontext, princ, &defname))) {
288         if (!status_only)
289             com_err(progname, code, "while unparsing principal name");
290         exit(1);
291     }
292     if (!status_only) {
293         printf("Ticket cache: %s\nDefault principal: %s\n\n",
294                krb5_cc_get_name(kcontext, cache), defname);
295         fputs("Valid starting", stdout);
296         fillit(stdout, timestamp_width - sizeof("Valid starting") + 3,
297                (int) ' ');
298         fputs("Expires", stdout);
299         fillit(stdout, timestamp_width - sizeof("Expires") + 3,
300                (int) ' ');
301         fputs("Service principal\n", stdout);
302     }
303     if ((code = krb5_cc_start_seq_get(kcontext, cache, &cur))) {
304         if (!status_only)
305             com_err(progname, code, "while starting to retrieve tickets");
306         exit(1);
307     }
308     while (!(code = krb5_cc_next_cred(kcontext, cache, &cur, &creds))) {
309         if (status_only) {
310             if (exit_status && creds.server->length == 2 &&
311                 strcmp(creds.server->realm.data, princ->realm.data) == 0 &&
312                 strcmp((char *)creds.server->data[0].data, "krbtgt") == 0 &&
313                 strcmp((char *)creds.server->data[1].data,
314                        princ->realm.data) == 0 && 
315                 creds.times.endtime > now)
316                 exit_status = 0;
317         } else {
318             show_credential(progname, kcontext, &creds);
319         }
320         krb5_free_cred_contents(kcontext, &creds);
321     }
322     if (code == KRB5_CC_END) {
323         if ((code = krb5_cc_end_seq_get(kcontext, cache, &cur))) {
324             if (!status_only)
325                 com_err(progname, code, "while finishing ticket retrieval");
326             exit(1);
327         }
328         flags = KRB5_TC_OPENCLOSE;      /* turns on OPENCLOSE mode */
329         if ((code = krb5_cc_set_flags(kcontext, cache, flags))) {
330             if (!status_only)
331                 com_err(progname, code, "while closing ccache");
332             exit(1);
333         }
334         exit(exit_status);
335     } else {
336         if (!status_only)
337             com_err(progname, code, "while retrieving a ticket");
338         exit(1);
339     }   
340 }
341
342 char *
343 etype_string(enctype)
344     krb5_enctype enctype;
345 {
346     static char buf[12];
347     
348     switch (enctype) {
349     case ENCTYPE_DES_CBC_CRC:
350         return "DES-CBC-CRC";
351         break;
352     case ENCTYPE_DES_CBC_MD4:
353         return "DES-CBC-MD4";
354         break;
355     case ENCTYPE_DES_CBC_MD5:
356         return "DES-CBC-MD5";
357         break;
358     case ENCTYPE_DES3_CBC_MD5:
359         return "DES3-CBC-MD5";
360         break;
361     default:
362         sprintf(buf, "etype %d", enctype);
363         return buf;
364         break;
365     }
366 }
367
368 char *
369 flags_string(cred)
370     register krb5_creds *cred;
371 {
372     static char buf[32];
373     int i = 0;
374         
375     if (cred->ticket_flags & TKT_FLG_FORWARDABLE)
376         buf[i++] = 'F';
377     if (cred->ticket_flags & TKT_FLG_FORWARDED)
378         buf[i++] = 'f';
379     if (cred->ticket_flags & TKT_FLG_PROXIABLE)
380         buf[i++] = 'P';
381     if (cred->ticket_flags & TKT_FLG_PROXY)
382         buf[i++] = 'p';
383     if (cred->ticket_flags & TKT_FLG_MAY_POSTDATE)
384         buf[i++] = 'D';
385     if (cred->ticket_flags & TKT_FLG_POSTDATED)
386         buf[i++] = 'd';
387     if (cred->ticket_flags & TKT_FLG_INVALID)
388         buf[i++] = 'i';
389     if (cred->ticket_flags & TKT_FLG_RENEWABLE)
390         buf[i++] = 'R';
391     if (cred->ticket_flags & TKT_FLG_INITIAL)
392         buf[i++] = 'I';
393     if (cred->ticket_flags & TKT_FLG_HW_AUTH)
394         buf[i++] = 'H';
395     if (cred->ticket_flags & TKT_FLG_PRE_AUTH)
396         buf[i++] = 'A';
397     buf[i] = '\0';
398     return(buf);
399 }
400
401 void 
402 printtime(tv)
403     time_t tv;
404 {
405     char timestring[BUFSIZ];
406     char fill;
407
408     fill = ' ';
409     if (!krb5_timestamp_to_sfstring((krb5_timestamp) tv,
410                                     timestring,
411                                     timestamp_width+1,
412                                     &fill)) {
413         printf(timestring);
414     }
415 }
416
417 void
418 show_credential(progname, kcontext, cred)
419     char                * progname;
420     krb5_context          kcontext;
421     register krb5_creds * cred;
422 {
423     krb5_error_code retval;
424     krb5_ticket *tkt;
425     char *name, *sname, *flags;
426     int extra_field = 0;
427
428     retval = krb5_unparse_name(kcontext, cred->client, &name);
429     if (retval) {
430         com_err(progname, retval, "while unparsing client name");
431         return;
432     }
433     retval = krb5_unparse_name(kcontext, cred->server, &sname);
434     if (retval) {
435         com_err(progname, retval, "while unparsing server name");
436         free(name);
437         return;
438     }
439     if (!cred->times.starttime)
440         cred->times.starttime = cred->times.authtime;
441
442     printtime(cred->times.starttime);
443     putchar(' '); putchar(' ');
444     printtime(cred->times.endtime);
445     putchar(' '); putchar(' ');
446
447     printf("%s\n", sname);
448
449     if (strcmp(name, defname)) {
450             printf("\tfor client %s", name);
451             extra_field++;
452     }
453     
454     if (cred->times.renew_till) {
455         if (!extra_field)
456                 fputs("\t",stdout);
457         else
458                 fputs(", ",stdout);
459         fputs("renew until ", stdout);
460         printtime(cred->times.renew_till);
461         extra_field += 2;
462     }
463
464     if (extra_field > 3) {
465         fputs("\n", stdout);
466         extra_field = 0;
467     }
468
469     if (show_flags) {
470         flags = flags_string(cred);
471         if (flags && *flags) {
472             if (!extra_field)
473                 fputs("\t",stdout);
474             else
475                 fputs(", ",stdout);
476             printf("Flags: %s", flags);
477             extra_field++;
478         }
479     }
480
481     if (extra_field > 2) {
482         fputs("\n", stdout);
483         extra_field = 0;
484     }
485
486     if (show_etype) {
487         retval = decode_krb5_ticket(&cred->ticket, &tkt);
488         if (!extra_field)
489             fputs("\t",stdout);
490         else
491             fputs(", ",stdout);
492         printf("Etype (skey, tkt): %s, %s ",
493                etype_string(cred->keyblock.enctype), 
494                etype_string(tkt->enc_part.enctype));
495         krb5_free_ticket(kcontext, tkt);
496         extra_field++;
497     }
498
499     /* if any additional info was printed, extra_field is non-zero */
500     if (extra_field)
501         putchar('\n');
502     free(name);
503     free(sname);
504 }
505
506 void
507 fillit(f, num, c)
508     FILE        *f;
509     int         num;
510     int         c;
511 {
512     int i;
513
514     for (i=0; i<num; i++)
515         fputc(c, f);
516 }
517