172445Sassar/*
2233294Sstas * Copyright (c) 2000 Kungliga Tekniska H��gskolan
372445Sassar * (Royal Institute of Technology, Stockholm, Sweden).
472445Sassar * All rights reserved.
5233294Sstas *
672445Sassar * Redistribution and use in source and binary forms, with or without
772445Sassar * modification, are permitted provided that the following conditions
872445Sassar * are met:
9233294Sstas *
1072445Sassar * 1. Redistributions of source code must retain the above copyright
1172445Sassar *    notice, this list of conditions and the following disclaimer.
12233294Sstas *
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.
16233294Sstas *
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.
20233294Sstas *
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
3672445Sassar/*
3772445Sassarcan have any number of princ stanzas.
3872445Sassarformat is as follows (only \n indicates newlines)
3972445Sassarprinc\t%d\t (%d is KRB5_KDB_V1_BASE_LENGTH, always 38)
4072445Sassar%d\t (strlen of principal e.g. shadow/foo@ANDREW.CMU.EDU)
4172445Sassar%d\t (number of tl_data)
4272445Sassar%d\t (number of key data, e.g. how many keys for this user)
43233294Sstas%d\t (extra data length)
4472445Sassar%s\t (principal name)
4572445Sassar%d\t (attributes)
4672445Sassar%d\t (max lifetime, seconds)
4772445Sassar%d\t (max renewable life, seconds)
4872445Sassar%d\t (expiration, seconds since epoch or 2145830400 for never)
49233294Sstas%d\t (password expiration, seconds, 0 for never)
5072445Sassar%d\t (last successful auth, seconds since epoch)
5172445Sassar%d\t (last failed auth, per above)
5272445Sassar%d\t (failed auth count)
5372445Sassarforeach tl_data 0 to number of tl_data - 1 as above
5472445Sassar  %d\t%d\t (data type, data length)
5572445Sassar  foreach tl_data 0 to length-1
5672445Sassar    %02x (tl data contents[element n])
5772445Sassar  except if tl_data length is 0
5872445Sassar    %d (always -1)
5972445Sassar  \t
6072445Sassarforeach key 0 to number of keys - 1 as above
6172445Sassar  %d\t%d\t (key data version, kvno)
6272445Sassar  foreach version 0 to key data version - 1 (a key or a salt)
6372445Sassar    %d\t%d\t(data type for this key, data length for this key)
6472445Sassar    foreach key data length 0 to length-1
6572445Sassar      %02x (key data contents[element n])
6672445Sassar    except if key_data length is 0
6772445Sassar      %d (always -1)
68233294Sstas    \t
6972445Sassarforeach extra data length 0 to length - 1
7072445Sassar  %02x (extra data part)
7172445Sassarunless no extra data
7272445Sassar  %d (always -1)
7372445Sassar;\n
7472445Sassar
7572445Sassar*/
7672445Sassar
7772445Sassarstatic int
7872445Sassarhex_to_octet_string(const char *ptr, krb5_data *data)
7972445Sassar{
80233294Sstas    size_t i;
8172445Sassar    unsigned int v;
8272445Sassar    for(i = 0; i < data->length; i++) {
8372445Sassar	if(sscanf(ptr + 2 * i, "%02x", &v) != 1)
8472445Sassar	    return -1;
8572445Sassar	((unsigned char*)data->data)[i] = v;
8672445Sassar    }
8772445Sassar    return 2 * i;
8872445Sassar}
8972445Sassar
9072445Sassarstatic char *
9172445Sassarnexttoken(char **p)
9272445Sassar{
9372445Sassar    char *q;
9472445Sassar    do {
9572445Sassar	q = strsep(p, " \t");
9672445Sassar    } while(q && *q == '\0');
9772445Sassar    return q;
9872445Sassar}
9972445Sassar
10072445Sassarstatic size_t
10172445Sassargetdata(char **p, unsigned char *buf, size_t len)
10272445Sassar{
10372445Sassar    size_t i;
10472445Sassar    int v;
10572445Sassar    char *q = nexttoken(p);
10672445Sassar    i = 0;
10772445Sassar    while(*q && i < len) {
10872445Sassar	if(sscanf(q, "%02x", &v) != 1)
10972445Sassar	    break;
11072445Sassar	buf[i++] = v;
11172445Sassar	q += 2;
11272445Sassar    }
11372445Sassar    return i;
11472445Sassar}
11572445Sassar
11672445Sassarstatic int
11772445Sassargetint(char **p)
11872445Sassar{
11972445Sassar    int val;
12072445Sassar    char *q = nexttoken(p);
12172445Sassar    sscanf(q, "%d", &val);
12272445Sassar    return val;
12372445Sassar}
12472445Sassar
12572445Sassar#include <kadm5/admin.h>
12672445Sassar
12772445Sassarstatic void
12872445Sassarattr_to_flags(unsigned attr, HDBFlags *flags)
12972445Sassar{
13072445Sassar    flags->postdate =		!(attr & KRB5_KDB_DISALLOW_POSTDATED);
13172445Sassar    flags->forwardable =	!(attr & KRB5_KDB_DISALLOW_FORWARDABLE);
13272445Sassar    flags->initial =	       !!(attr & KRB5_KDB_DISALLOW_TGT_BASED);
13372445Sassar    flags->renewable =		!(attr & KRB5_KDB_DISALLOW_RENEWABLE);
13472445Sassar    flags->proxiable =		!(attr & KRB5_KDB_DISALLOW_PROXIABLE);
13572445Sassar    /* DUP_SKEY */
13672445Sassar    flags->invalid =	       !!(attr & KRB5_KDB_DISALLOW_ALL_TIX);
13772445Sassar    flags->require_preauth =   !!(attr & KRB5_KDB_REQUIRES_PRE_AUTH);
138233294Sstas    flags->require_hwauth =    !!(attr & KRB5_KDB_REQUIRES_HW_AUTH);
13972445Sassar    flags->server =		!(attr & KRB5_KDB_DISALLOW_SVR);
14072445Sassar    flags->change_pw = 	       !!(attr & KRB5_KDB_PWCHANGE_SERVICE);
14172445Sassar    flags->client =	        1; /* XXX */
14272445Sassar}
14372445Sassar
14472445Sassar#define KRB5_KDB_SALTTYPE_NORMAL	0
14572445Sassar#define KRB5_KDB_SALTTYPE_V4		1
14672445Sassar#define KRB5_KDB_SALTTYPE_NOREALM	2
14772445Sassar#define KRB5_KDB_SALTTYPE_ONLYREALM	3
14872445Sassar#define KRB5_KDB_SALTTYPE_SPECIAL	4
14972445Sassar#define KRB5_KDB_SALTTYPE_AFS3		5
15072445Sassar
15172445Sassarstatic krb5_error_code
15272445Sassarfix_salt(krb5_context context, hdb_entry *ent, int key_num)
15372445Sassar{
15472445Sassar    krb5_error_code ret;
15572445Sassar    Salt *salt = ent->keys.val[key_num].salt;
15672445Sassar    /* fix salt type */
15772445Sassar    switch((int)salt->type) {
15872445Sassar    case KRB5_KDB_SALTTYPE_NORMAL:
15972445Sassar	salt->type = KRB5_PADATA_PW_SALT;
16072445Sassar	break;
16172445Sassar    case KRB5_KDB_SALTTYPE_V4:
16272445Sassar	krb5_data_free(&salt->salt);
16372445Sassar	salt->type = KRB5_PADATA_PW_SALT;
16472445Sassar	break;
16572445Sassar    case KRB5_KDB_SALTTYPE_NOREALM:
16672445Sassar    {
16772445Sassar	size_t len;
168233294Sstas	size_t i;
16972445Sassar	char *p;
170233294Sstas
17172445Sassar	len = 0;
17272445Sassar	for (i = 0; i < ent->principal->name.name_string.len; ++i)
17372445Sassar	    len += strlen(ent->principal->name.name_string.val[i]);
17472445Sassar	ret = krb5_data_alloc (&salt->salt, len);
17572445Sassar	if (ret)
17672445Sassar	    return ret;
17772445Sassar	p = salt->salt.data;
17872445Sassar	for (i = 0; i < ent->principal->name.name_string.len; ++i) {
17972445Sassar	    memcpy (p,
18072445Sassar		    ent->principal->name.name_string.val[i],
18172445Sassar		    strlen(ent->principal->name.name_string.val[i]));
18272445Sassar	    p += strlen(ent->principal->name.name_string.val[i]);
18372445Sassar	}
18472445Sassar
18572445Sassar	salt->type = KRB5_PADATA_PW_SALT;
18672445Sassar	break;
18772445Sassar    }
18872445Sassar    case KRB5_KDB_SALTTYPE_ONLYREALM:
18972445Sassar	krb5_data_free(&salt->salt);
190233294Sstas	ret = krb5_data_copy(&salt->salt,
191233294Sstas			     ent->principal->realm,
19272445Sassar			     strlen(ent->principal->realm));
19372445Sassar	if(ret)
19472445Sassar	    return ret;
19572445Sassar	salt->type = KRB5_PADATA_PW_SALT;
19672445Sassar	break;
19772445Sassar    case KRB5_KDB_SALTTYPE_SPECIAL:
19872445Sassar	salt->type = KRB5_PADATA_PW_SALT;
19972445Sassar	break;
20072445Sassar    case KRB5_KDB_SALTTYPE_AFS3:
20172445Sassar	krb5_data_free(&salt->salt);
202233294Sstas	ret = krb5_data_copy(&salt->salt,
203233294Sstas		       ent->principal->realm,
20472445Sassar		       strlen(ent->principal->realm));
20572445Sassar	if(ret)
20672445Sassar	    return ret;
20772445Sassar	salt->type = KRB5_PADATA_AFS3_SALT;
20872445Sassar	break;
20972445Sassar    default:
21072445Sassar	abort();
21172445Sassar    }
21272445Sassar    return 0;
21372445Sassar}
21472445Sassar
21572445Sassarint
21672445Sassarmit_prop_dump(void *arg, const char *file)
21772445Sassar{
21872445Sassar    krb5_error_code ret;
219178825Sdfr    char line [2048];
22072445Sassar    FILE *f;
22172445Sassar    int lineno = 0;
222178825Sdfr    struct hdb_entry_ex ent;
22372445Sassar
22472445Sassar    struct prop_data *pd = arg;
22572445Sassar
22672445Sassar    f = fopen(file, "r");
22772445Sassar    if(f == NULL)
22872445Sassar	return errno;
229233294Sstas
230178825Sdfr    while(fgets(line, sizeof(line), f)) {
231178825Sdfr	char *p = line, *q;
23272445Sassar
23372445Sassar	int i;
23472445Sassar
23572445Sassar	int num_tl_data;
23672445Sassar	int num_key_data;
237233294Sstas	int high_kvno;
23872445Sassar	int attributes;
23972445Sassar
24072445Sassar	int tmp;
24172445Sassar
24272445Sassar	lineno++;
24372445Sassar
24472445Sassar	memset(&ent, 0, sizeof(ent));
24572445Sassar
24672445Sassar	q = nexttoken(&p);
24772445Sassar	if(strcmp(q, "kdb5_util") == 0) {
24872445Sassar	    int major;
24972445Sassar	    q = nexttoken(&p); /* load_dump */
25072445Sassar	    if(strcmp(q, "load_dump"))
25172445Sassar		errx(1, "line %d: unknown version", lineno);
25272445Sassar	    q = nexttoken(&p); /* load_dump */
25372445Sassar	    if(strcmp(q, "version"))
25472445Sassar		errx(1, "line %d: unknown version", lineno);
25572445Sassar	    q = nexttoken(&p); /* x.0 */
25672445Sassar	    if(sscanf(q, "%d", &major) != 1)
25772445Sassar		errx(1, "line %d: unknown version", lineno);
258233294Sstas	    if(major != 4 && major != 5 && major != 6)
259233294Sstas		errx(1, "unknown dump file format, got %d, expected 4-6",
260233294Sstas		     major);
26172445Sassar	    continue;
262233294Sstas	} else if(strcmp(q, "policy") == 0) {
263233294Sstas	    continue;
26472445Sassar	} else if(strcmp(q, "princ") != 0) {
26572445Sassar	    warnx("line %d: not a principal", lineno);
26672445Sassar	    continue;
26772445Sassar	}
26872445Sassar	tmp = getint(&p);
26972445Sassar	if(tmp != 38) {
27072445Sassar	    warnx("line %d: bad base length %d != 38", lineno, tmp);
27172445Sassar	    continue;
27272445Sassar	}
273233294Sstas	nexttoken(&p); /* length of principal */
27472445Sassar	num_tl_data = getint(&p); /* number of tl-data */
27572445Sassar	num_key_data = getint(&p); /* number of key-data */
276233294Sstas	getint(&p);  /* length of extra data */
27772445Sassar	q = nexttoken(&p); /* principal name */
278178825Sdfr	krb5_parse_name(pd->context, q, &ent.entry.principal);
27972445Sassar	attributes = getint(&p); /* attributes */
280178825Sdfr	attr_to_flags(attributes, &ent.entry.flags);
28172445Sassar	tmp = getint(&p); /* max life */
28272445Sassar	if(tmp != 0) {
283178825Sdfr	    ALLOC(ent.entry.max_life);
284178825Sdfr	    *ent.entry.max_life = tmp;
28572445Sassar	}
28672445Sassar	tmp = getint(&p); /* max renewable life */
28772445Sassar	if(tmp != 0) {
288178825Sdfr	    ALLOC(ent.entry.max_renew);
289178825Sdfr	    *ent.entry.max_renew = tmp;
29072445Sassar	}
29172445Sassar	tmp = getint(&p); /* expiration */
29272445Sassar	if(tmp != 0 && tmp != 2145830400) {
293178825Sdfr	    ALLOC(ent.entry.valid_end);
294178825Sdfr	    *ent.entry.valid_end = tmp;
29572445Sassar	}
29672445Sassar	tmp = getint(&p); /* pw expiration */
29772445Sassar	if(tmp != 0) {
298178825Sdfr	    ALLOC(ent.entry.pw_end);
299178825Sdfr	    *ent.entry.pw_end = tmp;
30072445Sassar	}
301233294Sstas	nexttoken(&p); /* last auth */
302233294Sstas	nexttoken(&p); /* last failed auth */
303233294Sstas	nexttoken(&p); /* fail auth count */
30472445Sassar	for(i = 0; i < num_tl_data; i++) {
30572445Sassar	    unsigned long val;
30672445Sassar	    int tl_type, tl_length;
30772445Sassar	    unsigned char *buf;
30872445Sassar	    krb5_principal princ;
30972445Sassar
31072445Sassar	    tl_type = getint(&p); /* data type */
31172445Sassar	    tl_length = getint(&p); /* data length */
31272445Sassar
313178825Sdfr#define mit_KRB5_TL_LAST_PWD_CHANGE	1
314178825Sdfr#define mit_KRB5_TL_MOD_PRINC		2
31572445Sassar	    switch(tl_type) {
316233294Sstas	    case mit_KRB5_TL_LAST_PWD_CHANGE:
317233294Sstas		buf = malloc(tl_length);
318233294Sstas		if (buf == NULL)
319233294Sstas		    errx(ENOMEM, "malloc");
320233294Sstas		getdata(&p, buf, tl_length); /* data itself */
321233294Sstas		val = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
322233294Sstas		free(buf);
323233294Sstas		ALLOC(ent.entry.extensions);
324233294Sstas		ALLOC_SEQ(ent.entry.extensions, 1);
325233294Sstas		ent.entry.extensions->val[0].mandatory = 0;
326233294Sstas		ent.entry.extensions->val[0].data.element
327233294Sstas		    = choice_HDB_extension_data_last_pw_change;
328233294Sstas		ent.entry.extensions->val[0].data.u.last_pw_change = val;
329233294Sstas		break;
330178825Sdfr	    case mit_KRB5_TL_MOD_PRINC:
33172445Sassar		buf = malloc(tl_length);
332178825Sdfr		if (buf == NULL)
333178825Sdfr		    errx(ENOMEM, "malloc");
33472445Sassar		getdata(&p, buf, tl_length); /* data itself */
33572445Sassar		val = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
336178825Sdfr		ret = krb5_parse_name(pd->context, (char *)buf + 4, &princ);
337233294Sstas		if (ret)
338233294Sstas		    krb5_err(pd->context, 1, ret,
339233294Sstas			     "parse_name: %s", (char *)buf + 4);
34072445Sassar		free(buf);
341178825Sdfr		ALLOC(ent.entry.modified_by);
342178825Sdfr		ent.entry.modified_by->time = val;
343178825Sdfr		ent.entry.modified_by->principal = princ;
34472445Sassar		break;
34572445Sassar	    default:
34672445Sassar		nexttoken(&p);
34772445Sassar		break;
34872445Sassar	    }
34972445Sassar	}
350178825Sdfr	ALLOC_SEQ(&ent.entry.keys, num_key_data);
351233294Sstas	high_kvno = -1;
35272445Sassar	for(i = 0; i < num_key_data; i++) {
35372445Sassar	    int key_versions;
354233294Sstas	    int kvno;
35572445Sassar	    key_versions = getint(&p); /* key data version */
356233294Sstas	    kvno = getint(&p);
357233294Sstas
358233294Sstas	    /*
359233294Sstas	     * An MIT dump file may contain multiple sets of keys with
360233294Sstas	     * different kvnos.  Since the Heimdal database can only represent
361233294Sstas	     * one kvno per principal, we only want the highest set.  Assume
362233294Sstas	     * that set will be given first, and discard all keys with lower
363233294Sstas	     * kvnos.
364233294Sstas	     */
365233294Sstas	    if (kvno > high_kvno && high_kvno != -1)
366233294Sstas		errx(1, "line %d: high kvno keys given after low kvno keys",
367233294Sstas		     lineno);
368233294Sstas	    else if (kvno < high_kvno) {
369233294Sstas		nexttoken(&p); /* key type */
370233294Sstas		nexttoken(&p); /* key length */
371233294Sstas		nexttoken(&p); /* key */
372233294Sstas		if (key_versions > 1) {
373233294Sstas		    nexttoken(&p); /* salt type */
374233294Sstas		    nexttoken(&p); /* salt length */
375233294Sstas		    nexttoken(&p); /* salt */
376233294Sstas		}
377233294Sstas		ent.entry.keys.len--;
378233294Sstas		continue;
379233294Sstas	    }
380233294Sstas	    ent.entry.kvno = kvno;
381233294Sstas	    high_kvno = kvno;
382178825Sdfr	    ALLOC(ent.entry.keys.val[i].mkvno);
383233294Sstas	    *ent.entry.keys.val[i].mkvno = 1;
384233294Sstas
38572445Sassar	    /* key version 0 -- actual key */
386178825Sdfr	    ent.entry.keys.val[i].key.keytype = getint(&p); /* key type */
38772445Sassar	    tmp = getint(&p); /* key length */
38872445Sassar	    /* the first two bytes of the key is the key length --
38972445Sassar	       skip it */
390178825Sdfr	    krb5_data_alloc(&ent.entry.keys.val[i].key.keyvalue, tmp - 2);
39172445Sassar	    q = nexttoken(&p); /* key itself */
392178825Sdfr	    hex_to_octet_string(q + 4, &ent.entry.keys.val[i].key.keyvalue);
39372445Sassar
39472445Sassar	    if(key_versions > 1) {
39572445Sassar		/* key version 1 -- optional salt */
396178825Sdfr		ALLOC(ent.entry.keys.val[i].salt);
397178825Sdfr		ent.entry.keys.val[i].salt->type = getint(&p); /* salt type */
39872445Sassar		tmp = getint(&p); /* salt length */
39972445Sassar		if(tmp > 0) {
400178825Sdfr		    krb5_data_alloc(&ent.entry.keys.val[i].salt->salt, tmp - 2);
40172445Sassar		    q = nexttoken(&p); /* salt itself */
402178825Sdfr		    hex_to_octet_string(q + 4,
403178825Sdfr					&ent.entry.keys.val[i].salt->salt);
40472445Sassar		} else {
405178825Sdfr		    ent.entry.keys.val[i].salt->salt.length = 0;
406178825Sdfr		    ent.entry.keys.val[i].salt->salt.data = NULL;
407233294Sstas		    getint(&p);	/* -1, if no data. */
40872445Sassar		}
409178825Sdfr		fix_salt(pd->context, &ent.entry, i);
41072445Sassar	    }
41172445Sassar	}
412233294Sstas	nexttoken(&p); /* extra data */
41372445Sassar	v5_prop(pd->context, NULL, &ent, arg);
41472445Sassar    }
415178825Sdfr    fclose(f);
41672445Sassar    return 0;
41772445Sassar}
418