xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/hdb/print.c (revision d3273b5b76f5afaafe308cead5511dbb8df8c5e9)
1*d3273b5bSchristos /*	$NetBSD: print.c,v 1.2 2017/01/28 21:31:48 christos Exp $	*/
2ca1c9b0cSelric 
3ca1c9b0cSelric /*
4ca1c9b0cSelric  * Copyright (c) 1999-2005 Kungliga Tekniska Högskolan
5ca1c9b0cSelric  * (Royal Institute of Technology, Stockholm, Sweden).
6ca1c9b0cSelric  * All rights reserved.
7ca1c9b0cSelric  *
8ca1c9b0cSelric  * Redistribution and use in source and binary forms, with or without
9ca1c9b0cSelric  * modification, are permitted provided that the following conditions
10ca1c9b0cSelric  * are met:
11ca1c9b0cSelric  *
12ca1c9b0cSelric  * 1. Redistributions of source code must retain the above copyright
13ca1c9b0cSelric  *    notice, this list of conditions and the following disclaimer.
14ca1c9b0cSelric  *
15ca1c9b0cSelric  * 2. Redistributions in binary form must reproduce the above copyright
16ca1c9b0cSelric  *    notice, this list of conditions and the following disclaimer in the
17ca1c9b0cSelric  *    documentation and/or other materials provided with the distribution.
18ca1c9b0cSelric  *
19ca1c9b0cSelric  * 3. Neither the name of KTH nor the names of its contributors may be
20ca1c9b0cSelric  *    used to endorse or promote products derived from this software without
21ca1c9b0cSelric  *    specific prior written permission.
22ca1c9b0cSelric  *
23ca1c9b0cSelric  * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
24ca1c9b0cSelric  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25ca1c9b0cSelric  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26ca1c9b0cSelric  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
27ca1c9b0cSelric  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28ca1c9b0cSelric  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29ca1c9b0cSelric  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
30ca1c9b0cSelric  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31ca1c9b0cSelric  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32ca1c9b0cSelric  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
33ca1c9b0cSelric  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
34ca1c9b0cSelric 
35ca1c9b0cSelric #include "hdb_locl.h"
36ca1c9b0cSelric #include <krb5/hex.h>
37ca1c9b0cSelric #include <ctype.h>
38ca1c9b0cSelric 
39ca1c9b0cSelric /*
40ca1c9b0cSelric    This is the present contents of a dump line. This might change at
41ca1c9b0cSelric    any time. Fields are separated by white space.
42ca1c9b0cSelric 
43ca1c9b0cSelric   principal
44ca1c9b0cSelric   keyblock
45ca1c9b0cSelric   	kvno
46ca1c9b0cSelric 	keys...
47ca1c9b0cSelric 		mkvno
48ca1c9b0cSelric 		enctype
49ca1c9b0cSelric 		keyvalue
50ca1c9b0cSelric 		salt (- means use normal salt)
51ca1c9b0cSelric   creation date and principal
52ca1c9b0cSelric   modification date and principal
53ca1c9b0cSelric   principal valid from date (not used)
54ca1c9b0cSelric   principal valid end date (not used)
55ca1c9b0cSelric   principal key expires (not used)
56ca1c9b0cSelric   max ticket life
57ca1c9b0cSelric   max renewable life
58ca1c9b0cSelric   flags
59ca1c9b0cSelric   generation number
60ca1c9b0cSelric   */
61ca1c9b0cSelric 
62b9d004c6Schristos /*
63b9d004c6Schristos  * These utility functions return the number of bytes written or -1, and
64b9d004c6Schristos  * they set an error in the context.
65b9d004c6Schristos  */
66b9d004c6Schristos static ssize_t
append_string(krb5_context context,krb5_storage * sp,const char * fmt,...)67ca1c9b0cSelric append_string(krb5_context context, krb5_storage *sp, const char *fmt, ...)
68ca1c9b0cSelric {
69b9d004c6Schristos     ssize_t sz;
70ca1c9b0cSelric     char *s;
71b9d004c6Schristos     int rc;
72ca1c9b0cSelric     va_list ap;
73ca1c9b0cSelric     va_start(ap, fmt);
74b9d004c6Schristos     rc = vasprintf(&s, fmt, ap);
75ca1c9b0cSelric     va_end(ap);
76b9d004c6Schristos     if(rc < 0) {
77ca1c9b0cSelric 	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
78b9d004c6Schristos 	return -1;
79ca1c9b0cSelric     }
80b9d004c6Schristos     sz = krb5_storage_write(sp, s, strlen(s));
81ca1c9b0cSelric     free(s);
82b9d004c6Schristos     return sz;
83ca1c9b0cSelric }
84ca1c9b0cSelric 
85ca1c9b0cSelric static krb5_error_code
append_hex(krb5_context context,krb5_storage * sp,int always_encode,int lower,krb5_data * data)86b9d004c6Schristos append_hex(krb5_context context, krb5_storage *sp,
87b9d004c6Schristos            int always_encode, int lower, krb5_data *data)
88ca1c9b0cSelric {
89b9d004c6Schristos     ssize_t sz;
904f77a458Spettai     int printable = 1;
914f77a458Spettai     size_t i;
92ca1c9b0cSelric     char *p;
93ca1c9b0cSelric 
94ca1c9b0cSelric     p = data->data;
95b9d004c6Schristos     if (!always_encode) {
96b9d004c6Schristos         for (i = 0; i < data->length; i++) {
97ca1c9b0cSelric             if (!isalnum((unsigned char)p[i]) && p[i] != '.'){
98ca1c9b0cSelric                 printable = 0;
99ca1c9b0cSelric                 break;
100ca1c9b0cSelric             }
101b9d004c6Schristos         }
102b9d004c6Schristos     }
103b9d004c6Schristos     if (printable && !always_encode)
104ca1c9b0cSelric 	return append_string(context, sp, "\"%.*s\"",
105ca1c9b0cSelric 			     data->length, data->data);
106b9d004c6Schristos     sz = hex_encode(data->data, data->length, &p);
107b9d004c6Schristos     if (sz == -1) return sz;
108b9d004c6Schristos     if (lower)
109b9d004c6Schristos         strlwr(p);
110b9d004c6Schristos     sz = append_string(context, sp, "%s", p);
111ca1c9b0cSelric     free(p);
112b9d004c6Schristos     return sz;
113ca1c9b0cSelric }
114ca1c9b0cSelric 
115ca1c9b0cSelric static char *
time2str(time_t t)116ca1c9b0cSelric time2str(time_t t)
117ca1c9b0cSelric {
118ca1c9b0cSelric     static char buf[128];
119ca1c9b0cSelric     strftime(buf, sizeof(buf), "%Y%m%d%H%M%S", gmtime(&t));
120ca1c9b0cSelric     return buf;
121ca1c9b0cSelric }
122ca1c9b0cSelric 
123b9d004c6Schristos static ssize_t
append_event(krb5_context context,krb5_storage * sp,Event * ev)124ca1c9b0cSelric append_event(krb5_context context, krb5_storage *sp, Event *ev)
125ca1c9b0cSelric {
126ca1c9b0cSelric     krb5_error_code ret;
127b9d004c6Schristos     ssize_t sz;
128b9d004c6Schristos     char *pr = NULL;
129ca1c9b0cSelric     if(ev == NULL)
130ca1c9b0cSelric 	return append_string(context, sp, "- ");
131ca1c9b0cSelric     if (ev->principal != NULL) {
132ca1c9b0cSelric        ret = krb5_unparse_name(context, ev->principal, &pr);
133b9d004c6Schristos        if (ret) return -1; /* krb5_unparse_name() sets error info */
134ca1c9b0cSelric     }
135b9d004c6Schristos     sz = append_string(context, sp, "%s:%s ", time2str(ev->time),
136b9d004c6Schristos                        pr ? pr : "UNKNOWN");
137ca1c9b0cSelric     free(pr);
138b9d004c6Schristos     return sz;
139b9d004c6Schristos }
140b9d004c6Schristos 
141b9d004c6Schristos #define KRB5_KDB_SALTTYPE_NORMAL        0
142b9d004c6Schristos #define KRB5_KDB_SALTTYPE_V4            1
143b9d004c6Schristos #define KRB5_KDB_SALTTYPE_NOREALM       2
144b9d004c6Schristos #define KRB5_KDB_SALTTYPE_ONLYREALM     3
145b9d004c6Schristos #define KRB5_KDB_SALTTYPE_SPECIAL       4
146b9d004c6Schristos #define KRB5_KDB_SALTTYPE_AFS3          5
147b9d004c6Schristos 
148b9d004c6Schristos static ssize_t
append_mit_key(krb5_context context,krb5_storage * sp,krb5_const_principal princ,unsigned int kvno,Key * key)149b9d004c6Schristos append_mit_key(krb5_context context, krb5_storage *sp,
150b9d004c6Schristos                krb5_const_principal princ,
151b9d004c6Schristos                unsigned int kvno, Key *key)
152b9d004c6Schristos {
153b9d004c6Schristos     krb5_error_code ret;
154b9d004c6Schristos     krb5_salt k5salt;
155b9d004c6Schristos     ssize_t sz;
156b9d004c6Schristos     size_t key_versions = key->salt ? 2 : 1;
157b9d004c6Schristos     size_t decrypted_key_length;
158b9d004c6Schristos     char buf[2];
159b9d004c6Schristos     krb5_data keylenbytes;
160b9d004c6Schristos     unsigned int salttype;
161b9d004c6Schristos 
162b9d004c6Schristos     sz = append_string(context, sp, "\t%u\t%u\t%d\t%d\t", key_versions, kvno,
163b9d004c6Schristos                         key->key.keytype, key->key.keyvalue.length + 2);
164b9d004c6Schristos     if (sz == -1) return sz;
165b9d004c6Schristos     ret = krb5_enctype_keysize(context, key->key.keytype, &decrypted_key_length);
166b9d004c6Schristos     if (ret) return -1; /* XXX we lose the error code */
167b9d004c6Schristos     buf[0] = decrypted_key_length & 0xff;
168b9d004c6Schristos     buf[1] = (decrypted_key_length & 0xff00) >> 8;
169b9d004c6Schristos     keylenbytes.data = buf;
170b9d004c6Schristos     keylenbytes.length = sizeof (buf);
171b9d004c6Schristos     sz = append_hex(context, sp, 1, 1, &keylenbytes);
172b9d004c6Schristos     if (sz == -1) return sz;
173b9d004c6Schristos     sz = append_hex(context, sp, 1, 1, &key->key.keyvalue);
174b9d004c6Schristos     if (!key->salt)
175b9d004c6Schristos         return sz;
176b9d004c6Schristos 
177b9d004c6Schristos     /* Map salt to MIT KDB style */
178b9d004c6Schristos     switch (key->salt->type) {
179b9d004c6Schristos     case KRB5_PADATA_PW_SALT:
180b9d004c6Schristos 
181b9d004c6Schristos         /*
182b9d004c6Schristos          * Compute normal salt and then see whether it matches the stored one
183b9d004c6Schristos          */
184b9d004c6Schristos         ret = krb5_get_pw_salt(context, princ, &k5salt);
185b9d004c6Schristos         if (ret) return -1;
186b9d004c6Schristos         if (k5salt.saltvalue.length == key->salt->salt.length &&
187b9d004c6Schristos             memcmp(k5salt.saltvalue.data, key->salt->salt.data,
188b9d004c6Schristos                    k5salt.saltvalue.length) == 0)
189b9d004c6Schristos             salttype = KRB5_KDB_SALTTYPE_NORMAL; /* matches */
190b9d004c6Schristos         else if (key->salt->salt.length == strlen(princ->realm) &&
191b9d004c6Schristos                  memcmp(key->salt->salt.data, princ->realm,
192b9d004c6Schristos                         key->salt->salt.length) == 0)
193b9d004c6Schristos             salttype = KRB5_KDB_SALTTYPE_ONLYREALM; /* matches realm */
194b9d004c6Schristos         else if (key->salt->salt.length ==
195b9d004c6Schristos 		 k5salt.saltvalue.length - strlen(princ->realm) &&
196b9d004c6Schristos                  memcmp((char *)k5salt.saltvalue.data + strlen(princ->realm),
197b9d004c6Schristos                         key->salt->salt.data, key->salt->salt.length) == 0)
198b9d004c6Schristos             salttype = KRB5_KDB_SALTTYPE_NOREALM; /* matches w/o realm */
199b9d004c6Schristos         else
200b9d004c6Schristos             salttype = KRB5_KDB_SALTTYPE_NORMAL;  /* hope for best */
201b9d004c6Schristos 
202b9d004c6Schristos 	break;
203b9d004c6Schristos 
204b9d004c6Schristos     case KRB5_PADATA_AFS3_SALT:
205b9d004c6Schristos         salttype = KRB5_KDB_SALTTYPE_AFS3;
206b9d004c6Schristos 	break;
207b9d004c6Schristos 
208b9d004c6Schristos     default:
209b9d004c6Schristos 	return -1;
210b9d004c6Schristos     }
211b9d004c6Schristos 
212b9d004c6Schristos     sz = append_string(context, sp, "\t%u\t%u\t", salttype,
213b9d004c6Schristos                        key->salt->salt.length);
214b9d004c6Schristos     if (sz == -1) return sz;
215b9d004c6Schristos     return append_hex(context, sp, 1, 1, &key->salt->salt);
216ca1c9b0cSelric }
217ca1c9b0cSelric 
218ca1c9b0cSelric static krb5_error_code
entry2string_int(krb5_context context,krb5_storage * sp,hdb_entry * ent)219ca1c9b0cSelric entry2string_int (krb5_context context, krb5_storage *sp, hdb_entry *ent)
220ca1c9b0cSelric {
221ca1c9b0cSelric     char *p;
2224f77a458Spettai     size_t i;
223ca1c9b0cSelric     krb5_error_code ret;
224ca1c9b0cSelric 
225ca1c9b0cSelric     /* --- principal */
226ca1c9b0cSelric     ret = krb5_unparse_name(context, ent->principal, &p);
227ca1c9b0cSelric     if(ret)
228ca1c9b0cSelric 	return ret;
229ca1c9b0cSelric     append_string(context, sp, "%s ", p);
230ca1c9b0cSelric     free(p);
231ca1c9b0cSelric     /* --- kvno */
232ca1c9b0cSelric     append_string(context, sp, "%d", ent->kvno);
233ca1c9b0cSelric     /* --- keys */
234ca1c9b0cSelric     for(i = 0; i < ent->keys.len; i++){
235ca1c9b0cSelric 	/* --- mkvno, keytype */
236ca1c9b0cSelric 	if(ent->keys.val[i].mkvno)
237ca1c9b0cSelric 	    append_string(context, sp, ":%d:%d:",
238ca1c9b0cSelric 			  *ent->keys.val[i].mkvno,
239ca1c9b0cSelric 			  ent->keys.val[i].key.keytype);
240ca1c9b0cSelric 	else
241ca1c9b0cSelric 	    append_string(context, sp, "::%d:",
242ca1c9b0cSelric 			  ent->keys.val[i].key.keytype);
243ca1c9b0cSelric 	/* --- keydata */
244b9d004c6Schristos 	append_hex(context, sp, 0, 0, &ent->keys.val[i].key.keyvalue);
245ca1c9b0cSelric 	append_string(context, sp, ":");
246ca1c9b0cSelric 	/* --- salt */
247ca1c9b0cSelric 	if(ent->keys.val[i].salt){
248ca1c9b0cSelric 	    append_string(context, sp, "%u/", ent->keys.val[i].salt->type);
249b9d004c6Schristos 	    append_hex(context, sp, 0, 0, &ent->keys.val[i].salt->salt);
250ca1c9b0cSelric 	}else
251ca1c9b0cSelric 	    append_string(context, sp, "-");
252ca1c9b0cSelric     }
253ca1c9b0cSelric     append_string(context, sp, " ");
254ca1c9b0cSelric     /* --- created by */
255ca1c9b0cSelric     append_event(context, sp, &ent->created_by);
256ca1c9b0cSelric     /* --- modified by */
257ca1c9b0cSelric     append_event(context, sp, ent->modified_by);
258ca1c9b0cSelric 
259ca1c9b0cSelric     /* --- valid start */
260ca1c9b0cSelric     if(ent->valid_start)
261ca1c9b0cSelric 	append_string(context, sp, "%s ", time2str(*ent->valid_start));
262ca1c9b0cSelric     else
263ca1c9b0cSelric 	append_string(context, sp, "- ");
264ca1c9b0cSelric 
265ca1c9b0cSelric     /* --- valid end */
266ca1c9b0cSelric     if(ent->valid_end)
267ca1c9b0cSelric 	append_string(context, sp, "%s ", time2str(*ent->valid_end));
268ca1c9b0cSelric     else
269ca1c9b0cSelric 	append_string(context, sp, "- ");
270ca1c9b0cSelric 
271ca1c9b0cSelric     /* --- password ends */
272ca1c9b0cSelric     if(ent->pw_end)
273ca1c9b0cSelric 	append_string(context, sp, "%s ", time2str(*ent->pw_end));
274ca1c9b0cSelric     else
275ca1c9b0cSelric 	append_string(context, sp, "- ");
276ca1c9b0cSelric 
277ca1c9b0cSelric     /* --- max life */
278ca1c9b0cSelric     if(ent->max_life)
279ca1c9b0cSelric 	append_string(context, sp, "%d ", *ent->max_life);
280ca1c9b0cSelric     else
281ca1c9b0cSelric 	append_string(context, sp, "- ");
282ca1c9b0cSelric 
283ca1c9b0cSelric     /* --- max renewable life */
284ca1c9b0cSelric     if(ent->max_renew)
285ca1c9b0cSelric 	append_string(context, sp, "%d ", *ent->max_renew);
286ca1c9b0cSelric     else
287ca1c9b0cSelric 	append_string(context, sp, "- ");
288ca1c9b0cSelric 
289ca1c9b0cSelric     /* --- flags */
290ca1c9b0cSelric     append_string(context, sp, "%d ", HDBFlags2int(ent->flags));
291ca1c9b0cSelric 
292ca1c9b0cSelric     /* --- generation number */
293ca1c9b0cSelric     if(ent->generation) {
294ca1c9b0cSelric 	append_string(context, sp, "%s:%d:%d ", time2str(ent->generation->time),
295ca1c9b0cSelric 		      ent->generation->usec,
296ca1c9b0cSelric 		      ent->generation->gen);
297ca1c9b0cSelric     } else
298ca1c9b0cSelric 	append_string(context, sp, "- ");
299ca1c9b0cSelric 
300ca1c9b0cSelric     /* --- extensions */
301ca1c9b0cSelric     if(ent->extensions && ent->extensions->len > 0) {
302ca1c9b0cSelric 	for(i = 0; i < ent->extensions->len; i++) {
303ca1c9b0cSelric 	    void *d;
3044f77a458Spettai 	    size_t size, sz = 0;
305ca1c9b0cSelric 
306ca1c9b0cSelric 	    ASN1_MALLOC_ENCODE(HDB_extension, d, size,
307ca1c9b0cSelric 			       &ent->extensions->val[i], &sz, ret);
308ca1c9b0cSelric 	    if (ret) {
309ca1c9b0cSelric 		krb5_clear_error_message(context);
310ca1c9b0cSelric 		return ret;
311ca1c9b0cSelric 	    }
312ca1c9b0cSelric 	    if(size != sz)
313ca1c9b0cSelric 		krb5_abortx(context, "internal asn.1 encoder error");
314ca1c9b0cSelric 
315ca1c9b0cSelric 	    if (hex_encode(d, size, &p) < 0) {
316ca1c9b0cSelric 		free(d);
317ca1c9b0cSelric 		krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
318ca1c9b0cSelric 		return ENOMEM;
319ca1c9b0cSelric 	    }
320ca1c9b0cSelric 
321ca1c9b0cSelric 	    free(d);
322ca1c9b0cSelric 	    append_string(context, sp, "%s%s", p,
323ca1c9b0cSelric 			  ent->extensions->len - 1 != i ? ":" : "");
324ca1c9b0cSelric 	    free(p);
325ca1c9b0cSelric 	}
326ca1c9b0cSelric     } else
327ca1c9b0cSelric 	append_string(context, sp, "-");
328ca1c9b0cSelric 
329b9d004c6Schristos     return 0;
330b9d004c6Schristos }
331ca1c9b0cSelric 
332b9d004c6Schristos #define KRB5_KDB_DISALLOW_POSTDATED     0x00000001
333b9d004c6Schristos #define KRB5_KDB_DISALLOW_FORWARDABLE   0x00000002
334b9d004c6Schristos #define KRB5_KDB_DISALLOW_TGT_BASED     0x00000004
335b9d004c6Schristos #define KRB5_KDB_DISALLOW_RENEWABLE     0x00000008
336b9d004c6Schristos #define KRB5_KDB_DISALLOW_PROXIABLE     0x00000010
337b9d004c6Schristos #define KRB5_KDB_DISALLOW_DUP_SKEY      0x00000020
338b9d004c6Schristos #define KRB5_KDB_DISALLOW_ALL_TIX       0x00000040
339b9d004c6Schristos #define KRB5_KDB_REQUIRES_PRE_AUTH      0x00000080
340b9d004c6Schristos #define KRB5_KDB_REQUIRES_HW_AUTH       0x00000100
341b9d004c6Schristos #define KRB5_KDB_REQUIRES_PWCHANGE      0x00000200
342b9d004c6Schristos #define KRB5_KDB_DISALLOW_SVR           0x00001000
343b9d004c6Schristos #define KRB5_KDB_PWCHANGE_SERVICE       0x00002000
344b9d004c6Schristos #define KRB5_KDB_SUPPORT_DESMD5         0x00004000
345b9d004c6Schristos #define KRB5_KDB_NEW_PRINC              0x00008000
346b9d004c6Schristos 
347b9d004c6Schristos static int
flags_to_attr(HDBFlags flags)348b9d004c6Schristos flags_to_attr(HDBFlags flags)
349b9d004c6Schristos {
350b9d004c6Schristos     int a = 0;
351b9d004c6Schristos 
352b9d004c6Schristos     if (!flags.postdate)
353b9d004c6Schristos         a |= KRB5_KDB_DISALLOW_POSTDATED;
354b9d004c6Schristos     if (!flags.forwardable)
355b9d004c6Schristos         a |= KRB5_KDB_DISALLOW_FORWARDABLE;
356b9d004c6Schristos     if (flags.initial)
357b9d004c6Schristos         a |= KRB5_KDB_DISALLOW_TGT_BASED;
358b9d004c6Schristos     if (!flags.renewable)
359b9d004c6Schristos         a |= KRB5_KDB_DISALLOW_RENEWABLE;
360b9d004c6Schristos     if (!flags.proxiable)
361b9d004c6Schristos         a |= KRB5_KDB_DISALLOW_PROXIABLE;
362b9d004c6Schristos     if (flags.invalid)
363b9d004c6Schristos         a |= KRB5_KDB_DISALLOW_ALL_TIX;
364b9d004c6Schristos     if (flags.require_preauth)
365b9d004c6Schristos         a |= KRB5_KDB_REQUIRES_PRE_AUTH;
366b9d004c6Schristos     if (flags.require_hwauth)
367b9d004c6Schristos         a |= KRB5_KDB_REQUIRES_HW_AUTH;
368b9d004c6Schristos     if (!flags.server)
369b9d004c6Schristos         a |= KRB5_KDB_DISALLOW_SVR;
370b9d004c6Schristos     if (flags.change_pw)
371b9d004c6Schristos         a |= KRB5_KDB_PWCHANGE_SERVICE;
372b9d004c6Schristos     return a;
373b9d004c6Schristos }
374b9d004c6Schristos 
375b9d004c6Schristos krb5_error_code
entry2mit_string_int(krb5_context context,krb5_storage * sp,hdb_entry * ent)376b9d004c6Schristos entry2mit_string_int(krb5_context context, krb5_storage *sp, hdb_entry *ent)
377b9d004c6Schristos {
378b9d004c6Schristos     krb5_error_code ret;
379b9d004c6Schristos     ssize_t sz;
380b9d004c6Schristos     size_t i, k;
381b9d004c6Schristos     size_t num_tl_data = 0;
382b9d004c6Schristos     size_t num_key_data = 0;
383b9d004c6Schristos     char *p;
384b9d004c6Schristos     HDB_Ext_KeySet *hist_keys = NULL;
385b9d004c6Schristos     HDB_extension *extp;
386b9d004c6Schristos     time_t last_pw_chg = 0;
387b9d004c6Schristos     time_t exp = 0;
388b9d004c6Schristos     time_t pwexp = 0;
389b9d004c6Schristos     unsigned int max_life = 0;
390b9d004c6Schristos     unsigned int max_renew = 0;
391b9d004c6Schristos 
392b9d004c6Schristos     if (ent->modified_by)
393b9d004c6Schristos         num_tl_data++;
394b9d004c6Schristos 
395b9d004c6Schristos     ret = hdb_entry_get_pw_change_time(ent, &last_pw_chg);
396b9d004c6Schristos     if (ret) return ret;
397b9d004c6Schristos     if (last_pw_chg)
398b9d004c6Schristos         num_tl_data++;
399b9d004c6Schristos 
400b9d004c6Schristos     extp = hdb_find_extension(ent, choice_HDB_extension_data_hist_keys);
401b9d004c6Schristos     if (extp)
402b9d004c6Schristos         hist_keys = &extp->data.u.hist_keys;
403b9d004c6Schristos 
404b9d004c6Schristos     for (i = 0; i < ent->keys.len;i++) {
405b9d004c6Schristos         if (ent->keys.val[i].key.keytype == ETYPE_DES_CBC_MD4 ||
406b9d004c6Schristos             ent->keys.val[i].key.keytype == ETYPE_DES_CBC_MD5)
407b9d004c6Schristos             continue;
408b9d004c6Schristos         num_key_data++;
409b9d004c6Schristos     }
410b9d004c6Schristos     if (hist_keys) {
411b9d004c6Schristos         for (i = 0; i < hist_keys->len; i++) {
412b9d004c6Schristos             /*
413b9d004c6Schristos              * MIT uses the highest kvno as the current kvno instead of
414b9d004c6Schristos              * tracking kvno separately, so we can't dump keysets with kvno
415b9d004c6Schristos              * higher than the entry's kvno.
416b9d004c6Schristos              */
417b9d004c6Schristos             if (hist_keys->val[i].kvno >= ent->kvno)
418b9d004c6Schristos                 continue;
419b9d004c6Schristos             for (k = 0; k < hist_keys->val[i].keys.len; k++) {
420b9d004c6Schristos                 if (ent->keys.val[k].key.keytype == ETYPE_DES_CBC_MD4 ||
421b9d004c6Schristos                     ent->keys.val[k].key.keytype == ETYPE_DES_CBC_MD5)
422b9d004c6Schristos                     continue;
423b9d004c6Schristos                 num_key_data++;
424b9d004c6Schristos             }
425b9d004c6Schristos         }
426b9d004c6Schristos     }
427b9d004c6Schristos 
428b9d004c6Schristos     ret = krb5_unparse_name(context, ent->principal, &p);
429b9d004c6Schristos     if (ret) return ret;
430b9d004c6Schristos     sz = append_string(context, sp, "princ\t38\t%u\t%u\t%u\t0\t%s\t%d",
431b9d004c6Schristos                        strlen(p), num_tl_data, num_key_data, p,
432b9d004c6Schristos                        flags_to_attr(ent->flags));
433b9d004c6Schristos     free(p);
434b9d004c6Schristos     if (sz == -1) return ENOMEM;
435b9d004c6Schristos 
436b9d004c6Schristos     if (ent->max_life)
437b9d004c6Schristos         max_life = *ent->max_life;
438b9d004c6Schristos     if (ent->max_renew)
439b9d004c6Schristos         max_renew = *ent->max_renew;
440b9d004c6Schristos     if (ent->valid_end)
441b9d004c6Schristos         exp = *ent->valid_end;
442b9d004c6Schristos     if (ent->pw_end)
443b9d004c6Schristos         pwexp = *ent->pw_end;
444b9d004c6Schristos 
445b9d004c6Schristos     sz = append_string(context, sp, "\t%u\t%u\t%u\t%u\t0\t0\t0",
446b9d004c6Schristos                        max_life, max_renew, exp, pwexp);
447b9d004c6Schristos     if (sz == -1) return ENOMEM;
448b9d004c6Schristos 
449b9d004c6Schristos     /* Dump TL data we know: last pw chg and modified_by */
450b9d004c6Schristos #define mit_KRB5_TL_LAST_PWD_CHANGE     1
451b9d004c6Schristos #define mit_KRB5_TL_MOD_PRINC           2
452b9d004c6Schristos     if (last_pw_chg) {
453b9d004c6Schristos         krb5_data d;
454b9d004c6Schristos         time_t val;
455b9d004c6Schristos         unsigned char *ptr;
456b9d004c6Schristos 
457b9d004c6Schristos         ptr = (unsigned char *)&last_pw_chg;
458b9d004c6Schristos         val = ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
459b9d004c6Schristos         d.data = &val;
460b9d004c6Schristos         d.length = sizeof (last_pw_chg);
461b9d004c6Schristos         sz = append_string(context, sp, "\t%u\t%u\t",
462b9d004c6Schristos                            mit_KRB5_TL_LAST_PWD_CHANGE, d.length);
463b9d004c6Schristos         if (sz == -1) return ENOMEM;
464b9d004c6Schristos         sz = append_hex(context, sp, 1, 1, &d);
465b9d004c6Schristos         if (sz == -1) return ENOMEM;
466b9d004c6Schristos     }
467b9d004c6Schristos     if (ent->modified_by) {
468b9d004c6Schristos         krb5_data d;
469b9d004c6Schristos         unsigned int val;
470b9d004c6Schristos         size_t plen;
471b9d004c6Schristos         unsigned char *ptr;
472b9d004c6Schristos         char *modby_p;
473b9d004c6Schristos 
474b9d004c6Schristos         ptr = (unsigned char *)&ent->modified_by->time;
475b9d004c6Schristos         val = ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
476b9d004c6Schristos         d.data = &val;
477b9d004c6Schristos         d.length = sizeof (ent->modified_by->time);
478b9d004c6Schristos         ret = krb5_unparse_name(context, ent->modified_by->principal, &modby_p);
479b9d004c6Schristos         if (ret) return ret;
480b9d004c6Schristos         plen = strlen(modby_p);
481b9d004c6Schristos         sz = append_string(context, sp, "\t%u\t%u\t",
482b9d004c6Schristos                            mit_KRB5_TL_MOD_PRINC,
483b9d004c6Schristos                            d.length + plen + 1 /* NULL counted */);
484b9d004c6Schristos         if (sz == -1) return ENOMEM;
485b9d004c6Schristos         sz = append_hex(context, sp, 1, 1, &d);
486b9d004c6Schristos         if (sz == -1) {
487b9d004c6Schristos             free(modby_p);
488b9d004c6Schristos             return ENOMEM;
489b9d004c6Schristos         }
490b9d004c6Schristos         d.data = modby_p;
491b9d004c6Schristos         d.length = plen + 1;
492b9d004c6Schristos         sz = append_hex(context, sp, 1, 1, &d);
493b9d004c6Schristos         free(modby_p);
494b9d004c6Schristos         if (sz == -1) return ENOMEM;
495b9d004c6Schristos     }
496b9d004c6Schristos     /*
497b9d004c6Schristos      * Dump keys (remembering to not include any with kvno higher than
498b9d004c6Schristos      * the entry's because MIT doesn't track entry kvno separately from
499b9d004c6Schristos      * the entry's keys -- max kvno is it)
500b9d004c6Schristos      */
501b9d004c6Schristos     for (i = 0; i < ent->keys.len; i++) {
502b9d004c6Schristos         if (ent->keys.val[i].key.keytype == ETYPE_DES_CBC_MD4 ||
503b9d004c6Schristos             ent->keys.val[i].key.keytype == ETYPE_DES_CBC_MD5)
504b9d004c6Schristos             continue;
505b9d004c6Schristos         sz = append_mit_key(context, sp, ent->principal, ent->kvno,
506b9d004c6Schristos                             &ent->keys.val[i]);
507b9d004c6Schristos         if (sz == -1) return ENOMEM;
508b9d004c6Schristos     }
509b9d004c6Schristos     for (i = 0; hist_keys && i < ent->kvno; i++) {
510b9d004c6Schristos         size_t m;
511b9d004c6Schristos 
512b9d004c6Schristos         /* dump historical keys */
513b9d004c6Schristos         for (k = 0; k < hist_keys->len; k++) {
514b9d004c6Schristos             if (hist_keys->val[k].kvno != ent->kvno - i)
515b9d004c6Schristos                 continue;
516b9d004c6Schristos             for (m = 0; m < hist_keys->val[k].keys.len; m++) {
517b9d004c6Schristos                 if (ent->keys.val[k].key.keytype == ETYPE_DES_CBC_MD4 ||
518b9d004c6Schristos                     ent->keys.val[k].key.keytype == ETYPE_DES_CBC_MD5)
519b9d004c6Schristos                     continue;
520b9d004c6Schristos                 sz = append_mit_key(context, sp, ent->principal,
521b9d004c6Schristos                                     hist_keys->val[k].kvno,
522b9d004c6Schristos                                     &hist_keys->val[k].keys.val[m]);
523b9d004c6Schristos                 if (sz == -1) return ENOMEM;
524b9d004c6Schristos             }
525b9d004c6Schristos         }
526b9d004c6Schristos     }
527b9d004c6Schristos     sz = append_string(context, sp, "\t-1;"); /* "extra data" */
528b9d004c6Schristos     if (sz == -1) return ENOMEM;
529ca1c9b0cSelric     return 0;
530ca1c9b0cSelric }
531ca1c9b0cSelric 
532ca1c9b0cSelric krb5_error_code
hdb_entry2string(krb5_context context,hdb_entry * ent,char ** str)533ca1c9b0cSelric hdb_entry2string(krb5_context context, hdb_entry *ent, char **str)
534ca1c9b0cSelric {
535ca1c9b0cSelric     krb5_error_code ret;
536ca1c9b0cSelric     krb5_data data;
537ca1c9b0cSelric     krb5_storage *sp;
538ca1c9b0cSelric 
539ca1c9b0cSelric     sp = krb5_storage_emem();
540ca1c9b0cSelric     if (sp == NULL) {
541ca1c9b0cSelric 	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
542ca1c9b0cSelric 	return ENOMEM;
543ca1c9b0cSelric     }
544ca1c9b0cSelric 
545ca1c9b0cSelric     ret = entry2string_int(context, sp, ent);
546ca1c9b0cSelric     if (ret) {
547ca1c9b0cSelric 	krb5_storage_free(sp);
548ca1c9b0cSelric 	return ret;
549ca1c9b0cSelric     }
550ca1c9b0cSelric 
551ca1c9b0cSelric     krb5_storage_write(sp, "\0", 1);
552ca1c9b0cSelric     krb5_storage_to_data(sp, &data);
553ca1c9b0cSelric     krb5_storage_free(sp);
554ca1c9b0cSelric     *str = data.data;
555ca1c9b0cSelric     return 0;
556ca1c9b0cSelric }
557ca1c9b0cSelric 
558ca1c9b0cSelric /* print a hdb_entry to (FILE*)data; suitable for hdb_foreach */
559ca1c9b0cSelric 
560ca1c9b0cSelric krb5_error_code
hdb_print_entry(krb5_context context,HDB * db,hdb_entry_ex * entry,void * data)561b9d004c6Schristos hdb_print_entry(krb5_context context, HDB *db, hdb_entry_ex *entry,
562b9d004c6Schristos                 void *data)
563ca1c9b0cSelric {
564b9d004c6Schristos     struct hdb_print_entry_arg *parg = data;
565ca1c9b0cSelric     krb5_error_code ret;
566ca1c9b0cSelric     krb5_storage *sp;
567ca1c9b0cSelric 
568b9d004c6Schristos     fflush(parg->out);
569b9d004c6Schristos     sp = krb5_storage_from_fd(fileno(parg->out));
570ca1c9b0cSelric     if (sp == NULL) {
571ca1c9b0cSelric 	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
572ca1c9b0cSelric 	return ENOMEM;
573ca1c9b0cSelric     }
574ca1c9b0cSelric 
575b9d004c6Schristos     switch (parg->fmt) {
576b9d004c6Schristos     case HDB_DUMP_HEIMDAL:
577ca1c9b0cSelric         ret = entry2string_int(context, sp, &entry->entry);
578b9d004c6Schristos         break;
579b9d004c6Schristos     case HDB_DUMP_MIT:
580b9d004c6Schristos         ret = entry2mit_string_int(context, sp, &entry->entry);
581b9d004c6Schristos         break;
582b9d004c6Schristos     default:
583b9d004c6Schristos         heim_abort("Only two dump formats supported: Heimdal and MIT");
584b9d004c6Schristos     }
585ca1c9b0cSelric     if (ret) {
586ca1c9b0cSelric 	krb5_storage_free(sp);
587ca1c9b0cSelric 	return ret;
588ca1c9b0cSelric     }
589ca1c9b0cSelric 
590ca1c9b0cSelric     krb5_storage_write(sp, "\n", 1);
591ca1c9b0cSelric     krb5_storage_free(sp);
592ca1c9b0cSelric     return 0;
593ca1c9b0cSelric }
594