xref: /freebsd/crypto/krb5/src/kprop/kproplog.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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(&params, 0, sizeof(params));
467 
468     if (kadm5_get_config_params(context, 1, &params, &params)) {
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, &params);
559     krb5_free_context(context);
560     return 0;
561 }
562