xref: /freebsd/crypto/krb5/src/kadmin/dbutil/tabdump.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1*7f2fe78bSCy Schubert /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2*7f2fe78bSCy Schubert /* kdc/tabdump.c - reporting-friendly tabular KDB dumps */
3*7f2fe78bSCy Schubert /*
4*7f2fe78bSCy Schubert  * Copyright (C) 2015 by the Massachusetts Institute of Technology.
5*7f2fe78bSCy Schubert  * All rights reserved.
6*7f2fe78bSCy Schubert  *
7*7f2fe78bSCy Schubert  * Redistribution and use in source and binary forms, with or without
8*7f2fe78bSCy Schubert  * modification, are permitted provided that the following conditions
9*7f2fe78bSCy Schubert  * are met:
10*7f2fe78bSCy Schubert  *
11*7f2fe78bSCy Schubert  * * Redistributions of source code must retain the above copyright
12*7f2fe78bSCy Schubert  *   notice, this list of conditions and the following disclaimer.
13*7f2fe78bSCy Schubert  *
14*7f2fe78bSCy Schubert  * * Redistributions in binary form must reproduce the above copyright
15*7f2fe78bSCy Schubert  *   notice, this list of conditions and the following disclaimer in
16*7f2fe78bSCy Schubert  *   the documentation and/or other materials provided with the
17*7f2fe78bSCy Schubert  *   distribution.
18*7f2fe78bSCy Schubert  *
19*7f2fe78bSCy Schubert  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20*7f2fe78bSCy Schubert  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21*7f2fe78bSCy Schubert  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22*7f2fe78bSCy Schubert  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23*7f2fe78bSCy Schubert  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24*7f2fe78bSCy Schubert  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25*7f2fe78bSCy Schubert  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26*7f2fe78bSCy Schubert  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27*7f2fe78bSCy Schubert  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28*7f2fe78bSCy Schubert  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29*7f2fe78bSCy Schubert  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30*7f2fe78bSCy Schubert  * OF THE POSSIBILITY OF SUCH DAMAGE.
31*7f2fe78bSCy Schubert  */
32*7f2fe78bSCy Schubert 
33*7f2fe78bSCy Schubert #include <k5-int.h>
34*7f2fe78bSCy Schubert #include "k5-platform.h"        /* for asprintf */
35*7f2fe78bSCy Schubert #include "k5-hex.h"
36*7f2fe78bSCy Schubert 
37*7f2fe78bSCy Schubert #include <limits.h>
38*7f2fe78bSCy Schubert #include <stdio.h>
39*7f2fe78bSCy Schubert #include <string.h>
40*7f2fe78bSCy Schubert #include <unistd.h>
41*7f2fe78bSCy Schubert 
42*7f2fe78bSCy Schubert #include <kadm5/admin.h>
43*7f2fe78bSCy Schubert #include <kadm5/server_internal.h>
44*7f2fe78bSCy Schubert 
45*7f2fe78bSCy Schubert #include "adm_proto.h"
46*7f2fe78bSCy Schubert #include "kdb5_util.h"
47*7f2fe78bSCy Schubert #include "tdumputil.h"
48*7f2fe78bSCy Schubert 
49*7f2fe78bSCy Schubert struct tdopts {
50*7f2fe78bSCy Schubert     int csv;                    /* 1 for CSV, 0 for tab-separated */
51*7f2fe78bSCy Schubert     int emptyhex_empty;         /* print empty hex strings as "" not "-1" */
52*7f2fe78bSCy Schubert     int numeric;                /* numeric instead of symbolic output */
53*7f2fe78bSCy Schubert     int omitheader;             /* omit field headers */
54*7f2fe78bSCy Schubert     int writerectype;           /* write record type prefix */
55*7f2fe78bSCy Schubert     char *fname;                /* output file name */
56*7f2fe78bSCy Schubert };
57*7f2fe78bSCy Schubert 
58*7f2fe78bSCy Schubert struct rec_args;
59*7f2fe78bSCy Schubert 
60*7f2fe78bSCy Schubert typedef int (tdump_princ_fn)(struct rec_args *, const char *, krb5_db_entry *);
61*7f2fe78bSCy Schubert typedef int (tdump_policy_fn)(struct rec_args *, const char *,
62*7f2fe78bSCy Schubert                               kadm5_policy_ent_t);
63*7f2fe78bSCy Schubert 
64*7f2fe78bSCy Schubert /* Descriptor for a tabdump record type */
65*7f2fe78bSCy Schubert struct tdtype {
66*7f2fe78bSCy Schubert     const char *rectype;
67*7f2fe78bSCy Schubert     char * const *fieldnames;
68*7f2fe78bSCy Schubert     tdump_princ_fn *princ_fn;
69*7f2fe78bSCy Schubert     tdump_policy_fn *policy_fn;
70*7f2fe78bSCy Schubert };
71*7f2fe78bSCy Schubert 
72*7f2fe78bSCy Schubert static tdump_princ_fn keydata;
73*7f2fe78bSCy Schubert static tdump_princ_fn keyinfo;
74*7f2fe78bSCy Schubert static tdump_princ_fn princ_flags;
75*7f2fe78bSCy Schubert static tdump_princ_fn princ_lockout;
76*7f2fe78bSCy Schubert static tdump_princ_fn princ_meta;
77*7f2fe78bSCy Schubert static tdump_princ_fn princ_stringattrs;
78*7f2fe78bSCy Schubert static tdump_princ_fn princ_tktpolicy;
79*7f2fe78bSCy Schubert 
80*7f2fe78bSCy Schubert static char * const keydata_fields[] = {
81*7f2fe78bSCy Schubert     "name", "keyindex", "kvno", "enctype", "key", "salttype", "salt", NULL
82*7f2fe78bSCy Schubert };
83*7f2fe78bSCy Schubert static char * const keyinfo_fields[] = {
84*7f2fe78bSCy Schubert     "name", "keyindex", "kvno", "enctype", "salttype", "salt", NULL
85*7f2fe78bSCy Schubert };
86*7f2fe78bSCy Schubert static char * const princ_flags_fields[] = {
87*7f2fe78bSCy Schubert     "name", "flag", "value", NULL
88*7f2fe78bSCy Schubert };
89*7f2fe78bSCy Schubert static char * const princ_lockout_fields[] = {
90*7f2fe78bSCy Schubert     "name", "last_success", "last_failed", "fail_count", NULL
91*7f2fe78bSCy Schubert };
92*7f2fe78bSCy Schubert static char * const princ_meta_fields[] = {
93*7f2fe78bSCy Schubert     "name", "modby", "modtime", "lastpwd", "policy", "mkvno", "hist_kvno", NULL
94*7f2fe78bSCy Schubert };
95*7f2fe78bSCy Schubert static char * const princ_stringattrs_fields[] = {
96*7f2fe78bSCy Schubert     "name", "key", "value", NULL
97*7f2fe78bSCy Schubert };
98*7f2fe78bSCy Schubert static char * const princ_tktpolicy_fields[] = {
99*7f2fe78bSCy Schubert     "name", "expiration", "pw_expiration", "max_life", "max_renew_life", NULL
100*7f2fe78bSCy Schubert };
101*7f2fe78bSCy Schubert 
102*7f2fe78bSCy Schubert /* Lookup table for tabdump record types */
103*7f2fe78bSCy Schubert static struct tdtype tdtypes[] = {
104*7f2fe78bSCy Schubert     {"keydata", keydata_fields, keydata, NULL},
105*7f2fe78bSCy Schubert     {"keyinfo", keyinfo_fields, keyinfo, NULL},
106*7f2fe78bSCy Schubert     {"princ_flags", princ_flags_fields, princ_flags, NULL},
107*7f2fe78bSCy Schubert     {"princ_lockout", princ_lockout_fields, princ_lockout, NULL},
108*7f2fe78bSCy Schubert     {"princ_meta", princ_meta_fields, princ_meta, NULL},
109*7f2fe78bSCy Schubert     {"princ_stringattrs", princ_stringattrs_fields, princ_stringattrs, NULL},
110*7f2fe78bSCy Schubert     {"princ_tktpolicy", princ_tktpolicy_fields, princ_tktpolicy, NULL},
111*7f2fe78bSCy Schubert };
112*7f2fe78bSCy Schubert #define NTDTYPES (sizeof(tdtypes)/sizeof(tdtypes[0]))
113*7f2fe78bSCy Schubert 
114*7f2fe78bSCy Schubert /* State to pass to KDB iterator */
115*7f2fe78bSCy Schubert struct rec_args {
116*7f2fe78bSCy Schubert     FILE *f;
117*7f2fe78bSCy Schubert     struct tdtype *tdtype;
118*7f2fe78bSCy Schubert     struct rechandle *rh;
119*7f2fe78bSCy Schubert     struct tdopts *opts;
120*7f2fe78bSCy Schubert };
121*7f2fe78bSCy Schubert 
122*7f2fe78bSCy Schubert /* Decode the KADM_DATA from a DB entry.*/
123*7f2fe78bSCy Schubert static int
get_adb(krb5_db_entry * dbe,osa_princ_ent_rec * adb)124*7f2fe78bSCy Schubert get_adb(krb5_db_entry *dbe, osa_princ_ent_rec *adb)
125*7f2fe78bSCy Schubert {
126*7f2fe78bSCy Schubert     XDR xdrs;
127*7f2fe78bSCy Schubert     int success;
128*7f2fe78bSCy Schubert     krb5_tl_data tl_data;
129*7f2fe78bSCy Schubert     krb5_error_code ret;
130*7f2fe78bSCy Schubert 
131*7f2fe78bSCy Schubert     memset(adb, 0, sizeof(*adb));
132*7f2fe78bSCy Schubert     tl_data.tl_data_type = KRB5_TL_KADM_DATA;
133*7f2fe78bSCy Schubert     ret = krb5_dbe_lookup_tl_data(util_context, dbe, &tl_data);
134*7f2fe78bSCy Schubert     if (ret != 0 || tl_data.tl_data_length == 0)
135*7f2fe78bSCy Schubert         return 0;
136*7f2fe78bSCy Schubert     xdrmem_create(&xdrs, (caddr_t)tl_data.tl_data_contents,
137*7f2fe78bSCy Schubert                   tl_data.tl_data_length, XDR_DECODE);
138*7f2fe78bSCy Schubert     success = xdr_osa_princ_ent_rec(&xdrs, adb);
139*7f2fe78bSCy Schubert     xdr_destroy(&xdrs);
140*7f2fe78bSCy Schubert     return success;
141*7f2fe78bSCy Schubert }
142*7f2fe78bSCy Schubert 
143*7f2fe78bSCy Schubert /* Write a date field as an ISO 8601 UTC date/time representation. */
144*7f2fe78bSCy Schubert static int
write_date_iso(struct rec_args * args,krb5_timestamp when)145*7f2fe78bSCy Schubert write_date_iso(struct rec_args *args, krb5_timestamp when)
146*7f2fe78bSCy Schubert {
147*7f2fe78bSCy Schubert     char buf[64];
148*7f2fe78bSCy Schubert     time_t t;
149*7f2fe78bSCy Schubert     struct tm *tm = NULL;
150*7f2fe78bSCy Schubert     struct rechandle *h = args->rh;
151*7f2fe78bSCy Schubert 
152*7f2fe78bSCy Schubert     t = ts2tt(when);
153*7f2fe78bSCy Schubert     tm = gmtime(&t);
154*7f2fe78bSCy Schubert     if (tm == NULL) {
155*7f2fe78bSCy Schubert         errno = EINVAL;
156*7f2fe78bSCy Schubert         return -1;
157*7f2fe78bSCy Schubert     }
158*7f2fe78bSCy Schubert     if (strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%SZ", tm) == 0) {
159*7f2fe78bSCy Schubert         errno = EINVAL;
160*7f2fe78bSCy Schubert         return -1;
161*7f2fe78bSCy Schubert     }
162*7f2fe78bSCy Schubert     if (writefield(h, "%s", buf) < 0)
163*7f2fe78bSCy Schubert         return -1;
164*7f2fe78bSCy Schubert     return 0;
165*7f2fe78bSCy Schubert }
166*7f2fe78bSCy Schubert 
167*7f2fe78bSCy Schubert /* Write a date field, optionally as a decimal POSIX timestamp. */
168*7f2fe78bSCy Schubert static int
write_date(struct rec_args * args,krb5_timestamp when)169*7f2fe78bSCy Schubert write_date(struct rec_args *args, krb5_timestamp when)
170*7f2fe78bSCy Schubert {
171*7f2fe78bSCy Schubert     struct tdopts *opts = args->opts;
172*7f2fe78bSCy Schubert     struct rechandle *h = args->rh;
173*7f2fe78bSCy Schubert 
174*7f2fe78bSCy Schubert     if (opts->numeric)
175*7f2fe78bSCy Schubert         return writefield(h, "%d", when);
176*7f2fe78bSCy Schubert 
177*7f2fe78bSCy Schubert     return write_date_iso(args, when);
178*7f2fe78bSCy Schubert }
179*7f2fe78bSCy Schubert 
180*7f2fe78bSCy Schubert /* Write an enctype field, optionally as decimal. */
181*7f2fe78bSCy Schubert static krb5_error_code
write_enctype(struct rec_args * args,krb5_int16 etype)182*7f2fe78bSCy Schubert write_enctype(struct rec_args *args, krb5_int16 etype)
183*7f2fe78bSCy Schubert {
184*7f2fe78bSCy Schubert     char buf[256];
185*7f2fe78bSCy Schubert     krb5_error_code ret;
186*7f2fe78bSCy Schubert     struct rechandle *h = args->rh;
187*7f2fe78bSCy Schubert     struct tdopts *opts = args->opts;
188*7f2fe78bSCy Schubert 
189*7f2fe78bSCy Schubert     if (!opts->numeric) {
190*7f2fe78bSCy Schubert         ret = krb5_enctype_to_name(etype, 0, buf, sizeof(buf));
191*7f2fe78bSCy Schubert         if (ret == 0) {
192*7f2fe78bSCy Schubert             if (writefield(h, "%s", buf) < 0)
193*7f2fe78bSCy Schubert                 return errno;
194*7f2fe78bSCy Schubert             return ret;
195*7f2fe78bSCy Schubert         }
196*7f2fe78bSCy Schubert     }
197*7f2fe78bSCy Schubert     /* decimal if requested, or if conversion failed */
198*7f2fe78bSCy Schubert     if (writefield(h, "%d", etype) < 0)
199*7f2fe78bSCy Schubert         return errno;
200*7f2fe78bSCy Schubert     return 0;
201*7f2fe78bSCy Schubert }
202*7f2fe78bSCy Schubert 
203*7f2fe78bSCy Schubert /* Write a salttype field, optionally as decimal. */
204*7f2fe78bSCy Schubert static krb5_error_code
write_salttype(struct rec_args * args,krb5_int16 salttype)205*7f2fe78bSCy Schubert write_salttype(struct rec_args *args, krb5_int16 salttype)
206*7f2fe78bSCy Schubert {
207*7f2fe78bSCy Schubert     char buf[256];
208*7f2fe78bSCy Schubert     krb5_error_code ret;
209*7f2fe78bSCy Schubert     struct rechandle *h = args->rh;
210*7f2fe78bSCy Schubert     struct tdopts *opts = args->opts;
211*7f2fe78bSCy Schubert 
212*7f2fe78bSCy Schubert     if (!opts->numeric) {
213*7f2fe78bSCy Schubert         ret = krb5_salttype_to_string(salttype, buf, sizeof(buf));
214*7f2fe78bSCy Schubert         if (ret == 0) {
215*7f2fe78bSCy Schubert             if (writefield(h, "%s", buf) < 0)
216*7f2fe78bSCy Schubert                 return errno;
217*7f2fe78bSCy Schubert             return ret;
218*7f2fe78bSCy Schubert         }
219*7f2fe78bSCy Schubert     }
220*7f2fe78bSCy Schubert     /* decimal if requested, or if conversion failed */
221*7f2fe78bSCy Schubert     if (writefield(h, "%d", salttype) < 0)
222*7f2fe78bSCy Schubert         return errno;
223*7f2fe78bSCy Schubert     return 0;
224*7f2fe78bSCy Schubert }
225*7f2fe78bSCy Schubert 
226*7f2fe78bSCy Schubert /*
227*7f2fe78bSCy Schubert  * Write a field of bytes from krb5_data as a hexadecimal string.  Write empty
228*7f2fe78bSCy Schubert  * strings as "-1" unless requested.
229*7f2fe78bSCy Schubert  */
230*7f2fe78bSCy Schubert static int
write_data(struct rec_args * args,krb5_data * data)231*7f2fe78bSCy Schubert write_data(struct rec_args *args, krb5_data *data)
232*7f2fe78bSCy Schubert {
233*7f2fe78bSCy Schubert     int ret;
234*7f2fe78bSCy Schubert     char *hex;
235*7f2fe78bSCy Schubert     struct rechandle *h = args->rh;
236*7f2fe78bSCy Schubert     struct tdopts *opts = args->opts;
237*7f2fe78bSCy Schubert 
238*7f2fe78bSCy Schubert     if (data->length == 0 && !opts->emptyhex_empty) {
239*7f2fe78bSCy Schubert         if (writefield(h, "-1") < 0)
240*7f2fe78bSCy Schubert             return -1;
241*7f2fe78bSCy Schubert         return 0;
242*7f2fe78bSCy Schubert     }
243*7f2fe78bSCy Schubert 
244*7f2fe78bSCy Schubert     ret = k5_hex_encode(data->data, data->length, FALSE, &hex);
245*7f2fe78bSCy Schubert     if (ret) {
246*7f2fe78bSCy Schubert         errno = ret;
247*7f2fe78bSCy Schubert         return -1;
248*7f2fe78bSCy Schubert     }
249*7f2fe78bSCy Schubert 
250*7f2fe78bSCy Schubert     ret = writefield(h, "%s", hex);
251*7f2fe78bSCy Schubert     free(hex);
252*7f2fe78bSCy Schubert     return ret;
253*7f2fe78bSCy Schubert }
254*7f2fe78bSCy Schubert 
255*7f2fe78bSCy Schubert /* Write a single record of a keydata/keyinfo key set. */
256*7f2fe78bSCy Schubert static krb5_error_code
keyinfo_rec(struct rec_args * args,const char * name,int i,krb5_key_data * kd,int dumpkeys)257*7f2fe78bSCy Schubert keyinfo_rec(struct rec_args *args, const char *name, int i, krb5_key_data *kd,
258*7f2fe78bSCy Schubert             int dumpkeys)
259*7f2fe78bSCy Schubert {
260*7f2fe78bSCy Schubert     int ret;
261*7f2fe78bSCy Schubert     krb5_data data;
262*7f2fe78bSCy Schubert     struct rechandle *h = args->rh;
263*7f2fe78bSCy Schubert 
264*7f2fe78bSCy Schubert     if (startrec(h) < 0)
265*7f2fe78bSCy Schubert         return errno;
266*7f2fe78bSCy Schubert     if (writefield(h, "%s", name) < 0)
267*7f2fe78bSCy Schubert         return errno;
268*7f2fe78bSCy Schubert     if (writefield(h, "%d", i) < 0)
269*7f2fe78bSCy Schubert         return errno;
270*7f2fe78bSCy Schubert     if (writefield(h, "%d", kd->key_data_kvno) < 0)
271*7f2fe78bSCy Schubert         return errno;
272*7f2fe78bSCy Schubert     if (write_enctype(args, kd->key_data_type[0]) < 0)
273*7f2fe78bSCy Schubert         return errno;
274*7f2fe78bSCy Schubert     if (dumpkeys) {
275*7f2fe78bSCy Schubert         data.length = kd->key_data_length[0];
276*7f2fe78bSCy Schubert         data.data = (void *)kd->key_data_contents[0];
277*7f2fe78bSCy Schubert         if (write_data(args, &data) < 0)
278*7f2fe78bSCy Schubert             return errno;
279*7f2fe78bSCy Schubert     }
280*7f2fe78bSCy Schubert     ret = write_salttype(args, kd->key_data_type[1]);
281*7f2fe78bSCy Schubert     if (ret)
282*7f2fe78bSCy Schubert         return ret;
283*7f2fe78bSCy Schubert     data.length = kd->key_data_length[1];
284*7f2fe78bSCy Schubert     data.data = (void *)kd->key_data_contents[1];
285*7f2fe78bSCy Schubert     if (write_data(args, &data) < 0)
286*7f2fe78bSCy Schubert         return errno;
287*7f2fe78bSCy Schubert     if (endrec(h) < 0)
288*7f2fe78bSCy Schubert         return errno;
289*7f2fe78bSCy Schubert     return 0;
290*7f2fe78bSCy Schubert }
291*7f2fe78bSCy Schubert 
292*7f2fe78bSCy Schubert /* Write out a principal's key set, optionally including actual key data. */
293*7f2fe78bSCy Schubert static krb5_error_code
keyinfo_common(struct rec_args * args,const char * name,krb5_db_entry * entry,int dumpkeys)294*7f2fe78bSCy Schubert keyinfo_common(struct rec_args *args, const char *name, krb5_db_entry *entry,
295*7f2fe78bSCy Schubert                int dumpkeys)
296*7f2fe78bSCy Schubert {
297*7f2fe78bSCy Schubert     krb5_error_code ret;
298*7f2fe78bSCy Schubert     krb5_key_data kd;
299*7f2fe78bSCy Schubert     int i;
300*7f2fe78bSCy Schubert 
301*7f2fe78bSCy Schubert     for (i = 0; i < entry->n_key_data; i++) {
302*7f2fe78bSCy Schubert         kd = entry->key_data[i];
303*7f2fe78bSCy Schubert         /* missing salt data -> normal salt */
304*7f2fe78bSCy Schubert         if (kd.key_data_ver == 1) {
305*7f2fe78bSCy Schubert             kd.key_data_ver = 2;
306*7f2fe78bSCy Schubert             kd.key_data_type[1] = KRB5_KDB_SALTTYPE_NORMAL;
307*7f2fe78bSCy Schubert             kd.key_data_length[1] = 0;
308*7f2fe78bSCy Schubert             kd.key_data_contents[1] = NULL;
309*7f2fe78bSCy Schubert         }
310*7f2fe78bSCy Schubert         ret = keyinfo_rec(args, name, i, &kd, dumpkeys);
311*7f2fe78bSCy Schubert         if (ret)
312*7f2fe78bSCy Schubert             return ret;
313*7f2fe78bSCy Schubert     }
314*7f2fe78bSCy Schubert     return 0;
315*7f2fe78bSCy Schubert }
316*7f2fe78bSCy Schubert 
317*7f2fe78bSCy Schubert /* Write a principal's key data. */
318*7f2fe78bSCy Schubert static krb5_error_code
keydata(struct rec_args * args,const char * name,krb5_db_entry * dbe)319*7f2fe78bSCy Schubert keydata(struct rec_args *args, const char *name, krb5_db_entry *dbe)
320*7f2fe78bSCy Schubert {
321*7f2fe78bSCy Schubert     return keyinfo_common(args, name, dbe, 1);
322*7f2fe78bSCy Schubert }
323*7f2fe78bSCy Schubert 
324*7f2fe78bSCy Schubert /* Write a principal's key info (suppressing actual key data). */
325*7f2fe78bSCy Schubert static krb5_error_code
keyinfo(struct rec_args * args,const char * name,krb5_db_entry * dbe)326*7f2fe78bSCy Schubert keyinfo(struct rec_args *args, const char *name, krb5_db_entry *dbe)
327*7f2fe78bSCy Schubert {
328*7f2fe78bSCy Schubert     return keyinfo_common(args, name, dbe, 0);
329*7f2fe78bSCy Schubert }
330*7f2fe78bSCy Schubert 
331*7f2fe78bSCy Schubert /* Write a record corresponding to a single principal flag setting. */
332*7f2fe78bSCy Schubert static krb5_error_code
princflag_rec(struct rechandle * h,const char * name,const char * flagname,int set)333*7f2fe78bSCy Schubert princflag_rec(struct rechandle *h, const char *name, const char *flagname,
334*7f2fe78bSCy Schubert               int set)
335*7f2fe78bSCy Schubert {
336*7f2fe78bSCy Schubert     if (startrec(h) < 0)
337*7f2fe78bSCy Schubert         return errno;
338*7f2fe78bSCy Schubert     if (writefield(h, "%s", name) < 0)
339*7f2fe78bSCy Schubert         return errno;
340*7f2fe78bSCy Schubert     if (writefield(h, "%s", flagname) < 0)
341*7f2fe78bSCy Schubert         return errno;
342*7f2fe78bSCy Schubert     if (writefield(h, "%d", set) < 0)
343*7f2fe78bSCy Schubert         return errno;
344*7f2fe78bSCy Schubert     if (endrec(h) < 0)
345*7f2fe78bSCy Schubert         return errno;
346*7f2fe78bSCy Schubert     return 0;
347*7f2fe78bSCy Schubert }
348*7f2fe78bSCy Schubert 
349*7f2fe78bSCy Schubert /* Write a principal's flag settings. */
350*7f2fe78bSCy Schubert static krb5_error_code
princ_flags(struct rec_args * args,const char * name,krb5_db_entry * dbe)351*7f2fe78bSCy Schubert princ_flags(struct rec_args *args, const char *name, krb5_db_entry *dbe)
352*7f2fe78bSCy Schubert {
353*7f2fe78bSCy Schubert     int i;
354*7f2fe78bSCy Schubert     char *s = NULL;
355*7f2fe78bSCy Schubert     krb5_flags flags = dbe->attributes;
356*7f2fe78bSCy Schubert     krb5_error_code ret;
357*7f2fe78bSCy Schubert     struct tdopts *opts = args->opts;
358*7f2fe78bSCy Schubert     struct rechandle *h = args->rh;
359*7f2fe78bSCy Schubert 
360*7f2fe78bSCy Schubert     for (i = 0; i < 32; i++) {
361*7f2fe78bSCy Schubert         if (opts->numeric) {
362*7f2fe78bSCy Schubert             if (asprintf(&s, "0x%08lx", 1UL << i) == -1)
363*7f2fe78bSCy Schubert                 return ENOMEM;
364*7f2fe78bSCy Schubert         } else {
365*7f2fe78bSCy Schubert             ret = krb5_flagnum_to_string(i, &s);
366*7f2fe78bSCy Schubert             if (ret)
367*7f2fe78bSCy Schubert                 return ret;
368*7f2fe78bSCy Schubert             /* Don't print unknown flags if they're not set and numeric output
369*7f2fe78bSCy Schubert              * isn't requested. */
370*7f2fe78bSCy Schubert             if (!(flags & (1UL << i)) && strncmp(s, "0x", 2) == 0) {
371*7f2fe78bSCy Schubert                 free(s);
372*7f2fe78bSCy Schubert                 continue;
373*7f2fe78bSCy Schubert             }
374*7f2fe78bSCy Schubert         }
375*7f2fe78bSCy Schubert         ret = princflag_rec(h, name, s, ((flags & (1UL << i)) != 0));
376*7f2fe78bSCy Schubert         free(s);
377*7f2fe78bSCy Schubert         if (ret)
378*7f2fe78bSCy Schubert             return ret;
379*7f2fe78bSCy Schubert     }
380*7f2fe78bSCy Schubert     return 0;
381*7f2fe78bSCy Schubert }
382*7f2fe78bSCy Schubert 
383*7f2fe78bSCy Schubert /* Write a principal's lockout data. */
384*7f2fe78bSCy Schubert static krb5_error_code
princ_lockout(struct rec_args * args,const char * name,krb5_db_entry * dbe)385*7f2fe78bSCy Schubert princ_lockout(struct rec_args *args, const char *name, krb5_db_entry *dbe)
386*7f2fe78bSCy Schubert {
387*7f2fe78bSCy Schubert     struct rechandle *h = args->rh;
388*7f2fe78bSCy Schubert 
389*7f2fe78bSCy Schubert     if (startrec(h) < 0)
390*7f2fe78bSCy Schubert         return errno;
391*7f2fe78bSCy Schubert     if (writefield(h, "%s", name) < 0)
392*7f2fe78bSCy Schubert         return errno;
393*7f2fe78bSCy Schubert     if (write_date(args, dbe->last_success) < 0)
394*7f2fe78bSCy Schubert         return errno;
395*7f2fe78bSCy Schubert     if (write_date(args, dbe->last_failed) < 0)
396*7f2fe78bSCy Schubert         return errno;
397*7f2fe78bSCy Schubert     if (writefield(h, "%d", dbe->fail_auth_count) < 0)
398*7f2fe78bSCy Schubert         return errno;
399*7f2fe78bSCy Schubert     if (endrec(h) < 0)
400*7f2fe78bSCy Schubert         return errno;
401*7f2fe78bSCy Schubert     return 0;
402*7f2fe78bSCy Schubert }
403*7f2fe78bSCy Schubert 
404*7f2fe78bSCy Schubert /* Write a principal's metadata. */
405*7f2fe78bSCy Schubert static krb5_error_code
princ_meta(struct rec_args * args,const char * name,krb5_db_entry * dbe)406*7f2fe78bSCy Schubert princ_meta(struct rec_args *args, const char *name, krb5_db_entry *dbe)
407*7f2fe78bSCy Schubert {
408*7f2fe78bSCy Schubert     int got_adb = 0;
409*7f2fe78bSCy Schubert     char *modby;
410*7f2fe78bSCy Schubert     krb5_kvno mkvno;
411*7f2fe78bSCy Schubert     const char *policy;
412*7f2fe78bSCy Schubert     krb5_principal mod_princ = NULL;
413*7f2fe78bSCy Schubert     krb5_timestamp mod_time, last_pwd;
414*7f2fe78bSCy Schubert     krb5_error_code ret;
415*7f2fe78bSCy Schubert     osa_princ_ent_rec adb;
416*7f2fe78bSCy Schubert     struct rechandle *h = args->rh;
417*7f2fe78bSCy Schubert 
418*7f2fe78bSCy Schubert     memset(&adb, 0, sizeof(adb));
419*7f2fe78bSCy Schubert     if (startrec(h) < 0)
420*7f2fe78bSCy Schubert         return errno;
421*7f2fe78bSCy Schubert     if (writefield(h, "%s", name) < 0)
422*7f2fe78bSCy Schubert         return errno;
423*7f2fe78bSCy Schubert 
424*7f2fe78bSCy Schubert     ret = krb5_dbe_lookup_last_pwd_change(util_context, dbe, &last_pwd);
425*7f2fe78bSCy Schubert     if (ret)
426*7f2fe78bSCy Schubert         return ret;
427*7f2fe78bSCy Schubert     ret = krb5_dbe_get_mkvno(util_context, dbe, &mkvno);
428*7f2fe78bSCy Schubert     if (ret)
429*7f2fe78bSCy Schubert         return ret;
430*7f2fe78bSCy Schubert 
431*7f2fe78bSCy Schubert     ret = krb5_dbe_lookup_mod_princ_data(util_context, dbe, &mod_time,
432*7f2fe78bSCy Schubert                                          &mod_princ);
433*7f2fe78bSCy Schubert     if (ret)
434*7f2fe78bSCy Schubert         return ret;
435*7f2fe78bSCy Schubert     ret = krb5_unparse_name(util_context, mod_princ, &modby);
436*7f2fe78bSCy Schubert     krb5_free_principal(util_context, mod_princ);
437*7f2fe78bSCy Schubert     if (ret)
438*7f2fe78bSCy Schubert         return ret;
439*7f2fe78bSCy Schubert     ret = writefield(h, "%s", modby);
440*7f2fe78bSCy Schubert     krb5_free_unparsed_name(util_context, modby);
441*7f2fe78bSCy Schubert     if (ret < 0)
442*7f2fe78bSCy Schubert         return errno;
443*7f2fe78bSCy Schubert 
444*7f2fe78bSCy Schubert     if (write_date(args, mod_time) < 0)
445*7f2fe78bSCy Schubert         return errno;
446*7f2fe78bSCy Schubert     if (write_date(args, last_pwd) < 0)
447*7f2fe78bSCy Schubert         return errno;
448*7f2fe78bSCy Schubert 
449*7f2fe78bSCy Schubert     got_adb = get_adb(dbe, &adb);
450*7f2fe78bSCy Schubert     if (got_adb && adb.policy != NULL)
451*7f2fe78bSCy Schubert         policy = adb.policy;
452*7f2fe78bSCy Schubert     else
453*7f2fe78bSCy Schubert         policy = "";
454*7f2fe78bSCy Schubert     ret = writefield(h, "%s", policy);
455*7f2fe78bSCy Schubert     if (ret < 0) {
456*7f2fe78bSCy Schubert         ret = errno;
457*7f2fe78bSCy Schubert         goto cleanup;
458*7f2fe78bSCy Schubert     }
459*7f2fe78bSCy Schubert     if (writefield(h, "%d", mkvno) < 0) {
460*7f2fe78bSCy Schubert         ret = errno;
461*7f2fe78bSCy Schubert         goto cleanup;
462*7f2fe78bSCy Schubert     }
463*7f2fe78bSCy Schubert     if (writefield(h, "%d", adb.admin_history_kvno) < 0) {
464*7f2fe78bSCy Schubert         ret = errno;
465*7f2fe78bSCy Schubert         goto cleanup;
466*7f2fe78bSCy Schubert     }
467*7f2fe78bSCy Schubert     if (endrec(h) < 0)
468*7f2fe78bSCy Schubert         ret = errno;
469*7f2fe78bSCy Schubert     else
470*7f2fe78bSCy Schubert         ret = 0;
471*7f2fe78bSCy Schubert 
472*7f2fe78bSCy Schubert cleanup:
473*7f2fe78bSCy Schubert     kdb_free_entry(NULL, NULL, &adb);
474*7f2fe78bSCy Schubert     return ret;
475*7f2fe78bSCy Schubert }
476*7f2fe78bSCy Schubert 
477*7f2fe78bSCy Schubert /* Write a principal's string attributes. */
478*7f2fe78bSCy Schubert static krb5_error_code
princ_stringattrs(struct rec_args * args,const char * name,krb5_db_entry * dbe)479*7f2fe78bSCy Schubert princ_stringattrs(struct rec_args *args, const char *name, krb5_db_entry *dbe)
480*7f2fe78bSCy Schubert {
481*7f2fe78bSCy Schubert     int i, nattrs;
482*7f2fe78bSCy Schubert     krb5_error_code ret;
483*7f2fe78bSCy Schubert     krb5_string_attr *attrs;
484*7f2fe78bSCy Schubert     struct rechandle *h = args->rh;
485*7f2fe78bSCy Schubert 
486*7f2fe78bSCy Schubert     ret = krb5_dbe_get_strings(util_context, dbe, &attrs, &nattrs);
487*7f2fe78bSCy Schubert     if (ret)
488*7f2fe78bSCy Schubert         return ret;
489*7f2fe78bSCy Schubert     for (i = 0; i < nattrs; i++) {
490*7f2fe78bSCy Schubert         if (startrec(h) < 0) {
491*7f2fe78bSCy Schubert             ret = errno;
492*7f2fe78bSCy Schubert             goto cleanup;
493*7f2fe78bSCy Schubert         }
494*7f2fe78bSCy Schubert         if (writefield(h, "%s", name) < 0) {
495*7f2fe78bSCy Schubert             ret = errno;
496*7f2fe78bSCy Schubert             goto cleanup;
497*7f2fe78bSCy Schubert         }
498*7f2fe78bSCy Schubert         if (writefield(h, "%s", attrs[i].key) < 0) {
499*7f2fe78bSCy Schubert             ret = errno;
500*7f2fe78bSCy Schubert             goto cleanup;
501*7f2fe78bSCy Schubert         }
502*7f2fe78bSCy Schubert         if (writefield(h, "%s", attrs[i].value) < 0) {
503*7f2fe78bSCy Schubert             ret = errno;
504*7f2fe78bSCy Schubert             goto cleanup;
505*7f2fe78bSCy Schubert         }
506*7f2fe78bSCy Schubert         if (endrec(h) < 0) {
507*7f2fe78bSCy Schubert             ret = errno;
508*7f2fe78bSCy Schubert             goto cleanup;
509*7f2fe78bSCy Schubert         }
510*7f2fe78bSCy Schubert     }
511*7f2fe78bSCy Schubert cleanup:
512*7f2fe78bSCy Schubert     krb5_dbe_free_strings(util_context, attrs, nattrs);
513*7f2fe78bSCy Schubert     return ret;
514*7f2fe78bSCy Schubert }
515*7f2fe78bSCy Schubert 
516*7f2fe78bSCy Schubert /* Write a principal's ticket policy. */
517*7f2fe78bSCy Schubert static krb5_error_code
princ_tktpolicy(struct rec_args * args,const char * name,krb5_db_entry * dbe)518*7f2fe78bSCy Schubert princ_tktpolicy(struct rec_args *args, const char *name, krb5_db_entry *dbe)
519*7f2fe78bSCy Schubert {
520*7f2fe78bSCy Schubert     struct rechandle *h = args->rh;
521*7f2fe78bSCy Schubert 
522*7f2fe78bSCy Schubert     if (startrec(h) < 0)
523*7f2fe78bSCy Schubert         return errno;
524*7f2fe78bSCy Schubert     if (writefield(h, "%s", name) < 0)
525*7f2fe78bSCy Schubert         return errno;
526*7f2fe78bSCy Schubert     if (write_date(args, dbe->expiration) < 0)
527*7f2fe78bSCy Schubert         return errno;
528*7f2fe78bSCy Schubert     if (write_date(args, dbe->pw_expiration) < 0)
529*7f2fe78bSCy Schubert         return errno;
530*7f2fe78bSCy Schubert     if (writefield(h, "%d", dbe->max_life) < 0)
531*7f2fe78bSCy Schubert         return errno;
532*7f2fe78bSCy Schubert     if (writefield(h, "%d", dbe->max_renewable_life) < 0)
533*7f2fe78bSCy Schubert         return errno;
534*7f2fe78bSCy Schubert     if (endrec(h) < 0)
535*7f2fe78bSCy Schubert         return errno;
536*7f2fe78bSCy Schubert     return 0;
537*7f2fe78bSCy Schubert }
538*7f2fe78bSCy Schubert 
539*7f2fe78bSCy Schubert /* Iterator function for krb5_db_iterate() */
540*7f2fe78bSCy Schubert static krb5_error_code
tditer(void * ptr,krb5_db_entry * entry)541*7f2fe78bSCy Schubert tditer(void *ptr, krb5_db_entry *entry)
542*7f2fe78bSCy Schubert {
543*7f2fe78bSCy Schubert     krb5_error_code ret;
544*7f2fe78bSCy Schubert     struct rec_args *args = ptr;
545*7f2fe78bSCy Schubert     char *name;
546*7f2fe78bSCy Schubert 
547*7f2fe78bSCy Schubert     ret = krb5_unparse_name(util_context, entry->princ, &name);
548*7f2fe78bSCy Schubert     if (ret) {
549*7f2fe78bSCy Schubert         com_err(progname, ret, _("while unparsing principal name"));
550*7f2fe78bSCy Schubert         return ret;
551*7f2fe78bSCy Schubert     }
552*7f2fe78bSCy Schubert     ret = args->tdtype->princ_fn(args, name, entry);
553*7f2fe78bSCy Schubert     krb5_free_unparsed_name(util_context, name);
554*7f2fe78bSCy Schubert     if (ret)
555*7f2fe78bSCy Schubert         return ret;
556*7f2fe78bSCy Schubert     return 0;
557*7f2fe78bSCy Schubert }
558*7f2fe78bSCy Schubert 
559*7f2fe78bSCy Schubert /* Set up state structure for the iterator. */
560*7f2fe78bSCy Schubert static krb5_error_code
setup_args(struct rec_args * args,struct tdtype * tdtype,struct tdopts * opts)561*7f2fe78bSCy Schubert setup_args(struct rec_args *args, struct tdtype *tdtype,
562*7f2fe78bSCy Schubert              struct tdopts *opts)
563*7f2fe78bSCy Schubert {
564*7f2fe78bSCy Schubert     FILE *f = NULL;
565*7f2fe78bSCy Schubert     const char *rectype = NULL;
566*7f2fe78bSCy Schubert     struct rechandle *rh;
567*7f2fe78bSCy Schubert 
568*7f2fe78bSCy Schubert     args->tdtype = tdtype;
569*7f2fe78bSCy Schubert     args->opts = opts;
570*7f2fe78bSCy Schubert     if (opts->fname != NULL && strcmp(opts->fname, "-") != 0) {
571*7f2fe78bSCy Schubert         f = fopen(opts->fname, "w");
572*7f2fe78bSCy Schubert         if (f == NULL) {
573*7f2fe78bSCy Schubert             com_err(progname, errno, _("opening %s for writing"),
574*7f2fe78bSCy Schubert                     opts->fname);
575*7f2fe78bSCy Schubert             return errno;
576*7f2fe78bSCy Schubert         }
577*7f2fe78bSCy Schubert         args->f = f;
578*7f2fe78bSCy Schubert     } else {
579*7f2fe78bSCy Schubert         f = stdout;
580*7f2fe78bSCy Schubert         args->f = NULL;
581*7f2fe78bSCy Schubert     }
582*7f2fe78bSCy Schubert     if (opts->writerectype)
583*7f2fe78bSCy Schubert         rectype = tdtype->rectype;
584*7f2fe78bSCy Schubert     if (opts->csv)
585*7f2fe78bSCy Schubert         rh = rechandle_csv(f, rectype);
586*7f2fe78bSCy Schubert     else
587*7f2fe78bSCy Schubert         rh = rechandle_tabsep(f, rectype);
588*7f2fe78bSCy Schubert     if (rh == NULL)
589*7f2fe78bSCy Schubert         return ENOMEM;
590*7f2fe78bSCy Schubert     args->rh = rh;
591*7f2fe78bSCy Schubert     if (!opts->omitheader && writeheader(rh, tdtype->fieldnames) < 0)
592*7f2fe78bSCy Schubert         return errno;
593*7f2fe78bSCy Schubert     return 0;
594*7f2fe78bSCy Schubert }
595*7f2fe78bSCy Schubert 
596*7f2fe78bSCy Schubert /* Clean up the state structure. */
597*7f2fe78bSCy Schubert static void
cleanup_args(struct rec_args * args)598*7f2fe78bSCy Schubert cleanup_args(struct rec_args *args)
599*7f2fe78bSCy Schubert {
600*7f2fe78bSCy Schubert     rechandle_free(args->rh);
601*7f2fe78bSCy Schubert     if (args->f != NULL)
602*7f2fe78bSCy Schubert         fclose(args->f);
603*7f2fe78bSCy Schubert }
604*7f2fe78bSCy Schubert 
605*7f2fe78bSCy Schubert void
tabdump(int argc,char ** argv)606*7f2fe78bSCy Schubert tabdump(int argc, char **argv)
607*7f2fe78bSCy Schubert {
608*7f2fe78bSCy Schubert     int ch;
609*7f2fe78bSCy Schubert     size_t i;
610*7f2fe78bSCy Schubert     const char *rectype;
611*7f2fe78bSCy Schubert     struct rec_args args;
612*7f2fe78bSCy Schubert     struct tdopts opts;
613*7f2fe78bSCy Schubert     krb5_error_code ret;
614*7f2fe78bSCy Schubert 
615*7f2fe78bSCy Schubert     memset(&opts, 0, sizeof(opts));
616*7f2fe78bSCy Schubert     memset(&args, 0, sizeof(args));
617*7f2fe78bSCy Schubert     optind = 1;
618*7f2fe78bSCy Schubert     while ((ch = getopt(argc, argv, "Hceno:")) != -1) {
619*7f2fe78bSCy Schubert         switch (ch) {
620*7f2fe78bSCy Schubert         case 'H':
621*7f2fe78bSCy Schubert             opts.omitheader = 1;
622*7f2fe78bSCy Schubert             break;
623*7f2fe78bSCy Schubert         case 'c':
624*7f2fe78bSCy Schubert             opts.csv = 1;
625*7f2fe78bSCy Schubert             break;
626*7f2fe78bSCy Schubert         case 'e':
627*7f2fe78bSCy Schubert             opts.emptyhex_empty = 1;
628*7f2fe78bSCy Schubert             break;
629*7f2fe78bSCy Schubert         case 'n':
630*7f2fe78bSCy Schubert             opts.numeric = 1;
631*7f2fe78bSCy Schubert             break;
632*7f2fe78bSCy Schubert         case 'o':
633*7f2fe78bSCy Schubert             opts.fname = optarg;
634*7f2fe78bSCy Schubert             break;
635*7f2fe78bSCy Schubert         case '?':
636*7f2fe78bSCy Schubert         default:
637*7f2fe78bSCy Schubert             usage();
638*7f2fe78bSCy Schubert             break;
639*7f2fe78bSCy Schubert         }
640*7f2fe78bSCy Schubert     }
641*7f2fe78bSCy Schubert     if (argc - optind < 1)
642*7f2fe78bSCy Schubert         usage();
643*7f2fe78bSCy Schubert     rectype = argv[optind];
644*7f2fe78bSCy Schubert     for (i = 0; i < NTDTYPES; i++) {
645*7f2fe78bSCy Schubert         if (strcmp(rectype, tdtypes[i].rectype) == 0) {
646*7f2fe78bSCy Schubert             setup_args(&args, &tdtypes[i], &opts);
647*7f2fe78bSCy Schubert             break;
648*7f2fe78bSCy Schubert         }
649*7f2fe78bSCy Schubert     }
650*7f2fe78bSCy Schubert     if (i >= NTDTYPES)
651*7f2fe78bSCy Schubert         usage();
652*7f2fe78bSCy Schubert     ret = krb5_db_iterate(util_context, NULL, tditer, &args, 0);
653*7f2fe78bSCy Schubert     cleanup_args(&args);
654*7f2fe78bSCy Schubert     if (ret) {
655*7f2fe78bSCy Schubert         com_err(progname, ret, _("performing tabular dump"));
656*7f2fe78bSCy Schubert         exit_status++;
657*7f2fe78bSCy Schubert     }
658*7f2fe78bSCy Schubert }
659