Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/heimdal/lib/hdb/hdb-mitdb.c
34907 views
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
819