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