1/*	$NetBSD$	*/
2
3/*
4 * Copyright (c) 1999-2005 Kungliga Tekniska H��gskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of KTH nor the names of its contributors may be
20 *    used to endorse or promote products derived from this software without
21 *    specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
24 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
30 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
34
35#include "hdb_locl.h"
36#include <krb5/hex.h>
37#include <ctype.h>
38
39/*
40   This is the present contents of a dump line. This might change at
41   any time. Fields are separated by white space.
42
43  principal
44  keyblock
45  	kvno
46	keys...
47		mkvno
48		enctype
49		keyvalue
50		salt (- means use normal salt)
51  creation date and principal
52  modification date and principal
53  principal valid from date (not used)
54  principal valid end date (not used)
55  principal key expires (not used)
56  max ticket life
57  max renewable life
58  flags
59  generation number
60  */
61
62static krb5_error_code
63append_string(krb5_context context, krb5_storage *sp, const char *fmt, ...)
64{
65    krb5_error_code ret;
66    char *s;
67    va_list ap;
68    va_start(ap, fmt);
69    vasprintf(&s, fmt, ap);
70    va_end(ap);
71    if(s == NULL) {
72	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
73	return ENOMEM;
74    }
75    ret = krb5_storage_write(sp, s, strlen(s));
76    free(s);
77    return ret;
78}
79
80static krb5_error_code
81append_hex(krb5_context context, krb5_storage *sp, krb5_data *data)
82{
83    int i, printable = 1;
84    char *p;
85
86    p = data->data;
87    for(i = 0; i < data->length; i++)
88	if(!isalnum((unsigned char)p[i]) && p[i] != '.'){
89	    printable = 0;
90	    break;
91	}
92    if(printable)
93	return append_string(context, sp, "\"%.*s\"",
94			     data->length, data->data);
95    hex_encode(data->data, data->length, &p);
96    append_string(context, sp, "%s", p);
97    free(p);
98    return 0;
99}
100
101static char *
102time2str(time_t t)
103{
104    static char buf[128];
105    strftime(buf, sizeof(buf), "%Y%m%d%H%M%S", gmtime(&t));
106    return buf;
107}
108
109static krb5_error_code
110append_event(krb5_context context, krb5_storage *sp, Event *ev)
111{
112    char *pr = NULL;
113    krb5_error_code ret;
114    if(ev == NULL)
115	return append_string(context, sp, "- ");
116    if (ev->principal != NULL) {
117       ret = krb5_unparse_name(context, ev->principal, &pr);
118       if(ret)
119           return ret;
120    }
121    ret = append_string(context, sp, "%s:%s ",
122			time2str(ev->time), pr ? pr : "UNKNOWN");
123    free(pr);
124    return ret;
125}
126
127static krb5_error_code
128entry2string_int (krb5_context context, krb5_storage *sp, hdb_entry *ent)
129{
130    char *p;
131    int i;
132    krb5_error_code ret;
133
134    /* --- principal */
135    ret = krb5_unparse_name(context, ent->principal, &p);
136    if(ret)
137	return ret;
138    append_string(context, sp, "%s ", p);
139    free(p);
140    /* --- kvno */
141    append_string(context, sp, "%d", ent->kvno);
142    /* --- keys */
143    for(i = 0; i < ent->keys.len; i++){
144	/* --- mkvno, keytype */
145	if(ent->keys.val[i].mkvno)
146	    append_string(context, sp, ":%d:%d:",
147			  *ent->keys.val[i].mkvno,
148			  ent->keys.val[i].key.keytype);
149	else
150	    append_string(context, sp, "::%d:",
151			  ent->keys.val[i].key.keytype);
152	/* --- keydata */
153	append_hex(context, sp, &ent->keys.val[i].key.keyvalue);
154	append_string(context, sp, ":");
155	/* --- salt */
156	if(ent->keys.val[i].salt){
157	    append_string(context, sp, "%u/", ent->keys.val[i].salt->type);
158	    append_hex(context, sp, &ent->keys.val[i].salt->salt);
159	}else
160	    append_string(context, sp, "-");
161    }
162    append_string(context, sp, " ");
163    /* --- created by */
164    append_event(context, sp, &ent->created_by);
165    /* --- modified by */
166    append_event(context, sp, ent->modified_by);
167
168    /* --- valid start */
169    if(ent->valid_start)
170	append_string(context, sp, "%s ", time2str(*ent->valid_start));
171    else
172	append_string(context, sp, "- ");
173
174    /* --- valid end */
175    if(ent->valid_end)
176	append_string(context, sp, "%s ", time2str(*ent->valid_end));
177    else
178	append_string(context, sp, "- ");
179
180    /* --- password ends */
181    if(ent->pw_end)
182	append_string(context, sp, "%s ", time2str(*ent->pw_end));
183    else
184	append_string(context, sp, "- ");
185
186    /* --- max life */
187    if(ent->max_life)
188	append_string(context, sp, "%d ", *ent->max_life);
189    else
190	append_string(context, sp, "- ");
191
192    /* --- max renewable life */
193    if(ent->max_renew)
194	append_string(context, sp, "%d ", *ent->max_renew);
195    else
196	append_string(context, sp, "- ");
197
198    /* --- flags */
199    append_string(context, sp, "%d ", HDBFlags2int(ent->flags));
200
201    /* --- generation number */
202    if(ent->generation) {
203	append_string(context, sp, "%s:%d:%d ", time2str(ent->generation->time),
204		      ent->generation->usec,
205		      ent->generation->gen);
206    } else
207	append_string(context, sp, "- ");
208
209    /* --- extensions */
210    if(ent->extensions && ent->extensions->len > 0) {
211	for(i = 0; i < ent->extensions->len; i++) {
212	    void *d;
213	    size_t size, sz;
214
215	    ASN1_MALLOC_ENCODE(HDB_extension, d, size,
216			       &ent->extensions->val[i], &sz, ret);
217	    if (ret) {
218		krb5_clear_error_message(context);
219		return ret;
220	    }
221	    if(size != sz)
222		krb5_abortx(context, "internal asn.1 encoder error");
223
224	    if (hex_encode(d, size, &p) < 0) {
225		free(d);
226		krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
227		return ENOMEM;
228	    }
229
230	    free(d);
231	    append_string(context, sp, "%s%s", p,
232			  ent->extensions->len - 1 != i ? ":" : "");
233	    free(p);
234	}
235    } else
236	append_string(context, sp, "-");
237
238
239    return 0;
240}
241
242krb5_error_code
243hdb_entry2string (krb5_context context, hdb_entry *ent, char **str)
244{
245    krb5_error_code ret;
246    krb5_data data;
247    krb5_storage *sp;
248
249    sp = krb5_storage_emem();
250    if(sp == NULL) {
251	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
252	return ENOMEM;
253    }
254
255    ret = entry2string_int(context, sp, ent);
256    if(ret) {
257	krb5_storage_free(sp);
258	return ret;
259    }
260
261    krb5_storage_write(sp, "\0", 1);
262    krb5_storage_to_data(sp, &data);
263    krb5_storage_free(sp);
264    *str = data.data;
265    return 0;
266}
267
268/* print a hdb_entry to (FILE*)data; suitable for hdb_foreach */
269
270krb5_error_code
271hdb_print_entry(krb5_context context, HDB *db, hdb_entry_ex *entry, void *data)
272{
273    krb5_error_code ret;
274    krb5_storage *sp;
275
276    FILE *f = data;
277
278    fflush(f);
279    sp = krb5_storage_from_fd(fileno(f));
280    if(sp == NULL) {
281	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
282	return ENOMEM;
283    }
284
285    ret = entry2string_int(context, sp, &entry->entry);
286    if(ret) {
287	krb5_storage_free(sp);
288	return ret;
289    }
290
291    krb5_storage_write(sp, "\n", 1);
292    krb5_storage_free(sp);
293    return 0;
294}
295