mit_dump.c revision 72445
1/*
2 * Copyright (c) 2000 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 the Institute nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include "hprop.h"
35
36RCSID("$Id: mit_dump.c,v 1.3 2000/08/09 09:57:37 joda Exp $");
37
38/*
39can have any number of princ stanzas.
40format is as follows (only \n indicates newlines)
41princ\t%d\t (%d is KRB5_KDB_V1_BASE_LENGTH, always 38)
42%d\t (strlen of principal e.g. shadow/foo@ANDREW.CMU.EDU)
43%d\t (number of tl_data)
44%d\t (number of key data, e.g. how many keys for this user)
45%d\t (extra data length)
46%s\t (principal name)
47%d\t (attributes)
48%d\t (max lifetime, seconds)
49%d\t (max renewable life, seconds)
50%d\t (expiration, seconds since epoch or 2145830400 for never)
51%d\t (password expiration, seconds, 0 for never)
52%d\t (last successful auth, seconds since epoch)
53%d\t (last failed auth, per above)
54%d\t (failed auth count)
55foreach tl_data 0 to number of tl_data - 1 as above
56  %d\t%d\t (data type, data length)
57  foreach tl_data 0 to length-1
58    %02x (tl data contents[element n])
59  except if tl_data length is 0
60    %d (always -1)
61  \t
62foreach key 0 to number of keys - 1 as above
63  %d\t%d\t (key data version, kvno)
64  foreach version 0 to key data version - 1 (a key or a salt)
65    %d\t%d\t(data type for this key, data length for this key)
66    foreach key data length 0 to length-1
67      %02x (key data contents[element n])
68    except if key_data length is 0
69      %d (always -1)
70    \t
71foreach extra data length 0 to length - 1
72  %02x (extra data part)
73unless no extra data
74  %d (always -1)
75;\n
76
77*/
78
79static int
80hex_to_octet_string(const char *ptr, krb5_data *data)
81{
82    int i;
83    unsigned int v;
84    for(i = 0; i < data->length; i++) {
85	if(sscanf(ptr + 2 * i, "%02x", &v) != 1)
86	    return -1;
87	((unsigned char*)data->data)[i] = v;
88    }
89    return 2 * i;
90}
91
92static char *
93nexttoken(char **p)
94{
95    char *q;
96    do {
97	q = strsep(p, " \t");
98    } while(q && *q == '\0');
99    return q;
100}
101
102static size_t
103getdata(char **p, unsigned char *buf, size_t len)
104{
105    size_t i;
106    int v;
107    char *q = nexttoken(p);
108    i = 0;
109    while(*q && i < len) {
110	if(sscanf(q, "%02x", &v) != 1)
111	    break;
112	buf[i++] = v;
113	q += 2;
114    }
115    return i;
116}
117
118static int
119getint(char **p)
120{
121    int val;
122    char *q = nexttoken(p);
123    sscanf(q, "%d", &val);
124    return val;
125}
126
127#include <kadm5/admin.h>
128
129static void
130attr_to_flags(unsigned attr, HDBFlags *flags)
131{
132    flags->postdate =		!(attr & KRB5_KDB_DISALLOW_POSTDATED);
133    flags->forwardable =	!(attr & KRB5_KDB_DISALLOW_FORWARDABLE);
134    flags->initial =	       !!(attr & KRB5_KDB_DISALLOW_TGT_BASED);
135    flags->renewable =		!(attr & KRB5_KDB_DISALLOW_RENEWABLE);
136    flags->proxiable =		!(attr & KRB5_KDB_DISALLOW_PROXIABLE);
137    /* DUP_SKEY */
138    flags->invalid =	       !!(attr & KRB5_KDB_DISALLOW_ALL_TIX);
139    flags->require_preauth =   !!(attr & KRB5_KDB_REQUIRES_PRE_AUTH);
140    /* HW_AUTH */
141    flags->server =		!(attr & KRB5_KDB_DISALLOW_SVR);
142    flags->change_pw = 	       !!(attr & KRB5_KDB_PWCHANGE_SERVICE);
143    flags->client =	        1; /* XXX */
144}
145
146#define KRB5_KDB_SALTTYPE_NORMAL	0
147#define KRB5_KDB_SALTTYPE_V4		1
148#define KRB5_KDB_SALTTYPE_NOREALM	2
149#define KRB5_KDB_SALTTYPE_ONLYREALM	3
150#define KRB5_KDB_SALTTYPE_SPECIAL	4
151#define KRB5_KDB_SALTTYPE_AFS3		5
152
153static krb5_error_code
154fix_salt(krb5_context context, hdb_entry *ent, int key_num)
155{
156    krb5_error_code ret;
157    Salt *salt = ent->keys.val[key_num].salt;
158    /* fix salt type */
159    switch((int)salt->type) {
160    case KRB5_KDB_SALTTYPE_NORMAL:
161	salt->type = KRB5_PADATA_PW_SALT;
162	break;
163    case KRB5_KDB_SALTTYPE_V4:
164	krb5_data_free(&salt->salt);
165	salt->type = KRB5_PADATA_PW_SALT;
166	break;
167    case KRB5_KDB_SALTTYPE_NOREALM:
168    {
169	size_t len;
170	int i;
171	krb5_error_code ret;
172	char *p;
173
174	len = 0;
175	for (i = 0; i < ent->principal->name.name_string.len; ++i)
176	    len += strlen(ent->principal->name.name_string.val[i]);
177	ret = krb5_data_alloc (&salt->salt, len);
178	if (ret)
179	    return ret;
180	p = salt->salt.data;
181	for (i = 0; i < ent->principal->name.name_string.len; ++i) {
182	    memcpy (p,
183		    ent->principal->name.name_string.val[i],
184		    strlen(ent->principal->name.name_string.val[i]));
185	    p += strlen(ent->principal->name.name_string.val[i]);
186	}
187
188	salt->type = KRB5_PADATA_PW_SALT;
189	break;
190    }
191    case KRB5_KDB_SALTTYPE_ONLYREALM:
192	krb5_data_free(&salt->salt);
193	ret = krb5_data_copy(&salt->salt,
194			     ent->principal->realm,
195			     strlen(ent->principal->realm));
196	if(ret)
197	    return ret;
198	salt->type = KRB5_PADATA_PW_SALT;
199	break;
200    case KRB5_KDB_SALTTYPE_SPECIAL:
201	salt->type = KRB5_PADATA_PW_SALT;
202	break;
203    case KRB5_KDB_SALTTYPE_AFS3:
204	krb5_data_free(&salt->salt);
205	ret = krb5_data_copy(&salt->salt,
206		       ent->principal->realm,
207		       strlen(ent->principal->realm));
208	if(ret)
209	    return ret;
210	salt->type = KRB5_PADATA_AFS3_SALT;
211	break;
212    default:
213	abort();
214    }
215    return 0;
216}
217
218int
219mit_prop_dump(void *arg, const char *file)
220{
221    krb5_error_code ret;
222    char buf [1024];
223    FILE *f;
224    int lineno = 0;
225    struct hdb_entry ent;
226
227    struct prop_data *pd = arg;
228
229    f = fopen(file, "r");
230    if(f == NULL)
231	return errno;
232
233    while(fgets(buf, sizeof(buf), f)) {
234	char *p = buf, *q;
235
236	int i;
237
238	int num_tl_data;
239	int num_key_data;
240	int extra_data_length;
241	int attributes;
242
243	int tmp;
244
245	lineno++;
246
247	memset(&ent, 0, sizeof(ent));
248
249	q = nexttoken(&p);
250	if(strcmp(q, "kdb5_util") == 0) {
251	    int major;
252	    q = nexttoken(&p); /* load_dump */
253	    if(strcmp(q, "load_dump"))
254		errx(1, "line %d: unknown version", lineno);
255	    q = nexttoken(&p); /* load_dump */
256	    if(strcmp(q, "version"))
257		errx(1, "line %d: unknown version", lineno);
258	    q = nexttoken(&p); /* x.0 */
259	    if(sscanf(q, "%d", &major) != 1)
260		errx(1, "line %d: unknown version", lineno);
261	    if(major != 4)
262		errx(1, "unknown dump file format, got %d, expected 4", major);
263	    continue;
264	} else if(strcmp(q, "princ") != 0) {
265	    warnx("line %d: not a principal", lineno);
266	    continue;
267	}
268	tmp = getint(&p);
269	if(tmp != 38) {
270	    warnx("line %d: bad base length %d != 38", lineno, tmp);
271	    continue;
272	}
273	q = nexttoken(&p); /* length of principal */
274	num_tl_data = getint(&p); /* number of tl-data */
275	num_key_data = getint(&p); /* number of key-data */
276	extra_data_length = getint(&p);  /* length of extra data */
277	q = nexttoken(&p); /* principal name */
278	krb5_parse_name(pd->context, q, &ent.principal);
279	attributes = getint(&p); /* attributes */
280	attr_to_flags(attributes, &ent.flags);
281	tmp = getint(&p); /* max life */
282	if(tmp != 0) {
283	    ALLOC(ent.max_life);
284	    *ent.max_life = tmp;
285	}
286	tmp = getint(&p); /* max renewable life */
287	if(tmp != 0) {
288	    ALLOC(ent.max_renew);
289	    *ent.max_renew = tmp;
290	}
291	tmp = getint(&p); /* expiration */
292	if(tmp != 0 && tmp != 2145830400) {
293	    ALLOC(ent.valid_end);
294	    *ent.valid_end = tmp;
295	}
296	tmp = getint(&p); /* pw expiration */
297	if(tmp != 0) {
298	    ALLOC(ent.pw_end);
299	    *ent.pw_end = tmp;
300	}
301	q = nexttoken(&p); /* last auth */
302	q = nexttoken(&p); /* last failed auth */
303	q = nexttoken(&p); /* fail auth count */
304	for(i = 0; i < num_tl_data; i++) {
305	    unsigned long val;
306	    int tl_type, tl_length;
307	    unsigned char *buf;
308	    krb5_principal princ;
309
310	    tl_type = getint(&p); /* data type */
311	    tl_length = getint(&p); /* data length */
312
313#define KRB5_TL_LAST_PWD_CHANGE	1
314#define KRB5_TL_MOD_PRINC	2
315	    switch(tl_type) {
316	    case KRB5_TL_MOD_PRINC:
317		buf = malloc(tl_length);
318		getdata(&p, buf, tl_length); /* data itself */
319		val = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
320		ret = krb5_parse_name(pd->context, buf + 4, &princ);
321		free(buf);
322		ALLOC(ent.modified_by);
323		ent.modified_by->time = val;
324		ent.modified_by->principal = princ;
325		break;
326	    default:
327		nexttoken(&p);
328		break;
329	    }
330	}
331	ALLOC_SEQ(&ent.keys, num_key_data);
332	for(i = 0; i < num_key_data; i++) {
333	    int key_versions;
334	    key_versions = getint(&p); /* key data version */
335	    ent.kvno = getint(&p); /* XXX kvno */
336
337	    ALLOC(ent.keys.val[i].mkvno);
338	    *ent.keys.val[i].mkvno = 0;
339
340	    /* key version 0 -- actual key */
341	    ent.keys.val[i].key.keytype = getint(&p); /* key type */
342	    tmp = getint(&p); /* key length */
343	    /* the first two bytes of the key is the key length --
344	       skip it */
345	    krb5_data_alloc(&ent.keys.val[i].key.keyvalue, tmp - 2);
346	    q = nexttoken(&p); /* key itself */
347	    hex_to_octet_string(q + 4, &ent.keys.val[i].key.keyvalue);
348
349	    if(key_versions > 1) {
350		/* key version 1 -- optional salt */
351		ALLOC(ent.keys.val[i].salt);
352		ent.keys.val[i].salt->type = getint(&p); /* salt type */
353		tmp = getint(&p); /* salt length */
354		if(tmp > 0) {
355		    krb5_data_alloc(&ent.keys.val[i].salt->salt, tmp - 2);
356		    q = nexttoken(&p); /* salt itself */
357		    hex_to_octet_string(q + 4, &ent.keys.val[i].salt->salt);
358		} else {
359		    ent.keys.val[i].salt->salt.length = 0;
360		    ent.keys.val[i].salt->salt.data = NULL;
361		    tmp = getint(&p);	/* -1, if no data. */
362		}
363		fix_salt(pd->context, &ent, i);
364	    }
365	}
366	q = nexttoken(&p); /* extra data */
367	v5_prop(pd->context, NULL, &ent, arg);
368    }
369    return 0;
370}
371