1321936Shselasky/*
2321936Shselasky * Copyright (c) 1999-2005 Kungliga Tekniska H��gskolan
3321936Shselasky * (Royal Institute of Technology, Stockholm, Sweden).
4321936Shselasky * All rights reserved.
5321936Shselasky *
6321936Shselasky * Redistribution and use in source and binary forms, with or without
7321936Shselasky * modification, are permitted provided that the following conditions
8321936Shselasky * are met:
9321936Shselasky *
10321936Shselasky * 1. Redistributions of source code must retain the above copyright
11321936Shselasky *    notice, this list of conditions and the following disclaimer.
12321936Shselasky *
13321936Shselasky * 2. Redistributions in binary form must reproduce the above copyright
14321936Shselasky *    notice, this list of conditions and the following disclaimer in the
15321936Shselasky *    documentation and/or other materials provided with the distribution.
16321936Shselasky *
17321936Shselasky * 3. Neither the name of KTH nor the names of its contributors may be
18321936Shselasky *    used to endorse or promote products derived from this software without
19321936Shselasky *    specific prior written permission.
20321936Shselasky *
21321936Shselasky * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
22321936Shselasky * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23321936Shselasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24321936Shselasky * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
25321936Shselasky * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26321936Shselasky * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27321936Shselasky * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28321936Shselasky * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29321936Shselasky * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30321936Shselasky * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31321936Shselasky * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
32321936Shselasky
33321936Shselasky#include "hdb_locl.h"
34321936Shselasky#include <hex.h>
35321936Shselasky#include <ctype.h>
36321936Shselasky
37321936Shselasky/*
38321936Shselasky   This is the present contents of a dump line. This might change at
39321936Shselasky   any time. Fields are separated by white space.
40321936Shselasky
41321936Shselasky  principal
42321936Shselasky  keyblock
43321936Shselasky  	kvno
44321936Shselasky	keys...
45321936Shselasky		mkvno
46321936Shselasky		enctype
47321936Shselasky		keyvalue
48321936Shselasky		salt (- means use normal salt)
49321936Shselasky  creation date and principal
50321936Shselasky  modification date and principal
51321936Shselasky  principal valid from date (not used)
52321936Shselasky  principal valid end date (not used)
53321936Shselasky  principal key expires (not used)
54321936Shselasky  max ticket life
55321936Shselasky  max renewable life
56321936Shselasky  flags
57321936Shselasky  generation number
58321936Shselasky  */
59321936Shselasky
60321936Shselaskystatic krb5_error_code
61321936Shselaskyappend_string(krb5_context context, krb5_storage *sp, const char *fmt, ...)
62321936Shselasky{
63321936Shselasky    krb5_error_code ret;
64321936Shselasky    char *s;
65321936Shselasky    va_list ap;
66321936Shselasky    va_start(ap, fmt);
67321936Shselasky    vasprintf(&s, fmt, ap);
68321936Shselasky    va_end(ap);
69321936Shselasky    if(s == NULL) {
70321936Shselasky	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
71321936Shselasky	return ENOMEM;
72321936Shselasky    }
73321936Shselasky    ret = krb5_storage_write(sp, s, strlen(s));
74321936Shselasky    free(s);
75321936Shselasky    return ret;
76321936Shselasky}
77321936Shselasky
78321936Shselaskystatic krb5_error_code
79321936Shselaskyappend_hex(krb5_context context, krb5_storage *sp, krb5_data *data)
80321936Shselasky{
81321936Shselasky    int printable = 1;
82321936Shselasky    size_t i;
83321936Shselasky    char *p;
84321936Shselasky
85321936Shselasky    p = data->data;
86321936Shselasky    for(i = 0; i < data->length; i++)
87321936Shselasky	if(!isalnum((unsigned char)p[i]) && p[i] != '.'){
88321936Shselasky	    printable = 0;
89321936Shselasky	    break;
90321936Shselasky	}
91321936Shselasky    if(printable)
92321936Shselasky	return append_string(context, sp, "\"%.*s\"",
93321936Shselasky			     data->length, data->data);
94321936Shselasky    hex_encode(data->data, data->length, &p);
95321936Shselasky    append_string(context, sp, "%s", p);
96321936Shselasky    free(p);
97321936Shselasky    return 0;
98321936Shselasky}
99321936Shselasky
100321936Shselaskystatic char *
101321936Shselaskytime2str(time_t t)
102321936Shselasky{
103321936Shselasky    static char buf[128];
104321936Shselasky    strftime(buf, sizeof(buf), "%Y%m%d%H%M%S", gmtime(&t));
105321936Shselasky    return buf;
106321936Shselasky}
107321936Shselasky
108321936Shselaskystatic krb5_error_code
109321936Shselaskyappend_event(krb5_context context, krb5_storage *sp, Event *ev)
110321936Shselasky{
111321936Shselasky    char *pr = NULL;
112321936Shselasky    krb5_error_code ret;
113321936Shselasky    if(ev == NULL)
114321936Shselasky	return append_string(context, sp, "- ");
115321936Shselasky    if (ev->principal != NULL) {
116321936Shselasky       ret = krb5_unparse_name(context, ev->principal, &pr);
117321936Shselasky       if(ret)
118321936Shselasky           return ret;
119321936Shselasky    }
120321936Shselasky    ret = append_string(context, sp, "%s:%s ",
121321936Shselasky			time2str(ev->time), pr ? pr : "UNKNOWN");
122321936Shselasky    free(pr);
123321936Shselasky    return ret;
124321936Shselasky}
125321936Shselasky
126321936Shselaskystatic krb5_error_code
127321936Shselaskyentry2string_int (krb5_context context, krb5_storage *sp, hdb_entry *ent)
128321936Shselasky{
129321936Shselasky    char *p;
130321936Shselasky    size_t i;
131321936Shselasky    krb5_error_code ret;
132321936Shselasky
133321936Shselasky    /* --- principal */
134321936Shselasky    ret = krb5_unparse_name(context, ent->principal, &p);
135321936Shselasky    if(ret)
136321936Shselasky	return ret;
137321936Shselasky    append_string(context, sp, "%s ", p);
138321936Shselasky    free(p);
139321936Shselasky    /* --- kvno */
140321936Shselasky    append_string(context, sp, "%d", ent->kvno);
141321936Shselasky    /* --- keys */
142321936Shselasky    for(i = 0; i < ent->keys.len; i++){
143321936Shselasky	/* --- mkvno, keytype */
144321936Shselasky	if(ent->keys.val[i].mkvno)
145321936Shselasky	    append_string(context, sp, ":%d:%d:",
146321936Shselasky			  *ent->keys.val[i].mkvno,
147321936Shselasky			  ent->keys.val[i].key.keytype);
148321936Shselasky	else
149321936Shselasky	    append_string(context, sp, "::%d:",
150321936Shselasky			  ent->keys.val[i].key.keytype);
151321936Shselasky	/* --- keydata */
152321936Shselasky	append_hex(context, sp, &ent->keys.val[i].key.keyvalue);
153321936Shselasky	append_string(context, sp, ":");
154321936Shselasky	/* --- salt */
155321936Shselasky	if(ent->keys.val[i].salt){
156321936Shselasky	    append_string(context, sp, "%u/", ent->keys.val[i].salt->type);
157321936Shselasky	    append_hex(context, sp, &ent->keys.val[i].salt->salt);
158321936Shselasky	}else
159321936Shselasky	    append_string(context, sp, "-");
160321936Shselasky    }
161321936Shselasky    append_string(context, sp, " ");
162321936Shselasky    /* --- created by */
163321936Shselasky    append_event(context, sp, &ent->created_by);
164321936Shselasky    /* --- modified by */
165321936Shselasky    append_event(context, sp, ent->modified_by);
166321936Shselasky
167321936Shselasky    /* --- valid start */
168321936Shselasky    if(ent->valid_start)
169321936Shselasky	append_string(context, sp, "%s ", time2str(*ent->valid_start));
170321936Shselasky    else
171321936Shselasky	append_string(context, sp, "- ");
172321936Shselasky
173321936Shselasky    /* --- valid end */
174321936Shselasky    if(ent->valid_end)
175321936Shselasky	append_string(context, sp, "%s ", time2str(*ent->valid_end));
176321936Shselasky    else
177321936Shselasky	append_string(context, sp, "- ");
178321936Shselasky
179321936Shselasky    /* --- password ends */
180321936Shselasky    if(ent->pw_end)
181321936Shselasky	append_string(context, sp, "%s ", time2str(*ent->pw_end));
182321936Shselasky    else
183321936Shselasky	append_string(context, sp, "- ");
184321936Shselasky
185321936Shselasky    /* --- max life */
186321936Shselasky    if(ent->max_life)
187321936Shselasky	append_string(context, sp, "%d ", *ent->max_life);
188321936Shselasky    else
189321936Shselasky	append_string(context, sp, "- ");
190321936Shselasky
191321936Shselasky    /* --- max renewable life */
192321936Shselasky    if(ent->max_renew)
193321936Shselasky	append_string(context, sp, "%d ", *ent->max_renew);
194321936Shselasky    else
195321936Shselasky	append_string(context, sp, "- ");
196321936Shselasky
197321936Shselasky    /* --- flags */
198321936Shselasky    append_string(context, sp, "%d ", HDBFlags2int(ent->flags));
199321936Shselasky
200321936Shselasky    /* --- generation number */
201321936Shselasky    if(ent->generation) {
202321936Shselasky	append_string(context, sp, "%s:%d:%d ", time2str(ent->generation->time),
203321936Shselasky		      ent->generation->usec,
204321936Shselasky		      ent->generation->gen);
205321936Shselasky    } else
206321936Shselasky	append_string(context, sp, "- ");
207321936Shselasky
208321936Shselasky    /* --- extensions */
209321936Shselasky    if(ent->extensions && ent->extensions->len > 0) {
210321936Shselasky	for(i = 0; i < ent->extensions->len; i++) {
211321936Shselasky	    void *d;
212321936Shselasky	    size_t size, sz = 0;
213321936Shselasky
214321936Shselasky	    ASN1_MALLOC_ENCODE(HDB_extension, d, size,
215321936Shselasky			       &ent->extensions->val[i], &sz, ret);
216321936Shselasky	    if (ret) {
217321936Shselasky		krb5_clear_error_message(context);
218321936Shselasky		return ret;
219321936Shselasky	    }
220321936Shselasky	    if(size != sz)
221321936Shselasky		krb5_abortx(context, "internal asn.1 encoder error");
222321936Shselasky
223321936Shselasky	    if (hex_encode(d, size, &p) < 0) {
224321936Shselasky		free(d);
225321936Shselasky		krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
226321936Shselasky		return ENOMEM;
227321936Shselasky	    }
228321936Shselasky
229321936Shselasky	    free(d);
230321936Shselasky	    append_string(context, sp, "%s%s", p,
231321936Shselasky			  ent->extensions->len - 1 != i ? ":" : "");
232321936Shselasky	    free(p);
233321936Shselasky	}
234321936Shselasky    } else
235321936Shselasky	append_string(context, sp, "-");
236321936Shselasky
237321936Shselasky
238321936Shselasky    return 0;
239321936Shselasky}
240321936Shselasky
241321936Shselaskykrb5_error_code
242321936Shselaskyhdb_entry2string (krb5_context context, hdb_entry *ent, char **str)
243321936Shselasky{
244321936Shselasky    krb5_error_code ret;
245321936Shselasky    krb5_data data;
246321936Shselasky    krb5_storage *sp;
247321936Shselasky
248321936Shselasky    sp = krb5_storage_emem();
249321936Shselasky    if(sp == NULL) {
250321936Shselasky	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
251321936Shselasky	return ENOMEM;
252321936Shselasky    }
253321936Shselasky
254321936Shselasky    ret = entry2string_int(context, sp, ent);
255321936Shselasky    if(ret) {
256321936Shselasky	krb5_storage_free(sp);
257321936Shselasky	return ret;
258321936Shselasky    }
259321936Shselasky
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