/ lib / hdb / mkey.c
mkey.c
  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  
 39  struct hdb_master_key_data {
 40      krb5_keytab_entry keytab;
 41      krb5_crypto crypto;
 42      struct hdb_master_key_data *next;
 43  };
 44  
 45  void
 46  hdb_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  
 59  krb5_error_code
 60  hdb_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  
 91  krb5_error_code
 92  hdb_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  
110  static krb5_error_code
111  read_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 */
147  static krb5_error_code
148  read_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 */
193  static krb5_error_code
194  read_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 */
240  static krb5_error_code
241  read_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  
284  krb5_error_code
285  hdb_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  
346  krb5_error_code
347  hdb_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  
370  hdb_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  
387  int
388  _hdb_mkey_version(hdb_master_key mkey)
389  {
390      return mkey->keytab.vno;
391  }
392  
393  int
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  
402  int
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  
411  krb5_error_code
412  hdb_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  
464  krb5_error_code
465  hdb_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  
479  krb5_error_code
480  hdb_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  
487  krb5_error_code
488  hdb_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  
608  krb5_error_code
609  hdb_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  
616  krb5_error_code
617  hdb_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  
652  krb5_error_code
653  hdb_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  
683  krb5_error_code
684  hdb_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  
692  krb5_error_code
693  hdb_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  
701  krb5_error_code
702  hdb_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  
720  krb5_error_code
721  hdb_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  
740  krb5_error_code
741  hdb_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  }