2 * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
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.
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.
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
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
53 key: krb5_unparse_name + NUL
58 32: max renewable time
61 32: last successful passwd
62 32: last failed attempt
63 32: num of failed attempts
72 for num key data times
73 16: version (num keyblocks)
84 read-of-data: key-encrypted, key-usage 0, master-key
87 version2 = salt in key_data->key_data_contents[1]
94 #define KDB_V1_BASE_LENGTH 38
98 #if defined(HAVE_DB_185_H)
100 #elif defined(HAVE_DB_H)
104 #define CHECK(x) do { if ((x)) goto out; } while(0)
106 static krb5_error_code
107 mdb_principal2key(krb5_context context,
108 krb5_const_principal principal,
114 ret = krb5_unparse_name(context, principal, &str);
118 key->length = strlen(str) + 1;
122 #define KRB5_KDB_SALTTYPE_NORMAL 0
123 #define KRB5_KDB_SALTTYPE_V4 1
124 #define KRB5_KDB_SALTTYPE_NOREALM 2
125 #define KRB5_KDB_SALTTYPE_ONLYREALM 3
126 #define KRB5_KDB_SALTTYPE_SPECIAL 4
127 #define KRB5_KDB_SALTTYPE_AFS3 5
128 #define KRB5_KDB_SALTTYPE_CERTHASH 6
130 static krb5_error_code
131 fix_salt(krb5_context context, hdb_entry *ent, int key_num)
134 Salt *salt = ent->keys.val[key_num].salt;
136 switch((int)salt->type) {
137 case KRB5_KDB_SALTTYPE_NORMAL:
138 salt->type = KRB5_PADATA_PW_SALT;
140 case KRB5_KDB_SALTTYPE_V4:
141 krb5_data_free(&salt->salt);
142 salt->type = KRB5_PADATA_PW_SALT;
144 case KRB5_KDB_SALTTYPE_NOREALM:
151 for (i = 0; i < ent->principal->name.name_string.len; ++i)
152 len += strlen(ent->principal->name.name_string.val[i]);
153 ret = krb5_data_alloc (&salt->salt, len);
157 for (i = 0; i < ent->principal->name.name_string.len; ++i) {
159 ent->principal->name.name_string.val[i],
160 strlen(ent->principal->name.name_string.val[i]));
161 p += strlen(ent->principal->name.name_string.val[i]);
164 salt->type = KRB5_PADATA_PW_SALT;
167 case KRB5_KDB_SALTTYPE_ONLYREALM:
168 krb5_data_free(&salt->salt);
169 ret = krb5_data_copy(&salt->salt,
170 ent->principal->realm,
171 strlen(ent->principal->realm));
174 salt->type = KRB5_PADATA_PW_SALT;
176 case KRB5_KDB_SALTTYPE_SPECIAL:
177 salt->type = KRB5_PADATA_PW_SALT;
179 case KRB5_KDB_SALTTYPE_AFS3:
180 krb5_data_free(&salt->salt);
181 ret = krb5_data_copy(&salt->salt,
182 ent->principal->realm,
183 strlen(ent->principal->realm));
186 salt->type = KRB5_PADATA_AFS3_SALT;
188 case KRB5_KDB_SALTTYPE_CERTHASH:
189 krb5_data_free(&salt->salt);
190 free(ent->keys.val[key_num].salt);
191 ent->keys.val[key_num].salt = NULL;
200 static krb5_error_code
201 mdb_value2entry(krb5_context context, krb5_data *data, krb5_kvno kvno, hdb_entry *entry)
206 uint16_t u16, num_keys, num_tl;
210 sp = krb5_storage_from_data(data);
212 krb5_set_error_message(context, ENOMEM, "out of memory");
216 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE);
221 * The story here is that these 16 bits have to be a constant:
222 * KDB_V1_BASE_LENGTH. Once upon a time a different value here
223 * would have been used to indicate the presence of "extra data"
224 * between the "base" contents and the {principal name, TL data,
225 * keys} that follow it. Nothing supports such "extra data"
226 * nowadays, so neither do we here.
228 * XXX But... surely we ought to log about this extra data, or skip
229 * it, or something, in case anyone has MIT KDBs with ancient
230 * entries in them... Logging would allow the admin to know which
231 * entries to dump with MIT krb5's kdb5_util.
233 CHECK(ret = krb5_ret_uint16(sp, &u16));
234 if (u16 != KDB_V1_BASE_LENGTH) { ret = EINVAL; goto out; }
236 CHECK(ret = krb5_ret_uint32(sp, &u32));
237 entry->flags.postdate = !(u32 & KRB5_KDB_DISALLOW_POSTDATED);
238 entry->flags.forwardable = !(u32 & KRB5_KDB_DISALLOW_FORWARDABLE);
239 entry->flags.initial = !!(u32 & KRB5_KDB_DISALLOW_TGT_BASED);
240 entry->flags.renewable = !(u32 & KRB5_KDB_DISALLOW_RENEWABLE);
241 entry->flags.proxiable = !(u32 & KRB5_KDB_DISALLOW_PROXIABLE);
243 entry->flags.invalid = !!(u32 & KRB5_KDB_DISALLOW_ALL_TIX);
244 entry->flags.require_preauth =!!(u32 & KRB5_KDB_REQUIRES_PRE_AUTH);
245 entry->flags.require_hwauth =!!(u32 & KRB5_KDB_REQUIRES_HW_AUTH);
246 entry->flags.server = !(u32 & KRB5_KDB_DISALLOW_SVR);
247 entry->flags.change_pw = !!(u32 & KRB5_KDB_PWCHANGE_SERVICE);
248 entry->flags.client = 1; /* XXX */
251 CHECK(ret = krb5_ret_uint32(sp, &u32));
253 entry->max_life = malloc(sizeof(*entry->max_life));
254 *entry->max_life = u32;
256 /* 32: max renewable time */
257 CHECK(ret = krb5_ret_uint32(sp, &u32));
259 entry->max_renew = malloc(sizeof(*entry->max_renew));
260 *entry->max_renew = u32;
262 /* 32: client expire */
263 CHECK(ret = krb5_ret_uint32(sp, &u32));
265 entry->valid_end = malloc(sizeof(*entry->valid_end));
266 *entry->valid_end = u32;
268 /* 32: passwd expire */
269 CHECK(ret = krb5_ret_uint32(sp, &u32));
271 entry->pw_end = malloc(sizeof(*entry->pw_end));
272 *entry->pw_end = u32;
274 /* 32: last successful passwd */
275 CHECK(ret = krb5_ret_uint32(sp, &u32));
276 /* 32: last failed attempt */
277 CHECK(ret = krb5_ret_uint32(sp, &u32));
278 /* 32: num of failed attempts */
279 CHECK(ret = krb5_ret_uint32(sp, &u32));
280 /* 16: num tl data */
281 CHECK(ret = krb5_ret_uint16(sp, &u16));
283 /* 16: num key data */
284 CHECK(ret = krb5_ret_uint16(sp, &u16));
286 /* 16: principal length */
287 CHECK(ret = krb5_ret_uint16(sp, &u16));
288 /* length: principal */
291 * Note that the principal name includes the NUL in the entry,
292 * but we don't want to take chances, so we add an extra NUL.
299 krb5_storage_read(sp, p, u16);
301 CHECK(ret = krb5_parse_name(context, p, &entry->principal));
304 /* for num tl data times
308 for (i = 0; i < num_tl; i++) {
309 /* 16: TL data type */
310 CHECK(ret = krb5_ret_uint16(sp, &u16));
311 /* 16: TL data length */
312 CHECK(ret = krb5_ret_uint16(sp, &u16));
313 krb5_storage_seek(sp, u16, SEEK_CUR);
316 * for num key data times
324 * "version" here is really 1 or 2, the first meaning there's only
325 * keys for this kvno, the second meaning there's keys and salt[s?].
326 * That's right... hold that gag reflex, you can do it.
328 for (i = 0; i < num_keys; i++) {
333 CHECK(ret = krb5_ret_uint16(sp, &u16));
335 CHECK(ret = krb5_ret_uint16(sp, &u16));
338 * First time through, and until we find one matching key,
341 if ((entry->kvno < u16) && (kvno == 0 || kvno == u16)) {
345 * Found a higher kvno than earlier, so free the old highest
348 * XXX Of course, we actually want to extract the old kvnos
349 * as well, for some of the kadm5 APIs. We shouldn't free
350 * these keys, but keep them elsewhere.
352 for (j = 0; j < entry->keys.len; j++)
353 free_Key(&entry->keys.val[j]);
354 free(entry->keys.val);
356 entry->keys.val = NULL;
357 } else if (entry->kvno == u16)
358 /* Accumulate keys */
364 ptr = realloc(entry->keys.val, sizeof(entry->keys.val[0]) * (entry->keys.len + 1));
369 entry->keys.val = ptr;
371 /* k points to current Key */
372 k = &entry->keys.val[entry->keys.len];
374 memset(k, 0, sizeof(*k));
375 entry->keys.len += 1;
377 k->mkvno = malloc(sizeof(*k->mkvno));
378 if (k->mkvno == NULL) {
384 for (j = 0; j < version; j++) {
386 CHECK(ret = krb5_ret_uint16(sp, &type));
387 CHECK(ret = krb5_ret_uint16(sp, &u16));
389 /* This "version" means we have a key */
390 k->key.keytype = type;
396 * MIT stores keys encrypted keys as {16-bit length
397 * of plaintext key, {encrypted key}}. The reason
398 * for this is that the Kerberos cryptosystem is not
399 * length-preserving. Heimdal's approach is to
400 * truncate the plaintext to the expected length of
401 * the key given its enctype, so we ignore this
402 * 16-bit length-of-plaintext-key field.
404 krb5_storage_seek(sp, 2, SEEK_CUR); /* skip real length */
405 k->key.keyvalue.length = u16 - 2; /* adjust cipher len */
406 k->key.keyvalue.data = malloc(k->key.keyvalue.length);
407 krb5_storage_read(sp, k->key.keyvalue.data,
408 k->key.keyvalue.length);
410 /* This "version" means we have a salt */
411 k->salt = calloc(1, sizeof(*k->salt));
412 if (k->salt == NULL) {
416 k->salt->type = type;
418 k->salt->salt.data = malloc(u16);
419 if (k->salt->salt.data == NULL) {
423 k->salt->salt.length = u16;
424 krb5_storage_read(sp, k->salt->salt.data, k->salt->salt.length);
426 fix_salt(context, entry, entry->keys.len - 1);
429 * Whatever this "version" might be, we skip it
431 * XXX A krb5.conf parameter requesting that we log
432 * about strangeness like this, or return an error
433 * from here, might be nice.
435 krb5_storage_seek(sp, u16, SEEK_CUR);
440 * XXX For now we skip older kvnos, but we should extract
443 for (j = 0; j < version; j++) {
445 CHECK(ret = krb5_ret_uint16(sp, &u16));
446 /* encrypted key (or plaintext salt) */
447 CHECK(ret = krb5_ret_uint16(sp, &u16));
448 krb5_storage_seek(sp, u16, SEEK_CUR);
453 if (entry->kvno == 0 && kvno != 0) {
454 ret = HDB_ERR_NOT_FOUND_HERE;
460 if (ret == HEIM_ERR_EOF)
461 /* Better error code than "end of file" */
462 ret = HEIM_ERR_BAD_HDBENT_ENCODING;
467 static krb5_error_code
468 mdb_entry2value(krb5_context context, hdb_entry *entry, krb5_data *data)
475 static krb5_error_code
476 mdb_close(krb5_context context, HDB *db)
478 DB *d = (DB*)db->hdb_db;
483 static krb5_error_code
484 mdb_destroy(krb5_context context, HDB *db)
488 ret = hdb_clear_master_key (context, db);
494 static krb5_error_code
495 mdb_lock(krb5_context context, HDB *db, int operation)
497 DB *d = (DB*)db->hdb_db;
498 int fd = (*d->fd)(d);
500 krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB,
501 "Can't lock database: %s", db->hdb_name);
502 return HDB_ERR_CANT_LOCK_DB;
504 return hdb_lock(fd, operation);
507 static krb5_error_code
508 mdb_unlock(krb5_context context, HDB *db)
510 DB *d = (DB*)db->hdb_db;
511 int fd = (*d->fd)(d);
513 krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB,
514 "Can't unlock database: %s", db->hdb_name);
515 return HDB_ERR_CANT_LOCK_DB;
517 return hdb_unlock(fd);
521 static krb5_error_code
522 mdb_seq(krb5_context context, HDB *db,
523 unsigned flags, hdb_entry_ex *entry, int flag)
525 DB *d = (DB*)db->hdb_db;
527 krb5_data key_data, data;
530 code = db->hdb_lock(context, db, HDB_RLOCK);
532 krb5_set_error_message(context, HDB_ERR_DB_INUSE, "Database %s in use", db->hdb_name);
533 return HDB_ERR_DB_INUSE;
535 code = (*d->seq)(d, &key, &value, flag);
536 db->hdb_unlock(context, db); /* XXX check value */
539 krb5_set_error_message(context, code, "Database %s seq error: %s",
540 db->hdb_name, strerror(code));
544 krb5_clear_error_message(context);
545 return HDB_ERR_NOENTRY;
548 key_data.data = key.data;
549 key_data.length = key.size;
550 data.data = value.data;
551 data.length = value.size;
552 memset(entry, 0, sizeof(*entry));
554 if (mdb_value2entry(context, &data, 0, &entry->entry))
555 return mdb_seq(context, db, flags, entry, R_NEXT);
557 if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
558 code = hdb_unseal_keys (context, db, &entry->entry);
560 hdb_free_entry (context, entry);
567 static krb5_error_code
568 mdb_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
570 return mdb_seq(context, db, flags, entry, R_FIRST);
574 static krb5_error_code
575 mdb_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
577 return mdb_seq(context, db, flags, entry, R_NEXT);
580 static krb5_error_code
581 mdb_rename(krb5_context context, HDB *db, const char *new_name)
586 asprintf(&old, "%s.db", db->hdb_name);
587 asprintf(&new, "%s.db", new_name);
588 ret = rename(old, new);
595 db->hdb_name = strdup(new_name);
599 static krb5_error_code
600 mdb__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply)
602 DB *d = (DB*)db->hdb_db;
608 code = db->hdb_lock(context, db, HDB_RLOCK);
611 code = (*d->get)(d, &k, &v, 0);
612 db->hdb_unlock(context, db);
615 krb5_set_error_message(context, code, "Database %s get error: %s",
616 db->hdb_name, strerror(code));
620 krb5_clear_error_message(context);
621 return HDB_ERR_NOENTRY;
624 krb5_data_copy(reply, v.data, v.size);
628 static krb5_error_code
629 mdb__put(krb5_context context, HDB *db, int replace,
630 krb5_data key, krb5_data value)
632 DB *d = (DB*)db->hdb_db;
639 v.size = value.length;
640 code = db->hdb_lock(context, db, HDB_WLOCK);
643 code = (*d->put)(d, &k, &v, replace ? 0 : R_NOOVERWRITE);
644 db->hdb_unlock(context, db);
647 krb5_set_error_message(context, code, "Database %s put error: %s",
648 db->hdb_name, strerror(code));
652 krb5_clear_error_message(context);
653 return HDB_ERR_EXISTS;
658 static krb5_error_code
659 mdb__del(krb5_context context, HDB *db, krb5_data key)
661 DB *d = (DB*)db->hdb_db;
663 krb5_error_code code;
666 code = db->hdb_lock(context, db, HDB_WLOCK);
669 code = (*d->del)(d, &k, 0);
670 db->hdb_unlock(context, db);
673 krb5_set_error_message(context, code, "Database %s put error: %s",
674 db->hdb_name, strerror(code));
682 static krb5_error_code
683 mdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal,
684 unsigned flags, krb5_kvno kvno, hdb_entry_ex *entry)
686 krb5_data key, value;
687 krb5_error_code code;
689 code = mdb_principal2key(context, principal, &key);
692 code = db->hdb__get(context, db, key, &value);
693 krb5_data_free(&key);
696 code = mdb_value2entry(context, &value, kvno, &entry->entry);
697 krb5_data_free(&value);
701 if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
702 code = hdb_unseal_keys (context, db, &entry->entry);
704 hdb_free_entry(context, entry);
710 static krb5_error_code
711 mdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
713 krb5_set_error_message(context, EINVAL, "can't set principal in mdb");
717 static krb5_error_code
718 mdb_remove(krb5_context context, HDB *db, krb5_const_principal principal)
720 krb5_error_code code;
723 mdb_principal2key(context, principal, &key);
724 code = db->hdb__del(context, db, key);
725 krb5_data_free(&key);
729 static krb5_error_code
730 mdb_open(krb5_context context, HDB *db, int flags, mode_t mode)
735 asprintf(&fn, "%s.db", db->hdb_name);
737 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
740 db->hdb_db = dbopen(fn, flags, mode, DB_BTREE, NULL);
743 if (db->hdb_db == NULL) {
749 db->hdb_db = dbopen(fn, flags, mode, DB_BTREE, NULL);
753 /* try to open without .db extension */
754 if(db->hdb_db == NULL && errno == ENOENT)
755 db->hdb_db = dbopen(db->hdb_name, flags, mode, DB_BTREE, NULL);
756 if(db->hdb_db == NULL) {
758 krb5_set_error_message(context, ret, "dbopen (%s): %s",
759 db->hdb_name, strerror(ret));
762 if((flags & O_ACCMODE) == O_RDONLY)
763 ret = hdb_check_db_format(context, db);
765 ret = hdb_init_db(context, db);
766 if(ret == HDB_ERR_NOENTRY) {
767 krb5_clear_error_message(context);
771 mdb_close(context, db);
772 krb5_set_error_message(context, ret, "hdb_open: failed %s database %s",
773 (flags & O_ACCMODE) == O_RDONLY ?
774 "checking format of" : "initialize",
781 hdb_mdb_create(krb5_context context, HDB **db,
782 const char *filename)
784 *db = calloc(1, sizeof(**db));
786 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
790 (*db)->hdb_db = NULL;
791 (*db)->hdb_name = strdup(filename);
792 if ((*db)->hdb_name == NULL) {
795 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
798 (*db)->hdb_master_key_set = 0;
799 (*db)->hdb_openp = 0;
800 (*db)->hdb_capability_flags = 0;
801 (*db)->hdb_open = mdb_open;
802 (*db)->hdb_close = mdb_close;
803 (*db)->hdb_fetch_kvno = mdb_fetch_kvno;
804 (*db)->hdb_store = mdb_store;
805 (*db)->hdb_remove = mdb_remove;
806 (*db)->hdb_firstkey = mdb_firstkey;
807 (*db)->hdb_nextkey= mdb_nextkey;
808 (*db)->hdb_lock = mdb_lock;
809 (*db)->hdb_unlock = mdb_unlock;
810 (*db)->hdb_rename = mdb_rename;
811 (*db)->hdb__get = mdb__get;
812 (*db)->hdb__put = mdb__put;
813 (*db)->hdb__del = mdb__del;
814 (*db)->hdb_destroy = mdb_destroy;
818 #endif /* HAVE_DB1 */