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