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