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/* 37 38key: krb5_unparse_name + NUL 39 40 16: baselength 41 32: attributes 42 32: max time 43 32: max renewable time 44 32: client expire 45 32: passwd expire 46 32: last successful passwd 47 32: last failed attempt 48 32: num of failed attempts 49 16: num tl data 50 16: num data data 51 16: principal length 52 length: principal 53 for num tl data times 54 16: tl data type 55 16: tl data length 56 length: length 57 for num key data times 58 16: version (num keyblocks) 59 16: kvno 60 for version times: 61 16: type 62 16: length 63 length: keydata 64 65 66key_data_contents[0] 67 68 int16: length 69 read-of-data: key-encrypted, key-usage 0, master-key 70 71salt: 72 version2 = salt in key_data->key_data_contents[1] 73 else default salt. 74 75*/ 76 77#include "hdb_locl.h" 78 79#define KDB_V1_BASE_LENGTH 38 80 81#if HAVE_DB1 82 83#if defined(HAVE_DB_185_H) 84#include <db_185.h> 85#elif defined(HAVE_DB_H) 86#include <db.h> 87#endif 88 89#define CHECK(x) do { if ((x)) goto out; } while(0) 90 91static krb5_error_code 92mdb_principal2key(krb5_context context, 93 krb5_const_principal principal, 94 krb5_data *key) 95{ 96 krb5_error_code ret; 97 char *str; 98 99 ret = krb5_unparse_name(context, principal, &str); 100 if (ret) 101 return ret; 102 key->data = str; 103 key->length = strlen(str) + 1; 104 return 0; 105} 106 107#define KRB5_KDB_SALTTYPE_NORMAL 0 108#define KRB5_KDB_SALTTYPE_V4 1 109#define KRB5_KDB_SALTTYPE_NOREALM 2 110#define KRB5_KDB_SALTTYPE_ONLYREALM 3 111#define KRB5_KDB_SALTTYPE_SPECIAL 4 112#define KRB5_KDB_SALTTYPE_AFS3 5 113#define KRB5_KDB_SALTTYPE_CERTHASH 6 114 115static krb5_error_code 116fix_salt(krb5_context context, hdb_entry *ent, Key *k) 117{ 118 krb5_error_code ret; 119 Salt *salt = k->salt; 120 /* fix salt type */ 121 switch((int)salt->type) { 122 case KRB5_KDB_SALTTYPE_NORMAL: 123 salt->type = KRB5_PADATA_PW_SALT; 124 break; 125 case KRB5_KDB_SALTTYPE_V4: 126 krb5_data_free(&salt->salt); 127 salt->type = KRB5_PADATA_PW_SALT; 128 break; 129 case KRB5_KDB_SALTTYPE_NOREALM: 130 { 131 size_t len; 132 size_t i; 133 char *p; 134 135 len = 0; 136 for (i = 0; i < ent->principal->name.name_string.len; ++i) 137 len += strlen(ent->principal->name.name_string.val[i]); 138 ret = krb5_data_alloc (&salt->salt, len); 139 if (ret) 140 return ret; 141 p = salt->salt.data; 142 for (i = 0; i < ent->principal->name.name_string.len; ++i) { 143 memcpy (p, 144 ent->principal->name.name_string.val[i], 145 strlen(ent->principal->name.name_string.val[i])); 146 p += strlen(ent->principal->name.name_string.val[i]); 147 } 148 149 salt->type = KRB5_PADATA_PW_SALT; 150 break; 151 } 152 case KRB5_KDB_SALTTYPE_ONLYREALM: 153 krb5_data_free(&salt->salt); 154 ret = krb5_data_copy(&salt->salt, 155 ent->principal->realm, 156 strlen(ent->principal->realm)); 157 if(ret) 158 return ret; 159 salt->type = KRB5_PADATA_PW_SALT; 160 break; 161 case KRB5_KDB_SALTTYPE_SPECIAL: 162 salt->type = KRB5_PADATA_PW_SALT; 163 break; 164 case KRB5_KDB_SALTTYPE_AFS3: 165 krb5_data_free(&salt->salt); 166 ret = krb5_data_copy(&salt->salt, 167 ent->principal->realm, 168 strlen(ent->principal->realm)); 169 if(ret) 170 return ret; 171 salt->type = KRB5_PADATA_AFS3_SALT; 172 break; 173 case KRB5_KDB_SALTTYPE_CERTHASH: 174 krb5_data_free(&salt->salt); 175 free(k->salt); 176 k->salt = NULL; 177 break; 178 default: 179 abort(); 180 } 181 return 0; 182} 183 184 185/** 186 * This function takes a key from a krb5_storage from an MIT KDB encoded 187 * entry and places it in the given Key object. 188 * 189 * @param context Context 190 * @param entry HDB entry 191 * @param sp krb5_storage with current offset set to the beginning of a 192 * key 193 * @param version See comments in caller body for the backstory on this 194 * @param k Key * to load the key into 195 */ 196static krb5_error_code 197mdb_keyvalue2key(krb5_context context, hdb_entry *entry, krb5_storage *sp, uint16_t version, Key *k) 198{ 199 size_t i; 200 uint16_t u16, type; 201 krb5_error_code ret; 202 203 k->mkvno = malloc(sizeof(*k->mkvno)); 204 if (k->mkvno == NULL) { 205 ret = ENOMEM; 206 goto out; 207 } 208 *k->mkvno = 1; 209 210 for (i = 0; i < version; i++) { 211 CHECK(ret = krb5_ret_uint16(sp, &type)); 212 CHECK(ret = krb5_ret_uint16(sp, &u16)); 213 if (i == 0) { 214 /* This "version" means we have a key */ 215 k->key.keytype = type; 216 if (u16 < 2) { 217 ret = EINVAL; 218 goto out; 219 } 220 /* 221 * MIT stores keys encrypted keys as {16-bit length 222 * of plaintext key, {encrypted key}}. The reason 223 * for this is that the Kerberos cryptosystem is not 224 * length-preserving. Heimdal's approach is to 225 * truncate the plaintext to the expected length of 226 * the key given its enctype, so we ignore this 227 * 16-bit length-of-plaintext-key field. 228 */ 229 krb5_storage_seek(sp, 2, SEEK_CUR); /* skip real length */ 230 k->key.keyvalue.length = u16 - 2; /* adjust cipher len */ 231 k->key.keyvalue.data = malloc(k->key.keyvalue.length); 232 krb5_storage_read(sp, k->key.keyvalue.data, 233 k->key.keyvalue.length); 234 } else if (i == 1) { 235 /* This "version" means we have a salt */ 236 k->salt = calloc(1, sizeof(*k->salt)); 237 if (k->salt == NULL) { 238 ret = ENOMEM; 239 goto out; 240 } 241 k->salt->type = type; 242 if (u16 != 0) { 243 k->salt->salt.data = malloc(u16); 244 if (k->salt->salt.data == NULL) { 245 ret = ENOMEM; 246 goto out; 247 } 248 k->salt->salt.length = u16; 249 krb5_storage_read(sp, k->salt->salt.data, k->salt->salt.length); 250 } 251 fix_salt(context, entry, k); 252 } else { 253 /* 254 * Whatever this "version" might be, we skip it 255 * 256 * XXX A krb5.conf parameter requesting that we log 257 * about strangeness like this, or return an error 258 * from here, might be nice. 259 */ 260 krb5_storage_seek(sp, u16, SEEK_CUR); 261 } 262 } 263 264 return 0; 265 266out: 267 free_Key(k); 268 return ret; 269} 270 271 272/** 273 * This function parses an MIT krb5 encoded KDB entry and fills in the 274 * given HDB entry with it. 275 * 276 * @param context krb5_context 277 * @param data Encoded MIT KDB entry 278 * @param target_kvno Desired kvno, or 0 for the entry's current kvno 279 * @param entry Desired kvno, or 0 for the entry's current kvno 280 */ 281static krb5_error_code 282mdb_value2entry(krb5_context context, krb5_data *data, krb5_kvno target_kvno, 283 hdb_entry *entry) 284{ 285 krb5_error_code ret; 286 krb5_storage *sp; 287 Key k; 288 krb5_kvno key_kvno; 289 uint32_t u32; 290 uint16_t u16, num_keys, num_tl; 291 size_t i; 292 char *p = NULL; 293 off_t e_length; 294 295 memset(entry, 0, sizeof(*entry)); 296 297 memset(&k, 0, sizeof (k)); 298 memset(entry, 0, sizeof(*entry)); 299 300 sp = krb5_storage_from_data(data); 301 if (sp == NULL) { 302 krb5_set_error_message(context, ENOMEM, "out of memory"); 303 return ENOMEM; 304 } 305 306 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE); 307 308 /* 309 * 16: baselength 310 * 311 * The story here is that these 16 bits have to be a constant: 312 * KDB_V1_BASE_LENGTH. Once upon a time a different value here 313 * would have been used to indicate the presence of "extra data" 314 * between the "base" contents and the {principal name, TL data, 315 * keys} that follow it. Nothing supports such "extra data" 316 * nowadays, so neither do we here. 317 * 318 * XXX But... surely we ought to log about this extra data, or skip 319 * it, or something, in case anyone has MIT KDBs with ancient 320 * entries in them... Logging would allow the admin to know which 321 * entries to dump with MIT krb5's kdb5_util. But logging would be 322 * noisy. For now we do nothing. 323 */ 324 CHECK(ret = krb5_ret_uint16(sp, &u16)); 325 if (u16 < KDB_V1_BASE_LENGTH) { 326 krb5_set_error_message(context, EINVAL, 327 "length too short %d", (int)u16); 328 ret = EINVAL; 329 goto out; 330 } 331 e_length = u16 - KDB_V1_BASE_LENGTH; 332 333 /* 32: attributes */ 334 CHECK(ret = krb5_ret_uint32(sp, &u32)); 335 entry->flags.postdate = !(u32 & KRB5_KDB_DISALLOW_POSTDATED); 336 entry->flags.forwardable = !(u32 & KRB5_KDB_DISALLOW_FORWARDABLE); 337 entry->flags.initial = !!(u32 & KRB5_KDB_DISALLOW_TGT_BASED); 338 entry->flags.renewable = !(u32 & KRB5_KDB_DISALLOW_RENEWABLE); 339 entry->flags.proxiable = !(u32 & KRB5_KDB_DISALLOW_PROXIABLE); 340 /* DUP_SKEY */ 341 entry->flags.invalid = !!(u32 & KRB5_KDB_DISALLOW_ALL_TIX); 342 entry->flags.require_preauth =!!(u32 & KRB5_KDB_REQUIRES_PRE_AUTH); 343 entry->flags.require_hwauth =!!(u32 & KRB5_KDB_REQUIRES_HW_AUTH); 344 entry->flags.server = !(u32 & KRB5_KDB_DISALLOW_SVR); 345 entry->flags.change_pw = !!(u32 & KRB5_KDB_PWCHANGE_SERVICE); 346 entry->flags.client = 1; /* XXX */ 347 348 /* 32: max time */ 349 CHECK(ret = krb5_ret_uint32(sp, &u32)); 350 if (u32) { 351 entry->max_life = malloc(sizeof(*entry->max_life)); 352 *entry->max_life = u32; 353 } 354 /* 32: max renewable time */ 355 CHECK(ret = krb5_ret_uint32(sp, &u32)); 356 if (u32) { 357 entry->max_renew = malloc(sizeof(*entry->max_renew)); 358 *entry->max_renew = u32; 359 } 360 /* 32: client expire */ 361 CHECK(ret = krb5_ret_uint32(sp, &u32)); 362 if (u32) { 363 entry->valid_end = malloc(sizeof(*entry->valid_end)); 364 *entry->valid_end = u32; 365 } 366 /* 32: passwd expire */ 367 CHECK(ret = krb5_ret_uint32(sp, &u32)); 368 if (u32) { 369 entry->pw_end = malloc(sizeof(*entry->pw_end)); 370 *entry->pw_end = u32; 371 } 372 /* 32: last successful passwd */ 373 CHECK(ret = krb5_ret_uint32(sp, &u32)); 374 /* 32: last failed attempt */ 375 CHECK(ret = krb5_ret_uint32(sp, &u32)); 376 /* 32: num of failed attempts */ 377 CHECK(ret = krb5_ret_uint32(sp, &u32)); 378 /* 16: num tl data */ 379 CHECK(ret = krb5_ret_uint16(sp, &u16)); 380 num_tl = u16; 381 /* 16: num key data */ 382 CHECK(ret = krb5_ret_uint16(sp, &u16)); 383 num_keys = u16; 384 385 /* e_data */ 386 if (e_length) { 387 /* ignore extra e_data that we don't know how to parse */ 388 krb5_storage_seek(sp, e_length, SEEK_CUR); 389 } 390 391 /* 16: principal length */ 392 CHECK(ret = krb5_ret_uint16(sp, &u16)); 393 /* length: principal */ 394 { 395 /* 396 * Note that the principal name includes the NUL in the entry, 397 * but we don't want to take chances, so we add an extra NUL. 398 */ 399 p = malloc(u16 + 1); 400 if (p == NULL) { 401 ret = ENOMEM; 402 goto out; 403 } 404 krb5_storage_read(sp, p, u16); 405 p[u16] = '\0'; 406 CHECK(ret = krb5_parse_name(context, p, &entry->principal)); 407 free(p); 408 } 409 /* for num tl data times 410 16: tl data type 411 16: tl data length 412 length: length */ 413 for (i = 0; i < num_tl; i++) { 414 /* 16: TL data type */ 415 CHECK(ret = krb5_ret_uint16(sp, &u16)); 416 /* 16: TL data length */ 417 CHECK(ret = krb5_ret_uint16(sp, &u16)); 418 krb5_storage_seek(sp, u16, SEEK_CUR); 419 } 420 /* 421 * for num key data times 422 * 16: "version" 423 * 16: kvno 424 * for version times: 425 * 16: type 426 * 16: length 427 * length: keydata 428 * 429 * "version" here is really 1 or 2, the first meaning there's only 430 * keys for this kvno, the second meaning there's keys and salt[s?]. 431 * That's right... hold that gag reflex, you can do it. 432 */ 433 for (i = 0; i < num_keys; i++) { 434 uint16_t version; 435 436 CHECK(ret = krb5_ret_uint16(sp, &u16)); 437 version = u16; 438 CHECK(ret = krb5_ret_uint16(sp, &u16)); 439 key_kvno = u16; 440 441 ret = mdb_keyvalue2key(context, entry, sp, version, &k); 442 if (ret) 443 goto out; 444 if (k.key.keytype == 0 || k.key.keyvalue.length == 0) { 445 /* 446 * Older MIT KDBs may have enctype 0 / length 0 keys. We 447 * ignore these. 448 */ 449 free_Key(&k); 450 continue; 451 } 452 453 if ((target_kvno == 0 && entry->kvno < key_kvno) || 454 (target_kvno == key_kvno && entry->kvno != target_kvno)) { 455 /* 456 * MIT's KDB doesn't keep track of kvno. The highest kvno 457 * is the current kvno, and we just found a new highest 458 * kvno or the desired kvno. 459 * 460 * Note that there's no guarantee of any key ordering, but 461 * generally MIT KDB entries have keys in strictly 462 * descending kvno order. 463 * 464 * XXX We do assume that keys are clustered by kvno. If 465 * not, then bad. It might be possible to construct 466 * non-clustered keys via the kadm5 API. It wouldn't be 467 * hard to cope with this, since if it happens the worst 468 * that will happen is that some of the current keys can be 469 * found in the history extension, and we could just pull 470 * them back out in that case. 471 */ 472 ret = hdb_add_current_keys_to_history(context, entry); 473 if (ret) 474 goto out; 475 free_Keys(&entry->keys); 476 ret = add_Keys(&entry->keys, &k); 477 free_Key(&k); 478 if (ret) 479 goto out; 480 entry->kvno = key_kvno; 481 continue; 482 } 483 484 if (entry->kvno == key_kvno) { 485 /* 486 * Note that if key_kvno == 0 and target_kvno == 0 then we 487 * end up adding those keys here. Yeah, kvno 0 is very 488 * special for us, but just in case, we keep such keys. 489 */ 490 ret = add_Keys(&entry->keys, &k); 491 free_Key(&k); 492 if (ret) 493 goto out; 494 entry->kvno = key_kvno; 495 } else { 496 ret = hdb_add_history_key(context, entry, key_kvno, &k); 497 if (ret) 498 goto out; 499 free_Key(&k); 500 } 501 } 502 503 if (target_kvno != 0 && entry->kvno != target_kvno) { 504 ret = HDB_ERR_KVNO_NOT_FOUND; 505 goto out; 506 } 507 508 krb5_storage_free(sp); 509 510 return 0; 511 512out: 513 krb5_storage_free(sp); 514 515 if (ret == HEIM_ERR_EOF) 516 /* Better error code than "end of file" */ 517 ret = HEIM_ERR_BAD_HDBENT_ENCODING; 518 free_hdb_entry(entry); 519 free_Key(&k); 520 return ret; 521} 522 523#if 0 524static krb5_error_code 525mdb_entry2value(krb5_context context, hdb_entry *entry, krb5_data *data) 526{ 527 return EINVAL; 528} 529#endif 530 531 532static krb5_error_code 533mdb_close(krb5_context context, HDB *db) 534{ 535 DB *d = (DB*)db->hdb_db; 536 (*d->close)(d); 537 return 0; 538} 539 540static krb5_error_code 541mdb_destroy(krb5_context context, HDB *db) 542{ 543 krb5_error_code ret; 544 545 ret = hdb_clear_master_key (context, db); 546 free(db->hdb_name); 547 free(db); 548 return ret; 549} 550 551static krb5_error_code 552mdb_lock(krb5_context context, HDB *db, int operation) 553{ 554 DB *d = (DB*)db->hdb_db; 555 int fd = (*d->fd)(d); 556 krb5_error_code ret; 557 558 if (db->lock_count > 1) { 559 db->lock_count++; 560 if (db->lock_type == HDB_WLOCK || db->lock_count == operation) 561 return 0; 562 } 563 564 if(fd < 0) { 565 krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB, 566 "Can't lock database: %s", db->hdb_name); 567 return HDB_ERR_CANT_LOCK_DB; 568 } 569 ret = hdb_lock(fd, operation); 570 if (ret) 571 return ret; 572 db->lock_count++; 573 return 0; 574} 575 576static krb5_error_code 577mdb_unlock(krb5_context context, HDB *db) 578{ 579 DB *d = (DB*)db->hdb_db; 580 int fd = (*d->fd)(d); 581 582 if (db->lock_count > 1) { 583 db->lock_count--; 584 return 0; 585 } 586 heim_assert(db->lock_count == 1, "HDB lock/unlock sequence does not match"); 587 db->lock_count--; 588 589 if(fd < 0) { 590 krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB, 591 "Can't unlock database: %s", db->hdb_name); 592 return HDB_ERR_CANT_LOCK_DB; 593 } 594 return hdb_unlock(fd); 595} 596 597 598static krb5_error_code 599mdb_seq(krb5_context context, HDB *db, 600 unsigned flags, hdb_entry_ex *entry, int flag) 601{ 602 DB *d = (DB*)db->hdb_db; 603 DBT key, value; 604 krb5_data key_data, data; 605 int code; 606 607 code = db->hdb_lock(context, db, HDB_RLOCK); 608 if(code == -1) { 609 krb5_set_error_message(context, HDB_ERR_DB_INUSE, "Database %s in use", db->hdb_name); 610 return HDB_ERR_DB_INUSE; 611 } 612 code = (*d->seq)(d, &key, &value, flag); 613 db->hdb_unlock(context, db); /* XXX check value */ 614 if(code == -1) { 615 code = errno; 616 krb5_set_error_message(context, code, "Database %s seq error: %s", 617 db->hdb_name, strerror(code)); 618 return code; 619 } 620 if(code == 1) { 621 krb5_clear_error_message(context); 622 return HDB_ERR_NOENTRY; 623 } 624 625 key_data.data = key.data; 626 key_data.length = key.size; 627 data.data = value.data; 628 data.length = value.size; 629 memset(entry, 0, sizeof(*entry)); 630 631 if (mdb_value2entry(context, &data, 0, &entry->entry)) 632 return mdb_seq(context, db, flags, entry, R_NEXT); 633 634 if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { 635 code = hdb_unseal_keys (context, db, &entry->entry); 636 if (code) 637 hdb_free_entry (context, entry); 638 } 639 640 return code; 641} 642 643 644static krb5_error_code 645mdb_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) 646{ 647 return mdb_seq(context, db, flags, entry, R_FIRST); 648} 649 650 651static krb5_error_code 652mdb_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) 653{ 654 return mdb_seq(context, db, flags, entry, R_NEXT); 655} 656 657static krb5_error_code 658mdb_rename(krb5_context context, HDB *db, const char *new_name) 659{ 660 int ret; 661 char *old = NULL; 662 char *new = NULL; 663 664 if (asprintf(&old, "%s.db", db->hdb_name) < 0) 665 goto out; 666 if (asprintf(&new, "%s.db", new_name) < 0) 667 goto out; 668 ret = rename(old, new); 669 if(ret) 670 goto out; 671 672 free(db->hdb_name); 673 db->hdb_name = strdup(new_name); 674 errno = 0; 675 676out: 677 free(old); 678 free(new); 679 return errno; 680} 681 682static krb5_error_code 683mdb__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply) 684{ 685 DB *d = (DB*)db->hdb_db; 686 DBT k, v; 687 int code; 688 689 k.data = key.data; 690 k.size = key.length; 691 code = db->hdb_lock(context, db, HDB_RLOCK); 692 if(code) 693 return code; 694 code = (*d->get)(d, &k, &v, 0); 695 db->hdb_unlock(context, db); 696 if(code < 0) { 697 code = errno; 698 krb5_set_error_message(context, code, "Database %s get error: %s", 699 db->hdb_name, strerror(code)); 700 return code; 701 } 702 if(code == 1) { 703 krb5_clear_error_message(context); 704 return HDB_ERR_NOENTRY; 705 } 706 707 krb5_data_copy(reply, v.data, v.size); 708 return 0; 709} 710 711static krb5_error_code 712mdb__put(krb5_context context, HDB *db, int replace, 713 krb5_data key, krb5_data value) 714{ 715 DB *d = (DB*)db->hdb_db; 716 DBT k, v; 717 int code; 718 719 k.data = key.data; 720 k.size = key.length; 721 v.data = value.data; 722 v.size = value.length; 723 code = db->hdb_lock(context, db, HDB_WLOCK); 724 if(code) 725 return code; 726 code = (*d->put)(d, &k, &v, replace ? 0 : R_NOOVERWRITE); 727 db->hdb_unlock(context, db); 728 if(code < 0) { 729 code = errno; 730 krb5_set_error_message(context, code, "Database %s put error: %s", 731 db->hdb_name, strerror(code)); 732 return code; 733 } 734 if(code == 1) { 735 krb5_clear_error_message(context); 736 return HDB_ERR_EXISTS; 737 } 738 return 0; 739} 740 741static krb5_error_code 742mdb__del(krb5_context context, HDB *db, krb5_data key) 743{ 744 DB *d = (DB*)db->hdb_db; 745 DBT k; 746 krb5_error_code code; 747 k.data = key.data; 748 k.size = key.length; 749 code = db->hdb_lock(context, db, HDB_WLOCK); 750 if(code) 751 return code; 752 code = (*d->del)(d, &k, 0); 753 db->hdb_unlock(context, db); 754 if(code == 1) { 755 code = errno; 756 krb5_set_error_message(context, code, "Database %s put error: %s", 757 db->hdb_name, strerror(code)); 758 return code; 759 } 760 if(code < 0) 761 return errno; 762 return 0; 763} 764 765static krb5_error_code 766mdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal, 767 unsigned flags, krb5_kvno kvno, hdb_entry_ex *entry) 768{ 769 krb5_data key, value; 770 krb5_error_code code; 771 772 code = mdb_principal2key(context, principal, &key); 773 if (code) 774 return code; 775 code = db->hdb__get(context, db, key, &value); 776 krb5_data_free(&key); 777 if(code) 778 return code; 779 code = mdb_value2entry(context, &value, kvno, &entry->entry); 780 krb5_data_free(&value); 781 if (code) 782 return code; 783 784 if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { 785 code = hdb_unseal_keys (context, db, &entry->entry); 786 if (code) 787 hdb_free_entry(context, entry); 788 } 789 790 return 0; 791} 792 793static krb5_error_code 794mdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) 795{ 796 krb5_set_error_message(context, EINVAL, "can't set principal in mdb"); 797 return EINVAL; 798} 799 800static krb5_error_code 801mdb_remove(krb5_context context, HDB *db, krb5_const_principal principal) 802{ 803 krb5_error_code code; 804 krb5_data key; 805 806 mdb_principal2key(context, principal, &key); 807 code = db->hdb__del(context, db, key); 808 krb5_data_free(&key); 809 return code; 810} 811 812static krb5_error_code 813mdb_open(krb5_context context, HDB *db, int flags, mode_t mode) 814{ 815 char *fn; 816 krb5_error_code ret; 817 818 if (asprintf(&fn, "%s.db", db->hdb_name) < 0) { 819 krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 820 return ENOMEM; 821 } 822 db->hdb_db = dbopen(fn, flags, mode, DB_BTREE, NULL); 823 free(fn); 824 825 if (db->hdb_db == NULL) { 826 switch (errno) { 827#ifdef EFTYPE 828 case EFTYPE: 829#endif 830 case EINVAL: 831 db->hdb_db = dbopen(fn, flags, mode, DB_BTREE, NULL); 832 } 833 } 834 835 /* try to open without .db extension */ 836 if(db->hdb_db == NULL && errno == ENOENT) 837 db->hdb_db = dbopen(db->hdb_name, flags, mode, DB_BTREE, NULL); 838 if(db->hdb_db == NULL) { 839 ret = errno; 840 krb5_set_error_message(context, ret, "dbopen (%s): %s", 841 db->hdb_name, strerror(ret)); 842 return ret; 843 } 844 if((flags & O_ACCMODE) == O_RDONLY) 845 ret = hdb_check_db_format(context, db); 846 else 847 ret = hdb_init_db(context, db); 848 if(ret == HDB_ERR_NOENTRY) { 849 krb5_clear_error_message(context); 850 return 0; 851 } 852 if (ret) { 853 mdb_close(context, db); 854 krb5_set_error_message(context, ret, "hdb_open: failed %s database %s", 855 (flags & O_ACCMODE) == O_RDONLY ? 856 "checking format of" : "initialize", 857 db->hdb_name); 858 } 859 return ret; 860} 861 862krb5_error_code 863hdb_mdb_create(krb5_context context, HDB **db, 864 const char *filename) 865{ 866 *db = calloc(1, sizeof(**db)); 867 if (*db == NULL) { 868 krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 869 return ENOMEM; 870 } 871 872 (*db)->hdb_db = NULL; 873 (*db)->hdb_name = strdup(filename); 874 if ((*db)->hdb_name == NULL) { 875 free(*db); 876 *db = NULL; 877 krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 878 return ENOMEM; 879 } 880 (*db)->hdb_master_key_set = 0; 881 (*db)->hdb_openp = 0; 882 (*db)->hdb_capability_flags = 0; 883 (*db)->hdb_open = mdb_open; 884 (*db)->hdb_close = mdb_close; 885 (*db)->hdb_fetch_kvno = mdb_fetch_kvno; 886 (*db)->hdb_store = mdb_store; 887 (*db)->hdb_remove = mdb_remove; 888 (*db)->hdb_firstkey = mdb_firstkey; 889 (*db)->hdb_nextkey= mdb_nextkey; 890 (*db)->hdb_lock = mdb_lock; 891 (*db)->hdb_unlock = mdb_unlock; 892 (*db)->hdb_rename = mdb_rename; 893 (*db)->hdb__get = mdb__get; 894 (*db)->hdb__put = mdb__put; 895 (*db)->hdb__del = mdb__del; 896 (*db)->hdb_destroy = mdb_destroy; 897 return 0; 898} 899 900#endif /* HAVE_DB1 */ 901