libtommath: Fix possible integer overflow CVE-2023-36328
[heimdal.git] / lib / hdb / mkey.c
blobcfc27d424a2f5fb945462335208b66d216750785
1 /*
2 * Copyright (c) 2000 - 2004 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
34 #include "hdb_locl.h"
35 #ifndef O_BINARY
36 #define O_BINARY 0
37 #endif
39 struct hdb_master_key_data {
40 krb5_keytab_entry keytab;
41 krb5_crypto crypto;
42 struct hdb_master_key_data *next;
43 unsigned int key_usage;
46 void
47 hdb_free_master_key(krb5_context context, hdb_master_key mkey)
49 struct hdb_master_key_data *ptr;
50 while(mkey) {
51 krb5_kt_free_entry(context, &mkey->keytab);
52 if (mkey->crypto)
53 krb5_crypto_destroy(context, mkey->crypto);
54 ptr = mkey;
55 mkey = mkey->next;
56 free(ptr);
60 krb5_error_code
61 hdb_process_master_key(krb5_context context,
62 int kvno, krb5_keyblock *key, krb5_enctype etype,
63 hdb_master_key *mkey)
65 krb5_error_code ret;
67 *mkey = calloc(1, sizeof(**mkey));
68 if(*mkey == NULL) {
69 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
70 return ENOMEM;
72 (*mkey)->key_usage = HDB_KU_MKEY;
73 (*mkey)->keytab.vno = kvno;
74 ret = krb5_parse_name(context, "K/M", &(*mkey)->keytab.principal);
75 if(ret)
76 goto fail;
77 ret = krb5_copy_keyblock_contents(context, key, &(*mkey)->keytab.keyblock);
78 if(ret)
79 goto fail;
80 if(etype != 0)
81 (*mkey)->keytab.keyblock.keytype = etype;
82 (*mkey)->keytab.timestamp = time(NULL);
83 ret = krb5_crypto_init(context, key, etype, &(*mkey)->crypto);
84 if(ret)
85 goto fail;
86 return 0;
87 fail:
88 hdb_free_master_key(context, *mkey);
89 *mkey = NULL;
90 return ret;
93 krb5_error_code
94 hdb_add_master_key(krb5_context context, krb5_keyblock *key,
95 hdb_master_key *inout)
97 int vno = 0;
98 hdb_master_key p;
99 krb5_error_code ret;
101 for(p = *inout; p; p = p->next)
102 vno = max(vno, p->keytab.vno);
103 vno++;
104 ret = hdb_process_master_key(context, vno, key, 0, &p);
105 if(ret)
106 return ret;
107 p->next = *inout;
108 *inout = p;
109 return 0;
112 static krb5_error_code
113 read_master_keytab(krb5_context context, const char *filename,
114 hdb_master_key *mkey)
116 krb5_error_code ret;
117 krb5_keytab id;
118 krb5_kt_cursor cursor;
119 krb5_keytab_entry entry;
120 hdb_master_key p;
122 *mkey = NULL;
123 ret = krb5_kt_resolve(context, filename, &id);
124 if(ret)
125 return ret;
127 ret = krb5_kt_start_seq_get(context, id, &cursor);
128 if(ret)
129 goto out;
130 while(krb5_kt_next_entry(context, id, &entry, &cursor) == 0) {
131 p = calloc(1, sizeof(*p));
132 if (p == NULL) {
133 ret = ENOMEM;
134 break;
136 p->keytab = entry;
137 p->next = *mkey;
138 *mkey = p;
139 ret = krb5_crypto_init(context, &p->keytab.keyblock, 0, &p->crypto);
140 if (ret)
141 break;
143 krb5_kt_end_seq_get(context, id, &cursor);
144 out:
145 krb5_kt_close(context, id);
146 if (ret) {
147 hdb_free_master_key(context, *mkey);
148 *mkey = NULL;
150 return ret;
153 /* read a MIT master keyfile */
154 static krb5_error_code
155 read_master_mit(krb5_context context, const char *filename,
156 int byteorder, hdb_master_key *mkey)
158 int fd;
159 krb5_error_code ret;
160 krb5_storage *sp;
161 int16_t enctype;
162 krb5_keyblock key;
164 fd = open(filename, O_RDONLY | O_BINARY);
165 if(fd < 0) {
166 int save_errno = errno;
167 krb5_set_error_message(context, save_errno, "failed to open %s: %s",
168 filename, strerror(save_errno));
169 return save_errno;
171 sp = krb5_storage_from_fd(fd);
172 if(sp == NULL) {
173 close(fd);
174 return errno;
176 krb5_storage_set_flags(sp, byteorder);
177 /* could possibly use ret_keyblock here, but do it with more
178 checks for now */
180 ret = krb5_ret_int16(sp, &enctype);
181 if (ret)
182 goto out;
183 ret = krb5_enctype_valid(context, enctype);
184 if (ret)
185 goto out;
186 key.keytype = enctype;
187 ret = krb5_ret_data(sp, &key.keyvalue);
188 if(ret)
189 goto out;
191 ret = hdb_process_master_key(context, 1, &key, 0, mkey);
192 krb5_free_keyblock_contents(context, &key);
193 out:
194 krb5_storage_free(sp);
195 close(fd);
196 return ret;
199 /* read an old master key file */
200 static krb5_error_code
201 read_master_encryptionkey(krb5_context context, const char *filename,
202 hdb_master_key *mkey)
204 int fd;
205 krb5_keyblock key;
206 krb5_error_code ret;
207 unsigned char buf[256];
208 ssize_t len;
209 size_t ret_len;
211 fd = open(filename, O_RDONLY | O_BINARY);
212 if(fd < 0) {
213 int save_errno = errno;
214 krb5_set_error_message(context, save_errno, "failed to open %s: %s",
215 filename, strerror(save_errno));
216 return save_errno;
219 len = read(fd, buf, sizeof(buf));
220 close(fd);
221 if(len < 0) {
222 int save_errno = errno;
223 krb5_set_error_message(context, save_errno, "error reading %s: %s",
224 filename, strerror(save_errno));
225 return save_errno;
228 ret = decode_EncryptionKey(buf, len, &key, &ret_len);
229 memset_s(buf, sizeof(buf), 0, sizeof(buf));
230 if(ret)
231 return ret;
233 /* Originally, the keytype was just that, and later it got changed
234 to des-cbc-md5, but we always used des in cfb64 mode. This
235 should cover all cases, but will break if someone has hacked
236 this code to really use des-cbc-md5 -- but then that's not my
237 problem. */
238 if(key.keytype == ETYPE_DES_CBC_CRC || key.keytype == ETYPE_DES_CBC_MD5)
239 key.keytype = ETYPE_DES_CFB64_NONE;
241 ret = hdb_process_master_key(context, 0, &key, 0, mkey);
242 krb5_free_keyblock_contents(context, &key);
243 return ret;
246 /* read a krb4 /.k style file */
247 static krb5_error_code
248 read_master_krb4(krb5_context context, const char *filename,
249 hdb_master_key *mkey)
251 int fd;
252 krb5_keyblock key;
253 krb5_error_code ret;
254 unsigned char buf[256];
255 ssize_t len;
257 fd = open(filename, O_RDONLY | O_BINARY);
258 if(fd < 0) {
259 int save_errno = errno;
260 krb5_set_error_message(context, save_errno, "failed to open %s: %s",
261 filename, strerror(save_errno));
262 return save_errno;
265 len = read(fd, buf, sizeof(buf));
266 close(fd);
267 if(len < 0) {
268 int save_errno = errno;
269 krb5_set_error_message(context, save_errno, "error reading %s: %s",
270 filename, strerror(save_errno));
271 return save_errno;
273 if(len != 8) {
274 krb5_set_error_message(context, HEIM_ERR_EOF,
275 "bad contents of %s", filename);
276 return HEIM_ERR_EOF; /* XXX file might be too large */
279 memset(&key, 0, sizeof(key));
280 key.keytype = ETYPE_DES_PCBC_NONE;
281 ret = krb5_data_copy(&key.keyvalue, buf, len);
282 memset_s(buf, sizeof(buf), 0, sizeof(buf));
283 if(ret)
284 return ret;
286 ret = hdb_process_master_key(context, 0, &key, 0, mkey);
287 krb5_free_keyblock_contents(context, &key);
288 return ret;
291 krb5_error_code
292 hdb_read_master_key(krb5_context context, const char *filename,
293 hdb_master_key *mkey)
295 FILE *f;
296 unsigned char buf[16];
297 krb5_error_code ret;
299 off_t len;
301 *mkey = NULL;
303 if(filename == NULL)
304 filename = HDB_DB_DIR "/m-key";
306 f = fopen(filename, "r");
307 if(f == NULL) {
308 int save_errno = errno;
309 krb5_set_error_message(context, save_errno, "failed to open %s: %s",
310 filename, strerror(save_errno));
311 return save_errno;
314 if(fread(buf, 1, 2, f) != 2) {
315 fclose(f);
316 krb5_set_error_message(context, HEIM_ERR_EOF, "end of file reading %s", filename);
317 return HEIM_ERR_EOF;
320 fseek(f, 0, SEEK_END);
321 len = ftell(f);
323 if(fclose(f) != 0)
324 return errno;
326 if(len < 0)
327 return errno;
329 if(len == 8) {
330 ret = read_master_krb4(context, filename, mkey);
331 } else if(buf[0] == 0x30 && len <= 127 && buf[1] == len - 2) {
332 ret = read_master_encryptionkey(context, filename, mkey);
333 } else if(buf[0] == 5 && buf[1] >= 1 && buf[1] <= 2) {
334 ret = read_master_keytab(context, filename, mkey);
335 } else {
337 * Check both LittleEndian and BigEndian since they key file
338 * might be moved from a machine with diffrent byte order, or
339 * its running on MacOS X that always uses BE master keys.
341 ret = read_master_mit(context, filename, KRB5_STORAGE_BYTEORDER_LE, mkey);
342 if (ret)
343 ret = read_master_mit(context, filename, KRB5_STORAGE_BYTEORDER_BE, mkey);
345 return ret;
348 krb5_error_code
349 hdb_write_master_key(krb5_context context, const char *filename,
350 hdb_master_key mkey)
352 krb5_error_code ret;
353 hdb_master_key p;
354 krb5_keytab kt;
356 if(filename == NULL)
357 filename = HDB_DB_DIR "/m-key";
359 ret = krb5_kt_resolve(context, filename, &kt);
360 if(ret)
361 return ret;
363 for(p = mkey; p; p = p->next) {
364 ret = krb5_kt_add_entry(context, kt, &p->keytab);
367 krb5_kt_close(context, kt);
369 return ret;
372 krb5_error_code
373 _hdb_set_master_key_usage(krb5_context context, HDB *db, unsigned int key_usage)
375 if (db->hdb_master_key_set == 0)
376 return HDB_ERR_NO_MKEY;
377 db->hdb_master_key->key_usage = key_usage;
378 return 0;
381 hdb_master_key
382 _hdb_find_master_key(unsigned int *mkvno, hdb_master_key mkey)
384 hdb_master_key ret = NULL;
385 while(mkey) {
386 if(ret == NULL && mkey->keytab.vno == 0)
387 ret = mkey;
388 if(mkvno == NULL) {
389 if(ret == NULL || mkey->keytab.vno > ret->keytab.vno)
390 ret = mkey;
391 } else if((uint32_t)mkey->keytab.vno == *mkvno)
392 return mkey;
393 mkey = mkey->next;
395 return ret;
399 _hdb_mkey_version(hdb_master_key mkey)
401 return mkey->keytab.vno;
405 _hdb_mkey_decrypt(krb5_context context, hdb_master_key key,
406 krb5_key_usage usage,
407 void *ptr, size_t size, krb5_data *res)
409 return krb5_decrypt(context, key->crypto, usage,
410 ptr, size, res);
414 _hdb_mkey_encrypt(krb5_context context, hdb_master_key key,
415 krb5_key_usage usage,
416 const void *ptr, size_t size, krb5_data *res)
418 return krb5_encrypt(context, key->crypto, usage,
419 ptr, size, res);
422 krb5_error_code
423 hdb_unseal_key_mkey(krb5_context context, Key *k, hdb_master_key mkey)
426 krb5_error_code ret;
427 krb5_data res;
428 size_t keysize;
430 hdb_master_key key;
432 if(k->mkvno == NULL)
433 return 0;
435 key = _hdb_find_master_key(k->mkvno, mkey);
437 if (key == NULL)
438 return HDB_ERR_NO_MKEY;
440 ret = _hdb_mkey_decrypt(context, key, HDB_KU_MKEY,
441 k->key.keyvalue.data,
442 k->key.keyvalue.length,
443 &res);
444 if(ret == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
445 /* try to decrypt with MIT key usage */
446 ret = _hdb_mkey_decrypt(context, key, 0,
447 k->key.keyvalue.data,
448 k->key.keyvalue.length,
449 &res);
451 if (ret)
452 return ret;
454 /* fixup keylength if the key got padded when encrypting it */
455 ret = krb5_enctype_keysize(context, k->key.keytype, &keysize);
456 if (ret) {
457 krb5_data_free(&res);
458 return ret;
460 if (keysize > res.length) {
461 krb5_data_free(&res);
462 return KRB5_BAD_KEYSIZE;
465 memset(k->key.keyvalue.data, 0, k->key.keyvalue.length);
466 free(k->key.keyvalue.data);
467 k->key.keyvalue = res;
468 k->key.keyvalue.length = keysize;
469 free(k->mkvno);
470 k->mkvno = NULL;
472 return 0;
475 krb5_error_code
476 hdb_unseal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey)
478 size_t i;
480 for(i = 0; i < ent->keys.len; i++){
481 krb5_error_code ret;
483 ret = hdb_unseal_key_mkey(context, &ent->keys.val[i], mkey);
484 if (ret)
485 return ret;
487 return 0;
490 krb5_error_code
491 hdb_unseal_keys(krb5_context context, HDB *db, hdb_entry *ent)
493 if (db->hdb_master_key_set == 0)
494 return 0;
495 return hdb_unseal_keys_mkey(context, ent, db->hdb_master_key);
499 * Unseal the keys for the given kvno (or all of them) of entry.
501 * If kvno == 0 -> unseal all.
502 * if kvno != 0 -> unseal the requested kvno and make sure it's the one listed
503 * as the current keyset for the entry (swapping it with a
504 * historical keyset if need be).
506 krb5_error_code
507 hdb_unseal_keys_kvno(krb5_context context, HDB *db, krb5_kvno kvno,
508 unsigned flags, hdb_entry *ent)
510 krb5_error_code ret = HDB_ERR_NOENTRY;
511 HDB_extension *ext;
512 HDB_Ext_KeySet *hist_keys;
513 Key *tmp_val;
514 time_t tmp_set_time;
515 unsigned int tmp_len;
516 unsigned int kvno_diff = 0;
517 krb5_kvno tmp_kvno;
518 size_t i, k;
519 int exclude_dead = 0;
520 KerberosTime now = 0;
522 if (kvno == 0)
523 ret = 0;
525 if ((flags & HDB_F_LIVE_CLNT_KVNOS) || (flags & HDB_F_LIVE_SVC_KVNOS)) {
526 exclude_dead = 1;
527 now = time(NULL);
528 if (HDB_F_LIVE_CLNT_KVNOS)
529 kvno_diff = hdb_entry_get_kvno_diff_clnt(ent);
530 else
531 kvno_diff = hdb_entry_get_kvno_diff_svc(ent);
534 ext = hdb_find_extension(ent, choice_HDB_extension_data_hist_keys);
535 if (ext == NULL || (&ext->data.u.hist_keys)->len == 0)
536 return hdb_unseal_keys_mkey(context, ent, db->hdb_master_key);
538 /* For swapping; see below */
539 tmp_len = ent->keys.len;
540 tmp_val = ent->keys.val;
541 tmp_kvno = ent->kvno;
542 (void) hdb_entry_get_pw_change_time(ent, &tmp_set_time);
544 hist_keys = &ext->data.u.hist_keys;
546 for (i = 0; i < hist_keys->len; i++) {
547 if (kvno != 0 && hist_keys->val[i].kvno != kvno)
548 continue;
550 if (exclude_dead &&
551 ((ent->max_life != NULL &&
552 hist_keys->val[i].set_time != NULL &&
553 (*hist_keys->val[i].set_time) < (now - (*ent->max_life))) ||
554 (hist_keys->val[i].kvno < kvno &&
555 (kvno - hist_keys->val[i].kvno) > kvno_diff)))
557 * The KDC may want to to check for this keyset's set_time
558 * is within the TGS principal's max_life, say. But we stop
559 * here.
561 continue;
563 /* Either the keys we want, or all the keys */
564 for (k = 0; k < hist_keys->val[i].keys.len; k++) {
565 ret = hdb_unseal_key_mkey(context,
566 &hist_keys->val[i].keys.val[k],
567 db->hdb_master_key);
569 * If kvno == 0 we might not want to bail here! E.g., if we
570 * no longer have the right master key, so just ignore this.
572 * We could filter out keys that we can't decrypt here
573 * because of HDB_ERR_NO_MKEY. However, it seems safest to
574 * filter them out only where necessary, say, in kadm5.
576 if (ret && kvno != 0)
577 return ret;
578 if (ret && ret != HDB_ERR_NO_MKEY)
579 return (ret);
582 if (kvno == 0)
583 continue;
586 * What follows is a bit of a hack.
588 * This is the keyset we're being asked for, but it's not the
589 * current keyset. So we add the current keyset to the history,
590 * leave the one we were asked for in the history, and pretend
591 * the one we were asked for is also the current keyset.
593 * This is a bit of a defensive hack in case an entry fetched
594 * this way ever gets modified then stored: if the keyset is not
595 * changed we can detect this and put things back, else we won't
596 * drop any keysets from history by accident.
598 * Note too that we only ever get called with a non-zero kvno
599 * either in the KDC or in cases where we aren't changing the
600 * HDB entry anyways, which is why this is just a defensive
601 * hack. We also don't fetch specific kvnos in the dump case,
602 * so there's no danger that we'll dump this entry and load it
603 * again, repeatedly causing the history to grow boundelessly.
606 /* Swap key sets */
607 ent->kvno = hist_keys->val[i].kvno;
608 ent->keys.val = hist_keys->val[i].keys.val;
609 ent->keys.len = hist_keys->val[i].keys.len;
610 if (hist_keys->val[i].set_time != NULL)
611 /* Sloppy, but the callers we expect won't care */
612 (void) hdb_entry_set_pw_change_time(context, ent,
613 *hist_keys->val[i].set_time);
614 hist_keys->val[i].kvno = tmp_kvno;
615 hist_keys->val[i].keys.val = tmp_val;
616 hist_keys->val[i].keys.len = tmp_len;
617 if (hist_keys->val[i].set_time != NULL)
618 /* Sloppy, but the callers we expect won't care */
619 *hist_keys->val[i].set_time = tmp_set_time;
621 return 0;
624 return (ret);
627 krb5_error_code
628 hdb_unseal_key(krb5_context context, HDB *db, Key *k)
630 if (db->hdb_master_key_set == 0)
631 return 0;
632 return hdb_unseal_key_mkey(context, k, db->hdb_master_key);
635 krb5_error_code
636 hdb_seal_key_mkey(krb5_context context, Key *k, hdb_master_key mkey)
638 krb5_error_code ret;
639 krb5_data res;
640 hdb_master_key key;
642 if(k->mkvno != NULL)
643 return 0;
645 key = _hdb_find_master_key(k->mkvno, mkey);
647 if (key == NULL)
648 return HDB_ERR_NO_MKEY;
650 ret = _hdb_mkey_encrypt(context, key, HDB_KU_MKEY,
651 k->key.keyvalue.data,
652 k->key.keyvalue.length,
653 &res);
654 if (ret)
655 return ret;
657 memset(k->key.keyvalue.data, 0, k->key.keyvalue.length);
658 free(k->key.keyvalue.data);
659 k->key.keyvalue = res;
661 if (k->mkvno == NULL) {
662 k->mkvno = malloc(sizeof(*k->mkvno));
663 if (k->mkvno == NULL)
664 return ENOMEM;
666 *k->mkvno = key->keytab.vno;
668 return 0;
671 krb5_error_code
672 hdb_seal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey)
674 HDB_extension *ext;
675 HDB_Ext_KeySet *hist_keys;
676 size_t i, k;
677 krb5_error_code ret;
679 for(i = 0; i < ent->keys.len; i++){
680 ret = hdb_seal_key_mkey(context, &ent->keys.val[i], mkey);
681 if (ret)
682 return ret;
685 ext = hdb_find_extension(ent, choice_HDB_extension_data_hist_keys);
686 if (ext == NULL)
687 return 0;
688 hist_keys = &ext->data.u.hist_keys;
690 for (i = 0; i < hist_keys->len; i++) {
691 for (k = 0; k < hist_keys->val[i].keys.len; k++) {
692 ret = hdb_seal_key_mkey(context, &hist_keys->val[i].keys.val[k],
693 mkey);
694 if (ret)
695 return ret;
699 return 0;
702 krb5_error_code
703 hdb_seal_keys(krb5_context context, HDB *db, hdb_entry *ent)
705 if (db->hdb_master_key_set == 0)
706 return 0;
708 return hdb_seal_keys_mkey(context, ent, db->hdb_master_key);
711 krb5_error_code
712 hdb_seal_key(krb5_context context, HDB *db, Key *k)
714 if (db->hdb_master_key_set == 0)
715 return 0;
717 return hdb_seal_key_mkey(context, k, db->hdb_master_key);
720 krb5_error_code
721 hdb_set_master_key(krb5_context context,
722 HDB *db,
723 krb5_keyblock *key)
725 krb5_error_code ret;
726 hdb_master_key mkey;
728 ret = hdb_process_master_key(context, 0, key, 0, &mkey);
729 if (ret)
730 return ret;
731 db->hdb_master_key = mkey;
732 #if 0 /* XXX - why? */
733 des_set_random_generator_seed(key.keyvalue.data);
734 #endif
735 db->hdb_master_key_set = 1;
736 db->hdb_master_key->key_usage = HDB_KU_MKEY;
737 return 0;
740 krb5_error_code
741 hdb_set_master_keyfile (krb5_context context,
742 HDB *db,
743 const char *keyfile)
745 hdb_master_key key;
746 krb5_error_code ret;
748 ret = hdb_read_master_key(context, keyfile, &key);
749 if (ret) {
750 if (ret != ENOENT)
751 return ret;
752 krb5_clear_error_message(context);
753 return 0;
755 db->hdb_master_key = key;
756 db->hdb_master_key_set = 1;
757 return ret;
760 krb5_error_code
761 hdb_clear_master_key (krb5_context context,
762 HDB *db)
764 if (db->hdb_master_key_set) {
765 hdb_free_master_key(context, db->hdb_master_key);
766 db->hdb_master_key_set = 0;
768 return 0;