1/* 2 * Copyright (c) 2000 - 2004 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#include "hdb_locl.h" 35#ifndef O_BINARY 36#define O_BINARY 0 37#endif 38 39struct hdb_master_key_data { 40 krb5_keytab_entry keytab; 41 krb5_crypto crypto; 42 struct hdb_master_key_data *next; 43}; 44 45void 46hdb_free_master_key(krb5_context context, hdb_master_key mkey) 47{ 48 struct hdb_master_key_data *ptr; 49 while(mkey) { 50 krb5_kt_free_entry(context, &mkey->keytab); 51 if (mkey->crypto) 52 krb5_crypto_destroy(context, mkey->crypto); 53 ptr = mkey; 54 mkey = mkey->next; 55 free(ptr); 56 } 57} 58 59krb5_error_code 60hdb_process_master_key(krb5_context context, 61 int kvno, krb5_keyblock *key, krb5_enctype etype, 62 hdb_master_key *mkey) 63{ 64 krb5_error_code ret; 65 66 *mkey = calloc(1, sizeof(**mkey)); 67 if(*mkey == NULL) { 68 krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 69 return ENOMEM; 70 } 71 (*mkey)->keytab.vno = kvno; 72 ret = krb5_parse_name(context, "K/M", &(*mkey)->keytab.principal); 73 if(ret) 74 goto fail; 75 ret = krb5_copy_keyblock_contents(context, key, &(*mkey)->keytab.keyblock); 76 if(ret) 77 goto fail; 78 if(etype != 0) 79 (*mkey)->keytab.keyblock.keytype = etype; 80 (*mkey)->keytab.timestamp = (uint32_t)time(NULL); 81 ret = krb5_crypto_init(context, key, etype, &(*mkey)->crypto); 82 if(ret) 83 goto fail; 84 return 0; 85 fail: 86 hdb_free_master_key(context, *mkey); 87 *mkey = NULL; 88 return ret; 89} 90 91krb5_error_code 92hdb_add_master_key(krb5_context context, krb5_keyblock *key, 93 hdb_master_key *inout) 94{ 95 int vno = 0; 96 hdb_master_key p; 97 krb5_error_code ret; 98 99 for(p = *inout; p; p = p->next) 100 vno = max(vno, p->keytab.vno); 101 vno++; 102 ret = hdb_process_master_key(context, vno, key, 0, &p); 103 if(ret) 104 return ret; 105 p->next = *inout; 106 *inout = p; 107 return 0; 108} 109 110static krb5_error_code 111read_master_keytab(krb5_context context, const char *filename, 112 hdb_master_key *mkey) 113{ 114 krb5_error_code ret; 115 krb5_keytab id; 116 krb5_kt_cursor cursor; 117 krb5_keytab_entry entry; 118 hdb_master_key p; 119 120 ret = krb5_kt_resolve(context, filename, &id); 121 if(ret) 122 return ret; 123 124 ret = krb5_kt_start_seq_get(context, id, &cursor); 125 if(ret) 126 goto out; 127 *mkey = NULL; 128 while(krb5_kt_next_entry(context, id, &entry, &cursor) == 0) { 129 p = calloc(1, sizeof(*p)); 130 if(p == NULL) { 131 krb5_kt_end_seq_get(context, id, &cursor); 132 ret = ENOMEM; 133 goto out; 134 } 135 p->keytab = entry; 136 ret = krb5_crypto_init(context, &p->keytab.keyblock, 0, &p->crypto); 137 p->next = *mkey; 138 *mkey = p; 139 } 140 krb5_kt_end_seq_get(context, id, &cursor); 141 out: 142 krb5_kt_close(context, id); 143 return ret; 144} 145 146/* read a MIT master keyfile */ 147static krb5_error_code 148read_master_mit(krb5_context context, const char *filename, 149 int byteorder, hdb_master_key *mkey) 150{ 151 int fd; 152 krb5_error_code ret; 153 krb5_storage *sp; 154 int16_t enctype; 155 krb5_keyblock key; 156 157 fd = open(filename, O_RDONLY | O_BINARY); 158 if(fd < 0) { 159 int save_errno = errno; 160 krb5_set_error_message(context, save_errno, "failed to open %s: %s", 161 filename, strerror(save_errno)); 162 return save_errno; 163 } 164 sp = krb5_storage_from_fd(fd); 165 if(sp == NULL) { 166 close(fd); 167 return errno; 168 } 169 krb5_storage_set_flags(sp, byteorder); 170 /* could possibly use ret_keyblock here, but do it with more 171 checks for now */ 172 { 173 ret = krb5_ret_int16(sp, &enctype); 174 if (ret) 175 goto out; 176 ret = krb5_enctype_valid(context, enctype); 177 if (ret) 178 goto out; 179 key.keytype = enctype; 180 ret = krb5_ret_data(sp, &key.keyvalue); 181 if(ret) 182 goto out; 183 } 184 ret = hdb_process_master_key(context, 1, &key, 0, mkey); 185 krb5_free_keyblock_contents(context, &key); 186 out: 187 krb5_storage_free(sp); 188 close(fd); 189 return ret; 190} 191 192/* read an old master key file */ 193static krb5_error_code 194read_master_encryptionkey(krb5_context context, const char *filename, 195 hdb_master_key *mkey) 196{ 197 int fd; 198 krb5_keyblock key; 199 krb5_error_code ret; 200 unsigned char buf[256]; 201 ssize_t len; 202 size_t ret_len; 203 204 fd = open(filename, O_RDONLY | O_BINARY); 205 if(fd < 0) { 206 int save_errno = errno; 207 krb5_set_error_message(context, save_errno, "failed to open %s: %s", 208 filename, strerror(save_errno)); 209 return save_errno; 210 } 211 212 len = read(fd, buf, sizeof(buf)); 213 close(fd); 214 if(len < 0) { 215 int save_errno = errno; 216 krb5_set_error_message(context, save_errno, "error reading %s: %s", 217 filename, strerror(save_errno)); 218 return save_errno; 219 } 220 221 ret = decode_EncryptionKey(buf, len, &key, &ret_len); 222 memset(buf, 0, sizeof(buf)); 223 if(ret) 224 return ret; 225 226 /* Originally, the keytype was just that, and later it got changed 227 to des-cbc-md5, but we always used des in cfb64 mode. This 228 should cover all cases, but will break if someone has hacked 229 this code to really use des-cbc-md5 -- but then that's not my 230 problem. */ 231 if(key.keytype == ETYPE_DES_CBC_CRC || key.keytype == ETYPE_DES_CBC_MD5) 232 key.keytype = ETYPE_DES_CFB64_NONE; 233 234 ret = hdb_process_master_key(context, 0, &key, 0, mkey); 235 krb5_free_keyblock_contents(context, &key); 236 return ret; 237} 238 239/* read a krb4 /.k style file */ 240static krb5_error_code 241read_master_krb4(krb5_context context, const char *filename, 242 hdb_master_key *mkey) 243{ 244 int fd; 245 krb5_keyblock key; 246 krb5_error_code ret; 247 unsigned char buf[256]; 248 ssize_t len; 249 250 fd = open(filename, O_RDONLY | O_BINARY); 251 if(fd < 0) { 252 int save_errno = errno; 253 krb5_set_error_message(context, save_errno, "failed to open %s: %s", 254 filename, strerror(save_errno)); 255 return save_errno; 256 } 257 258 len = read(fd, buf, sizeof(buf)); 259 close(fd); 260 if(len < 0) { 261 int save_errno = errno; 262 krb5_set_error_message(context, save_errno, "error reading %s: %s", 263 filename, strerror(save_errno)); 264 return save_errno; 265 } 266 if(len != 8) { 267 krb5_set_error_message(context, HEIM_ERR_EOF, 268 "bad contents of %s", filename); 269 return HEIM_ERR_EOF; /* XXX file might be too large */ 270 } 271 272 memset(&key, 0, sizeof(key)); 273 key.keytype = ETYPE_DES_PCBC_NONE; 274 ret = krb5_data_copy(&key.keyvalue, buf, len); 275 memset(buf, 0, sizeof(buf)); 276 if(ret) 277 return ret; 278 279 ret = hdb_process_master_key(context, 0, &key, 0, mkey); 280 krb5_free_keyblock_contents(context, &key); 281 return ret; 282} 283 284krb5_error_code 285hdb_read_master_key(krb5_context context, const char *filename, 286 hdb_master_key *mkey) 287{ 288 FILE *f; 289 unsigned char buf[16]; 290 krb5_error_code ret; 291 const char *fn; 292 293 off_t len; 294 295 *mkey = NULL; 296 297 if(filename == NULL) 298 filename = HDB_DB_DIR "/m-key"; 299 300 fn = filename; 301 if (strncmp("FILE:", filename, 5) == 0) 302 filename = filename + 5; 303 304 f = fopen(filename, "r"); 305 if(f == NULL) { 306 int save_errno = errno; 307 krb5_set_error_message(context, save_errno, "failed to open %s: %s", 308 filename, strerror(save_errno)); 309 return save_errno; 310 } 311 312 if(fread(buf, 1, 2, f) != 2) { 313 fclose(f); 314 krb5_set_error_message(context, HEIM_ERR_EOF, "end of file reading %s", filename); 315 return HEIM_ERR_EOF; 316 } 317 318 fseek(f, 0, SEEK_END); 319 len = ftell(f); 320 321 if(fclose(f) != 0) 322 return errno; 323 324 if(len < 0) 325 return errno; 326 327 if(len == 8) { 328 ret = read_master_krb4(context, filename, mkey); 329 } else if(buf[0] == 0x30 && len <= 127 && buf[1] == len - 2) { 330 ret = read_master_encryptionkey(context, filename, mkey); 331 } else if(buf[0] == 5 && buf[1] >= 1 && buf[1] <= 2) { 332 ret = read_master_keytab(context, fn, mkey); 333 } else { 334 /* 335 * Check both LittleEndian and BigEndian since they key file 336 * might be moved from a machine with diffrent byte order, or 337 * its running on MacOS X that always uses BE master keys. 338 */ 339 ret = read_master_mit(context, filename, KRB5_STORAGE_BYTEORDER_LE, mkey); 340 if (ret) 341 ret = read_master_mit(context, filename, KRB5_STORAGE_BYTEORDER_BE, mkey); 342 } 343 return ret; 344} 345 346krb5_error_code 347hdb_write_master_key(krb5_context context, const char *filename, 348 hdb_master_key mkey) 349{ 350 krb5_error_code ret; 351 hdb_master_key p; 352 krb5_keytab kt; 353 354 if(filename == NULL) 355 filename = HDB_DB_DIR "/m-key"; 356 357 ret = krb5_kt_resolve(context, filename, &kt); 358 if(ret) 359 return ret; 360 361 for(p = mkey; p; p = p->next) { 362 ret = krb5_kt_add_entry(context, kt, &p->keytab); 363 } 364 365 krb5_kt_close(context, kt); 366 367 return ret; 368} 369 370hdb_master_key 371_hdb_find_master_key(int32_t *mkvno, hdb_master_key mkey) 372{ 373 hdb_master_key ret = NULL; 374 while(mkey) { 375 if(ret == NULL && mkey->keytab.vno == 0) 376 ret = mkey; 377 if(mkvno == NULL) { 378 if(ret == NULL || mkey->keytab.vno > ret->keytab.vno) 379 ret = mkey; 380 } else if(mkey->keytab.vno == *mkvno) 381 return mkey; 382 mkey = mkey->next; 383 } 384 return ret; 385} 386 387int 388_hdb_mkey_version(hdb_master_key mkey) 389{ 390 return mkey->keytab.vno; 391} 392 393int 394_hdb_mkey_decrypt(krb5_context context, hdb_master_key key, 395 krb5_key_usage usage, 396 void *ptr, size_t size, krb5_data *res) 397{ 398 return krb5_decrypt(context, key->crypto, usage, 399 ptr, size, res); 400} 401 402int 403_hdb_mkey_encrypt(krb5_context context, hdb_master_key key, 404 krb5_key_usage usage, 405 const void *ptr, size_t size, krb5_data *res) 406{ 407 return krb5_encrypt(context, key->crypto, usage, 408 ptr, size, res); 409} 410 411krb5_error_code 412hdb_unseal_key_mkey(krb5_context context, Key *k, hdb_master_key mkey) 413{ 414 415 krb5_error_code ret; 416 krb5_data res; 417 size_t keysize; 418 419 hdb_master_key key; 420 421 if(k->mkvno == NULL) 422 return 0; 423 424 key = _hdb_find_master_key(k->mkvno, mkey); 425 426 if (key == NULL) 427 return HDB_ERR_NO_MKEY; 428 429 ret = _hdb_mkey_decrypt(context, key, HDB_KU_MKEY, 430 k->key.keyvalue.data, 431 k->key.keyvalue.length, 432 &res); 433 if(ret == KRB5KRB_AP_ERR_BAD_INTEGRITY) { 434 /* try to decrypt with MIT key usage */ 435 ret = _hdb_mkey_decrypt(context, key, 0, 436 k->key.keyvalue.data, 437 k->key.keyvalue.length, 438 &res); 439 } 440 if (ret) 441 return ret; 442 443 /* fixup keylength if the key got padded when encrypting it */ 444 ret = krb5_enctype_keysize(context, k->key.keytype, &keysize); 445 if (ret) { 446 krb5_data_free(&res); 447 return ret; 448 } 449 if (keysize > res.length) { 450 krb5_data_free(&res); 451 return KRB5_BAD_KEYSIZE; 452 } 453 454 memset(k->key.keyvalue.data, 0, k->key.keyvalue.length); 455 free(k->key.keyvalue.data); 456 k->key.keyvalue = res; 457 k->key.keyvalue.length = keysize; 458 free(k->mkvno); 459 k->mkvno = NULL; 460 461 return 0; 462} 463 464krb5_error_code 465hdb_unseal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey) 466{ 467 size_t i; 468 469 for(i = 0; i < ent->keys.len; i++){ 470 krb5_error_code ret; 471 472 ret = hdb_unseal_key_mkey(context, &ent->keys.val[i], mkey); 473 if (ret) 474 return ret; 475 } 476 return 0; 477} 478 479krb5_error_code 480hdb_unseal_keys(krb5_context context, HDB *db, hdb_entry *ent) 481{ 482 if (db->hdb_master_key_set == 0) 483 return 0; 484 return hdb_unseal_keys_mkey(context, ent, db->hdb_master_key); 485} 486 487krb5_error_code 488hdb_unseal_keys_kvno(krb5_context context, HDB *db, krb5_kvno kvno, 489 unsigned flags, hdb_entry *ent) 490{ 491 krb5_error_code ret = HDB_ERR_NOENTRY; 492 HDB_extension *ext; 493 HDB_Ext_KeySet *hist_keys; 494 Key *tmp_val; 495 time_t tmp_set_time; 496 unsigned int tmp_len; 497 krb5_kvno kvno_diff = 0; 498 krb5_kvno tmp_kvno; 499 size_t i, k; 500 int exclude_dead = 0; 501 KerberosTime now = 0; 502 503 if (kvno == 0) 504 ret = 0; 505 506 if ((flags & HDB_F_LIVE_CLNT_KVNOS) || (flags & HDB_F_LIVE_SVC_KVNOS)) { 507 exclude_dead = 1; 508 now = time(NULL); 509 if (flags & HDB_F_LIVE_CLNT_KVNOS) 510 kvno_diff = hdb_entry_get_kvno_diff_clnt(ent); 511 else 512 kvno_diff = hdb_entry_get_kvno_diff_svc(ent); 513 } 514 515 ext = hdb_find_extension(ent, choice_HDB_extension_data_hist_keys); 516 if (ext == NULL) 517 return ret; 518 519 /* For swapping; see below */ 520 tmp_len = ent->keys.len; 521 tmp_val = ent->keys.val; 522 tmp_kvno = ent->kvno; 523 (void) hdb_entry_get_pw_change_time(ent, &tmp_set_time); 524 525 hist_keys = &ext->data.u.hist_keys; 526 527 for (i = 0; i < hist_keys->len; i++) { 528 if (kvno != 0 && hist_keys->val[i].kvno != kvno) 529 continue; 530 531 if (exclude_dead && 532 ((ent->max_life != NULL && 533 hist_keys->val[i].set_time != NULL && 534 (*hist_keys->val[i].set_time) < (KerberosTime)(now - (*ent->max_life))) || 535 (hist_keys->val[i].kvno < kvno && 536 (kvno - hist_keys->val[i].kvno) > kvno_diff))) 537 /* 538 * The KDC may want to to check for this keyset's set_time 539 * is within the TGS principal's max_life, say. But we stop 540 * here. 541 */ 542 continue; 543 544 /* Either the keys we want, or all the keys */ 545 for (k = 0; k < hist_keys->val[i].keys.len; k++) { 546 ret = hdb_unseal_key_mkey(context, 547 &hist_keys->val[i].keys.val[k], 548 db->hdb_master_key); 549 /* 550 * If kvno == 0 we might not want to bail here! E.g., if we 551 * no longer have the right master key, so just ignore this. 552 * 553 * We could filter out keys that we can't decrypt here 554 * because of HDB_ERR_NO_MKEY. However, it seems safest to 555 * filter them out only where necessary, say, in kadm5. 556 */ 557 if (ret && kvno != 0) 558 return ret; 559 if (ret && ret != HDB_ERR_NO_MKEY) 560 return (ret); 561 } 562 563 if (kvno == 0) 564 continue; 565 566 /* 567 * What follows is a bit of a hack. 568 * 569 * This is the keyset we're being asked for, but it's not the 570 * current keyset. So we add the current keyset to the history, 571 * leave the one we were asked for in the history, and pretend 572 * the one we were asked for is also the current keyset. 573 * 574 * This is a bit of a defensive hack in case an entry fetched 575 * this way ever gets modified then stored: if the keyset is not 576 * changed we can detect this and put things back, else we won't 577 * drop any keysets from history by accident. 578 * 579 * Note too that we only ever get called with a non-zero kvno 580 * either in the KDC or in cases where we aren't changing the 581 * HDB entry anyways, which is why this is just a defensive 582 * hack. We also don't fetch specific kvnos in the dump case, 583 * so there's no danger that we'll dump this entry and load it 584 * again, repeatedly causing the history to grow boundelessly. 585 */ 586 587 /* Swap key sets */ 588 ent->kvno = hist_keys->val[i].kvno; 589 ent->keys.val = hist_keys->val[i].keys.val; 590 ent->keys.len = hist_keys->val[i].keys.len; 591 if (hist_keys->val[i].set_time != NULL) 592 /* Sloppy, but the callers we expect won't care */ 593 (void) hdb_entry_set_pw_change_time(context, ent, 594 *hist_keys->val[i].set_time); 595 hist_keys->val[i].kvno = tmp_kvno; 596 hist_keys->val[i].keys.val = tmp_val; 597 hist_keys->val[i].keys.len = tmp_len; 598 if (hist_keys->val[i].set_time != NULL) 599 /* Sloppy, but the callers we expect won't care */ 600 *hist_keys->val[i].set_time = tmp_set_time; 601 602 return 0; 603 } 604 605 return (ret); 606} 607 608krb5_error_code 609hdb_unseal_key(krb5_context context, HDB *db, Key *k) 610{ 611 if (db->hdb_master_key_set == 0) 612 return 0; 613 return hdb_unseal_key_mkey(context, k, db->hdb_master_key); 614} 615 616krb5_error_code 617hdb_seal_key_mkey(krb5_context context, Key *k, hdb_master_key mkey) 618{ 619 krb5_error_code ret; 620 krb5_data res; 621 hdb_master_key key; 622 623 if(k->mkvno != NULL) 624 return 0; 625 626 key = _hdb_find_master_key(k->mkvno, mkey); 627 628 if (key == NULL) 629 return HDB_ERR_NO_MKEY; 630 631 ret = _hdb_mkey_encrypt(context, key, HDB_KU_MKEY, 632 k->key.keyvalue.data, 633 k->key.keyvalue.length, 634 &res); 635 if (ret) 636 return ret; 637 638 memset(k->key.keyvalue.data, 0, k->key.keyvalue.length); 639 free(k->key.keyvalue.data); 640 k->key.keyvalue = res; 641 642 if (k->mkvno == NULL) { 643 k->mkvno = malloc(sizeof(*k->mkvno)); 644 if (k->mkvno == NULL) 645 return ENOMEM; 646 } 647 *k->mkvno = key->keytab.vno; 648 649 return 0; 650} 651 652krb5_error_code 653hdb_seal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey) 654{ 655 HDB_extension *ext; 656 HDB_Ext_KeySet *hist_keys; 657 size_t i, k; 658 krb5_error_code ret; 659 660 for(i = 0; i < ent->keys.len; i++){ 661 ret = hdb_seal_key_mkey(context, &ent->keys.val[i], mkey); 662 if (ret) 663 return ret; 664 } 665 666 ext = hdb_find_extension(ent, choice_HDB_extension_data_hist_keys); 667 if (ext == NULL) 668 return 0; 669 hist_keys = &ext->data.u.hist_keys; 670 671 for (i = 0; i < hist_keys->len; i++) { 672 for (k = 0; k < hist_keys->val[i].keys.len; k++) { 673 ret = hdb_seal_key_mkey(context, &hist_keys->val[i].keys.val[k], 674 mkey); 675 if (ret) 676 return ret; 677 } 678 } 679 680 return 0; 681} 682 683krb5_error_code 684hdb_seal_keys(krb5_context context, HDB *db, hdb_entry *ent) 685{ 686 if (db->hdb_master_key_set == 0) 687 return 0; 688 689 return hdb_seal_keys_mkey(context, ent, db->hdb_master_key); 690} 691 692krb5_error_code 693hdb_seal_key(krb5_context context, HDB *db, Key *k) 694{ 695 if (db->hdb_master_key_set == 0) 696 return 0; 697 698 return hdb_seal_key_mkey(context, k, db->hdb_master_key); 699} 700 701krb5_error_code 702hdb_set_master_key (krb5_context context, 703 HDB *db, 704 krb5_keyblock *key) 705{ 706 krb5_error_code ret; 707 hdb_master_key mkey; 708 709 ret = hdb_process_master_key(context, 0, key, 0, &mkey); 710 if (ret) 711 return ret; 712 db->hdb_master_key = mkey; 713#if 0 /* XXX - why? */ 714 des_set_random_generator_seed(key.keyvalue.data); 715#endif 716 db->hdb_master_key_set = 1; 717 return 0; 718} 719 720krb5_error_code 721hdb_set_master_keyfile (krb5_context context, 722 HDB *db, 723 const char *keyfile) 724{ 725 hdb_master_key key; 726 krb5_error_code ret; 727 728 ret = hdb_read_master_key(context, keyfile, &key); 729 if (ret) { 730 if (ret != ENOENT) 731 return ret; 732 krb5_clear_error_message(context); 733 return 0; 734 } 735 db->hdb_master_key = key; 736 db->hdb_master_key_set = 1; 737 return ret; 738} 739 740krb5_error_code 741hdb_clear_master_key (krb5_context context, 742 HDB *db) 743{ 744 if (db->hdb_master_key_set) { 745 hdb_free_master_key(context, db->hdb_master_key); 746 db->hdb_master_key_set = 0; 747 } 748 return 0; 749} 750