1/* $NetBSD$ */ 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 55key: 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 83key_data_contents[0] 84 85 int16: length 86 read-of-data: key-encrypted, key-usage 0, master-key 87 88salt: 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 108static krb5_error_code 109mdb_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 132static krb5_error_code 133fix_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 int 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 202static krb5_error_code 203mdb_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 469static krb5_error_code 470mdb_entry2value(krb5_context context, hdb_entry *entry, krb5_data *data) 471{ 472 return EINVAL; 473} 474#endif 475 476 477static krb5_error_code 478mdb_close(krb5_context context, HDB *db) 479{ 480 DB *d = (DB*)db->hdb_db; 481 (*d->close)(d); 482 return 0; 483} 484 485static krb5_error_code 486mdb_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 496static krb5_error_code 497mdb_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 509static krb5_error_code 510mdb_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 523static krb5_error_code 524mdb_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 569static krb5_error_code 570mdb_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 576static krb5_error_code 577mdb_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 582static krb5_error_code 583mdb_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 601static krb5_error_code 602mdb__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 630static krb5_error_code 631mdb__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 660static krb5_error_code 661mdb__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 684static krb5_error_code 685mdb_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 712static krb5_error_code 713mdb_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 719static krb5_error_code 720mdb_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 731static krb5_error_code 732mdb_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 782krb5_error_code 783hdb_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