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
37static krb5_error_code
38append_string(krb5_context context, krb5_storage *sp, const char *fmt, ...)
39    __attribute__((format (printf, 3, 4)));
40
41
42/*
43   This is the present contents of a dump line. This might change at
44   any time. Fields are separated by white space.
45
46  principal
47  keyblock
48  	kvno
49	keys...
50		mkvno
51		enctype
52		keyvalue
53		salt (- means use normal salt)
54  creation date and principal
55  modification date and principal
56  principal valid from date (not used)
57  principal valid end date (not used)
58  principal key expires (not used)
59  max ticket life
60  max renewable life
61  flags
62  generation number
63  */
64
65static krb5_error_code
66append_string(krb5_context context, krb5_storage *sp, const char *fmt, ...)
67{
68    krb5_ssize_t sret;
69    char *s;
70    int rc;
71    va_list ap;
72    va_start(ap, fmt);
73    rc = vasprintf(&s, fmt, ap);
74    va_end(ap);
75    if(rc < 0) {
76	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
77	return ENOMEM;
78    }
79    sret = krb5_storage_write(sp, s, strlen(s));
80    if (sret < 0 || (size_t)sret != strlen(s)) {
81	free(s);
82	return ENOMEM;
83    }
84    free(s);
85    return 0;
86}
87
88static krb5_error_code
89append_hex(krb5_context context, krb5_storage *sp, krb5_data *data)
90{
91    int printable = 1;
92    size_t i;
93    char *p;
94
95    p = data->data;
96    for(i = 0; i < data->length; i++)
97	if(!isalnum((unsigned char)p[i]) && p[i] != '.'){
98	    printable = 0;
99	    break;
100	}
101    if(printable)
102	return append_string(context, sp, "\"%.*s\"",
103			     (int)data->length, data->data);
104    hex_encode(data->data, data->length, &p);
105    append_string(context, sp, "%s", p);
106    free(p);
107    return 0;
108}
109
110static char *
111time2str(time_t t)
112{
113    static char buf[128];
114    strftime(buf, sizeof(buf), "%Y%m%d%H%M%S", gmtime(&t));
115    return buf;
116}
117
118static krb5_error_code
119append_event(krb5_context context, krb5_storage *sp, Event *ev)
120{
121    char *pr = NULL;
122    krb5_error_code ret;
123    if(ev == NULL)
124	return append_string(context, sp, "- ");
125    if (ev->principal != NULL) {
126       ret = krb5_unparse_name(context, ev->principal, &pr);
127       if(ret)
128           return ret;
129    }
130    ret = append_string(context, sp, "%s:%s ",
131			time2str(ev->time), pr ? pr : "UNKNOWN");
132    free(pr);
133    return ret;
134}
135
136static krb5_error_code
137entry2string_int (krb5_context context, krb5_storage *sp, hdb_entry *ent)
138{
139    char *p;
140    size_t i;
141    krb5_error_code ret;
142
143    /* --- principal */
144    ret = krb5_unparse_name(context, ent->principal, &p);
145    if(ret)
146	return ret;
147    append_string(context, sp, "%s ", p);
148    free(p);
149    /* --- kvno */
150    append_string(context, sp, "%d", ent->kvno);
151    /* --- keys */
152    for(i = 0; i < ent->keys.len; i++){
153	/* --- mkvno, keytype */
154	if(ent->keys.val[i].mkvno)
155	    append_string(context, sp, ":%d:%d:",
156			  *ent->keys.val[i].mkvno,
157			  ent->keys.val[i].key.keytype);
158	else
159	    append_string(context, sp, "::%d:",
160			  ent->keys.val[i].key.keytype);
161	/* --- keydata */
162	append_hex(context, sp, &ent->keys.val[i].key.keyvalue);
163	append_string(context, sp, ":");
164	/* --- salt */
165	if(ent->keys.val[i].salt){
166	    append_string(context, sp, "%u/", ent->keys.val[i].salt->type);
167	    append_hex(context, sp, &ent->keys.val[i].salt->salt);
168	}else
169	    append_string(context, sp, "-");
170    }
171    append_string(context, sp, " ");
172    /* --- created by */
173    append_event(context, sp, &ent->created_by);
174    /* --- modified by */
175    append_event(context, sp, ent->modified_by);
176
177    /* --- valid start */
178    if(ent->valid_start)
179	append_string(context, sp, "%s ", time2str(*ent->valid_start));
180    else
181	append_string(context, sp, "- ");
182
183    /* --- valid end */
184    if(ent->valid_end)
185	append_string(context, sp, "%s ", time2str(*ent->valid_end));
186    else
187	append_string(context, sp, "- ");
188
189    /* --- password ends */
190    if(ent->pw_end)
191	append_string(context, sp, "%s ", time2str(*ent->pw_end));
192    else
193	append_string(context, sp, "- ");
194
195    /* --- max life */
196    if(ent->max_life)
197	append_string(context, sp, "%d ", *ent->max_life);
198    else
199	append_string(context, sp, "- ");
200
201    /* --- max renewable life */
202    if(ent->max_renew)
203	append_string(context, sp, "%d ", *ent->max_renew);
204    else
205	append_string(context, sp, "- ");
206
207    /* --- flags */
208    append_string(context, sp, "%d ", HDBFlags2int(ent->flags));
209
210    /* --- generation number */
211    if(ent->generation) {
212	append_string(context, sp, "%s:%d:%d ", time2str(ent->generation->time),
213		      ent->generation->usec,
214		      ent->generation->gen);
215    } else
216	append_string(context, sp, "- ");
217
218    /* --- extensions */
219    if(ent->extensions && ent->extensions->len > 0) {
220	for(i = 0; i < ent->extensions->len; i++) {
221	    void *d;
222	    size_t size, sz = 0;
223
224	    ASN1_MALLOC_ENCODE(HDB_extension, d, size,
225			       &ent->extensions->val[i], &sz, ret);
226	    if (ret) {
227		krb5_clear_error_message(context);
228		return ret;
229	    }
230	    if(size != sz)
231		krb5_abortx(context, "internal asn.1 encoder error");
232
233	    if (hex_encode(d, size, &p) < 0) {
234		free(d);
235		krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
236		return ENOMEM;
237	    }
238
239	    free(d);
240	    append_string(context, sp, "%s%s", p,
241			  ent->extensions->len - 1 != i ? ":" : "");
242	    free(p);
243	}
244    } else
245	append_string(context, sp, "-");
246
247    return 0;
248}
249
250krb5_error_code
251hdb_entry2string (krb5_context context, hdb_entry *ent, char **str)
252{
253    krb5_error_code ret;
254    krb5_data data;
255    krb5_storage *sp;
256
257    sp = krb5_storage_emem();
258    if(sp == NULL) {
259	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
260	return ENOMEM;
261    }
262
263    ret = entry2string_int(context, sp, ent);
264    if(ret) {
265	krb5_storage_free(sp);
266	return ret;
267    }
268
269    krb5_storage_write(sp, "\0", 1);
270    krb5_storage_to_data(sp, &data);
271    krb5_storage_free(sp);
272    *str = data.data;
273    return 0;
274}
275
276/* print a hdb_entry to (FILE*)data; suitable for hdb_foreach */
277
278krb5_error_code
279hdb_print_entry(krb5_context context, HDB *db, hdb_entry_ex *entry, void *data)
280{
281    krb5_error_code ret;
282    krb5_storage *sp;
283
284    FILE *f = data;
285
286    fflush(f);
287    sp = krb5_storage_from_fd(fileno(f));
288    if(sp == NULL) {
289	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
290	return ENOMEM;
291    }
292
293    ret = entry2string_int(context, sp, &entry->entry);
294    if(ret) {
295	krb5_storage_free(sp);
296	return ret;
297    }
298
299    krb5_storage_write(sp, "\n", 1);
300    krb5_storage_free(sp);
301    return 0;
302}
303