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