don't use errx() since that require libroken
[heimdal.git] / lib / hdb / hdb-mitdb.c
blobcd619b3b8eb48de0496962996c627a59d68a845f
1 /*
2 * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
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
10 * are met:
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
33 * SUCH DAMAGE.
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
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
81 key_data_contents[0]
83 int16: length
84 read-of-data: key-encrypted, key-usage 0, master-key
86 salt:
87 version2 = salt in key_data->key_data_contents[1]
88 else default salt.
92 #include "hdb_locl.h"
94 #define KDB_V1_BASE_LENGTH 38
96 #if HAVE_DB1
98 #if defined(HAVE_DB_185_H)
99 #include <db_185.h>
100 #elif defined(HAVE_DB_H)
101 #include <db.h>
102 #endif
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,
109 krb5_data *key)
111 krb5_error_code ret;
112 char *str;
114 ret = krb5_unparse_name(context, principal, &str);
115 if (ret)
116 return ret;
117 key->data = str;
118 key->length = strlen(str) + 1;
119 return 0;
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)
133 krb5_error_code ret;
134 Salt *salt = ent->keys.val[key_num].salt;
135 /* fix salt type */
136 switch((int)salt->type) {
137 case KRB5_KDB_SALTTYPE_NORMAL:
138 salt->type = KRB5_PADATA_PW_SALT;
139 break;
140 case KRB5_KDB_SALTTYPE_V4:
141 krb5_data_free(&salt->salt);
142 salt->type = KRB5_PADATA_PW_SALT;
143 break;
144 case KRB5_KDB_SALTTYPE_NOREALM:
146 size_t len;
147 size_t i;
148 char *p;
150 len = 0;
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);
154 if (ret)
155 return ret;
156 p = salt->salt.data;
157 for (i = 0; i < ent->principal->name.name_string.len; ++i) {
158 memcpy (p,
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;
165 break;
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));
172 if(ret)
173 return ret;
174 salt->type = KRB5_PADATA_PW_SALT;
175 break;
176 case KRB5_KDB_SALTTYPE_SPECIAL:
177 salt->type = KRB5_PADATA_PW_SALT;
178 break;
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));
184 if(ret)
185 return ret;
186 salt->type = KRB5_PADATA_AFS3_SALT;
187 break;
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;
192 break;
193 default:
194 abort();
196 return 0;
200 static krb5_error_code
201 mdb_value2entry(krb5_context context, krb5_data *data, krb5_kvno kvno, hdb_entry *entry)
203 krb5_error_code ret;
204 krb5_storage *sp;
205 uint32_t u32;
206 uint16_t u16, num_keys, num_tl;
207 size_t i, j;
208 char *p;
210 sp = krb5_storage_from_data(data);
211 if (sp == NULL) {
212 krb5_set_error_message(context, ENOMEM, "out of memory");
213 return ENOMEM;
216 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE);
219 * 16: baselength
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; }
235 /* 32: attributes */
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);
242 /* DUP_SKEY */
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 */
250 /* 32: max time */
251 CHECK(ret = krb5_ret_uint32(sp, &u32));
252 if (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));
258 if (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));
264 if (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));
270 if (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));
282 num_tl = u16;
283 /* 16: num key data */
284 CHECK(ret = krb5_ret_uint16(sp, &u16));
285 num_keys = 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.
294 p = malloc(u16 + 1);
295 if (p == NULL) {
296 ret = ENOMEM;
297 goto out;
299 krb5_storage_read(sp, p, u16);
300 p[u16] = '\0';
301 CHECK(ret = krb5_parse_name(context, p, &entry->principal));
302 free(p);
304 /* for num tl data times
305 16: tl data type
306 16: tl data length
307 length: length */
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
317 * 16: "version"
318 * 16: kvno
319 * for version times:
320 * 16: type
321 * 16: length
322 * length: keydata
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++) {
329 int keep = 0;
330 uint16_t version;
331 void *ptr;
333 CHECK(ret = krb5_ret_uint16(sp, &u16));
334 version = u16;
335 CHECK(ret = krb5_ret_uint16(sp, &u16));
338 * First time through, and until we find one matching key,
339 * entry->kvno == 0.
341 if ((entry->kvno < u16) && (kvno == 0 || kvno == u16)) {
342 keep = 1;
343 entry->kvno = u16;
345 * Found a higher kvno than earlier, so free the old highest
346 * kvno keys.
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);
355 entry->keys.len = 0;
356 entry->keys.val = NULL;
357 } else if (entry->kvno == u16)
358 /* Accumulate keys */
359 keep = 1;
361 if (keep) {
362 Key *k;
364 ptr = realloc(entry->keys.val, sizeof(entry->keys.val[0]) * (entry->keys.len + 1));
365 if (ptr == NULL) {
366 ret = ENOMEM;
367 goto out;
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) {
379 ret = ENOMEM;
380 goto out;
382 *k->mkvno = 1;
384 for (j = 0; j < version; j++) {
385 uint16_t type;
386 CHECK(ret = krb5_ret_uint16(sp, &type));
387 CHECK(ret = krb5_ret_uint16(sp, &u16));
388 if (j == 0) {
389 /* This "version" means we have a key */
390 k->key.keytype = type;
391 if (u16 < 2) {
392 ret = EINVAL;
393 goto out;
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);
409 } else if (j == 1) {
410 /* This "version" means we have a salt */
411 k->salt = calloc(1, sizeof(*k->salt));
412 if (k->salt == NULL) {
413 ret = ENOMEM;
414 goto out;
416 k->salt->type = type;
417 if (u16 != 0) {
418 k->salt->salt.data = malloc(u16);
419 if (k->salt->salt.data == NULL) {
420 ret = ENOMEM;
421 goto out;
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);
427 } else {
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);
438 } else {
440 * XXX For now we skip older kvnos, but we should extract
441 * them...
443 for (j = 0; j < version; j++) {
444 /* enctype */
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;
455 goto out;
458 return 0;
459 out:
460 if (ret == HEIM_ERR_EOF)
461 /* Better error code than "end of file" */
462 ret = HEIM_ERR_BAD_HDBENT_ENCODING;
463 return ret;
466 #if 0
467 static krb5_error_code
468 mdb_entry2value(krb5_context context, hdb_entry *entry, krb5_data *data)
470 return EINVAL;
472 #endif
475 static krb5_error_code
476 mdb_close(krb5_context context, HDB *db)
478 DB *d = (DB*)db->hdb_db;
479 (*d->close)(d);
480 return 0;
483 static krb5_error_code
484 mdb_destroy(krb5_context context, HDB *db)
486 krb5_error_code ret;
488 ret = hdb_clear_master_key (context, db);
489 free(db->hdb_name);
490 free(db);
491 return ret;
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);
499 if(fd < 0) {
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);
512 if(fd < 0) {
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;
526 DBT key, value;
527 krb5_data key_data, data;
528 int code;
530 code = db->hdb_lock(context, db, HDB_RLOCK);
531 if(code == -1) {
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 */
537 if(code == -1) {
538 code = errno;
539 krb5_set_error_message(context, code, "Database %s seq error: %s",
540 db->hdb_name, strerror(code));
541 return code;
543 if(code == 1) {
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);
559 if (code)
560 hdb_free_entry (context, entry);
563 return code;
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)
583 int ret;
584 char *old, *new;
586 asprintf(&old, "%s.db", db->hdb_name);
587 asprintf(&new, "%s.db", new_name);
588 ret = rename(old, new);
589 free(old);
590 free(new);
591 if(ret)
592 return errno;
594 free(db->hdb_name);
595 db->hdb_name = strdup(new_name);
596 return 0;
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;
603 DBT k, v;
604 int code;
606 k.data = key.data;
607 k.size = key.length;
608 code = db->hdb_lock(context, db, HDB_RLOCK);
609 if(code)
610 return code;
611 code = (*d->get)(d, &k, &v, 0);
612 db->hdb_unlock(context, db);
613 if(code < 0) {
614 code = errno;
615 krb5_set_error_message(context, code, "Database %s get error: %s",
616 db->hdb_name, strerror(code));
617 return code;
619 if(code == 1) {
620 krb5_clear_error_message(context);
621 return HDB_ERR_NOENTRY;
624 krb5_data_copy(reply, v.data, v.size);
625 return 0;
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;
633 DBT k, v;
634 int code;
636 k.data = key.data;
637 k.size = key.length;
638 v.data = value.data;
639 v.size = value.length;
640 code = db->hdb_lock(context, db, HDB_WLOCK);
641 if(code)
642 return code;
643 code = (*d->put)(d, &k, &v, replace ? 0 : R_NOOVERWRITE);
644 db->hdb_unlock(context, db);
645 if(code < 0) {
646 code = errno;
647 krb5_set_error_message(context, code, "Database %s put error: %s",
648 db->hdb_name, strerror(code));
649 return code;
651 if(code == 1) {
652 krb5_clear_error_message(context);
653 return HDB_ERR_EXISTS;
655 return 0;
658 static krb5_error_code
659 mdb__del(krb5_context context, HDB *db, krb5_data key)
661 DB *d = (DB*)db->hdb_db;
662 DBT k;
663 krb5_error_code code;
664 k.data = key.data;
665 k.size = key.length;
666 code = db->hdb_lock(context, db, HDB_WLOCK);
667 if(code)
668 return code;
669 code = (*d->del)(d, &k, 0);
670 db->hdb_unlock(context, db);
671 if(code == 1) {
672 code = errno;
673 krb5_set_error_message(context, code, "Database %s put error: %s",
674 db->hdb_name, strerror(code));
675 return code;
677 if(code < 0)
678 return errno;
679 return 0;
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);
690 if (code)
691 return code;
692 code = db->hdb__get(context, db, key, &value);
693 krb5_data_free(&key);
694 if(code)
695 return code;
696 code = mdb_value2entry(context, &value, kvno, &entry->entry);
697 krb5_data_free(&value);
698 if (code)
699 return code;
701 if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
702 code = hdb_unseal_keys (context, db, &entry->entry);
703 if (code)
704 hdb_free_entry(context, entry);
707 return 0;
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");
714 return EINVAL;
717 static krb5_error_code
718 mdb_remove(krb5_context context, HDB *db, krb5_const_principal principal)
720 krb5_error_code code;
721 krb5_data key;
723 mdb_principal2key(context, principal, &key);
724 code = db->hdb__del(context, db, key);
725 krb5_data_free(&key);
726 return code;
729 static krb5_error_code
730 mdb_open(krb5_context context, HDB *db, int flags, mode_t mode)
732 char *fn;
733 krb5_error_code ret;
735 asprintf(&fn, "%s.db", db->hdb_name);
736 if (fn == NULL) {
737 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
738 return ENOMEM;
740 db->hdb_db = dbopen(fn, flags, mode, DB_BTREE, NULL);
741 free(fn);
743 if (db->hdb_db == NULL) {
744 switch (errno) {
745 #ifdef EFTYPE
746 case EFTYPE:
747 #endif
748 case EINVAL:
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) {
757 ret = errno;
758 krb5_set_error_message(context, ret, "dbopen (%s): %s",
759 db->hdb_name, strerror(ret));
760 return ret;
762 if((flags & O_ACCMODE) == O_RDONLY)
763 ret = hdb_check_db_format(context, db);
764 else
765 ret = hdb_init_db(context, db);
766 if(ret == HDB_ERR_NOENTRY) {
767 krb5_clear_error_message(context);
768 return 0;
770 if (ret) {
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",
775 db->hdb_name);
777 return ret;
780 krb5_error_code
781 hdb_mdb_create(krb5_context context, HDB **db,
782 const char *filename)
784 *db = calloc(1, sizeof(**db));
785 if (*db == NULL) {
786 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
787 return ENOMEM;
790 (*db)->hdb_db = NULL;
791 (*db)->hdb_name = strdup(filename);
792 if ((*db)->hdb_name == NULL) {
793 free(*db);
794 *db = NULL;
795 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
796 return ENOMEM;
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;
815 return 0;
818 #endif /* HAVE_DB1 */