klist.c revision 1.1.1.1
1/* $NetBSD: klist.c,v 1.1.1.1 2011/04/13 18:14:39 elric Exp $ */ 2 3/* 4 * Copyright (c) 1997-2008 Kungliga Tekniska H��gskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Portions Copyright (c) 2009 Apple Inc. All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * 3. Neither the name of the Institute nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 */ 37 38#include "kuser_locl.h" 39#include <krb5/rtbl.h> 40#include <krb5/parse_units.h> 41#include "kcc-commands.h" 42 43static char* 44printable_time(time_t t) 45{ 46 static char s[128]; 47 strlcpy(s, ctime(&t)+ 4, sizeof(s)); 48 s[15] = 0; 49 return s; 50} 51 52static char* 53printable_time_long(time_t t) 54{ 55 static char s[128]; 56 strlcpy(s, ctime(&t)+ 4, sizeof(s)); 57 s[20] = 0; 58 return s; 59} 60 61#define COL_ISSUED NP_(" Issued","") 62#define COL_EXPIRES NP_(" Expires", "") 63#define COL_FLAGS NP_("Flags", "") 64#define COL_NAME NP_(" Name", "") 65#define COL_PRINCIPAL NP_(" Principal", "in klist output") 66#define COL_PRINCIPAL_KVNO NP_(" Principal (kvno)", "in klist output") 67#define COL_CACHENAME NP_(" Cache name", "name in klist output") 68#define COL_DEFCACHE NP_("", "") 69 70static void 71print_cred(krb5_context context, krb5_creds *cred, rtbl_t ct, int do_flags) 72{ 73 char *str; 74 krb5_error_code ret; 75 krb5_timestamp sec; 76 77 krb5_timeofday (context, &sec); 78 79 80 if(cred->times.starttime) 81 rtbl_add_column_entry(ct, COL_ISSUED, 82 printable_time(cred->times.starttime)); 83 else 84 rtbl_add_column_entry(ct, COL_ISSUED, 85 printable_time(cred->times.authtime)); 86 87 if(cred->times.endtime > sec) 88 rtbl_add_column_entry(ct, COL_EXPIRES, 89 printable_time(cred->times.endtime)); 90 else 91 rtbl_add_column_entry(ct, COL_EXPIRES, N_(">>>Expired<<<", "")); 92 ret = krb5_unparse_name (context, cred->server, &str); 93 if (ret) 94 krb5_err(context, 1, ret, "krb5_unparse_name"); 95 rtbl_add_column_entry(ct, COL_PRINCIPAL, str); 96 if(do_flags) { 97 char s[16], *sp = s; 98 if(cred->flags.b.forwardable) 99 *sp++ = 'F'; 100 if(cred->flags.b.forwarded) 101 *sp++ = 'f'; 102 if(cred->flags.b.proxiable) 103 *sp++ = 'P'; 104 if(cred->flags.b.proxy) 105 *sp++ = 'p'; 106 if(cred->flags.b.may_postdate) 107 *sp++ = 'D'; 108 if(cred->flags.b.postdated) 109 *sp++ = 'd'; 110 if(cred->flags.b.renewable) 111 *sp++ = 'R'; 112 if(cred->flags.b.initial) 113 *sp++ = 'I'; 114 if(cred->flags.b.invalid) 115 *sp++ = 'i'; 116 if(cred->flags.b.pre_authent) 117 *sp++ = 'A'; 118 if(cred->flags.b.hw_authent) 119 *sp++ = 'H'; 120 *sp = '\0'; 121 rtbl_add_column_entry(ct, COL_FLAGS, s); 122 } 123 free(str); 124} 125 126static void 127print_cred_verbose(krb5_context context, krb5_creds *cred) 128{ 129 int j; 130 char *str; 131 krb5_error_code ret; 132 krb5_timestamp sec; 133 134 krb5_timeofday (context, &sec); 135 136 ret = krb5_unparse_name(context, cred->server, &str); 137 if(ret) 138 exit(1); 139 printf(N_("Server: %s\n", ""), str); 140 free (str); 141 142 ret = krb5_unparse_name(context, cred->client, &str); 143 if(ret) 144 exit(1); 145 printf(N_("Client: %s\n", ""), str); 146 free (str); 147 148 { 149 Ticket t; 150 size_t len; 151 char *s; 152 153 decode_Ticket(cred->ticket.data, cred->ticket.length, &t, &len); 154 ret = krb5_enctype_to_string(context, t.enc_part.etype, &s); 155 printf(N_("Ticket etype: ", "")); 156 if (ret == 0) { 157 printf("%s", s); 158 free(s); 159 } else { 160 printf(N_("unknown-enctype(%d)", ""), t.enc_part.etype); 161 } 162 if(t.enc_part.kvno) 163 printf(N_(", kvno %d", ""), *t.enc_part.kvno); 164 printf("\n"); 165 if(cred->session.keytype != t.enc_part.etype) { 166 ret = krb5_enctype_to_string(context, cred->session.keytype, &str); 167 if(ret) 168 krb5_warn(context, ret, "session keytype"); 169 else { 170 printf(N_("Session key: %s\n", "enctype"), str); 171 free(str); 172 } 173 } 174 free_Ticket(&t); 175 printf(N_("Ticket length: %lu\n", ""), 176 (unsigned long)cred->ticket.length); 177 } 178 printf(N_("Auth time: %s\n", ""), 179 printable_time_long(cred->times.authtime)); 180 if(cred->times.authtime != cred->times.starttime) 181 printf(N_("Start time: %s\n", ""), 182 printable_time_long(cred->times.starttime)); 183 printf(N_("End time: %s", ""), 184 printable_time_long(cred->times.endtime)); 185 if(sec > cred->times.endtime) 186 printf(N_(" (expired)", "")); 187 printf("\n"); 188 if(cred->flags.b.renewable) 189 printf(N_("Renew till: %s\n", ""), 190 printable_time_long(cred->times.renew_till)); 191 { 192 char flags[1024]; 193 unparse_flags(TicketFlags2int(cred->flags.b), 194 asn1_TicketFlags_units(), 195 flags, sizeof(flags)); 196 printf(N_("Ticket flags: %s\n", ""), flags); 197 } 198 printf(N_("Addresses: ", "")); 199 if (cred->addresses.len != 0) { 200 for(j = 0; j < cred->addresses.len; j++){ 201 char buf[128]; 202 size_t len; 203 if(j) printf(", "); 204 ret = krb5_print_address(&cred->addresses.val[j], 205 buf, sizeof(buf), &len); 206 207 if(ret == 0) 208 printf("%s", buf); 209 } 210 } else { 211 printf(N_("addressless", "")); 212 } 213 printf("\n\n"); 214} 215 216/* 217 * Print all tickets in `ccache' on stdout, verbosily iff do_verbose. 218 */ 219 220static void 221print_tickets (krb5_context context, 222 krb5_ccache ccache, 223 krb5_principal principal, 224 int do_verbose, 225 int do_flags, 226 int do_hidden) 227{ 228 krb5_error_code ret; 229 char *str, *name; 230 krb5_cc_cursor cursor; 231 krb5_creds creds; 232 krb5_deltat sec; 233 234 rtbl_t ct = NULL; 235 236 ret = krb5_unparse_name (context, principal, &str); 237 if (ret) 238 krb5_err (context, 1, ret, "krb5_unparse_name"); 239 240 printf ("%17s: %s:%s\n", 241 N_("Credentials cache", ""), 242 krb5_cc_get_type(context, ccache), 243 krb5_cc_get_name(context, ccache)); 244 printf ("%17s: %s\n", N_("Principal", ""), str); 245 246 ret = krb5_cc_get_friendly_name(context, ccache, &name); 247 if (ret == 0) { 248 if (strcmp(name, str) != 0) 249 printf ("%17s: %s\n", N_("Friendly name", ""), name); 250 free(name); 251 } 252 free (str); 253 254 if(do_verbose) { 255 printf ("%17s: %d\n", N_("Cache version", ""), 256 krb5_cc_get_version(context, ccache)); 257 } else { 258 krb5_cc_set_flags(context, ccache, KRB5_TC_NOTICKET); 259 } 260 261 ret = krb5_cc_get_kdc_offset(context, ccache, &sec); 262 263 if (ret == 0 && do_verbose && sec != 0) { 264 char buf[BUFSIZ]; 265 int val; 266 int sig; 267 268 val = sec; 269 sig = 1; 270 if (val < 0) { 271 sig = -1; 272 val = -val; 273 } 274 275 unparse_time (val, buf, sizeof(buf)); 276 277 printf ("%17s: %s%s\n", N_("KDC time offset", ""), 278 sig == -1 ? "-" : "", buf); 279 } 280 281 printf("\n"); 282 283 ret = krb5_cc_start_seq_get (context, ccache, &cursor); 284 if (ret) 285 krb5_err(context, 1, ret, "krb5_cc_start_seq_get"); 286 287 if(!do_verbose) { 288 ct = rtbl_create(); 289 rtbl_add_column(ct, COL_ISSUED, 0); 290 rtbl_add_column(ct, COL_EXPIRES, 0); 291 if(do_flags) 292 rtbl_add_column(ct, COL_FLAGS, 0); 293 rtbl_add_column(ct, COL_PRINCIPAL, 0); 294 rtbl_set_separator(ct, " "); 295 } 296 while ((ret = krb5_cc_next_cred (context, 297 ccache, 298 &cursor, 299 &creds)) == 0) { 300 if (!do_hidden && krb5_is_config_principal(context, creds.server)) { 301 ; 302 }else if(do_verbose){ 303 print_cred_verbose(context, &creds); 304 }else{ 305 print_cred(context, &creds, ct, do_flags); 306 } 307 krb5_free_cred_contents (context, &creds); 308 } 309 if(ret != KRB5_CC_END) 310 krb5_err(context, 1, ret, "krb5_cc_get_next"); 311 ret = krb5_cc_end_seq_get (context, ccache, &cursor); 312 if (ret) 313 krb5_err (context, 1, ret, "krb5_cc_end_seq_get"); 314 if(!do_verbose) { 315 rtbl_format(ct, stdout); 316 rtbl_destroy(ct); 317 } 318} 319 320/* 321 * Check if there's a tgt for the realm of `principal' and ccache and 322 * if so return 0, else 1 323 */ 324 325static int 326check_for_tgt (krb5_context context, 327 krb5_ccache ccache, 328 krb5_principal principal, 329 time_t *expiration) 330{ 331 krb5_error_code ret; 332 krb5_creds pattern; 333 krb5_creds creds; 334 krb5_const_realm client_realm; 335 int expired; 336 337 krb5_cc_clear_mcred(&pattern); 338 339 client_realm = krb5_principal_get_realm(context, principal); 340 341 ret = krb5_make_principal (context, &pattern.server, 342 client_realm, KRB5_TGS_NAME, client_realm, NULL); 343 if (ret) 344 krb5_err (context, 1, ret, "krb5_make_principal"); 345 pattern.client = principal; 346 347 ret = krb5_cc_retrieve_cred (context, ccache, 0, &pattern, &creds); 348 krb5_free_principal (context, pattern.server); 349 if (ret) { 350 if (ret == KRB5_CC_END) 351 return 1; 352 krb5_err (context, 1, ret, "krb5_cc_retrieve_cred"); 353 } 354 355 expired = time(NULL) > creds.times.endtime; 356 357 if (expiration) 358 *expiration = creds.times.endtime; 359 360 krb5_free_cred_contents (context, &creds); 361 362 return expired; 363} 364 365/* 366 * Print a list of all AFS tokens 367 */ 368 369#ifndef NO_AFS 370 371static void 372display_tokens(int do_verbose) 373{ 374 uint32_t i; 375 unsigned char t[4096]; 376 struct ViceIoctl parms; 377 378 parms.in = (void *)&i; 379 parms.in_size = sizeof(i); 380 parms.out = (void *)t; 381 parms.out_size = sizeof(t); 382 383 for (i = 0;; i++) { 384 int32_t size_secret_tok, size_public_tok; 385 unsigned char *cell; 386 struct ClearToken ct; 387 unsigned char *r = t; 388 struct timeval tv; 389 char buf1[20], buf2[20]; 390 391 if(k_pioctl(NULL, VIOCGETTOK, &parms, 0) < 0) { 392 if(errno == EDOM) 393 break; 394 continue; 395 } 396 if(parms.out_size > sizeof(t)) 397 continue; 398 if(parms.out_size < sizeof(size_secret_tok)) 399 continue; 400 t[min(parms.out_size,sizeof(t)-1)] = 0; 401 memcpy(&size_secret_tok, r, sizeof(size_secret_tok)); 402 /* dont bother about the secret token */ 403 r += size_secret_tok + sizeof(size_secret_tok); 404 if (parms.out_size < (r - t) + sizeof(size_public_tok)) 405 continue; 406 memcpy(&size_public_tok, r, sizeof(size_public_tok)); 407 r += sizeof(size_public_tok); 408 if (parms.out_size < (r - t) + size_public_tok + sizeof(int32_t)) 409 continue; 410 memcpy(&ct, r, size_public_tok); 411 r += size_public_tok; 412 /* there is a int32_t with length of cellname, but we dont read it */ 413 r += sizeof(int32_t); 414 cell = r; 415 416 gettimeofday (&tv, NULL); 417 strlcpy (buf1, printable_time(ct.BeginTimestamp), 418 sizeof(buf1)); 419 if (do_verbose || tv.tv_sec < ct.EndTimestamp) 420 strlcpy (buf2, printable_time(ct.EndTimestamp), 421 sizeof(buf2)); 422 else 423 strlcpy (buf2, N_(">>> Expired <<<", ""), sizeof(buf2)); 424 425 printf("%s %s ", buf1, buf2); 426 427 if ((ct.EndTimestamp - ct.BeginTimestamp) & 1) 428 printf(N_("User's (AFS ID %d) tokens for %s", ""), ct.ViceId, cell); 429 else 430 printf(N_("Tokens for %s", ""), cell); 431 if (do_verbose) 432 printf(" (%d)", ct.AuthHandle); 433 putchar('\n'); 434 } 435} 436#endif 437 438/* 439 * display the ccache in `cred_cache' 440 */ 441 442static int 443display_v5_ccache (krb5_context context, krb5_ccache ccache, 444 int do_test, int do_verbose, 445 int do_flags, int do_hidden) 446{ 447 krb5_error_code ret; 448 krb5_principal principal; 449 int exit_status = 0; 450 451 452 ret = krb5_cc_get_principal (context, ccache, &principal); 453 if (ret) { 454 if(ret == ENOENT) { 455 if (!do_test) 456 krb5_warnx(context, N_("No ticket file: %s", ""), 457 krb5_cc_get_name(context, ccache)); 458 return 1; 459 } else 460 krb5_err (context, 1, ret, "krb5_cc_get_principal"); 461 } 462 if (do_test) 463 exit_status = check_for_tgt (context, ccache, principal, NULL); 464 else 465 print_tickets (context, ccache, principal, do_verbose, 466 do_flags, do_hidden); 467 468 ret = krb5_cc_close (context, ccache); 469 if (ret) 470 krb5_err (context, 1, ret, "krb5_cc_close"); 471 472 krb5_free_principal (context, principal); 473 474 return exit_status; 475} 476 477/* 478 * 479 */ 480 481static int 482list_caches(krb5_context context) 483{ 484 krb5_cc_cache_cursor cursor; 485 const char *cdef_name; 486 char *def_name; 487 krb5_error_code ret; 488 krb5_ccache id; 489 rtbl_t ct; 490 491 cdef_name = krb5_cc_default_name(context); 492 if (cdef_name == NULL) 493 krb5_errx(context, 1, "krb5_cc_default_name"); 494 def_name = strdup(cdef_name); 495 496 ret = krb5_cc_cache_get_first (context, NULL, &cursor); 497 if (ret == KRB5_CC_NOSUPP) 498 return 0; 499 else if (ret) 500 krb5_err (context, 1, ret, "krb5_cc_cache_get_first"); 501 502 ct = rtbl_create(); 503 rtbl_add_column(ct, COL_NAME, 0); 504 rtbl_add_column(ct, COL_CACHENAME, 0); 505 rtbl_add_column(ct, COL_EXPIRES, 0); 506 rtbl_add_column(ct, COL_DEFCACHE, 0); 507 rtbl_set_prefix(ct, " "); 508 rtbl_set_column_prefix(ct, COL_NAME, ""); 509 510 while (krb5_cc_cache_next (context, cursor, &id) == 0) { 511 krb5_principal principal = NULL; 512 int expired = 0; 513 char *name; 514 time_t t; 515 516 ret = krb5_cc_get_principal(context, id, &principal); 517 if (ret) 518 continue; 519 520 expired = check_for_tgt (context, id, principal, &t); 521 522 ret = krb5_cc_get_friendly_name(context, id, &name); 523 if (ret == 0) { 524 const char *str; 525 char *fname; 526 rtbl_add_column_entry(ct, COL_NAME, name); 527 rtbl_add_column_entry(ct, COL_CACHENAME, 528 krb5_cc_get_name(context, id)); 529 if (expired) 530 str = N_(">>> Expired <<<", ""); 531 else 532 str = printable_time(t); 533 rtbl_add_column_entry(ct, COL_EXPIRES, str); 534 free(name); 535 536 ret = krb5_cc_get_full_name(context, id, &fname); 537 if (ret) 538 krb5_err (context, 1, ret, "krb5_cc_get_full_name"); 539 540 if (strcmp(fname, def_name) == 0) 541 rtbl_add_column_entry(ct, COL_DEFCACHE, "*"); 542 else 543 rtbl_add_column_entry(ct, COL_DEFCACHE, ""); 544 545 krb5_xfree(fname); 546 } 547 krb5_cc_close(context, id); 548 549 krb5_free_principal(context, principal); 550 } 551 552 krb5_cc_cache_end_seq_get(context, cursor); 553 554 free(def_name); 555 rtbl_format(ct, stdout); 556 rtbl_destroy(ct); 557 558 return 0; 559} 560 561/* 562 * 563 */ 564 565int 566klist(struct klist_options *opt, int argc, char **argv) 567{ 568 krb5_error_code ret; 569 int exit_status = 0; 570 571 int do_verbose = 572 opt->verbose_flag || 573 opt->a_flag || 574 opt->n_flag; 575 int do_test = 576 opt->test_flag || 577 opt->s_flag; 578 579 if (opt->list_all_flag) { 580 exit_status = list_caches(kcc_context); 581 return exit_status; 582 } 583 584 if (opt->v5_flag) { 585 krb5_ccache id; 586 587 if (opt->all_content_flag) { 588 krb5_cc_cache_cursor cursor; 589 590 ret = krb5_cc_cache_get_first(kcc_context, NULL, &cursor); 591 if (ret) 592 krb5_err(kcc_context, 1, ret, "krb5_cc_cache_get_first"); 593 594 595 while (krb5_cc_cache_next(kcc_context, cursor, &id) == 0) { 596 exit_status |= display_v5_ccache(kcc_context, id, do_test, 597 do_verbose, opt->flags_flag, 598 opt->hidden_flag); 599 printf("\n\n"); 600 } 601 krb5_cc_cache_end_seq_get(kcc_context, cursor); 602 603 } else { 604 if(opt->cache_string) { 605 ret = krb5_cc_resolve(kcc_context, opt->cache_string, &id); 606 if (ret) 607 krb5_err(kcc_context, 1, ret, "%s", opt->cache_string); 608 } else { 609 ret = krb5_cc_default(kcc_context, &id); 610 if (ret) 611 krb5_err(kcc_context, 1, ret, "krb5_cc_resolve"); 612 } 613 exit_status = display_v5_ccache(kcc_context, id, do_test, 614 do_verbose, opt->flags_flag, 615 opt->hidden_flag); 616 } 617 } 618 619 if (!do_test) { 620#ifndef NO_AFS 621 if (opt->tokens_flag && k_hasafs()) { 622 if (opt->v5_flag) 623 printf("\n"); 624 display_tokens(opt->verbose_flag); 625 } 626#endif 627 } 628 629 return exit_status; 630} 631