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 #define KDB_V1_BASE_LENGTH 38
95
96 #if HAVE_DB1
97
98 #if defined(HAVE_DB_185_H)
99 #include <db_185.h>
100 #elif defined(HAVE_DB_H)
101 #include <db.h>
102 #endif
103
104 #define CHECK(x) do { if ((x)) goto out; } while(0)
105
106 static krb5_error_code
mdb_principal2key(krb5_context context,krb5_const_principal principal,krb5_data * key)107 mdb_principal2key(krb5_context context,
108 krb5_const_principal principal,
109 krb5_data *key)
110 {
111 krb5_error_code ret;
112 char *str;
113
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;
120 }
121
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
129
130 static krb5_error_code
fix_salt(krb5_context context,hdb_entry * ent,int key_num)131 fix_salt(krb5_context context, hdb_entry *ent, int key_num)
132 {
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:
145 {
146 size_t len;
147 size_t i;
148 char *p;
149
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]);
162 }
163
164 salt->type = KRB5_PADATA_PW_SALT;
165 break;
166 }
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();
195 }
196 return 0;
197 }
198
199
200 static krb5_error_code
mdb_value2entry(krb5_context context,krb5_data * data,krb5_kvno kvno,hdb_entry * entry)201 mdb_value2entry(krb5_context context, krb5_data *data, krb5_kvno kvno, hdb_entry *entry)
202 {
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;
209
210 sp = krb5_storage_from_data(data);
211 if (sp == NULL) {
212 krb5_set_error_message(context, ENOMEM, "out of memory");
213 return ENOMEM;
214 }
215
216 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE);
217
218 /*
219 * 16: baselength
220 *
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.
227 *
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.
232 */
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 */
249
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;
255 }
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;
261 }
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;
267 }
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;
273 }
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 */
289 {
290 /*
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.
293 */
294 p = malloc(u16 + 1);
295 if (p == NULL) {
296 ret = ENOMEM;
297 goto out;
298 }
299 krb5_storage_read(sp, p, u16);
300 p[u16] = '\0';
301 CHECK(ret = krb5_parse_name(context, p, &entry->principal));
302 free(p);
303 }
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);
314 }
315 /*
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
323 *
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.
327 */
328 for (i = 0; i < num_keys; i++) {
329 int keep = 0;
330 uint16_t version;
331 void *ptr;
332
333 CHECK(ret = krb5_ret_uint16(sp, &u16));
334 version = u16;
335 CHECK(ret = krb5_ret_uint16(sp, &u16));
336
337 /*
338 * First time through, and until we find one matching key,
339 * entry->kvno == 0.
340 */
341 if ((entry->kvno < u16) && (kvno == 0 || kvno == u16)) {
342 keep = 1;
343 entry->kvno = u16;
344 /*
345 * Found a higher kvno than earlier, so free the old highest
346 * kvno keys.
347 *
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.
351 */
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;
360
361 if (keep) {
362 Key *k;
363
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;
368 }
369 entry->keys.val = ptr;
370
371 /* k points to current Key */
372 k = &entry->keys.val[entry->keys.len];
373
374 memset(k, 0, sizeof(*k));
375 entry->keys.len += 1;
376
377 k->mkvno = malloc(sizeof(*k->mkvno));
378 if (k->mkvno == NULL) {
379 ret = ENOMEM;
380 goto out;
381 }
382 *k->mkvno = 1;
383
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;
394 }
395 /*
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.
403 */
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;
415 }
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;
422 }
423 k->salt->salt.length = u16;
424 krb5_storage_read(sp, k->salt->salt.data, k->salt->salt.length);
425 }
426 fix_salt(context, entry, entry->keys.len - 1);
427 } else {
428 /*
429 * Whatever this "version" might be, we skip it
430 *
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.
434 */
435 krb5_storage_seek(sp, u16, SEEK_CUR);
436 }
437 }
438 } else {
439 /*
440 * XXX For now we skip older kvnos, but we should extract
441 * them...
442 */
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);
449 }
450 }
451 }
452
453 if (entry->kvno == 0 && kvno != 0) {
454 ret = HDB_ERR_NOT_FOUND_HERE;
455 goto out;
456 }
457
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;
464 }
465
466 #if 0
467 static krb5_error_code
468 mdb_entry2value(krb5_context context, hdb_entry *entry, krb5_data *data)
469 {
470 return EINVAL;
471 }
472 #endif
473
474
475 static krb5_error_code
mdb_close(krb5_context context,HDB * db)476 mdb_close(krb5_context context, HDB *db)
477 {
478 DB *d = (DB*)db->hdb_db;
479 (*d->close)(d);
480 return 0;
481 }
482
483 static krb5_error_code
mdb_destroy(krb5_context context,HDB * db)484 mdb_destroy(krb5_context context, HDB *db)
485 {
486 krb5_error_code ret;
487
488 ret = hdb_clear_master_key (context, db);
489 free(db->hdb_name);
490 free(db);
491 return ret;
492 }
493
494 static krb5_error_code
mdb_lock(krb5_context context,HDB * db,int operation)495 mdb_lock(krb5_context context, HDB *db, int operation)
496 {
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;
503 }
504 return hdb_lock(fd, operation);
505 }
506
507 static krb5_error_code
mdb_unlock(krb5_context context,HDB * db)508 mdb_unlock(krb5_context context, HDB *db)
509 {
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;
516 }
517 return hdb_unlock(fd);
518 }
519
520
521 static krb5_error_code
mdb_seq(krb5_context context,HDB * db,unsigned flags,hdb_entry_ex * entry,int flag)522 mdb_seq(krb5_context context, HDB *db,
523 unsigned flags, hdb_entry_ex *entry, int flag)
524 {
525 DB *d = (DB*)db->hdb_db;
526 DBT key, value;
527 krb5_data key_data, data;
528 int code;
529
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;
534 }
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;
542 }
543 if(code == 1) {
544 krb5_clear_error_message(context);
545 return HDB_ERR_NOENTRY;
546 }
547
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));
553
554 if (mdb_value2entry(context, &data, 0, &entry->entry))
555 return mdb_seq(context, db, flags, entry, R_NEXT);
556
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);
561 }
562
563 return code;
564 }
565
566
567 static krb5_error_code
mdb_firstkey(krb5_context context,HDB * db,unsigned flags,hdb_entry_ex * entry)568 mdb_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
569 {
570 return mdb_seq(context, db, flags, entry, R_FIRST);
571 }
572
573
574 static krb5_error_code
mdb_nextkey(krb5_context context,HDB * db,unsigned flags,hdb_entry_ex * entry)575 mdb_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
576 {
577 return mdb_seq(context, db, flags, entry, R_NEXT);
578 }
579
580 static krb5_error_code
mdb_rename(krb5_context context,HDB * db,const char * new_name)581 mdb_rename(krb5_context context, HDB *db, const char *new_name)
582 {
583 int ret;
584 char *old, *new;
585
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;
593
594 free(db->hdb_name);
595 db->hdb_name = strdup(new_name);
596 return 0;
597 }
598
599 static krb5_error_code
mdb__get(krb5_context context,HDB * db,krb5_data key,krb5_data * reply)600 mdb__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply)
601 {
602 DB *d = (DB*)db->hdb_db;
603 DBT k, v;
604 int code;
605
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;
618 }
619 if(code == 1) {
620 krb5_clear_error_message(context);
621 return HDB_ERR_NOENTRY;
622 }
623
624 krb5_data_copy(reply, v.data, v.size);
625 return 0;
626 }
627
628 static krb5_error_code
mdb__put(krb5_context context,HDB * db,int replace,krb5_data key,krb5_data value)629 mdb__put(krb5_context context, HDB *db, int replace,
630 krb5_data key, krb5_data value)
631 {
632 DB *d = (DB*)db->hdb_db;
633 DBT k, v;
634 int code;
635
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;
650 }
651 if(code == 1) {
652 krb5_clear_error_message(context);
653 return HDB_ERR_EXISTS;
654 }
655 return 0;
656 }
657
658 static krb5_error_code
mdb__del(krb5_context context,HDB * db,krb5_data key)659 mdb__del(krb5_context context, HDB *db, krb5_data key)
660 {
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;
676 }
677 if(code < 0)
678 return errno;
679 return 0;
680 }
681
682 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)683 mdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal,
684 unsigned flags, krb5_kvno kvno, hdb_entry_ex *entry)
685 {
686 krb5_data key, value;
687 krb5_error_code code;
688
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;
700
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);
705 }
706
707 return 0;
708 }
709
710 static krb5_error_code
mdb_store(krb5_context context,HDB * db,unsigned flags,hdb_entry_ex * entry)711 mdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
712 {
713 krb5_set_error_message(context, EINVAL, "can't set principal in mdb");
714 return EINVAL;
715 }
716
717 static krb5_error_code
mdb_remove(krb5_context context,HDB * db,krb5_const_principal principal)718 mdb_remove(krb5_context context, HDB *db, krb5_const_principal principal)
719 {
720 krb5_error_code code;
721 krb5_data key;
722
723 code = db->hdb__del(context, db, key);
724 krb5_data_free(&key);
725 return code;
726 }
727
728 static krb5_error_code
mdb_open(krb5_context context,HDB * db,int flags,mode_t mode)729 mdb_open(krb5_context context, HDB *db, int flags, mode_t mode)
730 {
731 char *fn;
732 krb5_error_code ret;
733
734 asprintf(&fn, "%s.db", db->hdb_name);
735 if (fn == NULL) {
736 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
737 return ENOMEM;
738 }
739 db->hdb_db = dbopen(fn, flags, mode, DB_BTREE, NULL);
740 free(fn);
741
742 if (db->hdb_db == NULL) {
743 switch (errno) {
744 #ifdef EFTYPE
745 case EFTYPE:
746 #endif
747 case EINVAL:
748 db->hdb_db = dbopen(fn, flags, mode, DB_BTREE, NULL);
749 }
750 }
751
752 /* try to open without .db extension */
753 if(db->hdb_db == NULL && errno == ENOENT)
754 db->hdb_db = dbopen(db->hdb_name, flags, mode, DB_BTREE, NULL);
755 if(db->hdb_db == NULL) {
756 ret = errno;
757 krb5_set_error_message(context, ret, "dbopen (%s): %s",
758 db->hdb_name, strerror(ret));
759 return ret;
760 }
761 if((flags & O_ACCMODE) == O_RDONLY)
762 ret = hdb_check_db_format(context, db);
763 else
764 ret = hdb_init_db(context, db);
765 if(ret == HDB_ERR_NOENTRY) {
766 krb5_clear_error_message(context);
767 return 0;
768 }
769 if (ret) {
770 mdb_close(context, db);
771 krb5_set_error_message(context, ret, "hdb_open: failed %s database %s",
772 (flags & O_ACCMODE) == O_RDONLY ?
773 "checking format of" : "initialize",
774 db->hdb_name);
775 }
776 return ret;
777 }
778
779 krb5_error_code
hdb_mdb_create(krb5_context context,HDB ** db,const char * filename)780 hdb_mdb_create(krb5_context context, HDB **db,
781 const char *filename)
782 {
783 *db = calloc(1, sizeof(**db));
784 if (*db == NULL) {
785 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
786 return ENOMEM;
787 }
788
789 (*db)->hdb_db = NULL;
790 (*db)->hdb_name = strdup(filename);
791 if ((*db)->hdb_name == NULL) {
792 free(*db);
793 *db = NULL;
794 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
795 return ENOMEM;
796 }
797 (*db)->hdb_master_key_set = 0;
798 (*db)->hdb_openp = 0;
799 (*db)->hdb_capability_flags = 0;
800 (*db)->hdb_open = mdb_open;
801 (*db)->hdb_close = mdb_close;
802 (*db)->hdb_fetch_kvno = mdb_fetch_kvno;
803 (*db)->hdb_store = mdb_store;
804 (*db)->hdb_remove = mdb_remove;
805 (*db)->hdb_firstkey = mdb_firstkey;
806 (*db)->hdb_nextkey= mdb_nextkey;
807 (*db)->hdb_lock = mdb_lock;
808 (*db)->hdb_unlock = mdb_unlock;
809 (*db)->hdb_rename = mdb_rename;
810 (*db)->hdb__get = mdb__get;
811 (*db)->hdb__put = mdb__put;
812 (*db)->hdb__del = mdb__del;
813 (*db)->hdb_destroy = mdb_destroy;
814 return 0;
815 }
816
817 #endif /* HAVE_DB1 */
818