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