xref: /freebsd/crypto/heimdal/lib/hdb/hdb-mitdb.c (revision 5000d023a446b81f6d45ed59aa379607ec814f01)
1 /*
2  * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * 3. Neither the name of the Institute nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #define KRB5_KDB_DISALLOW_POSTDATED	0x00000001
37 #define KRB5_KDB_DISALLOW_FORWARDABLE	0x00000002
38 #define KRB5_KDB_DISALLOW_TGT_BASED	0x00000004
39 #define KRB5_KDB_DISALLOW_RENEWABLE	0x00000008
40 #define KRB5_KDB_DISALLOW_PROXIABLE	0x00000010
41 #define KRB5_KDB_DISALLOW_DUP_SKEY	0x00000020
42 #define KRB5_KDB_DISALLOW_ALL_TIX	0x00000040
43 #define KRB5_KDB_REQUIRES_PRE_AUTH	0x00000080
44 #define KRB5_KDB_REQUIRES_HW_AUTH	0x00000100
45 #define KRB5_KDB_REQUIRES_PWCHANGE	0x00000200
46 #define KRB5_KDB_DISALLOW_SVR		0x00001000
47 #define KRB5_KDB_PWCHANGE_SERVICE	0x00002000
48 #define KRB5_KDB_SUPPORT_DESMD5		0x00004000
49 #define KRB5_KDB_NEW_PRINC		0x00008000
50 
51 /*
52 
53 key: krb5_unparse_name  + NUL
54 
55  16: baselength
56  32: attributes
57  32: max time
58  32: max renewable time
59  32: client expire
60  32: passwd expire
61  32: last successful passwd
62  32: last failed attempt
63  32: num of failed attempts
64  16: num tl data
65  16: num data data
66  16: principal length
67  length: principal
68  for num tl data times
69     16: tl data type
70     16: tl data length
71     length: length
72  for num key data times
73     16: version (num keyblocks)
74     16: kvno
75     for version times:
76         16: type
77         16: length
78         length: keydata
79 
80 
81 key_data_contents[0]
82 
83 	int16: length
84 	read-of-data: key-encrypted, key-usage 0, master-key
85 
86 salt:
87     version2 = salt in key_data->key_data_contents[1]
88     else default salt.
89 
90 */
91 
92 #include "hdb_locl.h"
93 
94 static void
attr_to_flags(unsigned attr,HDBFlags * flags)95 attr_to_flags(unsigned attr, HDBFlags *flags)
96 {
97     flags->postdate =		!(attr & KRB5_KDB_DISALLOW_POSTDATED);
98     flags->forwardable =	!(attr & KRB5_KDB_DISALLOW_FORWARDABLE);
99     flags->initial =	       !!(attr & KRB5_KDB_DISALLOW_TGT_BASED);
100     flags->renewable =		!(attr & KRB5_KDB_DISALLOW_RENEWABLE);
101     flags->proxiable =		!(attr & KRB5_KDB_DISALLOW_PROXIABLE);
102     /* DUP_SKEY */
103     flags->invalid =	       !!(attr & KRB5_KDB_DISALLOW_ALL_TIX);
104     flags->require_preauth =   !!(attr & KRB5_KDB_REQUIRES_PRE_AUTH);
105     flags->require_hwauth =    !!(attr & KRB5_KDB_REQUIRES_HW_AUTH);
106     flags->server =		!(attr & KRB5_KDB_DISALLOW_SVR);
107     flags->change_pw = 	       !!(attr & KRB5_KDB_PWCHANGE_SERVICE);
108     flags->client =	        1; /* XXX */
109 }
110 
111 #define KDB_V1_BASE_LENGTH 38
112 
113 #define CHECK(x) do { if ((x)) goto out; } while(0)
114 
115 #ifdef HAVE_DB1
116 static krb5_error_code
mdb_principal2key(krb5_context context,krb5_const_principal principal,krb5_data * key)117 mdb_principal2key(krb5_context context,
118 		  krb5_const_principal principal,
119 		  krb5_data *key)
120 {
121     krb5_error_code ret;
122     char *str;
123 
124     ret = krb5_unparse_name(context, principal, &str);
125     if (ret)
126 	return ret;
127     key->data = str;
128     key->length = strlen(str) + 1;
129     return 0;
130 }
131 #endif /* HAVE_DB1 */
132 
133 #define KRB5_KDB_SALTTYPE_NORMAL	0
134 #define KRB5_KDB_SALTTYPE_V4		1
135 #define KRB5_KDB_SALTTYPE_NOREALM	2
136 #define KRB5_KDB_SALTTYPE_ONLYREALM	3
137 #define KRB5_KDB_SALTTYPE_SPECIAL	4
138 #define KRB5_KDB_SALTTYPE_AFS3		5
139 #define KRB5_KDB_SALTTYPE_CERTHASH	6
140 
141 static krb5_error_code
fix_salt(krb5_context context,hdb_entry * ent,int key_num)142 fix_salt(krb5_context context, hdb_entry *ent, int key_num)
143 {
144     krb5_error_code ret;
145     Salt *salt = ent->keys.val[key_num].salt;
146     /* fix salt type */
147     switch((int)salt->type) {
148     case KRB5_KDB_SALTTYPE_NORMAL:
149 	salt->type = KRB5_PADATA_PW_SALT;
150 	break;
151     case KRB5_KDB_SALTTYPE_V4:
152 	krb5_data_free(&salt->salt);
153 	salt->type = KRB5_PADATA_PW_SALT;
154 	break;
155     case KRB5_KDB_SALTTYPE_NOREALM:
156     {
157 	size_t len;
158 	size_t i;
159 	char *p;
160 
161 	len = 0;
162 	for (i = 0; i < ent->principal->name.name_string.len; ++i)
163 	    len += strlen(ent->principal->name.name_string.val[i]);
164 	ret = krb5_data_alloc (&salt->salt, len);
165 	if (ret)
166 	    return ret;
167 	p = salt->salt.data;
168 	for (i = 0; i < ent->principal->name.name_string.len; ++i) {
169 	    memcpy (p,
170 		    ent->principal->name.name_string.val[i],
171 		    strlen(ent->principal->name.name_string.val[i]));
172 	    p += strlen(ent->principal->name.name_string.val[i]);
173 	}
174 
175 	salt->type = KRB5_PADATA_PW_SALT;
176 	break;
177     }
178     case KRB5_KDB_SALTTYPE_ONLYREALM:
179 	krb5_data_free(&salt->salt);
180 	ret = krb5_data_copy(&salt->salt,
181 			     ent->principal->realm,
182 			     strlen(ent->principal->realm));
183 	if(ret)
184 	    return ret;
185 	salt->type = KRB5_PADATA_PW_SALT;
186 	break;
187     case KRB5_KDB_SALTTYPE_SPECIAL:
188 	salt->type = KRB5_PADATA_PW_SALT;
189 	break;
190     case KRB5_KDB_SALTTYPE_AFS3:
191 	krb5_data_free(&salt->salt);
192 	ret = krb5_data_copy(&salt->salt,
193 		       ent->principal->realm,
194 		       strlen(ent->principal->realm));
195 	if(ret)
196 	    return ret;
197 	salt->type = KRB5_PADATA_AFS3_SALT;
198 	break;
199     case KRB5_KDB_SALTTYPE_CERTHASH:
200 	krb5_data_free(&salt->salt);
201 	free(ent->keys.val[key_num].salt);
202 	ent->keys.val[key_num].salt = NULL;
203 	break;
204     default:
205 	abort();
206     }
207     return 0;
208 }
209 
210 
211 krb5_error_code
_hdb_mdb_value2entry(krb5_context context,krb5_data * data,krb5_kvno kvno,hdb_entry * entry)212 _hdb_mdb_value2entry(krb5_context context, krb5_data *data,
213                      krb5_kvno kvno, hdb_entry *entry)
214 {
215     krb5_error_code ret;
216     krb5_storage *sp;
217     uint32_t u32;
218     uint16_t u16, num_keys, num_tl;
219     ssize_t sz;
220     size_t i, j;
221     char *p;
222 
223     sp = krb5_storage_from_data(data);
224     if (sp == NULL) {
225 	krb5_set_error_message(context, ENOMEM, "out of memory");
226 	return ENOMEM;
227     }
228 
229     krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE);
230 
231     /*
232      * 16: baselength
233      *
234      * The story here is that these 16 bits have to be a constant:
235      * KDB_V1_BASE_LENGTH.  Once upon a time a different value here
236      * would have been used to indicate the presence of "extra data"
237      * between the "base" contents and the {principal name, TL data,
238      * keys} that follow it.  Nothing supports such "extra data"
239      * nowadays, so neither do we here.
240      *
241      * XXX But... surely we ought to log about this extra data, or skip
242      * it, or something, in case anyone has MIT KDBs with ancient
243      * entries in them...  Logging would allow the admin to know which
244      * entries to dump with MIT krb5's kdb5_util.
245      */
246     CHECK(ret = krb5_ret_uint16(sp, &u16));
247     if (u16 != KDB_V1_BASE_LENGTH) { ret = EINVAL; goto out; }
248     /* 32: attributes */
249     CHECK(ret = krb5_ret_uint32(sp, &u32));
250     attr_to_flags(u32, &entry->flags);
251 
252     /* 32: max time */
253     CHECK(ret = krb5_ret_uint32(sp, &u32));
254     if (u32) {
255 	entry->max_life = malloc(sizeof(*entry->max_life));
256 	*entry->max_life = u32;
257     }
258     /* 32: max renewable time */
259     CHECK(ret = krb5_ret_uint32(sp, &u32));
260     if (u32) {
261 	entry->max_renew = malloc(sizeof(*entry->max_renew));
262 	*entry->max_renew = u32;
263     }
264     /* 32: client expire */
265     CHECK(ret = krb5_ret_uint32(sp, &u32));
266     if (u32) {
267 	entry->valid_end = malloc(sizeof(*entry->valid_end));
268 	*entry->valid_end = u32;
269     }
270     /* 32: passwd expire */
271     CHECK(ret = krb5_ret_uint32(sp, &u32));
272     if (u32) {
273 	entry->pw_end = malloc(sizeof(*entry->pw_end));
274 	*entry->pw_end = u32;
275     }
276     /* 32: last successful passwd */
277     CHECK(ret = krb5_ret_uint32(sp, &u32));
278     /* 32: last failed attempt */
279     CHECK(ret = krb5_ret_uint32(sp, &u32));
280     /* 32: num of failed attempts */
281     CHECK(ret = krb5_ret_uint32(sp, &u32));
282     /* 16: num tl data */
283     CHECK(ret = krb5_ret_uint16(sp, &u16));
284     num_tl = u16;
285     /* 16: num key data */
286     CHECK(ret = krb5_ret_uint16(sp, &u16));
287     num_keys = u16;
288     /* 16: principal length */
289     CHECK(ret = krb5_ret_uint16(sp, &u16));
290     /* length: principal */
291     {
292 	/*
293 	 * Note that the principal name includes the NUL in the entry,
294 	 * but we don't want to take chances, so we add an extra NUL.
295 	 */
296 	p = malloc(u16 + 1);
297 	if (p == NULL) {
298 	    ret = ENOMEM;
299 	    goto out;
300 	}
301 	sz = krb5_storage_read(sp, p, u16);
302         if (sz != u16) {
303             ret = EINVAL; /* XXX */
304             goto out;
305         }
306 	p[u16] = '\0';
307 	CHECK(ret = krb5_parse_name(context, p, &entry->principal));
308 	free(p);
309     }
310     /* for num tl data times
311            16: tl data type
312            16: tl data length
313            length: length */
314 #define mit_KRB5_TL_LAST_PWD_CHANGE     1
315 #define mit_KRB5_TL_MOD_PRINC           2
316     for (i = 0; i < num_tl; i++) {
317         int tl_type;
318         krb5_principal modby;
319 	/* 16: TL data type */
320 	CHECK(ret = krb5_ret_uint16(sp, &u16));
321         tl_type = u16;
322 	/* 16: TL data length */
323 	CHECK(ret = krb5_ret_uint16(sp, &u16));
324         /*
325          * For rollback to MIT purposes we really must understand some
326          * TL data!
327          *
328          * XXX Move all this to separate functions, one per-TL type.
329          */
330         switch (tl_type) {
331         case mit_KRB5_TL_LAST_PWD_CHANGE:
332             CHECK(ret = krb5_ret_uint32(sp, &u32));
333             CHECK(ret = hdb_entry_set_pw_change_time(context, entry, u32));
334             break;
335         case mit_KRB5_TL_MOD_PRINC:
336             if (u16 < 5) {
337                 ret = EINVAL; /* XXX */
338                 goto out;
339             }
340             CHECK(ret = krb5_ret_uint32(sp, &u32)); /* mod time */
341             p = malloc(u16 - 4 + 1);
342             if (!p) {
343                 ret = ENOMEM;
344                 goto out;
345             }
346             p[u16 - 4] = '\0';
347             sz = krb5_storage_read(sp, p, u16 - 4);
348             if (sz != u16 - 4) {
349                 ret = EINVAL; /* XXX */
350                 goto out;
351             }
352             CHECK(ret = krb5_parse_name(context, p, &modby));
353             ret = hdb_set_last_modified_by(context, entry, modby, u32);
354             krb5_free_principal(context, modby);
355             free(p);
356             break;
357         default:
358             krb5_storage_seek(sp, u16, SEEK_CUR);
359             break;
360         }
361     }
362     /*
363      * for num key data times
364      * 16: "version"
365      * 16: kvno
366      * for version times:
367      *     16: type
368      *     16: length
369      *     length: keydata
370      *
371      * "version" here is really 1 or 2, the first meaning there's only
372      * keys for this kvno, the second meaning there's keys and salt[s?].
373      * That's right... hold that gag reflex, you can do it.
374      */
375     for (i = 0; i < num_keys; i++) {
376 	int keep = 0;
377 	uint16_t version;
378 	void *ptr;
379 
380 	CHECK(ret = krb5_ret_uint16(sp, &u16));
381 	version = u16;
382 	CHECK(ret = krb5_ret_uint16(sp, &u16));
383 
384 	/*
385 	 * First time through, and until we find one matching key,
386 	 * entry->kvno == 0.
387 	 */
388 	if ((entry->kvno < u16) && (kvno == 0 || kvno == u16)) {
389 	    keep = 1;
390 	    entry->kvno = u16;
391 	    /*
392 	     * Found a higher kvno than earlier, so free the old highest
393 	     * kvno keys.
394 	     *
395 	     * XXX Of course, we actually want to extract the old kvnos
396 	     * as well, for some of the kadm5 APIs.  We shouldn't free
397 	     * these keys, but keep them elsewhere.
398 	     */
399 	    for (j = 0; j < entry->keys.len; j++)
400 		free_Key(&entry->keys.val[j]);
401 	    free(entry->keys.val);
402 	    entry->keys.len = 0;
403 	    entry->keys.val = NULL;
404 	} else if (entry->kvno == u16)
405 	    /* Accumulate keys */
406 	    keep = 1;
407 
408 	if (keep) {
409 	    Key *k;
410 
411 	    ptr = realloc(entry->keys.val, sizeof(entry->keys.val[0]) * (entry->keys.len + 1));
412 	    if (ptr == NULL) {
413 		ret = ENOMEM;
414 		goto out;
415 	    }
416 	    entry->keys.val = ptr;
417 
418 	    /* k points to current Key */
419 	    k = &entry->keys.val[entry->keys.len];
420 
421 	    memset(k, 0, sizeof(*k));
422 	    entry->keys.len += 1;
423 
424 	    k->mkvno = malloc(sizeof(*k->mkvno));
425 	    if (k->mkvno == NULL) {
426 		ret = ENOMEM;
427 		goto out;
428 	    }
429 	    *k->mkvno = 1;
430 
431 	    for (j = 0; j < version; j++) {
432 		uint16_t type;
433 		CHECK(ret = krb5_ret_uint16(sp, &type));
434 		CHECK(ret = krb5_ret_uint16(sp, &u16));
435 		if (j == 0) {
436 		    /* This "version" means we have a key */
437 		    k->key.keytype = type;
438 		    if (u16 < 2) {
439 			ret = EINVAL;
440 			goto out;
441 		    }
442 		    /*
443 		     * MIT stores keys encrypted keys as {16-bit length
444 		     * of plaintext key, {encrypted key}}.  The reason
445 		     * for this is that the Kerberos cryptosystem is not
446 		     * length-preserving.  Heimdal's approach is to
447 		     * truncate the plaintext to the expected length of
448 		     * the key given its enctype, so we ignore this
449 		     * 16-bit length-of-plaintext-key field.
450 		     */
451 		    krb5_storage_seek(sp, 2, SEEK_CUR); /* skip real length */
452 		    k->key.keyvalue.length = u16 - 2;   /* adjust cipher len */
453 		    k->key.keyvalue.data = malloc(k->key.keyvalue.length);
454 		    krb5_storage_read(sp, k->key.keyvalue.data,
455 				      k->key.keyvalue.length);
456 		} else if (j == 1) {
457 		    /* This "version" means we have a salt */
458 		    k->salt = calloc(1, sizeof(*k->salt));
459 		    if (k->salt == NULL) {
460 			ret = ENOMEM;
461 			goto out;
462 		    }
463 		    k->salt->type = type;
464 		    if (u16 != 0) {
465 			k->salt->salt.data = malloc(u16);
466 			if (k->salt->salt.data == NULL) {
467 			    ret = ENOMEM;
468 			    goto out;
469 			}
470 			k->salt->salt.length = u16;
471 			krb5_storage_read(sp, k->salt->salt.data, k->salt->salt.length);
472 		    }
473 		    fix_salt(context, entry, entry->keys.len - 1);
474 		} else {
475 		    /*
476 		     * Whatever this "version" might be, we skip it
477 		     *
478 		     * XXX A krb5.conf parameter requesting that we log
479 		     * about strangeness like this, or return an error
480 		     * from here, might be nice.
481 		     */
482 		    krb5_storage_seek(sp, u16, SEEK_CUR);
483 		}
484 	    }
485 	} else {
486 	    /*
487 	     * XXX For now we skip older kvnos, but we should extract
488 	     * them...
489 	     */
490 	    for (j = 0; j < version; j++) {
491 		/* enctype */
492 		CHECK(ret = krb5_ret_uint16(sp, &u16));
493 		/* encrypted key (or plaintext salt) */
494 		CHECK(ret = krb5_ret_uint16(sp, &u16));
495 		krb5_storage_seek(sp, u16, SEEK_CUR);
496 	    }
497 	}
498     }
499 
500     if (entry->kvno == 0 && kvno != 0) {
501 	ret = HDB_ERR_NOT_FOUND_HERE;
502 	goto out;
503     }
504 
505     return 0;
506  out:
507     if (ret == HEIM_ERR_EOF)
508 	/* Better error code than "end of file" */
509 	ret = HEIM_ERR_BAD_HDBENT_ENCODING;
510     return ret;
511 }
512 
513 #if 0
514 static krb5_error_code
515 mdb_entry2value(krb5_context context, hdb_entry *entry, krb5_data *data)
516 {
517     return EINVAL;
518 }
519 #endif
520 
521 #if HAVE_DB1
522 
523 #if defined(HAVE_DB_185_H)
524 #include <db_185.h>
525 #elif defined(HAVE_DB_H)
526 #include <db.h>
527 #endif
528 
529 
530 static krb5_error_code
mdb_close(krb5_context context,HDB * db)531 mdb_close(krb5_context context, HDB *db)
532 {
533     DB *d = (DB*)db->hdb_db;
534     (*d->close)(d);
535     return 0;
536 }
537 
538 static krb5_error_code
mdb_destroy(krb5_context context,HDB * db)539 mdb_destroy(krb5_context context, HDB *db)
540 {
541     krb5_error_code ret;
542 
543     ret = hdb_clear_master_key (context, db);
544     free(db->hdb_name);
545     free(db);
546     return ret;
547 }
548 
549 static krb5_error_code
mdb_lock(krb5_context context,HDB * db,int operation)550 mdb_lock(krb5_context context, HDB *db, int operation)
551 {
552     DB *d = (DB*)db->hdb_db;
553     int fd = (*d->fd)(d);
554     if(fd < 0) {
555 	krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB,
556 			       "Can't lock database: %s", db->hdb_name);
557 	return HDB_ERR_CANT_LOCK_DB;
558     }
559     return hdb_lock(fd, operation);
560 }
561 
562 static krb5_error_code
mdb_unlock(krb5_context context,HDB * db)563 mdb_unlock(krb5_context context, HDB *db)
564 {
565     DB *d = (DB*)db->hdb_db;
566     int fd = (*d->fd)(d);
567     if(fd < 0) {
568 	krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB,
569 			       "Can't unlock database: %s", db->hdb_name);
570 	return HDB_ERR_CANT_LOCK_DB;
571     }
572     return hdb_unlock(fd);
573 }
574 
575 
576 static krb5_error_code
mdb_seq(krb5_context context,HDB * db,unsigned flags,hdb_entry_ex * entry,int flag)577 mdb_seq(krb5_context context, HDB *db,
578        unsigned flags, hdb_entry_ex *entry, int flag)
579 {
580     DB *d = (DB*)db->hdb_db;
581     DBT key, value;
582     krb5_data key_data, data;
583     int code;
584 
585     code = db->hdb_lock(context, db, HDB_RLOCK);
586     if(code == -1) {
587 	krb5_set_error_message(context, HDB_ERR_DB_INUSE, "Database %s in use", db->hdb_name);
588 	return HDB_ERR_DB_INUSE;
589     }
590     code = (*d->seq)(d, &key, &value, flag);
591     db->hdb_unlock(context, db); /* XXX check value */
592     if(code == -1) {
593 	code = errno;
594 	krb5_set_error_message(context, code, "Database %s seq error: %s",
595 			       db->hdb_name, strerror(code));
596 	return code;
597     }
598     if(code == 1) {
599 	krb5_clear_error_message(context);
600 	return HDB_ERR_NOENTRY;
601     }
602 
603     key_data.data = key.data;
604     key_data.length = key.size;
605     data.data = value.data;
606     data.length = value.size;
607     memset(entry, 0, sizeof(*entry));
608 
609     if (_hdb_mdb_value2entry(context, &data, 0, &entry->entry))
610 	return mdb_seq(context, db, flags, entry, R_NEXT);
611 
612     if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
613 	code = hdb_unseal_keys (context, db, &entry->entry);
614 	if (code)
615 	    hdb_free_entry (context, entry);
616     }
617 
618     return code;
619 }
620 
621 
622 static krb5_error_code
mdb_firstkey(krb5_context context,HDB * db,unsigned flags,hdb_entry_ex * entry)623 mdb_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
624 {
625     return mdb_seq(context, db, flags, entry, R_FIRST);
626 }
627 
628 
629 static krb5_error_code
mdb_nextkey(krb5_context context,HDB * db,unsigned flags,hdb_entry_ex * entry)630 mdb_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
631 {
632     return mdb_seq(context, db, flags, entry, R_NEXT);
633 }
634 
635 static krb5_error_code
mdb_rename(krb5_context context,HDB * db,const char * new_name)636 mdb_rename(krb5_context context, HDB *db, const char *new_name)
637 {
638     int ret;
639     char *old, *new;
640 
641     asprintf(&old, "%s.db", db->hdb_name);
642     asprintf(&new, "%s.db", new_name);
643     ret = rename(old, new);
644     free(old);
645     free(new);
646     if(ret)
647 	return errno;
648 
649     free(db->hdb_name);
650     db->hdb_name = strdup(new_name);
651     return 0;
652 }
653 
654 static krb5_error_code
mdb__get(krb5_context context,HDB * db,krb5_data key,krb5_data * reply)655 mdb__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply)
656 {
657     DB *d = (DB*)db->hdb_db;
658     DBT k, v;
659     int code;
660 
661     k.data = key.data;
662     k.size = key.length;
663     code = db->hdb_lock(context, db, HDB_RLOCK);
664     if(code)
665 	return code;
666     code = (*d->get)(d, &k, &v, 0);
667     db->hdb_unlock(context, db);
668     if(code < 0) {
669 	code = errno;
670 	krb5_set_error_message(context, code, "Database %s get error: %s",
671 			       db->hdb_name, strerror(code));
672 	return code;
673     }
674     if(code == 1) {
675 	krb5_clear_error_message(context);
676 	return HDB_ERR_NOENTRY;
677     }
678 
679     krb5_data_copy(reply, v.data, v.size);
680     return 0;
681 }
682 
683 static krb5_error_code
mdb__put(krb5_context context,HDB * db,int replace,krb5_data key,krb5_data value)684 mdb__put(krb5_context context, HDB *db, int replace,
685 	krb5_data key, krb5_data value)
686 {
687     DB *d = (DB*)db->hdb_db;
688     DBT k, v;
689     int code;
690 
691     k.data = key.data;
692     k.size = key.length;
693     v.data = value.data;
694     v.size = value.length;
695     code = db->hdb_lock(context, db, HDB_WLOCK);
696     if(code)
697 	return code;
698     code = (*d->put)(d, &k, &v, replace ? 0 : R_NOOVERWRITE);
699     db->hdb_unlock(context, db);
700     if(code < 0) {
701 	code = errno;
702 	krb5_set_error_message(context, code, "Database %s put error: %s",
703 			       db->hdb_name, strerror(code));
704 	return code;
705     }
706     if(code == 1) {
707 	krb5_clear_error_message(context);
708 	return HDB_ERR_EXISTS;
709     }
710     return 0;
711 }
712 
713 static krb5_error_code
mdb__del(krb5_context context,HDB * db,krb5_data key)714 mdb__del(krb5_context context, HDB *db, krb5_data key)
715 {
716     DB *d = (DB*)db->hdb_db;
717     DBT k;
718     krb5_error_code code;
719     k.data = key.data;
720     k.size = key.length;
721     code = db->hdb_lock(context, db, HDB_WLOCK);
722     if(code)
723 	return code;
724     code = (*d->del)(d, &k, 0);
725     db->hdb_unlock(context, db);
726     if(code == 1) {
727 	code = errno;
728 	krb5_set_error_message(context, code, "Database %s put error: %s",
729 			       db->hdb_name, strerror(code));
730 	return code;
731     }
732     if(code < 0)
733 	return errno;
734     return 0;
735 }
736 
737 static krb5_error_code
mdb_fetch_kvno(krb5_context context,HDB * db,krb5_const_principal principal,unsigned flags,krb5_kvno kvno,hdb_entry_ex * entry)738 mdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal,
739 	       unsigned flags, krb5_kvno kvno, hdb_entry_ex *entry)
740 {
741     krb5_data key, value;
742     krb5_error_code ret;
743 
744     ret = mdb_principal2key(context, principal, &key);
745     if (ret)
746 	return ret;
747     ret = db->hdb__get(context, db, key, &value);
748     krb5_data_free(&key);
749     if(ret)
750 	return ret;
751     ret = _hdb_mdb_value2entry(context, &value, kvno, &entry->entry);
752     krb5_data_free(&value);
753     if (ret)
754 	return ret;
755 
756     if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
757 	ret = hdb_unseal_keys (context, db, &entry->entry);
758 	if (ret) {
759 	    hdb_free_entry(context, entry);
760             return ret;
761         }
762     }
763 
764     return 0;
765 }
766 
767 static krb5_error_code
mdb_store(krb5_context context,HDB * db,unsigned flags,hdb_entry_ex * entry)768 mdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
769 {
770     krb5_error_code ret;
771     krb5_storage *sp = NULL;
772     krb5_storage *spent = NULL;
773     krb5_data line = { 0, 0 };
774     krb5_data kdb_ent = { 0, 0 };
775     krb5_data key = { 0, 0 };
776     ssize_t sz;
777 
778     sp = krb5_storage_emem();
779     if (!sp) return ENOMEM;
780     ret = _hdb_set_master_key_usage(context, db, 0); /* MIT KDB uses KU 0 */
781     ret = hdb_seal_keys(context, db, &entry->entry);
782     if (ret) return ret;
783     ret = entry2mit_string_int(context, sp, &entry->entry);
784     if (ret) goto out;
785     sz = krb5_storage_write(sp, "\n", 2); /* NUL-terminate */
786     ret = ENOMEM;
787     if (sz == -1) goto out;
788     ret = krb5_storage_to_data(sp, &line);
789     if (ret) goto out;
790 
791     ret = ENOMEM;
792     spent = krb5_storage_emem();
793     if (!spent) goto out;
794     ret = _hdb_mit_dump2mitdb_entry(context, line.data, spent);
795     if (ret) goto out;
796     ret = krb5_storage_to_data(spent, &kdb_ent);
797     if (ret) goto out;
798     ret = mdb_principal2key(context, entry->entry.principal, &key);
799     if (ret) goto out;
800     ret = mdb__put(context, db, 1, key, kdb_ent);
801 
802 out:
803     if (sp)
804         krb5_storage_free(sp);
805     if (spent)
806         krb5_storage_free(spent);
807     krb5_data_free(&line);
808     krb5_data_free(&kdb_ent);
809     krb5_data_free(&key);
810 
811     return ret;
812 }
813 
814 static krb5_error_code
mdb_remove(krb5_context context,HDB * db,krb5_const_principal principal)815 mdb_remove(krb5_context context, HDB *db, krb5_const_principal principal)
816 {
817     krb5_error_code code;
818     krb5_data key;
819 
820     code = db->hdb__del(context, db, key);
821     krb5_data_free(&key);
822     return code;
823 }
824 
825 static krb5_error_code
mdb_open(krb5_context context,HDB * db,int flags,mode_t mode)826 mdb_open(krb5_context context, HDB *db, int flags, mode_t mode)
827 {
828     char *fn;
829     char *actual_fn;
830     krb5_error_code ret;
831     struct stat st;
832 
833     asprintf(&fn, "%s.db", db->hdb_name);
834     if (fn == NULL) {
835 	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
836 	return ENOMEM;
837     }
838 
839      if (stat(fn, &st) == 0)
840          actual_fn = fn;
841      else
842          actual_fn = db->hdb_name;
843      db->hdb_db = dbopen(actual_fn, flags, mode, DB_BTREE, NULL);
844     if (db->hdb_db == NULL) {
845 	switch (errno) {
846 #ifdef EFTYPE
847 	case EFTYPE:
848 #endif
849 	case EINVAL:
850 	    db->hdb_db = dbopen(actual_fn, flags, mode, DB_BTREE, NULL);
851 	}
852     }
853     free(fn);
854 
855     /* try to open without .db extension */
856     if(db->hdb_db == NULL && errno == ENOENT)
857 	db->hdb_db = dbopen(db->hdb_name, flags, mode, DB_BTREE, NULL);
858     if(db->hdb_db == NULL) {
859 	ret = errno;
860 	krb5_set_error_message(context, ret, "dbopen (%s): %s",
861 			      db->hdb_name, strerror(ret));
862 	return ret;
863     }
864 #if 0
865     /*
866      * Don't do this -- MIT won't be able to handle the
867      * HDB_DB_FORMAT_ENTRY key.
868      */
869     if ((flags & O_ACCMODE) != O_RDONLY)
870 	ret = hdb_init_db(context, db);
871 #endif
872     ret = hdb_check_db_format(context, db);
873     if (ret == HDB_ERR_NOENTRY) {
874 	krb5_clear_error_message(context);
875 	return 0;
876     }
877     if (ret) {
878 	mdb_close(context, db);
879 	krb5_set_error_message(context, ret, "hdb_open: failed %s database %s",
880 			      (flags & O_ACCMODE) == O_RDONLY ?
881 			      "checking format of" : "initialize",
882 			      db->hdb_name);
883     }
884     return ret;
885 }
886 
887 krb5_error_code
hdb_mdb_create(krb5_context context,HDB ** db,const char * filename)888 hdb_mdb_create(krb5_context context, HDB **db,
889 	       const char *filename)
890 {
891     *db = calloc(1, sizeof(**db));
892     if (*db == NULL) {
893 	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
894 	return ENOMEM;
895     }
896 
897     (*db)->hdb_db = NULL;
898     (*db)->hdb_name = strdup(filename);
899     if ((*db)->hdb_name == NULL) {
900 	free(*db);
901 	*db = NULL;
902 	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
903 	return ENOMEM;
904     }
905     (*db)->hdb_master_key_set = 0;
906     (*db)->hdb_openp = 0;
907     (*db)->hdb_capability_flags = 0;
908     (*db)->hdb_open = mdb_open;
909     (*db)->hdb_close = mdb_close;
910     (*db)->hdb_fetch_kvno = mdb_fetch_kvno;
911     (*db)->hdb_store = mdb_store;
912     (*db)->hdb_remove = mdb_remove;
913     (*db)->hdb_firstkey = mdb_firstkey;
914     (*db)->hdb_nextkey= mdb_nextkey;
915     (*db)->hdb_lock = mdb_lock;
916     (*db)->hdb_unlock = mdb_unlock;
917     (*db)->hdb_rename = mdb_rename;
918     (*db)->hdb__get = mdb__get;
919     (*db)->hdb__put = mdb__put;
920     (*db)->hdb__del = mdb__del;
921     (*db)->hdb_destroy = mdb_destroy;
922     return 0;
923 }
924 
925 #endif /* HAVE_DB1 */
926 
927 /*
928 can have any number of princ stanzas.
929 format is as follows (only \n indicates newlines)
930 princ\t%d\t (%d is KRB5_KDB_V1_BASE_LENGTH, always 38)
931 %d\t (strlen of principal e.g. shadow/foo@ANDREW.CMU.EDU)
932 %d\t (number of tl_data)
933 %d\t (number of key data, e.g. how many keys for this user)
934 %d\t (extra data length)
935 %s\t (principal name)
936 %d\t (attributes)
937 %d\t (max lifetime, seconds)
938 %d\t (max renewable life, seconds)
939 %d\t (expiration, seconds since epoch or 2145830400 for never)
940 %d\t (password expiration, seconds, 0 for never)
941 %d\t (last successful auth, seconds since epoch)
942 %d\t (last failed auth, per above)
943 %d\t (failed auth count)
944 foreach tl_data 0 to number of tl_data - 1 as above
945   %d\t%d\t (data type, data length)
946   foreach tl_data 0 to length-1
947     %02x (tl data contents[element n])
948   except if tl_data length is 0
949     %d (always -1)
950   \t
951 foreach key 0 to number of keys - 1 as above
952   %d\t%d\t (key data version, kvno)
953   foreach version 0 to key data version - 1 (a key or a salt)
954     %d\t%d\t(data type for this key, data length for this key)
955     foreach key data length 0 to length-1
956       %02x (key data contents[element n])
957     except if key_data length is 0
958       %d (always -1)
959     \t
960 foreach extra data length 0 to length - 1
961   %02x (extra data part)
962 unless no extra data
963   %d (always -1)
964 ;\n
965 
966 */
967 
968 static char *
nexttoken(char ** p)969 nexttoken(char **p)
970 {
971     char *q;
972     do {
973 	q = strsep(p, " \t");
974     } while(q && *q == '\0');
975     return q;
976 }
977 
978 static size_t
getdata(char ** p,unsigned char * buf,size_t len)979 getdata(char **p, unsigned char *buf, size_t len)
980 {
981     size_t i;
982     int v;
983     char *q = nexttoken(p);
984     i = 0;
985     while(*q && i < len) {
986 	if(sscanf(q, "%02x", &v) != 1)
987 	    break;
988 	buf[i++] = v;
989 	q += 2;
990     }
991     return i;
992 }
993 
994 static int
getint(char ** p)995 getint(char **p)
996 {
997     int val;
998     char *q = nexttoken(p);
999     sscanf(q, "%d", &val);
1000     return val;
1001 }
1002 
1003 static unsigned int
getuint(char ** p)1004 getuint(char **p)
1005 {
1006     int val;
1007     char *q = nexttoken(p);
1008     sscanf(q, "%u", &val);
1009     return val;
1010 }
1011 
1012 #define KRB5_KDB_SALTTYPE_NORMAL	0
1013 #define KRB5_KDB_SALTTYPE_V4		1
1014 #define KRB5_KDB_SALTTYPE_NOREALM	2
1015 #define KRB5_KDB_SALTTYPE_ONLYREALM	3
1016 #define KRB5_KDB_SALTTYPE_SPECIAL	4
1017 #define KRB5_KDB_SALTTYPE_AFS3		5
1018 
1019 #define CHECK_UINT(num)                            \
1020         if ((num) < 0 || (num) > INT_MAX) return EINVAL
1021 #define CHECK_UINT16(num)                          \
1022         if ((num) < 0 || (num) > 1<<15) return EINVAL
1023 #define CHECK_NUM(num, maxv)                     \
1024         if ((num) > (maxv)) return EINVAL
1025 
1026 /*
1027  * This utility function converts an MIT dump entry to an MIT on-disk
1028  * encoded entry, which can then be decoded with _hdb_mdb_value2entry().
1029  * This allows us to have a single decoding function (_hdb_mdb_value2entry),
1030  * which makes the code cleaner (less code duplication), if a bit less
1031  * efficient.  It also will allow us to have a function to dump an HDB
1032  * entry in MIT format so we can dump HDB into MIT format for rollback
1033  * purposes.  And that will allow us to write to MIT KDBs, again
1034  * somewhat inefficiently, also for migration/rollback purposes.
1035  */
1036 int
_hdb_mit_dump2mitdb_entry(krb5_context context,char * line,krb5_storage * sp)1037 _hdb_mit_dump2mitdb_entry(krb5_context context, char *line, krb5_storage *sp)
1038 {
1039     krb5_error_code ret = EINVAL;
1040     char *p = line, *q;
1041     char *princ;
1042     ssize_t sz;
1043     size_t i;
1044     size_t princ_len;
1045     unsigned int num_tl_data;
1046     size_t num_key_data;
1047     unsigned int attributes;
1048     int tmp;
1049 
1050     krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE);
1051 
1052     q = nexttoken(&p);
1053     if (strcmp(q, "kdb5_util") == 0 || strcmp(q, "policy") == 0 ||
1054         strcmp(q, "princ") != 0) {
1055         return -1;
1056     }
1057     if (getint(&p) != 38)
1058         return EINVAL;
1059 #define KDB_V1_BASE_LENGTH 38
1060     ret = krb5_store_int16(sp, KDB_V1_BASE_LENGTH);
1061     if (ret) return ret;
1062 
1063     nexttoken(&p); /* length of principal */
1064     num_tl_data = getuint(&p); /* number of tl-data */
1065     num_key_data = getuint(&p); /* number of key-data */
1066     getint(&p);  /* length of extra data */
1067     princ = nexttoken(&p); /* principal name */
1068 
1069     attributes = getuint(&p); /* attributes */
1070     ret = krb5_store_uint32(sp, attributes);
1071     if (ret) return ret;
1072 
1073     tmp = getint(&p); /* max life */
1074     CHECK_UINT(tmp);
1075     ret = krb5_store_uint32(sp, tmp);
1076     if (ret) return ret;
1077 
1078     tmp = getint(&p); /* max renewable life */
1079     CHECK_UINT(tmp);
1080     ret = krb5_store_uint32(sp, tmp);
1081     if (ret) return ret;
1082 
1083     tmp = getint(&p); /* expiration */
1084     CHECK_UINT(tmp);
1085     ret = krb5_store_uint32(sp, tmp);
1086     if (ret) return ret;
1087 
1088     tmp = getint(&p); /* pw expiration */
1089     CHECK_UINT(tmp);
1090     ret = krb5_store_uint32(sp, tmp);
1091     if (ret) return ret;
1092 
1093     tmp = getint(&p); /* last auth */
1094     CHECK_UINT(tmp);
1095     ret = krb5_store_uint32(sp, tmp);
1096     if (ret) return ret;
1097 
1098     tmp = getint(&p); /* last failed auth */
1099     CHECK_UINT(tmp);
1100     ret = krb5_store_uint32(sp, tmp);
1101     if (ret) return ret;
1102 
1103     tmp = getint(&p); /* fail auth count */
1104     CHECK_UINT(tmp);
1105     ret = krb5_store_uint32(sp, tmp);
1106     if (ret) return ret;
1107 
1108     /* add TL data count */
1109     CHECK_NUM(num_tl_data, 1023);
1110     ret = krb5_store_uint16(sp, num_tl_data);
1111     if (ret) return ret;
1112 
1113     /* add key count */
1114     CHECK_NUM(num_key_data, 1023);
1115     ret = krb5_store_uint16(sp, num_key_data);
1116     if (ret) return ret;
1117 
1118     /* add principal unparsed name length and unparsed name */
1119     princ_len = strlen(princ);
1120     if (princ_len > (1<<15) - 1) return EINVAL;
1121     princ_len++; /* must count and write the NUL in the on-disk encoding */
1122     ret = krb5_store_uint16(sp, princ_len);
1123     if (ret) return ret;
1124     sz = krb5_storage_write(sp, princ, princ_len);
1125     if (sz == -1) return ENOMEM;
1126 
1127     /* scan and write TL data */
1128     for (i = 0; i < num_tl_data; i++) {
1129         int tl_type, tl_length;
1130         unsigned char *buf;
1131 
1132         tl_type = getint(&p); /* data type */
1133         tl_length = getint(&p); /* data length */
1134 
1135         CHECK_UINT16(tl_type);
1136         ret = krb5_store_uint16(sp, tl_type);
1137         if (ret) return ret;
1138         CHECK_UINT16(tl_length);
1139         ret = krb5_store_uint16(sp, tl_length);
1140         if (ret) return ret;
1141 
1142         if (tl_length) {
1143             buf = malloc(tl_length);
1144             if (!buf) return ENOMEM;
1145             if (getdata(&p, buf, tl_length) != tl_length) return EINVAL;
1146             sz = krb5_storage_write(sp, buf, tl_length);
1147             free(buf);
1148             if (sz == -1) return ENOMEM;
1149         } else {
1150             if (strcmp(nexttoken(&p), "-1") != 0) return EINVAL;
1151         }
1152     }
1153 
1154     for (i = 0; i < num_key_data; i++) {
1155         unsigned char *buf;
1156         int key_versions;
1157         int kvno;
1158         int keytype;
1159         int keylen;
1160         size_t k;
1161 
1162         key_versions = getint(&p); /* key data version */
1163         CHECK_UINT16(key_versions);
1164         ret = krb5_store_int16(sp, key_versions);
1165         if (ret) return ret;
1166 
1167         kvno = getint(&p);
1168         CHECK_UINT16(kvno);
1169         ret = krb5_store_int16(sp, kvno);
1170         if (ret) return ret;
1171 
1172         for (k = 0; k < key_versions; k++) {
1173             keytype = getint(&p);
1174             CHECK_UINT16(keytype);
1175             ret = krb5_store_int16(sp, keytype);
1176             if (ret) return ret;
1177 
1178             keylen = getint(&p);
1179             CHECK_UINT16(keylen);
1180             ret = krb5_store_int16(sp, keylen);
1181             if (ret) return ret;
1182 
1183             if (keylen) {
1184                 buf = malloc(keylen);
1185                 if (!buf) return ENOMEM;
1186                 if (getdata(&p, buf, keylen) != keylen) return EINVAL;
1187                 sz = krb5_storage_write(sp, buf, keylen);
1188                 free(buf);
1189                 if (sz == -1) return ENOMEM;
1190             } else {
1191                 if (strcmp(nexttoken(&p), "-1") != 0) return EINVAL;
1192             }
1193         }
1194     }
1195     /*
1196      * The rest is "extra data", but there's never any and we wouldn't
1197      * know what to do with it.
1198      */
1199     /* nexttoken(&p); */
1200     return 0;
1201 }
1202 
1203