mit_dump.c revision 178825
172445Sassar/*
272445Sassar * Copyright (c) 2000 Kungliga Tekniska H�gskolan
372445Sassar * (Royal Institute of Technology, Stockholm, Sweden).
472445Sassar * All rights reserved.
572445Sassar *
672445Sassar * Redistribution and use in source and binary forms, with or without
772445Sassar * modification, are permitted provided that the following conditions
872445Sassar * are met:
972445Sassar *
1072445Sassar * 1. Redistributions of source code must retain the above copyright
1172445Sassar *    notice, this list of conditions and the following disclaimer.
1272445Sassar *
1372445Sassar * 2. Redistributions in binary form must reproduce the above copyright
1472445Sassar *    notice, this list of conditions and the following disclaimer in the
1572445Sassar *    documentation and/or other materials provided with the distribution.
1672445Sassar *
1772445Sassar * 3. Neither the name of the Institute nor the names of its contributors
1872445Sassar *    may be used to endorse or promote products derived from this software
1972445Sassar *    without specific prior written permission.
2072445Sassar *
2172445Sassar * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
2272445Sassar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2372445Sassar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2472445Sassar * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
2572445Sassar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2672445Sassar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2772445Sassar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2872445Sassar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2972445Sassar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3072445Sassar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3172445Sassar * SUCH DAMAGE.
3272445Sassar */
3372445Sassar
3472445Sassar#include "hprop.h"
3572445Sassar
36178825SdfrRCSID("$Id: mit_dump.c 21745 2007-07-31 16:11:25Z lha $");
3772445Sassar
3872445Sassar/*
3972445Sassarcan have any number of princ stanzas.
4072445Sassarformat is as follows (only \n indicates newlines)
4172445Sassarprinc\t%d\t (%d is KRB5_KDB_V1_BASE_LENGTH, always 38)
4272445Sassar%d\t (strlen of principal e.g. shadow/foo@ANDREW.CMU.EDU)
4372445Sassar%d\t (number of tl_data)
4472445Sassar%d\t (number of key data, e.g. how many keys for this user)
4572445Sassar%d\t (extra data length)
4672445Sassar%s\t (principal name)
4772445Sassar%d\t (attributes)
4872445Sassar%d\t (max lifetime, seconds)
4972445Sassar%d\t (max renewable life, seconds)
5072445Sassar%d\t (expiration, seconds since epoch or 2145830400 for never)
5172445Sassar%d\t (password expiration, seconds, 0 for never)
5272445Sassar%d\t (last successful auth, seconds since epoch)
5372445Sassar%d\t (last failed auth, per above)
5472445Sassar%d\t (failed auth count)
5572445Sassarforeach tl_data 0 to number of tl_data - 1 as above
5672445Sassar  %d\t%d\t (data type, data length)
5772445Sassar  foreach tl_data 0 to length-1
5872445Sassar    %02x (tl data contents[element n])
5972445Sassar  except if tl_data length is 0
6072445Sassar    %d (always -1)
6172445Sassar  \t
6272445Sassarforeach key 0 to number of keys - 1 as above
6372445Sassar  %d\t%d\t (key data version, kvno)
6472445Sassar  foreach version 0 to key data version - 1 (a key or a salt)
6572445Sassar    %d\t%d\t(data type for this key, data length for this key)
6672445Sassar    foreach key data length 0 to length-1
6772445Sassar      %02x (key data contents[element n])
6872445Sassar    except if key_data length is 0
6972445Sassar      %d (always -1)
7072445Sassar    \t
7172445Sassarforeach extra data length 0 to length - 1
7272445Sassar  %02x (extra data part)
7372445Sassarunless no extra data
7472445Sassar  %d (always -1)
7572445Sassar;\n
7672445Sassar
7772445Sassar*/
7872445Sassar
7972445Sassarstatic int
8072445Sassarhex_to_octet_string(const char *ptr, krb5_data *data)
8172445Sassar{
8272445Sassar    int i;
8372445Sassar    unsigned int v;
8472445Sassar    for(i = 0; i < data->length; i++) {
8572445Sassar	if(sscanf(ptr + 2 * i, "%02x", &v) != 1)
8672445Sassar	    return -1;
8772445Sassar	((unsigned char*)data->data)[i] = v;
8872445Sassar    }
8972445Sassar    return 2 * i;
9072445Sassar}
9172445Sassar
9272445Sassarstatic char *
9372445Sassarnexttoken(char **p)
9472445Sassar{
9572445Sassar    char *q;
9672445Sassar    do {
9772445Sassar	q = strsep(p, " \t");
9872445Sassar    } while(q && *q == '\0');
9972445Sassar    return q;
10072445Sassar}
10172445Sassar
10272445Sassarstatic size_t
10372445Sassargetdata(char **p, unsigned char *buf, size_t len)
10472445Sassar{
10572445Sassar    size_t i;
10672445Sassar    int v;
10772445Sassar    char *q = nexttoken(p);
10872445Sassar    i = 0;
10972445Sassar    while(*q && i < len) {
11072445Sassar	if(sscanf(q, "%02x", &v) != 1)
11172445Sassar	    break;
11272445Sassar	buf[i++] = v;
11372445Sassar	q += 2;
11472445Sassar    }
11572445Sassar    return i;
11672445Sassar}
11772445Sassar
11872445Sassarstatic int
11972445Sassargetint(char **p)
12072445Sassar{
12172445Sassar    int val;
12272445Sassar    char *q = nexttoken(p);
12372445Sassar    sscanf(q, "%d", &val);
12472445Sassar    return val;
12572445Sassar}
12672445Sassar
12772445Sassar#include <kadm5/admin.h>
12872445Sassar
12972445Sassarstatic void
13072445Sassarattr_to_flags(unsigned attr, HDBFlags *flags)
13172445Sassar{
13272445Sassar    flags->postdate =		!(attr & KRB5_KDB_DISALLOW_POSTDATED);
13372445Sassar    flags->forwardable =	!(attr & KRB5_KDB_DISALLOW_FORWARDABLE);
13472445Sassar    flags->initial =	       !!(attr & KRB5_KDB_DISALLOW_TGT_BASED);
13572445Sassar    flags->renewable =		!(attr & KRB5_KDB_DISALLOW_RENEWABLE);
13672445Sassar    flags->proxiable =		!(attr & KRB5_KDB_DISALLOW_PROXIABLE);
13772445Sassar    /* DUP_SKEY */
13872445Sassar    flags->invalid =	       !!(attr & KRB5_KDB_DISALLOW_ALL_TIX);
13972445Sassar    flags->require_preauth =   !!(attr & KRB5_KDB_REQUIRES_PRE_AUTH);
14072445Sassar    /* HW_AUTH */
14172445Sassar    flags->server =		!(attr & KRB5_KDB_DISALLOW_SVR);
14272445Sassar    flags->change_pw = 	       !!(attr & KRB5_KDB_PWCHANGE_SERVICE);
14372445Sassar    flags->client =	        1; /* XXX */
14472445Sassar}
14572445Sassar
14672445Sassar#define KRB5_KDB_SALTTYPE_NORMAL	0
14772445Sassar#define KRB5_KDB_SALTTYPE_V4		1
14872445Sassar#define KRB5_KDB_SALTTYPE_NOREALM	2
14972445Sassar#define KRB5_KDB_SALTTYPE_ONLYREALM	3
15072445Sassar#define KRB5_KDB_SALTTYPE_SPECIAL	4
15172445Sassar#define KRB5_KDB_SALTTYPE_AFS3		5
15272445Sassar
15372445Sassarstatic krb5_error_code
15472445Sassarfix_salt(krb5_context context, hdb_entry *ent, int key_num)
15572445Sassar{
15672445Sassar    krb5_error_code ret;
15772445Sassar    Salt *salt = ent->keys.val[key_num].salt;
15872445Sassar    /* fix salt type */
15972445Sassar    switch((int)salt->type) {
16072445Sassar    case KRB5_KDB_SALTTYPE_NORMAL:
16172445Sassar	salt->type = KRB5_PADATA_PW_SALT;
16272445Sassar	break;
16372445Sassar    case KRB5_KDB_SALTTYPE_V4:
16472445Sassar	krb5_data_free(&salt->salt);
16572445Sassar	salt->type = KRB5_PADATA_PW_SALT;
16672445Sassar	break;
16772445Sassar    case KRB5_KDB_SALTTYPE_NOREALM:
16872445Sassar    {
16972445Sassar	size_t len;
17072445Sassar	int i;
17172445Sassar	char *p;
17272445Sassar
17372445Sassar	len = 0;
17472445Sassar	for (i = 0; i < ent->principal->name.name_string.len; ++i)
17572445Sassar	    len += strlen(ent->principal->name.name_string.val[i]);
17672445Sassar	ret = krb5_data_alloc (&salt->salt, len);
17772445Sassar	if (ret)
17872445Sassar	    return ret;
17972445Sassar	p = salt->salt.data;
18072445Sassar	for (i = 0; i < ent->principal->name.name_string.len; ++i) {
18172445Sassar	    memcpy (p,
18272445Sassar		    ent->principal->name.name_string.val[i],
18372445Sassar		    strlen(ent->principal->name.name_string.val[i]));
18472445Sassar	    p += strlen(ent->principal->name.name_string.val[i]);
18572445Sassar	}
18672445Sassar
18772445Sassar	salt->type = KRB5_PADATA_PW_SALT;
18872445Sassar	break;
18972445Sassar    }
19072445Sassar    case KRB5_KDB_SALTTYPE_ONLYREALM:
19172445Sassar	krb5_data_free(&salt->salt);
19272445Sassar	ret = krb5_data_copy(&salt->salt,
19372445Sassar			     ent->principal->realm,
19472445Sassar			     strlen(ent->principal->realm));
19572445Sassar	if(ret)
19672445Sassar	    return ret;
19772445Sassar	salt->type = KRB5_PADATA_PW_SALT;
19872445Sassar	break;
19972445Sassar    case KRB5_KDB_SALTTYPE_SPECIAL:
20072445Sassar	salt->type = KRB5_PADATA_PW_SALT;
20172445Sassar	break;
20272445Sassar    case KRB5_KDB_SALTTYPE_AFS3:
20372445Sassar	krb5_data_free(&salt->salt);
20472445Sassar	ret = krb5_data_copy(&salt->salt,
20572445Sassar		       ent->principal->realm,
20672445Sassar		       strlen(ent->principal->realm));
20772445Sassar	if(ret)
20872445Sassar	    return ret;
20972445Sassar	salt->type = KRB5_PADATA_AFS3_SALT;
21072445Sassar	break;
21172445Sassar    default:
21272445Sassar	abort();
21372445Sassar    }
21472445Sassar    return 0;
21572445Sassar}
21672445Sassar
21772445Sassarint
21872445Sassarmit_prop_dump(void *arg, const char *file)
21972445Sassar{
22072445Sassar    krb5_error_code ret;
221178825Sdfr    char line [2048];
22272445Sassar    FILE *f;
22372445Sassar    int lineno = 0;
224178825Sdfr    struct hdb_entry_ex ent;
22572445Sassar
22672445Sassar    struct prop_data *pd = arg;
22772445Sassar
22872445Sassar    f = fopen(file, "r");
22972445Sassar    if(f == NULL)
23072445Sassar	return errno;
23172445Sassar
232178825Sdfr    while(fgets(line, sizeof(line), f)) {
233178825Sdfr	char *p = line, *q;
23472445Sassar
23572445Sassar	int i;
23672445Sassar
23772445Sassar	int num_tl_data;
23872445Sassar	int num_key_data;
23972445Sassar	int extra_data_length;
24072445Sassar	int attributes;
24172445Sassar
24272445Sassar	int tmp;
24372445Sassar
24472445Sassar	lineno++;
24572445Sassar
24672445Sassar	memset(&ent, 0, sizeof(ent));
24772445Sassar
24872445Sassar	q = nexttoken(&p);
24972445Sassar	if(strcmp(q, "kdb5_util") == 0) {
25072445Sassar	    int major;
25172445Sassar	    q = nexttoken(&p); /* load_dump */
25272445Sassar	    if(strcmp(q, "load_dump"))
25372445Sassar		errx(1, "line %d: unknown version", lineno);
25472445Sassar	    q = nexttoken(&p); /* load_dump */
25572445Sassar	    if(strcmp(q, "version"))
25672445Sassar		errx(1, "line %d: unknown version", lineno);
25772445Sassar	    q = nexttoken(&p); /* x.0 */
25872445Sassar	    if(sscanf(q, "%d", &major) != 1)
25972445Sassar		errx(1, "line %d: unknown version", lineno);
26072445Sassar	    if(major != 4)
26172445Sassar		errx(1, "unknown dump file format, got %d, expected 4", major);
26272445Sassar	    continue;
26372445Sassar	} else if(strcmp(q, "princ") != 0) {
26472445Sassar	    warnx("line %d: not a principal", lineno);
26572445Sassar	    continue;
26672445Sassar	}
26772445Sassar	tmp = getint(&p);
26872445Sassar	if(tmp != 38) {
26972445Sassar	    warnx("line %d: bad base length %d != 38", lineno, tmp);
27072445Sassar	    continue;
27172445Sassar	}
27272445Sassar	q = nexttoken(&p); /* length of principal */
27372445Sassar	num_tl_data = getint(&p); /* number of tl-data */
27472445Sassar	num_key_data = getint(&p); /* number of key-data */
27572445Sassar	extra_data_length = getint(&p);  /* length of extra data */
27672445Sassar	q = nexttoken(&p); /* principal name */
277178825Sdfr	krb5_parse_name(pd->context, q, &ent.entry.principal);
27872445Sassar	attributes = getint(&p); /* attributes */
279178825Sdfr	attr_to_flags(attributes, &ent.entry.flags);
28072445Sassar	tmp = getint(&p); /* max life */
28172445Sassar	if(tmp != 0) {
282178825Sdfr	    ALLOC(ent.entry.max_life);
283178825Sdfr	    *ent.entry.max_life = tmp;
28472445Sassar	}
28572445Sassar	tmp = getint(&p); /* max renewable life */
28672445Sassar	if(tmp != 0) {
287178825Sdfr	    ALLOC(ent.entry.max_renew);
288178825Sdfr	    *ent.entry.max_renew = tmp;
28972445Sassar	}
29072445Sassar	tmp = getint(&p); /* expiration */
29172445Sassar	if(tmp != 0 && tmp != 2145830400) {
292178825Sdfr	    ALLOC(ent.entry.valid_end);
293178825Sdfr	    *ent.entry.valid_end = tmp;
29472445Sassar	}
29572445Sassar	tmp = getint(&p); /* pw expiration */
29672445Sassar	if(tmp != 0) {
297178825Sdfr	    ALLOC(ent.entry.pw_end);
298178825Sdfr	    *ent.entry.pw_end = tmp;
29972445Sassar	}
30072445Sassar	q = nexttoken(&p); /* last auth */
30172445Sassar	q = nexttoken(&p); /* last failed auth */
30272445Sassar	q = nexttoken(&p); /* fail auth count */
30372445Sassar	for(i = 0; i < num_tl_data; i++) {
30472445Sassar	    unsigned long val;
30572445Sassar	    int tl_type, tl_length;
30672445Sassar	    unsigned char *buf;
30772445Sassar	    krb5_principal princ;
30872445Sassar
30972445Sassar	    tl_type = getint(&p); /* data type */
31072445Sassar	    tl_length = getint(&p); /* data length */
31172445Sassar
312178825Sdfr#define mit_KRB5_TL_LAST_PWD_CHANGE	1
313178825Sdfr#define mit_KRB5_TL_MOD_PRINC		2
31472445Sassar	    switch(tl_type) {
315178825Sdfr	    case mit_KRB5_TL_MOD_PRINC:
31672445Sassar		buf = malloc(tl_length);
317178825Sdfr		if (buf == NULL)
318178825Sdfr		    errx(ENOMEM, "malloc");
31972445Sassar		getdata(&p, buf, tl_length); /* data itself */
32072445Sassar		val = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
321178825Sdfr		ret = krb5_parse_name(pd->context, (char *)buf + 4, &princ);
32272445Sassar		free(buf);
323178825Sdfr		ALLOC(ent.entry.modified_by);
324178825Sdfr		ent.entry.modified_by->time = val;
325178825Sdfr		ent.entry.modified_by->principal = princ;
32672445Sassar		break;
32772445Sassar	    default:
32872445Sassar		nexttoken(&p);
32972445Sassar		break;
33072445Sassar	    }
33172445Sassar	}
332178825Sdfr	ALLOC_SEQ(&ent.entry.keys, num_key_data);
33372445Sassar	for(i = 0; i < num_key_data; i++) {
33472445Sassar	    int key_versions;
33572445Sassar	    key_versions = getint(&p); /* key data version */
336178825Sdfr	    ent.entry.kvno = getint(&p); /* XXX kvno */
33772445Sassar
338178825Sdfr	    ALLOC(ent.entry.keys.val[i].mkvno);
339178825Sdfr	    *ent.entry.keys.val[i].mkvno = 0;
34072445Sassar
34172445Sassar	    /* key version 0 -- actual key */
342178825Sdfr	    ent.entry.keys.val[i].key.keytype = getint(&p); /* key type */
34372445Sassar	    tmp = getint(&p); /* key length */
34472445Sassar	    /* the first two bytes of the key is the key length --
34572445Sassar	       skip it */
346178825Sdfr	    krb5_data_alloc(&ent.entry.keys.val[i].key.keyvalue, tmp - 2);
34772445Sassar	    q = nexttoken(&p); /* key itself */
348178825Sdfr	    hex_to_octet_string(q + 4, &ent.entry.keys.val[i].key.keyvalue);
34972445Sassar
35072445Sassar	    if(key_versions > 1) {
35172445Sassar		/* key version 1 -- optional salt */
352178825Sdfr		ALLOC(ent.entry.keys.val[i].salt);
353178825Sdfr		ent.entry.keys.val[i].salt->type = getint(&p); /* salt type */
35472445Sassar		tmp = getint(&p); /* salt length */
35572445Sassar		if(tmp > 0) {
356178825Sdfr		    krb5_data_alloc(&ent.entry.keys.val[i].salt->salt, tmp - 2);
35772445Sassar		    q = nexttoken(&p); /* salt itself */
358178825Sdfr		    hex_to_octet_string(q + 4,
359178825Sdfr					&ent.entry.keys.val[i].salt->salt);
36072445Sassar		} else {
361178825Sdfr		    ent.entry.keys.val[i].salt->salt.length = 0;
362178825Sdfr		    ent.entry.keys.val[i].salt->salt.data = NULL;
36372445Sassar		    tmp = getint(&p);	/* -1, if no data. */
36472445Sassar		}
365178825Sdfr		fix_salt(pd->context, &ent.entry, i);
36672445Sassar	    }
36772445Sassar	}
36872445Sassar	q = nexttoken(&p); /* extra data */
36972445Sassar	v5_prop(pd->context, NULL, &ent, arg);
37072445Sassar    }
371178825Sdfr    fclose(f);
37272445Sassar    return 0;
37372445Sassar}
374