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
usage()27 usage()
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
print_flags(unsigned int flags)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 *
ctime_uint32(uint32_t * time32)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
print_time(uint32_t * timep)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
print_deltat(uint32_t * deltat)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
print_hex(const char * tag,utf8str_t * str)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
print_str(const char * tag,utf8str_t * str)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
print_data(const char * tag,kdbe_data_t * data)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
print_princ(kdbe_princ_t * princ)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
print_key(kdbe_key_t * k)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
print_keydata(kdbe_key_t * keys,unsigned int len)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
print_tl(kdbe_tl_t * tl)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
print_tldata(kdbe_tl_t * tldata,int len)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
print_attr(kdbe_val_t * val,int vverbose)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
print_update(kdb_hlog_t * ulog,uint32_t entry,uint32_t ulogentries,unsigned int verbose)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 = 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(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 *
map_ulog(const char * filename,int * fd_out)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
main(int argc,char ** argv)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