1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* 3 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 4 * Use is subject to license terms. 5 */ 6 7 /* 8 * This module will parse the update logs on the primary or replica servers. 9 */ 10 11 #include "k5-int.h" 12 #include "k5-hex.h" 13 #include <locale.h> 14 #include <sys/types.h> 15 #include <sys/mman.h> 16 #include <time.h> 17 #include <limits.h> 18 #include <locale.h> 19 #include <syslog.h> 20 #include <kdb_log.h> 21 #include <kadm5/admin.h> 22 #include <adm_proto.h> 23 24 static char *progname; 25 26 static void 27 usage(void) 28 { 29 fprintf(stderr, _("\nUsage: %s [-h] [-v] [-v] [-e num]\n\t%s -R\n\n"), 30 progname, progname); 31 exit(1); 32 } 33 34 /* 35 * Print the attribute flags of principal in human readable form. 36 */ 37 static void 38 print_flags(unsigned int flags) 39 { 40 char **attrstrs, **sp; 41 42 if (krb5_flags_to_strings(flags, &attrstrs) != 0) { 43 printf("\t\t\t(error)\n"); 44 return; 45 } 46 for (sp = attrstrs; sp != NULL && *sp != NULL; sp++) { 47 printf("\t\t\t%s\n", *sp); 48 free(*sp); 49 } 50 free(attrstrs); 51 } 52 53 /* ctime() for uint32_t* */ 54 static const char * 55 ctime_uint32(uint32_t *time32) 56 { 57 time_t tmp; 58 const char *r; 59 60 tmp = *time32; 61 r = ctime(&tmp); 62 return (r == NULL) ? "(error)" : r; 63 } 64 65 /* Display time information. */ 66 static void 67 print_time(uint32_t *timep) 68 { 69 if (*timep == 0L) 70 printf("\t\t\tNone\n"); 71 else 72 printf("\t\t\t%s", ctime_uint32(timep)); 73 } 74 75 static void 76 print_deltat(uint32_t *deltat) 77 { 78 krb5_error_code ret; 79 static char buf[30]; 80 81 ret = krb5_deltat_to_string(*deltat, buf, sizeof(buf)); 82 if (ret) 83 printf("\t\t\t(error)\n"); 84 else 85 printf("\t\t\t%s\n", buf); 86 } 87 88 /* Display string in hex primitive. */ 89 static void 90 print_hex(const char *tag, utf8str_t *str) 91 { 92 unsigned int len; 93 char *hex; 94 95 len = str->utf8str_t_len; 96 97 if (k5_hex_encode(str->utf8str_t_val, len, FALSE, &hex) != 0) 98 abort(); 99 printf("\t\t\t%s(%d): 0x%s\n", tag, len, hex); 100 free(hex); 101 } 102 103 /* Display string primitive. */ 104 static void 105 print_str(const char *tag, utf8str_t *str) 106 { 107 krb5_error_code ret; 108 char *s; 109 110 s = k5memdup0(str->utf8str_t_val, str->utf8str_t_len, &ret); 111 if (s == NULL) { 112 fprintf(stderr, _("\nCouldn't allocate memory")); 113 exit(1); 114 } 115 printf("\t\t\t%s(%d): %s\n", tag, str->utf8str_t_len, s); 116 free(s); 117 } 118 119 /* Display data components. */ 120 static void 121 print_data(const char *tag, kdbe_data_t *data) 122 { 123 printf("\t\t\tmagic: 0x%x\n", data->k_magic); 124 print_str(tag, &data->k_data); 125 } 126 127 /* Display the principal components. */ 128 static void 129 print_princ(kdbe_princ_t *princ) 130 { 131 int i, len; 132 kdbe_data_t *data; 133 134 print_str("realm", &princ->k_realm); 135 136 len = princ->k_components.k_components_len; 137 data = princ->k_components.k_components_val; 138 for (i = 0; i < len; i++, data++) 139 print_data("princ", data); 140 } 141 142 /* Display individual key. */ 143 static void 144 print_key(kdbe_key_t *k) 145 { 146 unsigned int i; 147 utf8str_t *str; 148 149 printf("\t\t\tver: %d\n", k->k_ver); 150 printf("\t\t\tkvno: %d\n", k->k_kvno); 151 152 for (i = 0; i < k->k_enctype.k_enctype_len; i++) 153 printf("\t\t\tenc type: 0x%x\n", k->k_enctype.k_enctype_val[i]); 154 155 str = k->k_contents.k_contents_val; 156 for (i = 0; i < k->k_contents.k_contents_len; i++, str++) 157 print_hex("key", str); 158 } 159 160 /* Display all key data. */ 161 static void 162 print_keydata(kdbe_key_t *keys, unsigned int len) 163 { 164 unsigned int i; 165 166 for (i = 0; i < len; i++, keys++) 167 print_key(keys); 168 } 169 170 /* Display TL item. */ 171 static void 172 print_tl(kdbe_tl_t *tl) 173 { 174 int i, len; 175 176 printf("\t\t\ttype: 0x%x\n", tl->tl_type); 177 178 len = tl->tl_data.tl_data_len; 179 180 printf("\t\t\tvalue(%d): 0x", len); 181 for (i = 0; i < len; i++) 182 printf("%02x", (krb5_octet)tl->tl_data.tl_data_val[i]); 183 printf("\n"); 184 } 185 186 /* Display TL data items. */ 187 static void 188 print_tldata(kdbe_tl_t *tldata, int len) 189 { 190 int i; 191 192 printf("\t\t\titems: %d\n", len); 193 for (i = 0; i < len; i++, tldata++) 194 print_tl(tldata); 195 } 196 197 /* 198 * Print the individual types if verbose mode was specified. 199 * If verbose-verbose then print types along with respective values. 200 */ 201 static void 202 print_attr(kdbe_val_t *val, int vverbose) 203 { 204 switch (val->av_type) { 205 case AT_ATTRFLAGS: 206 printf(_("\t\tAttribute flags\n")); 207 if (vverbose) 208 print_flags(val->kdbe_val_t_u.av_attrflags); 209 break; 210 case AT_MAX_LIFE: 211 printf(_("\t\tMaximum ticket life\n")); 212 if (vverbose) 213 print_deltat(&val->kdbe_val_t_u.av_max_life); 214 break; 215 case AT_MAX_RENEW_LIFE: 216 printf(_("\t\tMaximum renewable life\n")); 217 if (vverbose) 218 print_deltat(&val->kdbe_val_t_u.av_max_renew_life); 219 break; 220 case AT_EXP: 221 printf(_("\t\tPrincipal expiration\n")); 222 if (vverbose) 223 print_time(&val->kdbe_val_t_u.av_exp); 224 break; 225 case AT_PW_EXP: 226 printf(_("\t\tPassword expiration\n")); 227 if (vverbose) 228 print_time(&val->kdbe_val_t_u.av_pw_exp); 229 break; 230 case AT_LAST_SUCCESS: 231 printf(_("\t\tLast successful auth\n")); 232 if (vverbose) 233 print_time(&val->kdbe_val_t_u.av_last_success); 234 break; 235 case AT_LAST_FAILED: 236 printf(_("\t\tLast failed auth\n")); 237 if (vverbose) 238 print_time(&val->kdbe_val_t_u.av_last_failed); 239 break; 240 case AT_FAIL_AUTH_COUNT: 241 printf(_("\t\tFailed passwd attempt\n")); 242 if (vverbose) 243 printf("\t\t\t%d\n", val->kdbe_val_t_u.av_fail_auth_count); 244 break; 245 case AT_PRINC: 246 printf(_("\t\tPrincipal\n")); 247 if (vverbose) 248 print_princ(&val->kdbe_val_t_u.av_princ); 249 break; 250 case AT_KEYDATA: 251 printf(_("\t\tKey data\n")); 252 if (vverbose) { 253 print_keydata(val->kdbe_val_t_u.av_keydata.av_keydata_val, 254 val->kdbe_val_t_u.av_keydata.av_keydata_len); 255 } 256 break; 257 case AT_TL_DATA: 258 printf(_("\t\tTL data\n")); 259 if (vverbose) { 260 print_tldata(val->kdbe_val_t_u.av_tldata.av_tldata_val, 261 val->kdbe_val_t_u.av_tldata.av_tldata_len); 262 } 263 break; 264 case AT_LEN: 265 printf(_("\t\tLength\n")); 266 if (vverbose) 267 printf("\t\t\t%d\n", val->kdbe_val_t_u.av_len); 268 break; 269 case AT_PW_LAST_CHANGE: 270 printf(_("\t\tPassword last changed\n")); 271 if (vverbose) 272 print_time(&val->kdbe_val_t_u.av_pw_last_change); 273 break; 274 case AT_MOD_PRINC: 275 printf(_("\t\tModifying principal\n")); 276 if (vverbose) 277 print_princ(&val->kdbe_val_t_u.av_mod_princ); 278 break; 279 case AT_MOD_TIME: 280 printf(_("\t\tModification time\n")); 281 if (vverbose) 282 print_time(&val->kdbe_val_t_u.av_mod_time); 283 break; 284 case AT_MOD_WHERE: 285 printf(_("\t\tModified where\n")); 286 if (vverbose) 287 print_str("where", &val->kdbe_val_t_u.av_mod_where); 288 break; 289 case AT_PW_POLICY: 290 printf(_("\t\tPassword policy\n")); 291 if (vverbose) 292 print_str("policy", &val->kdbe_val_t_u.av_pw_policy); 293 break; 294 case AT_PW_POLICY_SWITCH: 295 printf(_("\t\tPassword policy switch\n")); 296 if (vverbose) 297 printf("\t\t\t%d\n", val->kdbe_val_t_u.av_pw_policy_switch); 298 break; 299 case AT_PW_HIST_KVNO: 300 printf(_("\t\tPassword history KVNO\n")); 301 if (vverbose) 302 printf("\t\t\t%d\n", val->kdbe_val_t_u.av_pw_hist_kvno); 303 break; 304 case AT_PW_HIST: 305 printf(_("\t\tPassword history\n")); 306 if (vverbose) 307 printf("\t\t\tPW history elided\n"); 308 break; 309 } /* switch */ 310 311 } 312 /* 313 * Print the update entry information 314 */ 315 static void 316 print_update(kdb_hlog_t *ulog, uint32_t entry, uint32_t ulogentries, 317 unsigned int verbose) 318 { 319 XDR xdrs; 320 uint32_t start_sno, i, j, indx; 321 char *dbprinc; 322 kdb_ent_header_t *indx_log; 323 kdb_incr_update_t upd; 324 325 if (entry && (entry < ulog->kdb_num)) 326 start_sno = ulog->kdb_last_sno - entry; 327 else 328 start_sno = ulog->kdb_first_sno - 1; 329 330 for (i = start_sno; i < ulog->kdb_last_sno; i++) { 331 indx = i % ulogentries; 332 333 indx_log = ulog_index(ulog, indx); 334 335 /* 336 * Check for corrupt update entry 337 */ 338 if (indx_log->kdb_umagic != KDB_ULOG_MAGIC) { 339 fprintf(stderr, _("Corrupt update entry\n\n")); 340 exit(1); 341 } 342 343 printf("---\n"); 344 printf(_("Update Entry\n")); 345 346 printf(_("\tUpdate serial # : %u\n"), indx_log->kdb_entry_sno); 347 348 /* The initial entry after a reset is a dummy entry; skip it. */ 349 if (indx_log->kdb_entry_size == 0) { 350 printf(_("\tDummy entry\n")); 351 continue; 352 } 353 354 memset(&upd, 0, sizeof(kdb_incr_update_t)); 355 xdrmem_create(&xdrs, (char *)indx_log->entry_data, 356 indx_log->kdb_entry_size, XDR_DECODE); 357 if (!xdr_kdb_incr_update_t(&xdrs, &upd)) { 358 printf(_("Entry data decode failure\n\n")); 359 exit(1); 360 } 361 362 printf(_("\tUpdate operation : ")); 363 if (upd.kdb_deleted) 364 printf(_("Delete\n")); 365 else 366 printf(_("Add\n")); 367 368 dbprinc = malloc(upd.kdb_princ_name.utf8str_t_len + 1); 369 if (dbprinc == NULL) { 370 printf(_("Could not allocate principal name\n\n")); 371 exit(1); 372 } 373 strncpy(dbprinc, upd.kdb_princ_name.utf8str_t_val, 374 upd.kdb_princ_name.utf8str_t_len); 375 dbprinc[upd.kdb_princ_name.utf8str_t_len] = 0; 376 printf(_("\tUpdate principal : %s\n"), dbprinc); 377 378 printf(_("\tUpdate size : %u\n"), indx_log->kdb_entry_size); 379 printf(_("\tUpdate committed : %s\n"), 380 indx_log->kdb_commit ? "True" : "False"); 381 382 if (indx_log->kdb_time.seconds == 0L) { 383 printf(_("\tUpdate time stamp : None\n")); 384 } else{ 385 printf(_("\tUpdate time stamp : %s"), 386 ctime_uint32(&indx_log->kdb_time.seconds)); 387 } 388 389 printf(_("\tAttributes changed : %d\n"), upd.kdb_update.kdbe_t_len); 390 391 if (verbose) { 392 for (j = 0; j < upd.kdb_update.kdbe_t_len; j++) 393 print_attr(&upd.kdb_update.kdbe_t_val[j], verbose > 1 ? 1 : 0); 394 } 395 396 xdr_free((xdrproc_t)xdr_kdb_incr_update_t, (char *)&upd); 397 free(dbprinc); 398 } 399 } 400 401 /* Return a read-only mmap of the ulog, or NULL on failure. */ 402 static kdb_hlog_t * 403 map_ulog(const char *filename, int *fd_out) 404 { 405 int fd; 406 struct stat st; 407 kdb_hlog_t *ulog = MAP_FAILED; 408 409 *fd_out = -1; 410 411 fd = open(filename, O_RDONLY); 412 if (fd == -1) 413 return NULL; 414 if (fstat(fd, &st) < 0) { 415 close(fd); 416 return NULL; 417 } 418 ulog = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 419 if (ulog == MAP_FAILED) { 420 close(fd); 421 return NULL; 422 } 423 *fd_out = fd; 424 return ulog; 425 } 426 427 int 428 main(int argc, char **argv) 429 { 430 int c, ulog_fd = -1; 431 unsigned int verbose = 0; 432 bool_t headeronly = FALSE, reset = FALSE; 433 uint32_t entry = 0; 434 krb5_context context; 435 kadm5_config_params params; 436 kdb_hlog_t *ulog = NULL; 437 438 setlocale(LC_ALL, ""); 439 440 progname = argv[0]; 441 442 while ((c = getopt(argc, argv, "Rvhe:")) != -1) { 443 switch (c) { 444 case 'h': 445 headeronly = TRUE; 446 break; 447 case 'e': 448 entry = atoi(optarg); 449 break; 450 case 'R': 451 reset = TRUE; 452 break; 453 case 'v': 454 verbose++; 455 break; 456 default: 457 usage(); 458 } 459 } 460 461 if (kadm5_init_krb5_context(&context)) { 462 fprintf(stderr, _("Unable to initialize Kerberos\n\n")); 463 exit(1); 464 } 465 466 memset(¶ms, 0, sizeof(params)); 467 468 if (kadm5_get_config_params(context, 1, ¶ms, ¶ms)) { 469 fprintf(stderr, _("Couldn't read database_name\n\n")); 470 exit(1); 471 } 472 473 printf(_("\nKerberos update log (%s)\n"), params.iprop_logfile); 474 475 if (reset) { 476 if (ulog_map(context, params.iprop_logfile, params.iprop_ulogsize)) { 477 fprintf(stderr, _("Unable to map log file %s\n\n"), 478 params.iprop_logfile); 479 exit(1); 480 } 481 if (ulog_init_header(context) != 0) { 482 fprintf(stderr, _("Couldn't reinitialize ulog file %s\n\n"), 483 params.iprop_logfile); 484 exit(1); 485 } 486 printf(_("Reinitialized the ulog.\n")); 487 ulog_fini(context); 488 goto done; 489 } 490 491 ulog = map_ulog(params.iprop_logfile, &ulog_fd); 492 if (ulog == NULL) { 493 fprintf(stderr, _("Unable to map log file %s\n\n"), 494 params.iprop_logfile); 495 exit(1); 496 } 497 498 if (ulog->kdb_hmagic != KDB_ULOG_HDR_MAGIC) { 499 fprintf(stderr, _("Corrupt header log, exiting\n\n")); 500 exit(1); 501 } 502 503 printf(_("Update log dump :\n")); 504 printf(_("\tLog version # : %u\n"), ulog->db_version_num); 505 printf(_("\tLog state : ")); 506 switch (ulog->kdb_state) { 507 case KDB_STABLE: 508 printf(_("Stable\n")); 509 break; 510 case KDB_UNSTABLE: 511 printf(_("Unstable\n")); 512 break; 513 case KDB_CORRUPT: 514 printf(_("Corrupt\n")); 515 break; 516 default: 517 printf(_("Unknown state: %d\n"), ulog->kdb_state); 518 break; 519 } 520 printf(_("\tEntry block size : %u\n"), ulog->kdb_block); 521 printf(_("\tNumber of entries : %u\n"), ulog->kdb_num); 522 523 if (ulog->kdb_last_sno == 0) { 524 printf(_("\tLast serial # : None\n")); 525 } else { 526 if (ulog->kdb_first_sno == 0) { 527 printf(_("\tFirst serial # : None\n")); 528 } else { 529 printf(_("\tFirst serial # : ")); 530 printf("%u\n", ulog->kdb_first_sno); 531 } 532 533 printf(_("\tLast serial # : ")); 534 printf("%u\n", ulog->kdb_last_sno); 535 } 536 537 if (ulog->kdb_last_time.seconds == 0L) { 538 printf(_("\tLast time stamp : None\n")); 539 } else { 540 if (ulog->kdb_first_time.seconds == 0L) { 541 printf(_("\tFirst time stamp : None\n")); 542 } else { 543 printf(_("\tFirst time stamp : %s"), 544 ctime_uint32(&ulog->kdb_first_time.seconds)); 545 } 546 547 printf(_("\tLast time stamp : %s\n"), 548 ctime_uint32(&ulog->kdb_last_time.seconds)); 549 } 550 551 if (!headeronly && ulog->kdb_num) 552 print_update(ulog, entry, params.iprop_ulogsize, verbose); 553 554 printf("\n"); 555 556 done: 557 close(ulog_fd); 558 kadm5_free_config_params(context, ¶ms); 559 krb5_free_context(context); 560 return 0; 561 } 562