etc/services - sync with NetBSD-8
[minix.git] / crypto / external / bsd / heimdal / dist / lib / hdb / hdb-mitdb.c
blobe7c318d03498fd4fff9fb28c869b829c893f6618
1 /* $NetBSD: hdb-mitdb.c,v 1.1.1.2 2014/04/24 12:45:28 pettai Exp $ */
3 /*
4 * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
8 * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the Institute nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
38 #define KRB5_KDB_DISALLOW_POSTDATED 0x00000001
39 #define KRB5_KDB_DISALLOW_FORWARDABLE 0x00000002
40 #define KRB5_KDB_DISALLOW_TGT_BASED 0x00000004
41 #define KRB5_KDB_DISALLOW_RENEWABLE 0x00000008
42 #define KRB5_KDB_DISALLOW_PROXIABLE 0x00000010
43 #define KRB5_KDB_DISALLOW_DUP_SKEY 0x00000020
44 #define KRB5_KDB_DISALLOW_ALL_TIX 0x00000040
45 #define KRB5_KDB_REQUIRES_PRE_AUTH 0x00000080
46 #define KRB5_KDB_REQUIRES_HW_AUTH 0x00000100
47 #define KRB5_KDB_REQUIRES_PWCHANGE 0x00000200
48 #define KRB5_KDB_DISALLOW_SVR 0x00001000
49 #define KRB5_KDB_PWCHANGE_SERVICE 0x00002000
50 #define KRB5_KDB_SUPPORT_DESMD5 0x00004000
51 #define KRB5_KDB_NEW_PRINC 0x00008000
55 key: krb5_unparse_name + NUL
57 16: baselength
58 32: attributes
59 32: max time
60 32: max renewable time
61 32: client expire
62 32: passwd expire
63 32: last successful passwd
64 32: last failed attempt
65 32: num of failed attempts
66 16: num tl data
67 16: num data data
68 16: principal length
69 length: principal
70 for num tl data times
71 16: tl data type
72 16: tl data length
73 length: length
74 for num key data times
75 16: version (num keyblocks)
76 16: kvno
77 for version times:
78 16: type
79 16: length
80 length: keydata
83 key_data_contents[0]
85 int16: length
86 read-of-data: key-encrypted, key-usage 0, master-key
88 salt:
89 version2 = salt in key_data->key_data_contents[1]
90 else default salt.
94 #include "hdb_locl.h"
96 #define KDB_V1_BASE_LENGTH 38
98 #if HAVE_DB1
100 #if defined(HAVE_DB_185_H)
101 #include <db_185.h>
102 #elif defined(HAVE_DB_H)
103 #include <db.h>
104 #endif
106 #define CHECK(x) do { if ((x)) goto out; } while(0)
108 static krb5_error_code
109 mdb_principal2key(krb5_context context,
110 krb5_const_principal principal,
111 krb5_data *key)
113 krb5_error_code ret;
114 char *str;
116 ret = krb5_unparse_name(context, principal, &str);
117 if (ret)
118 return ret;
119 key->data = str;
120 key->length = strlen(str) + 1;
121 return 0;
124 #define KRB5_KDB_SALTTYPE_NORMAL 0
125 #define KRB5_KDB_SALTTYPE_V4 1
126 #define KRB5_KDB_SALTTYPE_NOREALM 2
127 #define KRB5_KDB_SALTTYPE_ONLYREALM 3
128 #define KRB5_KDB_SALTTYPE_SPECIAL 4
129 #define KRB5_KDB_SALTTYPE_AFS3 5
130 #define KRB5_KDB_SALTTYPE_CERTHASH 6
132 static krb5_error_code
133 fix_salt(krb5_context context, hdb_entry *ent, int key_num)
135 krb5_error_code ret;
136 Salt *salt = ent->keys.val[key_num].salt;
137 /* fix salt type */
138 switch((int)salt->type) {
139 case KRB5_KDB_SALTTYPE_NORMAL:
140 salt->type = KRB5_PADATA_PW_SALT;
141 break;
142 case KRB5_KDB_SALTTYPE_V4:
143 krb5_data_free(&salt->salt);
144 salt->type = KRB5_PADATA_PW_SALT;
145 break;
146 case KRB5_KDB_SALTTYPE_NOREALM:
148 size_t len;
149 size_t i;
150 char *p;
152 len = 0;
153 for (i = 0; i < ent->principal->name.name_string.len; ++i)
154 len += strlen(ent->principal->name.name_string.val[i]);
155 ret = krb5_data_alloc (&salt->salt, len);
156 if (ret)
157 return ret;
158 p = salt->salt.data;
159 for (i = 0; i < ent->principal->name.name_string.len; ++i) {
160 memcpy (p,
161 ent->principal->name.name_string.val[i],
162 strlen(ent->principal->name.name_string.val[i]));
163 p += strlen(ent->principal->name.name_string.val[i]);
166 salt->type = KRB5_PADATA_PW_SALT;
167 break;
169 case KRB5_KDB_SALTTYPE_ONLYREALM:
170 krb5_data_free(&salt->salt);
171 ret = krb5_data_copy(&salt->salt,
172 ent->principal->realm,
173 strlen(ent->principal->realm));
174 if(ret)
175 return ret;
176 salt->type = KRB5_PADATA_PW_SALT;
177 break;
178 case KRB5_KDB_SALTTYPE_SPECIAL:
179 salt->type = KRB5_PADATA_PW_SALT;
180 break;
181 case KRB5_KDB_SALTTYPE_AFS3:
182 krb5_data_free(&salt->salt);
183 ret = krb5_data_copy(&salt->salt,
184 ent->principal->realm,
185 strlen(ent->principal->realm));
186 if(ret)
187 return ret;
188 salt->type = KRB5_PADATA_AFS3_SALT;
189 break;
190 case KRB5_KDB_SALTTYPE_CERTHASH:
191 krb5_data_free(&salt->salt);
192 free(ent->keys.val[key_num].salt);
193 ent->keys.val[key_num].salt = NULL;
194 break;
195 default:
196 abort();
198 return 0;
202 static krb5_error_code
203 mdb_value2entry(krb5_context context, krb5_data *data, krb5_kvno kvno, hdb_entry *entry)
205 krb5_error_code ret;
206 krb5_storage *sp;
207 uint32_t u32;
208 uint16_t u16, num_keys, num_tl;
209 size_t i, j;
210 char *p;
212 sp = krb5_storage_from_data(data);
213 if (sp == NULL) {
214 krb5_set_error_message(context, ENOMEM, "out of memory");
215 return ENOMEM;
218 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE);
221 * 16: baselength
223 * The story here is that these 16 bits have to be a constant:
224 * KDB_V1_BASE_LENGTH. Once upon a time a different value here
225 * would have been used to indicate the presence of "extra data"
226 * between the "base" contents and the {principal name, TL data,
227 * keys} that follow it. Nothing supports such "extra data"
228 * nowadays, so neither do we here.
230 * XXX But... surely we ought to log about this extra data, or skip
231 * it, or something, in case anyone has MIT KDBs with ancient
232 * entries in them... Logging would allow the admin to know which
233 * entries to dump with MIT krb5's kdb5_util.
235 CHECK(ret = krb5_ret_uint16(sp, &u16));
236 if (u16 != KDB_V1_BASE_LENGTH) { ret = EINVAL; goto out; }
237 /* 32: attributes */
238 CHECK(ret = krb5_ret_uint32(sp, &u32));
239 entry->flags.postdate = !(u32 & KRB5_KDB_DISALLOW_POSTDATED);
240 entry->flags.forwardable = !(u32 & KRB5_KDB_DISALLOW_FORWARDABLE);
241 entry->flags.initial = !!(u32 & KRB5_KDB_DISALLOW_TGT_BASED);
242 entry->flags.renewable = !(u32 & KRB5_KDB_DISALLOW_RENEWABLE);
243 entry->flags.proxiable = !(u32 & KRB5_KDB_DISALLOW_PROXIABLE);
244 /* DUP_SKEY */
245 entry->flags.invalid = !!(u32 & KRB5_KDB_DISALLOW_ALL_TIX);
246 entry->flags.require_preauth =!!(u32 & KRB5_KDB_REQUIRES_PRE_AUTH);
247 entry->flags.require_hwauth =!!(u32 & KRB5_KDB_REQUIRES_HW_AUTH);
248 entry->flags.server = !(u32 & KRB5_KDB_DISALLOW_SVR);
249 entry->flags.change_pw = !!(u32 & KRB5_KDB_PWCHANGE_SERVICE);
250 entry->flags.client = 1; /* XXX */
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;
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;
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;
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;
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 */
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.
296 p = malloc(u16 + 1);
297 if (p == NULL) {
298 ret = ENOMEM;
299 goto out;
301 krb5_storage_read(sp, p, u16);
302 p[u16] = '\0';
303 CHECK(ret = krb5_parse_name(context, p, &entry->principal));
304 free(p);
306 /* for num tl data times
307 16: tl data type
308 16: tl data length
309 length: length */
310 for (i = 0; i < num_tl; i++) {
311 /* 16: TL data type */
312 CHECK(ret = krb5_ret_uint16(sp, &u16));
313 /* 16: TL data length */
314 CHECK(ret = krb5_ret_uint16(sp, &u16));
315 krb5_storage_seek(sp, u16, SEEK_CUR);
318 * for num key data times
319 * 16: "version"
320 * 16: kvno
321 * for version times:
322 * 16: type
323 * 16: length
324 * length: keydata
326 * "version" here is really 1 or 2, the first meaning there's only
327 * keys for this kvno, the second meaning there's keys and salt[s?].
328 * That's right... hold that gag reflex, you can do it.
330 for (i = 0; i < num_keys; i++) {
331 int keep = 0;
332 uint16_t version;
333 void *ptr;
335 CHECK(ret = krb5_ret_uint16(sp, &u16));
336 version = u16;
337 CHECK(ret = krb5_ret_uint16(sp, &u16));
340 * First time through, and until we find one matching key,
341 * entry->kvno == 0.
343 if ((entry->kvno < u16) && (kvno == 0 || kvno == u16)) {
344 keep = 1;
345 entry->kvno = u16;
347 * Found a higher kvno than earlier, so free the old highest
348 * kvno keys.
350 * XXX Of course, we actually want to extract the old kvnos
351 * as well, for some of the kadm5 APIs. We shouldn't free
352 * these keys, but keep them elsewhere.
354 for (j = 0; j < entry->keys.len; j++)
355 free_Key(&entry->keys.val[j]);
356 free(entry->keys.val);
357 entry->keys.len = 0;
358 entry->keys.val = NULL;
359 } else if (entry->kvno == u16)
360 /* Accumulate keys */
361 keep = 1;
363 if (keep) {
364 Key *k;
366 ptr = realloc(entry->keys.val, sizeof(entry->keys.val[0]) * (entry->keys.len + 1));
367 if (ptr == NULL) {
368 ret = ENOMEM;
369 goto out;
371 entry->keys.val = ptr;
373 /* k points to current Key */
374 k = &entry->keys.val[entry->keys.len];
376 memset(k, 0, sizeof(*k));
377 entry->keys.len += 1;
379 k->mkvno = malloc(sizeof(*k->mkvno));
380 if (k->mkvno == NULL) {
381 ret = ENOMEM;
382 goto out;
384 *k->mkvno = 1;
386 for (j = 0; j < version; j++) {
387 uint16_t type;
388 CHECK(ret = krb5_ret_uint16(sp, &type));
389 CHECK(ret = krb5_ret_uint16(sp, &u16));
390 if (j == 0) {
391 /* This "version" means we have a key */
392 k->key.keytype = type;
393 if (u16 < 2) {
394 ret = EINVAL;
395 goto out;
398 * MIT stores keys encrypted keys as {16-bit length
399 * of plaintext key, {encrypted key}}. The reason
400 * for this is that the Kerberos cryptosystem is not
401 * length-preserving. Heimdal's approach is to
402 * truncate the plaintext to the expected length of
403 * the key given its enctype, so we ignore this
404 * 16-bit length-of-plaintext-key field.
406 krb5_storage_seek(sp, 2, SEEK_CUR); /* skip real length */
407 k->key.keyvalue.length = u16 - 2; /* adjust cipher len */
408 k->key.keyvalue.data = malloc(k->key.keyvalue.length);
409 krb5_storage_read(sp, k->key.keyvalue.data,
410 k->key.keyvalue.length);
411 } else if (j == 1) {
412 /* This "version" means we have a salt */
413 k->salt = calloc(1, sizeof(*k->salt));
414 if (k->salt == NULL) {
415 ret = ENOMEM;
416 goto out;
418 k->salt->type = type;
419 if (u16 != 0) {
420 k->salt->salt.data = malloc(u16);
421 if (k->salt->salt.data == NULL) {
422 ret = ENOMEM;
423 goto out;
425 k->salt->salt.length = u16;
426 krb5_storage_read(sp, k->salt->salt.data, k->salt->salt.length);
428 fix_salt(context, entry, entry->keys.len - 1);
429 } else {
431 * Whatever this "version" might be, we skip it
433 * XXX A krb5.conf parameter requesting that we log
434 * about strangeness like this, or return an error
435 * from here, might be nice.
437 krb5_storage_seek(sp, u16, SEEK_CUR);
440 } else {
442 * XXX For now we skip older kvnos, but we should extract
443 * them...
445 for (j = 0; j < version; j++) {
446 /* enctype */
447 CHECK(ret = krb5_ret_uint16(sp, &u16));
448 /* encrypted key (or plaintext salt) */
449 CHECK(ret = krb5_ret_uint16(sp, &u16));
450 krb5_storage_seek(sp, u16, SEEK_CUR);
455 if (entry->kvno == 0 && kvno != 0) {
456 ret = HDB_ERR_NOT_FOUND_HERE;
457 goto out;
460 return 0;
461 out:
462 if (ret == HEIM_ERR_EOF)
463 /* Better error code than "end of file" */
464 ret = HEIM_ERR_BAD_HDBENT_ENCODING;
465 return ret;
468 #if 0
469 static krb5_error_code
470 mdb_entry2value(krb5_context context, hdb_entry *entry, krb5_data *data)
472 return EINVAL;
474 #endif
477 static krb5_error_code
478 mdb_close(krb5_context context, HDB *db)
480 DB *d = (DB*)db->hdb_db;
481 (*d->close)(d);
482 return 0;
485 static krb5_error_code
486 mdb_destroy(krb5_context context, HDB *db)
488 krb5_error_code ret;
490 ret = hdb_clear_master_key (context, db);
491 free(db->hdb_name);
492 free(db);
493 return ret;
496 static krb5_error_code
497 mdb_lock(krb5_context context, HDB *db, int operation)
499 DB *d = (DB*)db->hdb_db;
500 int fd = (*d->fd)(d);
501 if(fd < 0) {
502 krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB,
503 "Can't lock database: %s", db->hdb_name);
504 return HDB_ERR_CANT_LOCK_DB;
506 return hdb_lock(fd, operation);
509 static krb5_error_code
510 mdb_unlock(krb5_context context, HDB *db)
512 DB *d = (DB*)db->hdb_db;
513 int fd = (*d->fd)(d);
514 if(fd < 0) {
515 krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB,
516 "Can't unlock database: %s", db->hdb_name);
517 return HDB_ERR_CANT_LOCK_DB;
519 return hdb_unlock(fd);
523 static krb5_error_code
524 mdb_seq(krb5_context context, HDB *db,
525 unsigned flags, hdb_entry_ex *entry, int flag)
527 DB *d = (DB*)db->hdb_db;
528 DBT key, value;
529 krb5_data key_data, data;
530 int code;
532 code = db->hdb_lock(context, db, HDB_RLOCK);
533 if(code == -1) {
534 krb5_set_error_message(context, HDB_ERR_DB_INUSE, "Database %s in use", db->hdb_name);
535 return HDB_ERR_DB_INUSE;
537 code = (*d->seq)(d, &key, &value, flag);
538 db->hdb_unlock(context, db); /* XXX check value */
539 if(code == -1) {
540 code = errno;
541 krb5_set_error_message(context, code, "Database %s seq error: %s",
542 db->hdb_name, strerror(code));
543 return code;
545 if(code == 1) {
546 krb5_clear_error_message(context);
547 return HDB_ERR_NOENTRY;
550 key_data.data = key.data;
551 key_data.length = key.size;
552 data.data = value.data;
553 data.length = value.size;
554 memset(entry, 0, sizeof(*entry));
556 if (mdb_value2entry(context, &data, 0, &entry->entry))
557 return mdb_seq(context, db, flags, entry, R_NEXT);
559 if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
560 code = hdb_unseal_keys (context, db, &entry->entry);
561 if (code)
562 hdb_free_entry (context, entry);
565 return code;
569 static krb5_error_code
570 mdb_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
572 return mdb_seq(context, db, flags, entry, R_FIRST);
576 static krb5_error_code
577 mdb_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
579 return mdb_seq(context, db, flags, entry, R_NEXT);
582 static krb5_error_code
583 mdb_rename(krb5_context context, HDB *db, const char *new_name)
585 int ret;
586 char *old, *new;
588 asprintf(&old, "%s.db", db->hdb_name);
589 asprintf(&new, "%s.db", new_name);
590 ret = rename(old, new);
591 free(old);
592 free(new);
593 if(ret)
594 return errno;
596 free(db->hdb_name);
597 db->hdb_name = strdup(new_name);
598 return 0;
601 static krb5_error_code
602 mdb__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply)
604 DB *d = (DB*)db->hdb_db;
605 DBT k, v;
606 int code;
608 k.data = key.data;
609 k.size = key.length;
610 code = db->hdb_lock(context, db, HDB_RLOCK);
611 if(code)
612 return code;
613 code = (*d->get)(d, &k, &v, 0);
614 db->hdb_unlock(context, db);
615 if(code < 0) {
616 code = errno;
617 krb5_set_error_message(context, code, "Database %s get error: %s",
618 db->hdb_name, strerror(code));
619 return code;
621 if(code == 1) {
622 krb5_clear_error_message(context);
623 return HDB_ERR_NOENTRY;
626 krb5_data_copy(reply, v.data, v.size);
627 return 0;
630 static krb5_error_code
631 mdb__put(krb5_context context, HDB *db, int replace,
632 krb5_data key, krb5_data value)
634 DB *d = (DB*)db->hdb_db;
635 DBT k, v;
636 int code;
638 k.data = key.data;
639 k.size = key.length;
640 v.data = value.data;
641 v.size = value.length;
642 code = db->hdb_lock(context, db, HDB_WLOCK);
643 if(code)
644 return code;
645 code = (*d->put)(d, &k, &v, replace ? 0 : R_NOOVERWRITE);
646 db->hdb_unlock(context, db);
647 if(code < 0) {
648 code = errno;
649 krb5_set_error_message(context, code, "Database %s put error: %s",
650 db->hdb_name, strerror(code));
651 return code;
653 if(code == 1) {
654 krb5_clear_error_message(context);
655 return HDB_ERR_EXISTS;
657 return 0;
660 static krb5_error_code
661 mdb__del(krb5_context context, HDB *db, krb5_data key)
663 DB *d = (DB*)db->hdb_db;
664 DBT k;
665 krb5_error_code code;
666 k.data = key.data;
667 k.size = key.length;
668 code = db->hdb_lock(context, db, HDB_WLOCK);
669 if(code)
670 return code;
671 code = (*d->del)(d, &k, 0);
672 db->hdb_unlock(context, db);
673 if(code == 1) {
674 code = errno;
675 krb5_set_error_message(context, code, "Database %s put error: %s",
676 db->hdb_name, strerror(code));
677 return code;
679 if(code < 0)
680 return errno;
681 return 0;
684 static krb5_error_code
685 mdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal,
686 unsigned flags, krb5_kvno kvno, hdb_entry_ex *entry)
688 krb5_data key, value;
689 krb5_error_code code;
691 code = mdb_principal2key(context, principal, &key);
692 if (code)
693 return code;
694 code = db->hdb__get(context, db, key, &value);
695 krb5_data_free(&key);
696 if(code)
697 return code;
698 code = mdb_value2entry(context, &value, kvno, &entry->entry);
699 krb5_data_free(&value);
700 if (code)
701 return code;
703 if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
704 code = hdb_unseal_keys (context, db, &entry->entry);
705 if (code)
706 hdb_free_entry(context, entry);
709 return 0;
712 static krb5_error_code
713 mdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
715 krb5_set_error_message(context, EINVAL, "can't set principal in mdb");
716 return EINVAL;
719 static krb5_error_code
720 mdb_remove(krb5_context context, HDB *db, krb5_const_principal principal)
722 krb5_error_code code;
723 krb5_data key;
725 mdb_principal2key(context, principal, &key);
726 code = db->hdb__del(context, db, key);
727 krb5_data_free(&key);
728 return code;
731 static krb5_error_code
732 mdb_open(krb5_context context, HDB *db, int flags, mode_t mode)
734 char *fn;
735 krb5_error_code ret;
737 asprintf(&fn, "%s.db", db->hdb_name);
738 if (fn == NULL) {
739 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
740 return ENOMEM;
742 db->hdb_db = dbopen(fn, flags, mode, DB_BTREE, NULL);
743 free(fn);
745 if (db->hdb_db == NULL) {
746 switch (errno) {
747 #ifdef EFTYPE
748 case EFTYPE:
749 #endif
750 case EINVAL:
751 db->hdb_db = dbopen(fn, flags, mode, DB_BTREE, NULL);
755 /* try to open without .db extension */
756 if(db->hdb_db == NULL && errno == ENOENT)
757 db->hdb_db = dbopen(db->hdb_name, flags, mode, DB_BTREE, NULL);
758 if(db->hdb_db == NULL) {
759 ret = errno;
760 krb5_set_error_message(context, ret, "dbopen (%s): %s",
761 db->hdb_name, strerror(ret));
762 return ret;
764 if((flags & O_ACCMODE) == O_RDONLY)
765 ret = hdb_check_db_format(context, db);
766 else
767 ret = hdb_init_db(context, db);
768 if(ret == HDB_ERR_NOENTRY) {
769 krb5_clear_error_message(context);
770 return 0;
772 if (ret) {
773 mdb_close(context, db);
774 krb5_set_error_message(context, ret, "hdb_open: failed %s database %s",
775 (flags & O_ACCMODE) == O_RDONLY ?
776 "checking format of" : "initialize",
777 db->hdb_name);
779 return ret;
782 krb5_error_code
783 hdb_mdb_create(krb5_context context, HDB **db,
784 const char *filename)
786 *db = calloc(1, sizeof(**db));
787 if (*db == NULL) {
788 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
789 return ENOMEM;
792 (*db)->hdb_db = NULL;
793 (*db)->hdb_name = strdup(filename);
794 if ((*db)->hdb_name == NULL) {
795 free(*db);
796 *db = NULL;
797 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
798 return ENOMEM;
800 (*db)->hdb_master_key_set = 0;
801 (*db)->hdb_openp = 0;
802 (*db)->hdb_capability_flags = 0;
803 (*db)->hdb_open = mdb_open;
804 (*db)->hdb_close = mdb_close;
805 (*db)->hdb_fetch_kvno = mdb_fetch_kvno;
806 (*db)->hdb_store = mdb_store;
807 (*db)->hdb_remove = mdb_remove;
808 (*db)->hdb_firstkey = mdb_firstkey;
809 (*db)->hdb_nextkey= mdb_nextkey;
810 (*db)->hdb_lock = mdb_lock;
811 (*db)->hdb_unlock = mdb_unlock;
812 (*db)->hdb_rename = mdb_rename;
813 (*db)->hdb__get = mdb__get;
814 (*db)->hdb__put = mdb__put;
815 (*db)->hdb__del = mdb__del;
816 (*db)->hdb_destroy = mdb_destroy;
817 return 0;
820 #endif /* HAVE_DB1 */