1 /* $NetBSD: hdb-mitdb.c,v 1.1.1.2 2014/04/24 12:45:28 pettai Exp $ */
2
3 /*
4 * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 *
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 *
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.
20 *
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.
24 *
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.
36 */
37
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
52
53 /*
54
55 key: krb5_unparse_name + NUL
56
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
81
82
83 key_data_contents[0]
84
85 int16: length
86 read-of-data: key-encrypted, key-usage 0, master-key
87
88 salt:
89 version2 = salt in key_data->key_data_contents[1]
90 else default salt.
91
92 */
93
94 #include "hdb_locl.h"
95
96 #define KDB_V1_BASE_LENGTH 38
97
98 #if HAVE_DB1
99
100 #if defined(HAVE_DB_185_H)
101 #include <db_185.h>
102 #elif defined(HAVE_DB_H)
103 #include <db.h>
104 #endif
105
106 #define CHECK(x) do { if ((x)) goto out; } while(0)
107
108 static krb5_error_code
mdb_principal2key(krb5_context context,krb5_const_principal principal,krb5_data * key)109 mdb_principal2key(krb5_context context,
110 krb5_const_principal principal,
111 krb5_data *key)
112 {
113 krb5_error_code ret;
114 char *str;
115
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;
122 }
123
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
131
132 static krb5_error_code
fix_salt(krb5_context context,hdb_entry * ent,int key_num)133 fix_salt(krb5_context context, hdb_entry *ent, int key_num)
134 {
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:
147 {
148 size_t len;
149 size_t i;
150 char *p;
151
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]);
164 }
165
166 salt->type = KRB5_PADATA_PW_SALT;
167 break;
168 }
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();
197 }
198 return 0;
199 }
200
201
202 static krb5_error_code
mdb_value2entry(krb5_context context,krb5_data * data,krb5_kvno kvno,hdb_entry * entry)203 mdb_value2entry(krb5_context context, krb5_data *data, krb5_kvno kvno, hdb_entry *entry)
204 {
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;
211
212 sp = krb5_storage_from_data(data);
213 if (sp == NULL) {
214 krb5_set_error_message(context, ENOMEM, "out of memory");
215 return ENOMEM;
216 }
217
218 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE);
219
220 /*
221 * 16: baselength
222 *
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.
229 *
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.
234 */
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 */
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 krb5_storage_read(sp, p, u16);
302 p[u16] = '\0';
303 CHECK(ret = krb5_parse_name(context, p, &entry->principal));
304 free(p);
305 }
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);
316 }
317 /*
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
325 *
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.
329 */
330 for (i = 0; i < num_keys; i++) {
331 int keep = 0;
332 uint16_t version;
333 void *ptr;
334
335 CHECK(ret = krb5_ret_uint16(sp, &u16));
336 version = u16;
337 CHECK(ret = krb5_ret_uint16(sp, &u16));
338
339 /*
340 * First time through, and until we find one matching key,
341 * entry->kvno == 0.
342 */
343 if ((entry->kvno < u16) && (kvno == 0 || kvno == u16)) {
344 keep = 1;
345 entry->kvno = u16;
346 /*
347 * Found a higher kvno than earlier, so free the old highest
348 * kvno keys.
349 *
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.
353 */
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;
362
363 if (keep) {
364 Key *k;
365
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;
370 }
371 entry->keys.val = ptr;
372
373 /* k points to current Key */
374 k = &entry->keys.val[entry->keys.len];
375
376 memset(k, 0, sizeof(*k));
377 entry->keys.len += 1;
378
379 k->mkvno = malloc(sizeof(*k->mkvno));
380 if (k->mkvno == NULL) {
381 ret = ENOMEM;
382 goto out;
383 }
384 *k->mkvno = 1;
385
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;
396 }
397 /*
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.
405 */
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;
417 }
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;
424 }
425 k->salt->salt.length = u16;
426 krb5_storage_read(sp, k->salt->salt.data, k->salt->salt.length);
427 }
428 fix_salt(context, entry, entry->keys.len - 1);
429 } else {
430 /*
431 * Whatever this "version" might be, we skip it
432 *
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.
436 */
437 krb5_storage_seek(sp, u16, SEEK_CUR);
438 }
439 }
440 } else {
441 /*
442 * XXX For now we skip older kvnos, but we should extract
443 * them...
444 */
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);
451 }
452 }
453 }
454
455 if (entry->kvno == 0 && kvno != 0) {
456 ret = HDB_ERR_NOT_FOUND_HERE;
457 goto out;
458 }
459
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;
466 }
467
468 #if 0
469 static krb5_error_code
470 mdb_entry2value(krb5_context context, hdb_entry *entry, krb5_data *data)
471 {
472 return EINVAL;
473 }
474 #endif
475
476
477 static krb5_error_code
mdb_close(krb5_context context,HDB * db)478 mdb_close(krb5_context context, HDB *db)
479 {
480 DB *d = (DB*)db->hdb_db;
481 (*d->close)(d);
482 return 0;
483 }
484
485 static krb5_error_code
mdb_destroy(krb5_context context,HDB * db)486 mdb_destroy(krb5_context context, HDB *db)
487 {
488 krb5_error_code ret;
489
490 ret = hdb_clear_master_key (context, db);
491 free(db->hdb_name);
492 free(db);
493 return ret;
494 }
495
496 static krb5_error_code
mdb_lock(krb5_context context,HDB * db,int operation)497 mdb_lock(krb5_context context, HDB *db, int operation)
498 {
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;
505 }
506 return hdb_lock(fd, operation);
507 }
508
509 static krb5_error_code
mdb_unlock(krb5_context context,HDB * db)510 mdb_unlock(krb5_context context, HDB *db)
511 {
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;
518 }
519 return hdb_unlock(fd);
520 }
521
522
523 static krb5_error_code
mdb_seq(krb5_context context,HDB * db,unsigned flags,hdb_entry_ex * entry,int flag)524 mdb_seq(krb5_context context, HDB *db,
525 unsigned flags, hdb_entry_ex *entry, int flag)
526 {
527 DB *d = (DB*)db->hdb_db;
528 DBT key, value;
529 krb5_data key_data, data;
530 int code;
531
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;
536 }
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;
544 }
545 if(code == 1) {
546 krb5_clear_error_message(context);
547 return HDB_ERR_NOENTRY;
548 }
549
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));
555
556 if (mdb_value2entry(context, &data, 0, &entry->entry))
557 return mdb_seq(context, db, flags, entry, R_NEXT);
558
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);
563 }
564
565 return code;
566 }
567
568
569 static krb5_error_code
mdb_firstkey(krb5_context context,HDB * db,unsigned flags,hdb_entry_ex * entry)570 mdb_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
571 {
572 return mdb_seq(context, db, flags, entry, R_FIRST);
573 }
574
575
576 static krb5_error_code
mdb_nextkey(krb5_context context,HDB * db,unsigned flags,hdb_entry_ex * entry)577 mdb_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
578 {
579 return mdb_seq(context, db, flags, entry, R_NEXT);
580 }
581
582 static krb5_error_code
mdb_rename(krb5_context context,HDB * db,const char * new_name)583 mdb_rename(krb5_context context, HDB *db, const char *new_name)
584 {
585 int ret;
586 char *old, *new;
587
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;
595
596 free(db->hdb_name);
597 db->hdb_name = strdup(new_name);
598 return 0;
599 }
600
601 static krb5_error_code
mdb__get(krb5_context context,HDB * db,krb5_data key,krb5_data * reply)602 mdb__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply)
603 {
604 DB *d = (DB*)db->hdb_db;
605 DBT k, v;
606 int code;
607
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;
620 }
621 if(code == 1) {
622 krb5_clear_error_message(context);
623 return HDB_ERR_NOENTRY;
624 }
625
626 krb5_data_copy(reply, v.data, v.size);
627 return 0;
628 }
629
630 static krb5_error_code
mdb__put(krb5_context context,HDB * db,int replace,krb5_data key,krb5_data value)631 mdb__put(krb5_context context, HDB *db, int replace,
632 krb5_data key, krb5_data value)
633 {
634 DB *d = (DB*)db->hdb_db;
635 DBT k, v;
636 int code;
637
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;
652 }
653 if(code == 1) {
654 krb5_clear_error_message(context);
655 return HDB_ERR_EXISTS;
656 }
657 return 0;
658 }
659
660 static krb5_error_code
mdb__del(krb5_context context,HDB * db,krb5_data key)661 mdb__del(krb5_context context, HDB *db, krb5_data key)
662 {
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;
678 }
679 if(code < 0)
680 return errno;
681 return 0;
682 }
683
684 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)685 mdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal,
686 unsigned flags, krb5_kvno kvno, hdb_entry_ex *entry)
687 {
688 krb5_data key, value;
689 krb5_error_code code;
690
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;
702
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);
707 }
708
709 return 0;
710 }
711
712 static krb5_error_code
mdb_store(krb5_context context,HDB * db,unsigned flags,hdb_entry_ex * entry)713 mdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
714 {
715 krb5_set_error_message(context, EINVAL, "can't set principal in mdb");
716 return EINVAL;
717 }
718
719 static krb5_error_code
mdb_remove(krb5_context context,HDB * db,krb5_const_principal principal)720 mdb_remove(krb5_context context, HDB *db, krb5_const_principal principal)
721 {
722 krb5_error_code code;
723 krb5_data key;
724
725 mdb_principal2key(context, principal, &key);
726 code = db->hdb__del(context, db, key);
727 krb5_data_free(&key);
728 return code;
729 }
730
731 static krb5_error_code
mdb_open(krb5_context context,HDB * db,int flags,mode_t mode)732 mdb_open(krb5_context context, HDB *db, int flags, mode_t mode)
733 {
734 char *fn;
735 krb5_error_code ret;
736
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;
741 }
742 db->hdb_db = dbopen(fn, flags, mode, DB_BTREE, NULL);
743 free(fn);
744
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);
752 }
753 }
754
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;
763 }
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;
771 }
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);
778 }
779 return ret;
780 }
781
782 krb5_error_code
hdb_mdb_create(krb5_context context,HDB ** db,const char * filename)783 hdb_mdb_create(krb5_context context, HDB **db,
784 const char *filename)
785 {
786 *db = calloc(1, sizeof(**db));
787 if (*db == NULL) {
788 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
789 return ENOMEM;
790 }
791
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;
799 }
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;
818 }
819
820 #endif /* HAVE_DB1 */
821