cf/largefile.m4: Fix build with autoconf-2.72
[heimdal.git] / kuser / klist.c
blobf0a438218b78abde0f8101f3304c84cc258d8845
1 /*
2 * Copyright (c) 1997-2008 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
36 #include "kuser_locl.h"
37 #include "parse_units.h"
38 #include "heimtools-commands.h"
39 #undef HC_DEPRECATED_CRYPTO
41 static const char *
42 printable_time_internal(time_t t, int x)
44 static char s[128];
45 char *p;
47 if ((p = ctime(&t)) == NULL)
48 strlcpy(s, "?", sizeof(s));
49 else
50 strlcpy(s, p + 4, sizeof(s));
51 s[x] = 0;
52 return s;
55 static const char *
56 printable_time(time_t t)
58 return printable_time_internal(t, 20);
61 static const char *
62 printable_time_long(time_t t)
64 return printable_time_internal(t, 20);
67 #define COL_ISSUED NP_(" Issued","")
68 #define COL_EXPIRES NP_(" Expires", "")
69 #define COL_FLAGS NP_("Flags", "")
70 #define COL_NAME NP_(" Name", "")
71 #define COL_PRINCIPAL NP_(" Principal", "in klist output")
72 #define COL_PRINCIPAL_KVNO NP_(" Principal (kvno)", "in klist output")
73 #define COL_CACHENAME NP_(" Cache name", "name in klist output")
74 #define COL_DEFCACHE NP_("", "")
76 static void
77 print_cred(krb5_context context, krb5_creds *cred, rtbl_t ct, int do_flags)
79 char *str;
80 krb5_error_code ret;
81 krb5_timestamp sec;
83 krb5_timeofday (context, &sec);
86 if(cred->times.starttime)
87 rtbl_add_column_entry(ct, COL_ISSUED,
88 printable_time(cred->times.starttime));
89 else
90 rtbl_add_column_entry(ct, COL_ISSUED,
91 printable_time(cred->times.authtime));
93 if(cred->times.endtime > sec)
94 rtbl_add_column_entry(ct, COL_EXPIRES,
95 printable_time(cred->times.endtime));
96 else
97 rtbl_add_column_entry(ct, COL_EXPIRES, N_(">>>Expired<<<", ""));
98 ret = krb5_unparse_name (context, cred->server, &str);
99 if (ret)
100 krb5_err(context, 1, ret, "krb5_unparse_name");
101 rtbl_add_column_entry(ct, COL_PRINCIPAL, str);
102 if(do_flags) {
103 char s[16], *sp = s;
104 if(cred->flags.b.forwardable)
105 *sp++ = 'F';
106 if(cred->flags.b.forwarded)
107 *sp++ = 'f';
108 if(cred->flags.b.proxiable)
109 *sp++ = 'P';
110 if(cred->flags.b.proxy)
111 *sp++ = 'p';
112 if(cred->flags.b.may_postdate)
113 *sp++ = 'D';
114 if(cred->flags.b.postdated)
115 *sp++ = 'd';
116 if(cred->flags.b.renewable)
117 *sp++ = 'R';
118 if(cred->flags.b.initial)
119 *sp++ = 'I';
120 if(cred->flags.b.invalid)
121 *sp++ = 'i';
122 if(cred->flags.b.pre_authent)
123 *sp++ = 'A';
124 if(cred->flags.b.hw_authent)
125 *sp++ = 'H';
126 if(cred->flags.b.transited_policy_checked)
127 *sp++ = 'T';
128 if(cred->flags.b.ok_as_delegate)
129 *sp++ = 'O';
130 if(cred->flags.b.anonymous)
131 *sp++ = 'a';
132 *sp = '\0';
133 rtbl_add_column_entry(ct, COL_FLAGS, s);
135 free(str);
138 static void
139 cred2json(krb5_context context, krb5_creds *cred, heim_array_t tix)
141 heim_dict_t t = heim_dict_create(10); /* ticket top-level */
142 heim_dict_t e = heim_dict_create(10); /* ticket times */
143 heim_dict_t f = heim_dict_create(20); /* flags */
144 heim_object_t o;
145 char buf[16], *sp = buf;
146 char *str;
147 krb5_error_code ret;
148 krb5_timestamp sec;
150 heim_array_append_value(tix, t);
151 krb5_timeofday(context, &sec);
154 * JSON object names (keys) that start with capitals are for compatibility
155 * with the JSON we used to output. The others are new.
157 heim_dict_set_value(t, HSTR("times"), e);
158 heim_dict_set_value(t, HSTR("flags"), f);
160 heim_dict_set_value(e, HSTR("authtime"),
161 o = heim_number_create(cred->times.authtime));
162 heim_release(o);
163 heim_dict_set_value(t, HSTR("Issued"),
164 o = heim_string_create(printable_time(cred->times.authtime)));
165 heim_release(o);
166 heim_dict_set_value(e, HSTR("starttime"), heim_null_create());
167 if (cred->times.starttime) {
168 heim_dict_set_value(e, HSTR("starttime"),
169 o = heim_number_create(cred->times.starttime));
170 heim_release(o);
171 heim_dict_set_value(t, HSTR("Starttime"),
172 o = heim_string_create(printable_time(cred->times.starttime)));
173 heim_release(o);
176 if (cred->times.renew_till) {
177 heim_dict_set_value(e, HSTR("renew_till"),
178 o = heim_number_create(cred->times.starttime));
179 heim_release(o);
180 heim_dict_set_value(t, HSTR("Renew till"),
181 o = heim_string_create(printable_time(cred->times.starttime)));
182 heim_release(o);
185 heim_dict_set_value(e, HSTR("endtime"),
186 o = heim_number_create(cred->times.endtime));
187 heim_release(o);
189 if (cred->times.endtime > sec) {
190 heim_dict_set_value(t, HSTR("Expires"),
191 o = heim_string_create(printable_time(cred->times.endtime)));
192 heim_release(o);
193 heim_dict_set_value(t, HSTR("expired"), heim_bool_create(0));
194 } else {
195 heim_dict_set_value(t, HSTR("Expires"), HSTR(">>>Expired<<<"));
196 heim_dict_set_value(t, HSTR("expired"), heim_bool_create(1));
199 ret = krb5_unparse_name(context, cred->server, &str);
200 if (ret)
201 krb5_err(context, 1, ret, "krb5_unparse_name");
202 heim_dict_set_value(t, HSTR("Principal"), o = heim_string_create(str));
203 heim_release(o);
205 if (cred->flags.b.forwardable) {
206 heim_dict_set_value(f, HSTR("forwardable"), heim_bool_create(1));
207 *sp++ = 'F';
208 } else {
209 heim_dict_set_value(f, HSTR("forwardable"), heim_bool_create(0));
211 if (cred->flags.b.forwarded) {
212 heim_dict_set_value(f, HSTR("forwarded"), heim_bool_create(1));
213 *sp++ = 'f';
214 } else {
215 heim_dict_set_value(f, HSTR("forwarded"), heim_bool_create(0));
217 if (cred->flags.b.proxiable) {
218 heim_dict_set_value(f, HSTR("proxiable"), heim_bool_create(1));
219 *sp++ = 'P';
220 } else {
221 heim_dict_set_value(f, HSTR("proxiable"), heim_bool_create(0));
223 if (cred->flags.b.proxy) {
224 heim_dict_set_value(f, HSTR("proxy"), heim_bool_create(1));
225 *sp++ = 'p';
226 } else {
227 heim_dict_set_value(f, HSTR("proxy"), heim_bool_create(0));
229 if (cred->flags.b.may_postdate) {
230 heim_dict_set_value(f, HSTR("may_postdate"), heim_bool_create(1));
231 *sp++ = 'D';
232 } else {
233 heim_dict_set_value(f, HSTR("may_postdate"), heim_bool_create(0));
235 if (cred->flags.b.postdated) {
236 heim_dict_set_value(f, HSTR("postdated"), heim_bool_create(1));
237 *sp++ = 'd';
238 } else {
239 heim_dict_set_value(f, HSTR("postdated"), heim_bool_create(0));
241 if (cred->flags.b.renewable) {
242 heim_dict_set_value(f, HSTR("renewable"), heim_bool_create(1));
243 *sp++ = 'R';
244 } else {
245 heim_dict_set_value(f, HSTR("renewable"), heim_bool_create(0));
247 if (cred->flags.b.initial) {
248 heim_dict_set_value(f, HSTR("initial"), heim_bool_create(1));
249 *sp++ = 'I';
250 } else {
251 heim_dict_set_value(f, HSTR("initial"), heim_bool_create(0));
253 if (cred->flags.b.invalid) {
254 heim_dict_set_value(f, HSTR("invalid"), heim_bool_create(1));
255 *sp++ = 'i';
256 } else {
257 heim_dict_set_value(f, HSTR("invalid"), heim_bool_create(0));
259 if (cred->flags.b.pre_authent) {
260 heim_dict_set_value(f, HSTR("pre_authent"), heim_bool_create(1));
261 *sp++ = 'A';
262 } else {
263 heim_dict_set_value(f, HSTR("pre_authent"), heim_bool_create(0));
265 if (cred->flags.b.hw_authent) {
266 heim_dict_set_value(f, HSTR("hw_authent"), heim_bool_create(1));
267 *sp++ = 'H';
268 } else {
269 heim_dict_set_value(f, HSTR("hw_authent"), heim_bool_create(0));
271 if (cred->flags.b.transited_policy_checked) {
272 heim_dict_set_value(f, HSTR("transited_policy_checked"), heim_bool_create(1));
273 *sp++ = 'T';
274 } else {
275 heim_dict_set_value(f, HSTR("transited_policy_checked"), heim_bool_create(0));
277 if (cred->flags.b.ok_as_delegate) {
278 heim_dict_set_value(f, HSTR("ok_as_delegate"), heim_bool_create(1));
279 *sp++ = 'O';
280 } else {
281 heim_dict_set_value(f, HSTR("ok_as_delegate"), heim_bool_create(0));
283 if (cred->flags.b.anonymous) {
284 heim_dict_set_value(f, HSTR("anonymous"), heim_bool_create(1));
285 *sp++ = 'a';
286 } else {
287 heim_dict_set_value(f, HSTR("anonymous"), heim_bool_create(0));
289 *sp = '\0';
290 heim_dict_set_value(t, HSTR("Flags"), o = heim_string_create(sp));
291 heim_release(e);
292 heim_release(f);
293 heim_release(t);
294 heim_release(o);
295 free(str);
298 static void
299 print_cred_verbose(krb5_context context, krb5_creds *cred)
301 size_t j;
302 char *str;
303 krb5_error_code ret;
304 krb5_timestamp sec;
306 krb5_timeofday (context, &sec);
308 ret = krb5_unparse_name(context, cred->server, &str);
309 if(ret)
310 exit(1);
311 printf(N_("Server: %s\n", ""), str);
312 free (str);
314 ret = krb5_unparse_name(context, cred->client, &str);
315 if(ret)
316 exit(1);
317 printf(N_("Client: %s\n", ""), str);
318 free (str);
320 if (krb5_is_config_principal(context, cred->server)) {
321 if (krb5_principal_get_num_comp(context, cred->server) > 1) {
322 const char *s;
324 /* If the payload is text and not secret/sensitive, print it */
325 s = krb5_principal_get_comp_string(context, cred->server, 1);
326 if (strcmp(s, "start_realm") == 0 ||
327 strcmp(s, "anon_pkinit_realm") == 0 ||
328 strcmp(s, "default-ntlm-domain") == 0 ||
329 strcmp(s, "FriendlyName") == 0 ||
330 strcmp(s, "fast_avail") == 0 ||
331 strcmp(s, "kx509store") == 0 ||
332 strcmp(s, "kx509_service_realm") == 0 ||
333 strcmp(s, "kx509_service_status") == 0)
334 printf(N_("Configuration item payload: %.*s\n", ""),
335 (int)cred->ticket.length,
336 (const char *)cred->ticket.data);
337 else
338 printf(N_("Configuration item payload length: %lu\n", ""),
339 (unsigned long)cred->ticket.length);
340 } /* else... this is a meaningless entry; nothing would create it */
341 } else {
342 Ticket t;
343 size_t len;
344 char *s;
346 decode_Ticket(cred->ticket.data, cred->ticket.length, &t, &len);
347 ret = krb5_enctype_to_string(context, t.enc_part.etype, &s);
348 printf(N_("Ticket etype: ", ""));
349 if (ret == 0) {
350 printf("%s", s);
351 free(s);
352 } else {
353 printf(N_("unknown-enctype(%d)", ""), t.enc_part.etype);
355 if(t.enc_part.kvno)
356 printf(N_(", kvno %d", ""), *t.enc_part.kvno);
357 printf("\n");
358 if(cred->session.keytype != t.enc_part.etype) {
359 ret = krb5_enctype_to_string(context, cred->session.keytype, &str);
360 if(ret)
361 krb5_warn(context, ret, "session keytype");
362 else {
363 printf(N_("Session key: %s\n", "enctype"), str);
364 free(str);
367 free_Ticket(&t);
368 printf(N_("Ticket length: %lu\n", ""),
369 (unsigned long)cred->ticket.length);
370 printf(N_("Auth time: %s\n", ""),
371 printable_time_long(cred->times.authtime));
372 if(cred->times.authtime != cred->times.starttime)
373 printf(N_("Start time: %s\n", ""),
374 printable_time_long(cred->times.starttime));
375 printf(N_("End time: %s", ""),
376 printable_time_long(cred->times.endtime));
377 if(sec > cred->times.endtime)
378 printf(N_(" (expired)", ""));
379 printf("\n");
380 if(cred->flags.b.renewable)
381 printf(N_("Renew till: %s\n", ""),
382 printable_time_long(cred->times.renew_till));
384 char flags[1024];
385 int result = unparse_flags(TicketFlags2int(cred->flags.b),
386 asn1_TicketFlags_units(),
387 flags, sizeof(flags));
388 if (result > 0) {
389 printf(N_("Ticket flags: %s\n", ""), flags);
392 printf(N_("Addresses: ", ""));
393 if (cred->addresses.len != 0) {
394 for(j = 0; j < cred->addresses.len; j++){
395 char buf[128];
396 if(j) printf(", ");
397 ret = krb5_print_address(&cred->addresses.val[j],
398 buf, sizeof(buf), &len);
400 if(ret == 0)
401 printf("%s", buf);
403 } else {
404 printf(N_("addressless", ""));
407 printf("\n\n");
410 static void
411 cache2json(krb5_context context,
412 krb5_ccache ccache,
413 krb5_principal principal,
414 heim_dict_t dict)
416 heim_array_t tix = heim_array_create();
417 heim_object_t o;
418 char *str, *fullname;
419 char *name = NULL;
420 krb5_error_code ret;
421 krb5_cc_cursor cursor;
422 krb5_creds creds;
423 krb5_deltat sec;
425 ret = krb5_unparse_name(context, principal, &str);
426 if (ret)
427 krb5_err(context, 1, ret, "krb5_unparse_name");
429 ret = krb5_cc_get_full_name(context, ccache, &fullname);
430 if (ret)
431 krb5_err(context, 1, ret, "krb5_cc_get_full_name");
433 heim_dict_set_value(dict, HSTR("cache"),
434 o = heim_string_create(fullname));
435 heim_release(o);
436 heim_dict_set_value(dict, HSTR("principal"),
437 o = heim_string_create(str));
438 heim_release(o);
439 heim_dict_set_value(dict, HSTR("cache_version"),
440 o = heim_number_create(krb5_cc_get_version(context,
441 ccache)));
442 heim_release(o);
443 free(str);
445 ret = krb5_cc_get_friendly_name(context, ccache, &name);
446 if (ret == 0) {
447 heim_dict_set_value(dict, HSTR("friendly_name"),
448 o = heim_string_create(name));
449 heim_release(o);
451 free(name);
453 ret = krb5_cc_get_kdc_offset(context, ccache, &sec);
454 if (ret == 0) {
455 heim_dict_set_value(dict, HSTR("kdc_offset"),
456 o = heim_number_create(sec));
457 heim_release(o);
460 heim_dict_set_value(dict, HSTR("tickets"), tix);
461 ret = krb5_cc_start_seq_get(context, ccache, &cursor);
462 if (ret)
463 krb5_err(context, 1, ret, "krb5_cc_start_seq_get");
465 while ((ret = krb5_cc_next_cred(context, ccache, &cursor, &creds)) == 0) {
466 cred2json(context, &creds, tix);
467 krb5_free_cred_contents(context, &creds);
469 if (ret != KRB5_CC_END)
470 krb5_err(context, 1, ret, "krb5_cc_get_next");
471 ret = krb5_cc_end_seq_get(context, ccache, &cursor);
472 if (ret)
473 krb5_err(context, 1, ret, "krb5_cc_end_seq_get");
474 heim_release(tix);
475 free(fullname);
479 * Print all tickets in `ccache' on stdout, verbosely if do_verbose.
482 static void
483 print_tickets(krb5_context context,
484 krb5_ccache ccache,
485 krb5_principal principal,
486 int do_verbose,
487 int do_flags,
488 int do_hidden)
490 char *str, *name, *fullname;
491 krb5_error_code ret;
492 krb5_cc_cursor cursor;
493 krb5_creds creds;
494 krb5_deltat sec;
495 rtbl_t ct = NULL;
497 ret = krb5_unparse_name (context, principal, &str);
498 if (ret)
499 krb5_err (context, 1, ret, "krb5_unparse_name");
501 ret = krb5_cc_get_full_name(context, ccache, &fullname);
502 if (ret)
503 krb5_err (context, 1, ret, "krb5_cc_get_full_name");
505 printf ("%17s: %s\n", N_("Credentials cache", ""), fullname);
506 printf ("%17s: %s\n", N_("Principal", ""), str);
508 ret = krb5_cc_get_friendly_name(context, ccache, &name);
509 if (ret == 0) {
510 if (strcmp(name, str) != 0) {
511 printf ("%17s: %s\n", N_("Friendly name", ""), name);
513 free(name);
516 if(do_verbose) {
517 printf ("%17s: %d\n", N_("Cache version", ""),
518 krb5_cc_get_version(context, ccache));
521 ret = krb5_cc_get_kdc_offset(context, ccache, &sec);
522 if (ret == 0) {
523 if (do_verbose && sec != 0) {
525 char buf[BUFSIZ];
526 int val;
527 int sig;
529 val = (int)sec;
530 sig = 1;
531 if (val < 0) {
532 sig = -1;
533 val = -val;
536 unparse_time (val, buf, sizeof(buf));
538 printf ("%17s: %s%s\n", N_("KDC time offset", ""),
539 sig == -1 ? "-" : "", buf);
542 printf("\n");
543 free(str);
545 ret = krb5_cc_start_seq_get (context, ccache, &cursor);
546 if (ret)
547 krb5_err(context, 1, ret, "krb5_cc_start_seq_get");
549 if (!do_verbose) {
550 ct = rtbl_create();
551 rtbl_add_column(ct, COL_ISSUED, 0);
552 rtbl_add_column(ct, COL_EXPIRES, 0);
553 if(do_flags)
554 rtbl_add_column(ct, COL_FLAGS, 0);
555 rtbl_add_column(ct, COL_PRINCIPAL, 0);
556 rtbl_set_separator(ct, " ");
558 while ((ret = krb5_cc_next_cred(context, ccache, &cursor, &creds)) == 0) {
559 if (!do_hidden && krb5_is_config_principal(context, creds.server)) {
561 } else if (do_verbose) {
562 print_cred_verbose(context, &creds);
563 } else {
564 print_cred(context, &creds, ct, do_flags);
566 krb5_free_cred_contents(context, &creds);
568 if (ret != KRB5_CC_END)
569 krb5_err(context, 1, ret, "krb5_cc_get_next");
570 ret = krb5_cc_end_seq_get (context, ccache, &cursor);
571 if (ret)
572 krb5_err(context, 1, ret, "krb5_cc_end_seq_get");
574 if(!do_verbose) {
575 rtbl_format(ct, stdout);
576 rtbl_destroy(ct);
578 free(fullname);
582 * Check if there's a tgt for the realm of `principal' and ccache and
583 * if so return 0, else 1
586 static int
587 check_expiration(krb5_context context,
588 krb5_ccache ccache,
589 time_t *expiration)
591 krb5_error_code ret;
592 time_t t;
594 ret = krb5_cc_get_lifetime(context, ccache, &t);
595 if (ret || t == 0)
596 return 1;
598 if (expiration)
599 *expiration = time(NULL) + t;
601 return 0;
605 * Print a list of all AFS tokens
608 #ifndef NO_AFS
610 static void
611 display_tokens(int do_verbose)
613 uint32_t i;
614 unsigned char t[4096];
615 struct ViceIoctl parms;
617 parms.in = (void *)&i;
618 parms.in_size = sizeof(i);
619 parms.out = (void *)t;
620 parms.out_size = sizeof(t);
622 for (i = 0;; i++) {
623 int32_t size_secret_tok, size_public_tok;
624 unsigned char *cell;
625 struct ClearToken ct;
626 unsigned char *r = t;
627 struct timeval tv;
628 char buf1[20], buf2[20];
630 if(k_pioctl(NULL, VIOCGETTOK, &parms, 0) < 0) {
631 if(errno == EDOM)
632 break;
633 continue;
635 if(parms.out_size > sizeof(t))
636 continue;
637 if(parms.out_size < sizeof(size_secret_tok))
638 continue;
639 t[min(parms.out_size,sizeof(t)-1)] = 0;
640 memcpy(&size_secret_tok, r, sizeof(size_secret_tok));
641 /* don't bother about the secret token */
642 r += size_secret_tok + sizeof(size_secret_tok);
643 if (parms.out_size < (r - t) + sizeof(size_public_tok))
644 continue;
645 memcpy(&size_public_tok, r, sizeof(size_public_tok));
646 r += sizeof(size_public_tok);
647 if (parms.out_size < (r - t) + size_public_tok + sizeof(int32_t))
648 continue;
649 memcpy(&ct, r, size_public_tok);
650 r += size_public_tok;
651 /* there is a int32_t with length of cellname, but we don't read it */
652 r += sizeof(int32_t);
653 cell = r;
655 gettimeofday (&tv, NULL);
656 strlcpy (buf1, printable_time(ct.BeginTimestamp),
657 sizeof(buf1));
658 if (do_verbose || tv.tv_sec < ct.EndTimestamp)
659 strlcpy (buf2, printable_time(ct.EndTimestamp),
660 sizeof(buf2));
661 else
662 strlcpy (buf2, N_(">>> Expired <<<", ""), sizeof(buf2));
664 printf("%s %s ", buf1, buf2);
666 if ((ct.EndTimestamp - ct.BeginTimestamp) & 1)
667 printf(N_("User's (AFS ID %d) tokens for %s", ""), ct.ViceId, cell);
668 else
669 printf(N_("Tokens for %s", ""), cell);
670 if (do_verbose)
671 printf(" (%d)", ct.AuthHandle);
672 putchar('\n');
675 #endif
678 * display the ccache in `cred_cache'
681 static int
682 display_v5_ccache(krb5_context context, krb5_ccache ccache,
683 int do_test, int do_verbose,
684 int do_flags, int do_hidden,
685 heim_dict_t dict)
687 krb5_error_code ret;
688 krb5_principal principal;
689 int exit_status = 0;
692 ret = krb5_cc_get_principal (context, ccache, &principal);
693 if (ret) {
694 if (dict)
695 return 0;
696 if(ret == ENOENT) {
697 if (!do_test)
698 krb5_warnx(context, N_("No ticket file: %s", ""),
699 krb5_cc_get_name(context, ccache));
700 return 1;
701 } else
702 krb5_err (context, 1, ret, "krb5_cc_get_principal");
704 exit_status = check_expiration(context, ccache, NULL);
705 if (!do_test) {
706 if (dict) {
707 heim_dict_set_value(dict, HSTR("expired"),
708 heim_bool_create(!!exit_status));
709 cache2json(context, ccache, principal, dict);
710 } else {
711 print_tickets(context, ccache, principal, do_verbose,
712 do_flags, do_hidden);
714 exit_status = 0;
717 ret = krb5_cc_close (context, ccache);
718 if (ret)
719 krb5_err (context, 1, ret, "krb5_cc_close");
721 krb5_free_principal (context, principal);
723 return exit_status;
726 static int
727 caches2json(krb5_context context)
729 krb5_cccol_cursor cursor;
730 const char *cdef_name = krb5_cc_default_name(context);
731 char *def_name;
732 heim_object_t o;
733 heim_array_t a = heim_array_create();
734 krb5_error_code ret;
735 krb5_ccache id;
737 if ((def_name = krb5_cccol_get_default_ccname(context)) == NULL)
738 cdef_name = krb5_cc_default_name(context);
739 if (!def_name && cdef_name && (def_name = strdup(cdef_name)) == NULL)
740 krb5_err(context, 1, ENOMEM, "Out of memory");
742 ret = krb5_cccol_cursor_new(context, &cursor);
743 if (ret == KRB5_CC_NOSUPP) {
744 free(def_name);
745 return 0;
747 else if (ret)
748 krb5_err (context, 1, ret, "krb5_cc_cache_get_first");
750 while (krb5_cccol_cursor_next(context, cursor, &id) == 0 && id != NULL) {
751 heim_dict_t dict = heim_dict_create(10);
752 int expired = 0;
753 char *name;
754 time_t t;
756 expired = check_expiration(context, id, &t);
757 ret = krb5_cc_get_friendly_name(context, id, &name);
758 if (ret == 0) {
759 char *fname;
761 heim_dict_set_value(dict, HSTR("Name"),
762 o = heim_string_create(name));
763 heim_release(o);
764 free(name);
766 if (expired)
767 o = heim_string_create(N_(">>> Expired <<<", ""));
768 else
769 o = heim_string_create(printable_time(t));
770 heim_dict_set_value(dict, HSTR("Expires"), o);
771 heim_release(o);
773 ret = krb5_cc_get_full_name(context, id, &fname);
774 if (ret)
775 krb5_err (context, 1, ret, "krb5_cc_get_full_name");
777 heim_dict_set_value(dict, HSTR("Cache Name"),
778 o = heim_string_create(fname));
779 heim_release(o);
781 if (def_name && strcmp(fname, def_name) == 0)
782 heim_dict_set_value(dict, HSTR("is_default_cache"),
783 heim_bool_create(1));
784 else
785 heim_dict_set_value(dict, HSTR("is_default_cache"),
786 heim_bool_create(0));
787 heim_array_append_value(a, dict);
788 heim_release(dict);
790 krb5_xfree(fname);
792 krb5_cc_close(context, id);
795 krb5_cccol_cursor_free(context, &cursor);
796 free(def_name);
798 o = heim_json_copy_serialize(a, HEIM_JSON_F_STRICT | HEIM_JSON_F_INDENT2,
799 NULL);
800 printf("%s", heim_string_get_utf8(o));
801 heim_release(a);
802 heim_release(o);
804 return 0;
811 static int
812 list_caches(krb5_context context, struct klist_options *opt)
814 krb5_cccol_cursor cursor;
815 const char *cdef_name = krb5_cc_default_name(context);
816 char *def_name;
817 krb5_error_code ret;
818 krb5_ccache id;
819 rtbl_t ct;
821 if ((def_name = krb5_cccol_get_default_ccname(context)) == NULL)
822 cdef_name = krb5_cc_default_name(context);
823 if (!def_name && cdef_name && (def_name = strdup(cdef_name)) == NULL)
824 krb5_err(context, 1, ENOMEM, "Out of memory");
826 ret = krb5_cccol_cursor_new(context, &cursor);
827 if (ret == KRB5_CC_NOSUPP) {
828 free(def_name);
829 return 0;
831 else if (ret)
832 krb5_err (context, 1, ret, "krb5_cc_cache_get_first");
834 ct = rtbl_create();
835 rtbl_add_column(ct, COL_DEFCACHE, 0);
836 rtbl_add_column(ct, COL_NAME, 0);
837 rtbl_add_column(ct, COL_CACHENAME, 0);
838 rtbl_add_column(ct, COL_EXPIRES, 0);
839 rtbl_add_column(ct, COL_DEFCACHE, 0);
840 rtbl_set_prefix(ct, " ");
841 rtbl_set_column_prefix(ct, COL_DEFCACHE, "");
842 rtbl_set_column_prefix(ct, COL_NAME, " ");
844 while (krb5_cccol_cursor_next(context, cursor, &id) == 0 && id != NULL) {
845 int expired = 0;
846 char *name;
847 time_t t;
849 expired = check_expiration(context, id, &t);
851 ret = krb5_cc_get_friendly_name(context, id, &name);
852 if (ret == 0) {
853 const char *str;
854 char *fname;
856 rtbl_add_column_entry(ct, COL_NAME, name);
857 free(name);
859 if (expired)
860 str = N_(">>> Expired <<<", "");
861 else
862 str = printable_time(t);
863 rtbl_add_column_entry(ct, COL_EXPIRES, str);
865 ret = krb5_cc_get_full_name(context, id, &fname);
866 if (ret)
867 krb5_err (context, 1, ret, "krb5_cc_get_full_name");
869 rtbl_add_column_entry(ct, COL_CACHENAME, fname);
870 if (def_name && strcmp(fname, def_name) == 0)
871 rtbl_add_column_entry(ct, COL_DEFCACHE, "*");
872 else
873 rtbl_add_column_entry(ct, COL_DEFCACHE, "");
875 krb5_xfree(fname);
877 krb5_cc_close(context, id);
880 krb5_cccol_cursor_free(context, &cursor);
882 free(def_name);
883 rtbl_format(ct, stdout);
884 rtbl_destroy(ct);
886 return 0;
894 klist(struct klist_options *opt, int argc, char **argv)
896 krb5_error_code ret;
897 heim_object_t o = NULL;
898 int exit_status = 0;
900 int do_verbose =
901 opt->verbose_flag ||
902 opt->a_flag ||
903 opt->n_flag;
904 int do_test =
905 opt->test_flag ||
906 opt->s_flag;
908 if(opt->version_flag) {
909 print_version(NULL);
910 exit(0);
913 if (opt->list_all_flag) {
914 if (opt->json_flag)
915 exit_status = caches2json(heimtools_context);
916 else
917 exit_status = list_caches(heimtools_context, opt);
918 return exit_status;
921 if (opt->v5_flag) {
922 krb5_ccache id;
924 if (opt->all_content_flag) {
925 heim_array_t a = opt->json_flag ? heim_array_create() : NULL;
926 krb5_cc_cache_cursor cursor;
928 ret = krb5_cc_cache_get_first(heimtools_context, NULL, &cursor);
929 if (ret)
930 krb5_err(heimtools_context, 1, ret, "krb5_cc_cache_get_first");
932 while (krb5_cc_cache_next(heimtools_context, cursor, &id) == 0) {
933 heim_dict_t dict = opt->json_flag ? heim_dict_create(10) : NULL;
935 exit_status |= display_v5_ccache(heimtools_context, id, do_test,
936 do_verbose, opt->flags_flag,
937 opt->hidden_flag,
938 dict);
939 if (a)
940 heim_array_append_value(a, dict);
941 heim_release(dict);
943 krb5_cc_cache_end_seq_get(heimtools_context, cursor);
944 o = a;
945 } else {
946 heim_dict_t dict = opt->json_flag ? heim_dict_create(10) : NULL;
947 if(opt->cache_string) {
948 ret = krb5_cc_resolve(heimtools_context, opt->cache_string, &id);
949 if (ret)
950 krb5_err(heimtools_context, 1, ret, "%s", opt->cache_string);
951 } else {
952 ret = krb5_cc_default(heimtools_context, &id);
953 if (ret)
954 krb5_err(heimtools_context, 1, ret, "krb5_cc_resolve");
956 exit_status = display_v5_ccache(heimtools_context, id, do_test,
957 do_verbose, opt->flags_flag,
958 opt->hidden_flag, dict);
959 o = dict;
963 if (o) {
964 heim_string_t s = heim_json_copy_serialize(o,
965 HEIM_JSON_F_STRICT |
966 HEIM_JSON_F_INDENT2,
967 NULL);
969 if (s == NULL)
970 errx(1, "Could not format JSON text");
972 printf("%s", heim_string_get_utf8(s));
973 heim_release(o);
974 heim_release(s);
977 if (!do_test) {
978 #ifndef NO_AFS
979 if (opt->tokens_flag && k_hasafs()) {
980 if (opt->v5_flag)
981 printf("\n");
982 display_tokens(opt->verbose_flag);
984 #endif
987 return exit_status;