Allow KDC to always return the salt in the PA-ETYPE-INFO[2]
[heimdal.git] / lib / hdb / common.c
blob798236a98f88190060cd177e5768b65550da9d56
1 /*
2 * Copyright (c) 1997-2002 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 "krb5_locl.h"
35 #include "hdb_locl.h"
37 int
38 hdb_principal2key(krb5_context context, krb5_const_principal p, krb5_data *key)
40 Principal new;
41 size_t len = 0;
42 int ret;
44 ret = copy_Principal(p, &new);
45 if(ret)
46 return ret;
47 new.name.name_type = 0;
49 ASN1_MALLOC_ENCODE(Principal, key->data, key->length, &new, &len, ret);
50 if (ret == 0 && key->length != len)
51 krb5_abortx(context, "internal asn.1 encoder error");
52 free_Principal(&new);
53 return ret;
56 int
57 hdb_key2principal(krb5_context context, krb5_data *key, krb5_principal p)
59 return decode_Principal(key->data, key->length, p, NULL);
62 int
63 hdb_entry2value(krb5_context context, const hdb_entry *ent, krb5_data *value)
65 size_t len = 0;
66 int ret;
68 ASN1_MALLOC_ENCODE(HDB_entry, value->data, value->length, ent, &len, ret);
69 if (ret == 0 && value->length != len)
70 krb5_abortx(context, "internal asn.1 encoder error");
71 return ret;
74 int
75 hdb_value2entry(krb5_context context, krb5_data *value, hdb_entry *ent)
77 return decode_HDB_entry(value->data, value->length, ent, NULL);
80 int
81 hdb_entry_alias2value(krb5_context context,
82 const hdb_entry_alias *alias,
83 krb5_data *value)
85 size_t len = 0;
86 int ret;
88 ASN1_MALLOC_ENCODE(HDB_entry_alias, value->data, value->length,
89 alias, &len, ret);
90 if (ret == 0 && value->length != len)
91 krb5_abortx(context, "internal asn.1 encoder error");
92 return ret;
95 int
96 hdb_value2entry_alias(krb5_context context, krb5_data *value,
97 hdb_entry_alias *ent)
99 return decode_HDB_entry_alias(value->data, value->length, ent, NULL);
103 * Some old databases may not have stored the salt with each key, which will
104 * break clients when aliases or canonicalization are used. Generate a
105 * default salt based on the real principal name in the entry to handle
106 * this case.
108 static krb5_error_code
109 add_default_salts(krb5_context context, HDB *db, hdb_entry *entry)
111 krb5_error_code ret;
112 size_t i;
113 krb5_salt pwsalt;
115 ret = krb5_get_pw_salt(context, entry->principal, &pwsalt);
116 if (ret)
117 return ret;
119 for (i = 0; i < entry->keys.len; i++) {
120 Key *key = &entry->keys.val[i];
122 if (key->salt != NULL ||
123 _krb5_enctype_requires_random_salt(context, key->key.keytype))
124 continue;
126 key->salt = calloc(1, sizeof(*key->salt));
127 if (key->salt == NULL) {
128 ret = krb5_enomem(context);
129 break;
132 key->salt->type = KRB5_PADATA_PW_SALT;
134 ret = krb5_data_copy(&key->salt->salt,
135 pwsalt.saltvalue.data,
136 pwsalt.saltvalue.length);
137 if (ret)
138 break;
141 krb5_free_salt(context, pwsalt);
143 return ret;
146 static krb5_error_code
147 fetch_entry_or_alias(krb5_context context,
148 HDB *db,
149 krb5_const_principal principal,
150 unsigned flags,
151 hdb_entry_ex *entry)
153 HDB_EntryOrAlias eoa;
154 krb5_principal enterprise_principal = NULL;
155 krb5_data key, value;
156 krb5_error_code ret;
158 value.length = 0;
159 value.data = 0;
160 key = value;
162 if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
163 if (principal->name.name_string.len != 1) {
164 ret = KRB5_PARSE_MALFORMED;
165 krb5_set_error_message(context, ret, "malformed principal: "
166 "enterprise name with %d name components",
167 principal->name.name_string.len);
168 return ret;
170 ret = krb5_parse_name(context, principal->name.name_string.val[0],
171 &enterprise_principal);
172 if (ret)
173 return ret;
174 principal = enterprise_principal;
177 ret = hdb_principal2key(context, principal, &key);
178 if (ret == 0)
179 ret = db->hdb__get(context, db, key, &value);
180 if (ret == 0)
181 ret = decode_HDB_EntryOrAlias(value.data, value.length, &eoa, NULL);
182 if (ret == 0 && eoa.element == choice_HDB_EntryOrAlias_entry) {
183 entry->entry = eoa.u.entry;
184 } else if (ret == 0 && eoa.element == choice_HDB_EntryOrAlias_alias) {
185 krb5_data_free(&key);
186 ret = hdb_principal2key(context, eoa.u.alias.principal, &key);
187 if (ret == 0) {
188 krb5_data_free(&value);
189 ret = db->hdb__get(context, db, key, &value);
191 if (ret == 0)
192 /* No alias chaining */
193 ret = hdb_value2entry(context, &value, &entry->entry);
194 krb5_free_principal(context, eoa.u.alias.principal);
195 } else if (ret == 0)
196 ret = ENOTSUP;
197 if (ret == 0 && enterprise_principal) {
199 * Whilst Windows does not canonicalize enterprise principal names if
200 * the canonicalize flag is unset, the original specification in
201 * draft-ietf-krb-wg-kerberos-referrals-03.txt says we should.
203 entry->entry.flags.force_canonicalize = 1;
206 /* HDB_F_GET_ANY indicates request originated from KDC (not kadmin) */
207 if (ret == 0 && eoa.element == choice_HDB_EntryOrAlias_alias &&
208 (flags & (HDB_F_CANON|HDB_F_GET_ANY)) == 0) {
210 /* `principal' was alias but canon not req'd */
211 free_HDB_entry(&entry->entry);
212 ret = HDB_ERR_NOENTRY;
215 krb5_free_principal(context, enterprise_principal);
216 krb5_data_free(&value);
217 krb5_data_free(&key);
218 principal = enterprise_principal = NULL;
219 return ret;
222 krb5_error_code
223 _hdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal,
224 unsigned flags, krb5_kvno kvno, hdb_entry_ex *entry)
226 krb5_error_code ret;
228 ret = fetch_entry_or_alias(context, db, principal, flags, entry);
229 if (ret)
230 return ret;
232 if ((flags & HDB_F_DECRYPT) && (flags & HDB_F_ALL_KVNOS)) {
233 /* Decrypt the current keys */
234 ret = hdb_unseal_keys(context, db, &entry->entry);
235 if (ret) {
236 hdb_free_entry(context, entry);
237 return ret;
239 /* Decrypt the key history too */
240 ret = hdb_unseal_keys_kvno(context, db, 0, flags, &entry->entry);
241 if (ret) {
242 hdb_free_entry(context, entry);
243 return ret;
245 } else if ((flags & HDB_F_DECRYPT)) {
246 if ((flags & HDB_F_KVNO_SPECIFIED) == 0 || kvno == entry->entry.kvno) {
247 /* Decrypt the current keys */
248 ret = hdb_unseal_keys(context, db, &entry->entry);
249 if (ret) {
250 hdb_free_entry(context, entry);
251 return ret;
253 } else {
254 if ((flags & HDB_F_ALL_KVNOS))
255 kvno = 0;
257 * Find and decrypt the keys from the history that we want,
258 * and swap them with the current keys
260 ret = hdb_unseal_keys_kvno(context, db, kvno, flags, &entry->entry);
261 if (ret) {
262 hdb_free_entry(context, entry);
263 return ret;
267 if ((flags & HDB_F_FOR_AS_REQ) && (flags & HDB_F_GET_CLIENT)) {
269 * Generate default salt for any principals missing one; note such
270 * principals could include those for which a random (non-password)
271 * key was generated, but given the salt will be ignored by a keytab
272 * client it doesn't hurt to include the default salt.
274 ret = add_default_salts(context, db, &entry->entry);
275 if (ret) {
276 hdb_free_entry(context, entry);
277 return ret;
281 return 0;
284 static krb5_error_code
285 hdb_remove_aliases(krb5_context context, HDB *db, krb5_data *key)
287 const HDB_Ext_Aliases *aliases;
288 krb5_error_code code;
289 hdb_entry oldentry;
290 krb5_data value;
291 size_t i;
293 code = db->hdb__get(context, db, *key, &value);
294 if (code == HDB_ERR_NOENTRY)
295 return 0;
296 else if (code)
297 return code;
299 code = hdb_value2entry(context, &value, &oldentry);
300 krb5_data_free(&value);
301 if (code)
302 return code;
304 code = hdb_entry_get_aliases(&oldentry, &aliases);
305 if (code || aliases == NULL) {
306 free_HDB_entry(&oldentry);
307 return code;
309 for (i = 0; i < aliases->aliases.len; i++) {
310 krb5_data akey;
312 code = hdb_principal2key(context, &aliases->aliases.val[i], &akey);
313 if (code == 0) {
314 code = db->hdb__del(context, db, akey);
315 krb5_data_free(&akey);
317 if (code) {
318 free_HDB_entry(&oldentry);
319 return code;
322 free_HDB_entry(&oldentry);
323 return 0;
326 static krb5_error_code
327 hdb_add_aliases(krb5_context context, HDB *db,
328 unsigned flags, hdb_entry_ex *entry)
330 const HDB_Ext_Aliases *aliases;
331 krb5_error_code code;
332 krb5_data key, value;
333 size_t i;
335 code = hdb_entry_get_aliases(&entry->entry, &aliases);
336 if (code || aliases == NULL)
337 return code;
339 for (i = 0; i < aliases->aliases.len; i++) {
340 hdb_entry_alias entryalias;
341 entryalias.principal = entry->entry.principal;
343 code = hdb_entry_alias2value(context, &entryalias, &value);
344 if (code)
345 return code;
347 code = hdb_principal2key(context, &aliases->aliases.val[i], &key);
348 if (code == 0) {
349 code = db->hdb__put(context, db, flags, key, value);
350 krb5_data_free(&key);
352 krb5_data_free(&value);
353 if (code)
354 return code;
356 return 0;
359 /* Check if new aliases are already used for other entries */
360 static krb5_error_code
361 hdb_check_aliases(krb5_context context, HDB *db, hdb_entry_ex *entry)
363 const HDB_Ext_Aliases *aliases = NULL;
364 HDB_EntryOrAlias eoa;
365 krb5_data akey, value;
366 size_t i;
367 int ret;
369 memset(&eoa, 0, sizeof(eoa));
370 krb5_data_zero(&value);
371 akey = value;
373 ret = hdb_entry_get_aliases(&entry->entry, &aliases);
374 for (i = 0; ret == 0 && aliases && i < aliases->aliases.len; i++) {
375 ret = hdb_principal2key(context, &aliases->aliases.val[i], &akey);
376 if (ret == 0)
377 ret = db->hdb__get(context, db, akey, &value);
378 if (ret == 0)
379 ret = decode_HDB_EntryOrAlias(value.data, value.length, &eoa, NULL);
380 if (ret == 0 && eoa.element != choice_HDB_EntryOrAlias_entry &&
381 eoa.element != choice_HDB_EntryOrAlias_alias)
382 ret = ENOTSUP;
383 if (ret == 0 && eoa.element == choice_HDB_EntryOrAlias_entry)
384 /* New alias names an existing non-alias entry in the HDB */
385 ret = HDB_ERR_EXISTS;
386 if (ret == 0 && eoa.element == choice_HDB_EntryOrAlias_alias &&
387 !krb5_principal_compare(context, eoa.u.alias.principal,
388 entry->entry.principal))
389 /* New alias names an existing alias of a different entry */
390 ret = HDB_ERR_EXISTS;
391 if (ret == HDB_ERR_NOENTRY) /* from db->hdb__get */
392 /* New alias is a name that doesn't exist in the HDB */
393 ret = 0;
395 free_HDB_EntryOrAlias(&eoa);
396 krb5_data_free(&value);
397 krb5_data_free(&akey);
399 return ret;
403 * Many HDB entries don't have `etypes' setup. Historically we use the
404 * enctypes of the selected keyset as the entry's supported enctypes, but that
405 * is problematic. By doing this at store time and, if need be, at fetch time,
406 * we can make sure to stop deriving supported etypes from keys in the long
407 * run. We also need kadm5/kadmin support for etypes. We'll use this function
408 * there to derive etypes when using a kadm5_principal_ent_t that lacks the new
409 * TL data for etypes.
411 krb5_error_code
412 hdb_derive_etypes(krb5_context context, hdb_entry *e, HDB_Ext_KeySet *base_keys)
414 krb5_error_code ret = 0;
415 size_t i, k, netypes;
416 HDB_extension *ext;
418 if (!base_keys &&
419 (ext = hdb_find_extension(e, choice_HDB_extension_data_hist_keys)))
420 base_keys = &ext->data.u.hist_keys;
422 netypes = e->keys.len;
423 if (netypes == 0 && base_keys) {
424 /* There's no way that base_keys->val[i].keys.len == 0, but hey */
425 for (i = 0; netypes == 0 && i < base_keys->len; i++)
426 netypes = base_keys->val[i].keys.len;
429 if (netypes == 0)
430 return 0;
432 if (e->etypes != NULL) {
433 free(e->etypes->val);
434 e->etypes->len = 0;
435 e->etypes->val = 0;
438 if (e->etypes == NULL &&
439 (e->etypes = malloc(sizeof(e->etypes[0]))) == NULL)
440 ret = krb5_enomem(context);
441 if (ret == 0) {
442 e->etypes->len = 0;
443 e->etypes->val = 0;
445 if (ret == 0 &&
446 (e->etypes->val = calloc(netypes, sizeof(e->etypes->val[0]))) == NULL)
447 ret = krb5_enomem(context);
448 if (ret) {
449 free(e->etypes);
450 e->etypes = 0;
451 return ret;
453 e->etypes->len = netypes;
454 for (i = 0; i < e->keys.len && i < netypes; i++)
455 e->etypes->val[i] = e->keys.val[i].key.keytype;
456 if (!base_keys || i)
457 return 0;
458 for (k = 0; i == 0 && k < base_keys->len; k++) {
459 if (!base_keys->val[k].keys.len)
460 continue;
461 for (; i < base_keys->val[k].keys.len; i++)
462 e->etypes->val[i] = base_keys->val[k].keys.val[i].key.keytype;
464 return 0;
467 krb5_error_code
468 _hdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
470 krb5_data key, value;
471 int code;
473 if (entry->entry.flags.do_not_store ||
474 entry->entry.flags.force_canonicalize)
475 return HDB_ERR_MISUSE;
476 /* check if new aliases already is used */
477 code = hdb_check_aliases(context, db, entry);
478 if (code)
479 return code;
481 if ((flags & HDB_F_PRECHECK) && (flags & HDB_F_REPLACE))
482 return 0;
484 if ((flags & HDB_F_PRECHECK)) {
485 code = hdb_principal2key(context, entry->entry.principal, &key);
486 if (code)
487 return code;
488 code = db->hdb__get(context, db, key, &value);
489 krb5_data_free(&key);
490 if (code == 0)
491 krb5_data_free(&value);
492 if (code == HDB_ERR_NOENTRY)
493 return 0;
494 return code ? code : HDB_ERR_EXISTS;
497 if ((entry->entry.etypes == NULL || entry->entry.etypes->len == 0) &&
498 (code = hdb_derive_etypes(context, &entry->entry, NULL)))
499 return code;
501 if (entry->entry.generation == NULL) {
502 struct timeval t;
503 entry->entry.generation = malloc(sizeof(*entry->entry.generation));
504 if(entry->entry.generation == NULL) {
505 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
506 return ENOMEM;
508 gettimeofday(&t, NULL);
509 entry->entry.generation->time = t.tv_sec;
510 entry->entry.generation->usec = t.tv_usec;
511 entry->entry.generation->gen = 0;
512 } else
513 entry->entry.generation->gen++;
515 code = hdb_seal_keys(context, db, &entry->entry);
516 if (code)
517 return code;
519 hdb_principal2key(context, entry->entry.principal, &key);
521 /* remove aliases */
522 code = hdb_remove_aliases(context, db, &key);
523 if (code) {
524 krb5_data_free(&key);
525 return code;
527 hdb_entry2value(context, &entry->entry, &value);
528 code = db->hdb__put(context, db, flags & HDB_F_REPLACE, key, value);
529 krb5_data_free(&value);
530 krb5_data_free(&key);
531 if (code)
532 return code;
534 code = hdb_add_aliases(context, db, flags, entry);
536 return code;
539 krb5_error_code
540 _hdb_remove(krb5_context context, HDB *db,
541 unsigned flags, krb5_const_principal principal)
543 krb5_data key, value;
544 int code;
546 hdb_principal2key(context, principal, &key);
548 if ((flags & HDB_F_PRECHECK)) {
550 * We don't check that we can delete the aliases because we
551 * assume that the DB is consistent. If we did check for alias
552 * consistency we'd also have to provide a way to fsck the DB,
553 * otherwise admins would have no way to recover -- papering
554 * over this here is less work, but we really ought to provide
555 * an HDB fsck.
557 code = db->hdb__get(context, db, key, &value);
558 krb5_data_free(&key);
559 if (code == 0) {
560 krb5_data_free(&value);
561 return 0;
563 return code;
566 code = hdb_remove_aliases(context, db, &key);
567 if (code) {
568 krb5_data_free(&key);
569 return code;
571 code = db->hdb__del(context, db, key);
572 krb5_data_free(&key);
573 return code;
576 /* PRF+(K_base, pad, keylen(etype)) */
577 static krb5_error_code
578 derive_Key1(krb5_context context,
579 krb5_data *pad,
580 EncryptionKey *base,
581 krb5int32 etype,
582 EncryptionKey *nk)
584 krb5_error_code ret;
585 krb5_crypto crypto = NULL;
586 krb5_data out;
587 size_t len;
589 out.data = 0;
590 out.length = 0;
592 ret = krb5_enctype_keysize(context, base->keytype, &len);
593 if (ret == 0)
594 ret = krb5_crypto_init(context, base, 0, &crypto);
595 if (ret == 0)
596 ret = krb5_crypto_prfplus(context, crypto, pad, len, &out);
597 if (crypto)
598 krb5_crypto_destroy(context, crypto);
599 if (ret == 0)
600 ret = krb5_random_to_key(context, etype, out.data, out.length, nk);
601 krb5_data_free(&out);
602 return ret;
605 /* PRF+(PRF+(K_base, princ, keylen(etype)), kvno, keylen(etype)) */
606 /* XXX Make it PRF+(PRF+(K_base, princ, keylen(K_base.etype)), and lift it, kvno, keylen(etype)) */
607 static krb5_error_code
608 derive_Key(krb5_context context,
609 const char *princ,
610 krb5uint32 kvno,
611 EncryptionKey *base,
612 krb5int32 etype,
613 Key *nk)
615 krb5_error_code ret = 0;
616 EncryptionKey intermediate;
617 krb5_data pad;
619 nk->salt = NULL;
620 nk->mkvno = NULL;
621 nk->key.keytype = 0;
622 nk->key.keyvalue.data = 0;
623 nk->key.keyvalue.length = 0;
625 intermediate.keytype = 0;
626 intermediate.keyvalue.data = 0;
627 intermediate.keyvalue.length = 0;
628 if (princ) {
629 /* Derive intermediate key for the given principal */
630 /* XXX Lift to optimize? */
631 pad.data = (void *)(uintptr_t)princ;
632 pad.length = strlen(princ);
633 ret = derive_Key1(context, &pad, base, etype, &intermediate);
634 if (ret == 0)
635 base = &intermediate;
636 } /* else `base' is already an intermediate key for the desired princ */
638 /* Derive final key for `kvno' from intermediate key */
639 kvno = htonl(kvno);
640 pad.data = &kvno;
641 pad.length = sizeof(kvno);
642 if (ret == 0)
643 ret = derive_Key1(context, &pad, base, etype, &nk->key);
644 free_EncryptionKey(&intermediate);
645 return ret;
649 * PRF+(PRF+(K_base, princ, keylen(etype)), kvno, keylen(etype)) for one
650 * enctype.
652 static krb5_error_code
653 derive_Keys(krb5_context context,
654 const char *princ,
655 krb5uint32 kvno,
656 krb5int32 etype,
657 const Keys *base,
658 Keys *dk)
661 krb5_error_code ret = 0;
662 size_t i;
663 Key nk;
665 dk->len = 0;
666 dk->val = 0;
669 * The enctypes of the base keys is the list of enctypes to derive keys
670 * for. Still, we derive all keys from the first base key.
672 for (i = 0; ret == 0 && i < base->len; i++) {
673 if (etype != KRB5_ENCTYPE_NULL && etype != base->val[i].key.keytype)
674 continue;
675 ret = derive_Key(context, princ, kvno, &base->val[0].key,
676 base->val[i].key.keytype, &nk);
677 if (ret)
678 break;
679 ret = add_Keys(dk, &nk);
680 free_Key(&nk);
682 * FIXME We need to finish kdc/kadm5/kadmin support for the `etypes' so
683 * we can reduce the number of keys in keytabs to just those in current
684 * use and only of *one* enctype.
686 * What we could do is derive *one* key and for the others output a
687 * one-byte key of the intended enctype (which will never work).
689 * We'll never need any keys but the first one...
693 if (ret)
694 free_Keys(dk);
695 return ret;
698 /* Helper for derive_keys_for_kr() */
699 static krb5_error_code
700 derive_keyset(krb5_context context,
701 const Keys *base_keys,
702 const char *princ,
703 krb5int32 etype,
704 krb5uint32 kvno,
705 KerberosTime set_time, /* "now" */
706 hdb_keyset *dks)
708 dks->kvno = kvno;
709 dks->keys.val = 0;
710 dks->set_time = malloc(sizeof(dks->set_time));
711 if (dks->set_time == NULL)
712 return krb5_enomem(context);
713 *dks->set_time = set_time;
714 return derive_Keys(context, princ, kvno, etype, base_keys, &dks->keys);
717 /* Possibly derive and install in `h' a keyset identified by `t' */
718 static krb5_error_code
719 derive_keys_for_kr(krb5_context context,
720 hdb_entry_ex *h,
721 HDB_Ext_KeySet *base_keys,
722 int is_current_keyset,
723 int rotation_period_offset,
724 const char *princ,
725 krb5int32 etype,
726 krb5uint32 kvno_wanted,
727 KerberosTime t,
728 struct KeyRotation *krp)
730 krb5_error_code ret;
731 hdb_keyset dks;
732 KerberosTime set_time, n;
733 krb5uint32 kvno;
734 size_t i;
736 if (rotation_period_offset < -1 || rotation_period_offset > 1)
737 return EINVAL; /* wat */
740 * Compute `kvno' and `set_time' given `t' and `krp'.
742 * There be signed 32-bit time_t dragons here.
744 * (t - krp->epoch < 0) is better than (krp->epoch < t), making us more
745 * tolerant of signed 32-bit time_t here near 2038. Of course, we have
746 * signed 32-bit time_t dragons elsewhere.
748 if (t - krp->epoch < 0)
749 return 0; /* This KR is not relevant yet */
750 n = (t - krp->epoch) / krp->period;
751 n += rotation_period_offset;
752 set_time = krp->epoch + krp->period * n;
753 kvno = krp->base_kvno + n;
757 * Do not waste cycles computing keys not wanted or needed.
758 * A past kvno is too old if its set_time + rotation period is in the past
759 * by more than half a rotation period, since then no service ticket
760 * encrypted with keys of that kvno can still be extant.
762 * A future kvno is not coming up soon enough if we're more than a quarter
763 * of the rotation period away from it.
765 * Recall: the assumption for virtually-keyed principals is that services
766 * fetch their future keys frequently enough that they'll never miss having
767 * the keys they need.
769 if (!is_current_keyset || rotation_period_offset != 0) {
770 if ((kvno_wanted && kvno != kvno_wanted) ||
771 t - (set_time + krp->period + (krp->period >> 1)) > 0 ||
772 (set_time - t > 0 && (set_time - t) > (krp->period >> 2)))
773 return 0;
776 for (i = 0; i < base_keys->len; i++) {
777 if (base_keys->val[i].kvno == krp->base_key_kvno)
778 break;
780 if (i == base_keys->len) {
781 /* Base key not found! */
782 if (kvno_wanted || is_current_keyset) {
783 krb5_set_error_message(context, ret = HDB_ERR_KVNO_NOT_FOUND,
784 "Base key version %u not found for %s",
785 krp->base_key_kvno, princ);
786 return ret;
788 return 0;
791 ret = derive_keyset(context, &base_keys->val[i].keys, princ, etype, kvno,
792 set_time, &dks);
793 if (ret == 0)
794 ret = hdb_install_keyset(context, &h->entry, is_current_keyset, &dks);
796 free_HDB_keyset(&dks);
797 return ret;
800 /* Derive and install current keys, and possibly preceding or next keys */
801 static krb5_error_code
802 derive_keys_for_current_kr(krb5_context context,
803 hdb_entry_ex *h,
804 HDB_Ext_KeySet *base_keys,
805 const char *princ,
806 unsigned int flags,
807 krb5int32 etype,
808 krb5uint32 kvno_wanted,
809 KerberosTime t,
810 struct KeyRotation *krp,
811 KerberosTime future_epoch)
813 krb5_error_code ret;
815 /* derive_keys_for_kr() for current kvno and install as the current keys */
816 ret = derive_keys_for_kr(context, h, base_keys, 1, 0, princ, etype,
817 kvno_wanted, t, krp);
818 if (!(flags & HDB_F_ALL_KVNOS))
819 return ret;
821 /* */
825 * derive_keys_for_kr() for prev kvno if still needed -- it can only be
826 * needed if the prev kvno's start time is within this KR's epoch.
828 * Note that derive_keys_for_kr() can return without doing anything if this
829 * is isn't the current keyset. So these conditions need not be
830 * sufficiently narrow.
832 if (ret == 0 && t - krp->epoch >= krp->period)
833 ret = derive_keys_for_kr(context, h, base_keys, 0, -1, princ, etype,
834 kvno_wanted, t, krp);
836 * derive_keys_for_kr() for next kvno if near enough, but only if it
837 * doesn't start after the next KR's epoch.
839 if (future_epoch &&
840 t - krp->epoch >= 0 /* We know! Hint to the compiler */) {
841 KerberosTime next_kvno_start, n;
843 n = (t - krp->epoch) / krp->period;
844 next_kvno_start = krp->epoch + krp->period * (n + 1);
845 if (future_epoch - next_kvno_start <= 0)
846 return ret;
848 if (ret == 0)
849 ret = derive_keys_for_kr(context, h, base_keys, 0, 1, princ, etype,
850 kvno_wanted, t, krp);
851 return ret;
855 * Derive and install all keysets in `h' that `princ' needs at time `now'.
857 * This mutates the entry `h' to
859 * a) not have base keys,
860 * b) have keys derived from the base keys according to
861 * c) the key rotation periods for the base principal (possibly the same
862 * principal if it's a concrete principal with virtual keys), and the
863 * requested time, enctype, and kvno (all of which are optional, with zero
864 * implying some default).
866 * Arguments:
868 * - `flags' is the flags passed to `hdb_fetch_kvno()'
869 * - `princ' is the name of the principal we'll end up with in `h->entry'
870 * - `h_is_namespace' indicates whether `h' is for a namespace or a concrete
871 * principal (that might nonetheless have virtual/derived keys)
872 * - `t' is the time such that the derived keys are for kvnos needed at `t'
873 * - `etype' indicates what enctype to derive keys for (0 for all enctypes in
874 * `h->entry.etypes')
875 * - `kvno' requests a particular kvno, or all if zero
877 * The caller doesn't know if the principal needs key derivation -- we make
878 * that determination in this function.
880 * Note that this function is fully deterministic for any given set of
881 * arguments and HDB contents.
883 * Definitions:
885 * - A keyset is a set of keys for a single kvno.
886 * - A keyset is relevant IFF:
887 * - it is the keyset for a time period identified by `t' in a
888 * corresponding KR
889 * - it is a keyset for a past time period for which there may be extant,
890 * not-yet-expired tickets that a service may need to decrypt
891 * - it is a keyset for an upcoming time period that a service will need to
892 * fetch before that time period becomes current, that way the service
893 * can have keytab entries for those keys in time for when the KDC starts
894 * encrypting service tickets to those keys
896 * This function derives the keyset(s) for the current KR first. The idea is
897 * to optimize the order of resulting keytabs so that the most likely keys to
898 * be used come first.
900 * Invariants:
902 * - KR metadata is sane because sanity is checked for when storing HDB
903 * entries
904 * - KRs are sorted by epoch in descending order; KR #0's epoch is the most
905 * recent
906 * - KR periods are non-zero (we divide by period)
907 * - kvnos are numerically ordered and correspond to time periods
908 * - within each KR, the kvnos for larger times are larger than (or equal
909 * to) the kvnos of earlier times
910 * - at KR boundaries, the first kvno of the newer boundary is larger than
911 * the kvno of the last time period of the previous KR
912 * - the time `t' must fall into exactly one KR period
913 * - the time `t' must fall into exactly one period within a KR period
914 * - at most two kvnos will be relevant from the KR that `t' falls into
915 * (the current kvno for `t', and possibly either the preceding, or the
916 * next)
917 * - at most one kvno from non-current KRs will be derived: possibly one for a
918 * preceding KR, and possibly one from an upcoming KR
920 * There can be:
922 * - no KR extension (not a namespace principal, and no virtual keys)
923 * - 1, 2, or 3 KRs (see above)
924 * - the newest KR may have the `deleted' flag, meaning "does not exist after
925 * this epoch"
927 * Note that the last time period in any older KR can be partial.
929 * Timeline diagram:
931 * .......|--+--+...+--|---+---+---+...+--|----+...
932 * T20 T10 T11 RT12 T1n T01
933 * ^ ^ ^ ^ ^ ^ ^ T00
934 * | | | T22 T2n | | ^
935 * ^ | T21 | | |
936 * princ | | epoch of | epoch of
937 * did | | middle KR | newest epoch
938 * not | | |
939 * exist! | start of Note that T1n
940 * | second kvno is shown as shorter
941 * | in 1st epoch than preceding periods
944 * first KR's
945 * epoch, and start
946 * of its first kvno
948 * Tmn == the start of the Mth KR's Nth time period.
949 * (higher M -> older KR; lower M -> newer KR)
950 * (N is the reverse: lower N -> older time period in KR)
951 * T20 == start of oldest KR -- no keys before this time will be derived.
952 * T2n == last time period in oldest KR
953 * T10 == start of middle KR
954 * T1n == last time period in middle KR
955 * T00 == start of newest KR
956 * T0n == current time period in newest KR for wall clock time
958 static krb5_error_code
959 derive_keys(krb5_context context,
960 unsigned flags,
961 krb5_const_principal princ,
962 int h_is_namespace,
963 krb5_timestamp t,
964 krb5int32 etype,
965 krb5uint32 kvno,
966 hdb_entry_ex *h)
968 HDB_Ext_KeyRotation kr;
969 HDB_Ext_KeySet base_keys;
970 krb5_error_code ret = 0;
971 size_t current_kr, future_kr, past_kr, i;
972 char *p = NULL;
973 int valid = 1;
975 if (!h_is_namespace && !h->entry.flags.virtual_keys)
976 return 0;
977 h->entry.flags.virtual = 1;
978 if (h_is_namespace) {
979 /* Set the entry's principal name */
980 free_Principal(h->entry.principal);
981 ret = copy_Principal(princ, h->entry.principal);
984 kr.len = 0;
985 kr.val = 0;
986 if (ret == 0) {
987 const HDB_Ext_KeyRotation *ckr;
989 /* Installing keys invalidates `ckr', so we copy it */
990 ret = hdb_entry_get_key_rotation(context, &h->entry, &ckr);
991 if (ret == 0)
992 ret = copy_HDB_Ext_KeyRotation(ckr, &kr);
995 /* Get the base keys from the entry, and remove them */
996 base_keys.val = 0;
997 base_keys.len = 0;
998 if (ret == 0)
999 ret = hdb_remove_base_keys(context, &h->entry, &base_keys);
1001 /* Make sure we have h->entry.etypes */
1002 if (ret == 0 && !h->entry.etypes)
1003 ret = hdb_derive_etypes(context, &h->entry, &base_keys);
1005 /* Keys not desired? Don't derive them! */
1006 if (ret || !(flags & HDB_F_DECRYPT)) {
1007 free_HDB_Ext_KeyRotation(&kr);
1008 free_HDB_Ext_KeySet(&base_keys);
1009 return ret;
1012 /* The principal name will be used in key derivation and error messages */
1013 if (ret == 0 && h_is_namespace)
1014 ret = krb5_unparse_name(context, princ, &p);
1016 /* Sanity check key rotations, determine current & last kr */
1017 if (ret == 0 && kr.len < 1)
1018 krb5_set_error_message(context, ret = HDB_ERR_NOENTRY,
1019 "no key rotation periods for %s", p);
1020 if (ret == 0)
1021 current_kr = future_kr = past_kr = kr.len;
1022 else
1023 current_kr = future_kr = past_kr = 1;
1026 * Identify a current, next, and previous KRs if there are any.
1028 * There can be up to three KRs, ordered by epoch, descending, making up a
1029 * timeline like:
1031 * ...|---------|--------|------>
1032 * ^ | | |
1033 * | | | |
1034 * | | | Newest KR (kr.val[0])
1035 * | | Middle KR (kr.val[1])
1036 * | Oldest (last) KR (kr.val[2])
1038 * Before the begging of time for this namespace
1040 * We step through these from future towards past looking for the best
1041 * future, current, and past KRs. The best current KR is one that has its
1042 * epoch nearest to `t' but in the past of `t'.
1044 * We validate KRs before storing HDB entries with the KR extension, so we
1045 * can assume they are valid here. However, we do some validity checking,
1046 * and if they're not valid, we pick the best current KR and ignore the
1047 * others.
1049 * In principle there cannot be two future KRs, but this function is
1050 * deterministic and takes a time value, so it should not enforce this just
1051 * so we can test. Enforcement of such rules should be done at store time.
1053 for (i = 0; ret == 0 && i < kr.len; i++) {
1054 /* Minimal validation: order and period */
1055 if (i && kr.val[i - 1].epoch - kr.val[i].epoch <= 0) {
1056 future_kr = past_kr = kr.len;
1057 valid = 0;
1059 if (!kr.val[i].period) {
1060 future_kr = past_kr = kr.len;
1061 valid = 0;
1062 continue;
1064 if (t - kr.val[i].epoch >= 0) {
1066 * `t' is in the future of this KR's epoch, so it's a candidate for
1067 * either current or past KR.
1069 if (current_kr == kr.len)
1070 current_kr = i; /* First curr KR candidate; should be best */
1071 else if (kr.val[current_kr].epoch - kr.val[i].epoch < 0)
1072 current_kr = i; /* Invalid KRs, but better curr KR cand. */
1073 else if (valid && past_kr == kr.len)
1074 past_kr = i;
1075 } else if (valid) {
1076 /* This KR is in the future of `t', a candidate for next KR */
1077 future_kr = i;
1080 if (ret == 0 && current_kr == kr.len)
1081 /* No current KR -> too soon */
1082 krb5_set_error_message(context, ret = HDB_ERR_NOENTRY,
1083 "Too soon for virtual principal to exist");
1085 /* Check that the principal has not been marked deleted */
1086 if (ret == 0 && current_kr < kr.len && kr.val[current_kr].flags.deleted)
1087 krb5_set_error_message(context, ret = HDB_ERR_NOENTRY,
1088 "virtual principal %s does not exist "
1089 "because last key rotation period "
1090 "marks deletion", p);
1093 * Derive and set in `h' its current kvno and current keys.
1095 * This will set h->entry.kvno as well.
1097 * This may set up to TWO keysets for the current key rotation period:
1098 * - current keys (h->entry.keys and h->entry.kvno)
1099 * - possibly one future
1100 * OR
1101 * possibly one past keyset in hist_keys for the current_kr
1103 if (ret == 0 && current_kr < kr.len)
1104 ret = derive_keys_for_current_kr(context, h, &base_keys, p, flags,
1105 etype, kvno, t, &kr.val[current_kr],
1106 current_kr ? kr.val[0].epoch : 0);
1109 * Derive and set in `h' its future keys for next KR if it is soon to be
1110 * current.
1112 * We want to derive keys for the first kvno of the next (future) KR if
1113 * it's sufficiently close to `t', meaning within 1 period of the current
1114 * KR, but we want these keys to be available sooner, so 1.5 of the current
1115 * period.
1117 if (ret == 0 && future_kr < kr.len && (flags & HDB_F_ALL_KVNOS))
1118 ret = derive_keys_for_kr(context, h, &base_keys, 0, 0, p, etype, kvno,
1119 kr.val[future_kr].epoch, &kr.val[future_kr]);
1122 * Derive and set in `h' its past keys for the previous KR if its last time
1123 * period could still have extant, unexpired service tickets encrypted in
1124 * its keys.
1126 if (ret == 0 && past_kr < kr.len && (flags & HDB_F_ALL_KVNOS))
1127 ret = derive_keys_for_kr(context, h, &base_keys, 0, 0, p, etype, kvno,
1128 kr.val[current_kr].epoch - 1, &kr.val[past_kr]);
1131 * Impose a bound on h->entry.max_life so that [when the KDC is the caller]
1132 * the KDC won't issue tickets longer lived than this.
1134 if (ret == 0 && !h->entry.max_life &&
1135 (h->entry.max_life = malloc(sizeof(h->entry.max_life[0]))) == NULL)
1136 ret = krb5_enomem(context);
1137 if (ret == 0 && *h->entry.max_life > kr.val[current_kr].period >> 1)
1138 *h->entry.max_life = kr.val[current_kr].period >> 1;
1140 free_HDB_Ext_KeyRotation(&kr);
1141 free_HDB_Ext_KeySet(&base_keys);
1142 free(p);
1143 return ret;
1147 * In order for disparate keytab provisioning systems such as OSKT and our own
1148 * kadmin ext_keytab and httpkadmind's get-keys to coexist, we need to be able
1149 * to force keys set by the former to not become current keys until users of
1150 * the latter have had a chance to fetch those keys into their keytabs. To do
1151 * this we have to search the list of keys in the entry looking for the newest
1152 * keys older than `now - db->new_service_key_delay'.
1154 * The context is that OSKT's krb5_keytab is very happy to change keys in a way
1155 * that requires all members of a cluster to rekey together. If one also
1156 * wishes to have cluster members that opt out of this and just fetch current,
1157 * past, and future keys periodically, then the keys set by OSKT need to not
1158 * come into effect until all the opt-out members have had a chance to fetch
1159 * the new keys.
1161 * The assumption is that services will fetch new keys periodically, say, every
1162 * four hours. Then one can set `[hdb] new_service_key_delay = 8h' in the
1163 * configuration and new keys set by OSKT will not be used until 8h after they
1164 * are set.
1166 * Naturally, this applies only to concrete principals with concrete keys.
1168 static krb5_error_code
1169 fix_keys(krb5_context context,
1170 HDB *db,
1171 unsigned flags,
1172 krb5_timestamp now,
1173 krb5uint32 kvno,
1174 hdb_entry_ex *h)
1176 HDB_extension *ext;
1177 HDB_Ext_KeySet keys;
1178 time_t current = 0;
1179 time_t best;
1180 size_t i;
1183 * If we want a specific kvno, or if the caller doesn't want new keys
1184 * delayed, or if there's no new-key delay configured, or we're not
1185 * fetching for use as a service principal, then we're out.
1187 if (!(flags & HDB_F_DELAY_NEW_KEYS) || kvno || h->entry.flags.virtual ||
1188 h->entry.flags.virtual_keys || db->new_service_key_delay <= 0)
1189 return 0;
1191 /* No history -> current keyset is the only one and therefore the best */
1192 ext = hdb_find_extension(&h->entry, choice_HDB_extension_data_hist_keys);
1193 if (!ext)
1194 return 0;
1196 /* Assume the current keyset is the best to start with */
1197 (void) hdb_entry_get_pw_change_time(&h->entry, &current);
1198 if (current == 0 && h->entry.modified_by)
1199 current = h->entry.modified_by->time;
1200 if (current == 0)
1201 current = h->entry.created_by.time;
1203 /* Current keyset starts out as best */
1204 best = current;
1205 kvno = h->entry.kvno;
1207 /* Look for a better keyset in the history */
1208 keys = ext->data.u.hist_keys;
1209 for (i = 0; i < keys.len; i++) {
1210 /* No set_time? Ignore. Too new? Ignore */
1211 if (!keys.val[i].set_time ||
1212 keys.val[i].set_time[0] + db->new_service_key_delay > now)
1213 continue;
1216 * Ignore the keyset with kvno 1 when the entry has better kvnos
1217 * because kadmin's `ank -r' command immediately changes the keys.
1219 if (kvno > 1 && keys.val[i].kvno == 1)
1220 continue;
1223 * This keyset's set_time older than the previous best? Ignore.
1224 * However, if the current best is the entry's current and that one
1225 * is too new, then don't ignore this one.
1227 if (keys.val[i].set_time[0] < best &&
1228 (best != current || current + db->new_service_key_delay < now))
1229 continue;
1232 * If two good enough keysets have the same set_time, take the keyset
1233 * with the highest kvno.
1235 if (keys.val[i].set_time[0] == best && keys.val[i].kvno <= kvno)
1236 continue;
1239 * This keyset is clearly more current than the previous best keyset
1240 * but still old enough to use for encrypting tickets with.
1242 best = keys.val[i].set_time[0];
1243 kvno = keys.val[i].kvno;
1245 return hdb_change_kvno(context, kvno, &h->entry);
1249 * Make a WELLKNOWN/HOSTBASED-NAMESPACE/${svc}/${hostname} or
1250 * WELLKNOWN/HOSTBASED-NAMESPACE/${svc}/${hostname}/${domainname} principal
1251 * object, with the service and hostname components take from `wanted', but if
1252 * the service name is not in the list `db->virtual_hostbased_princ_svcs[]'
1253 * then use "_" (wildcard) instead. This way we can have different attributes
1254 * for different services in the same namespaces.
1256 * For example, virtual hostbased service names for the "host" service might
1257 * have ok-as-delegate set, but ones for the "HTTP" service might not.
1259 static krb5_error_code
1260 make_namespace_princ(krb5_context context,
1261 HDB *db,
1262 krb5_const_principal wanted,
1263 krb5_principal *namespace)
1265 krb5_error_code ret = 0;
1266 const char *realm = krb5_principal_get_realm(context, wanted);
1267 const char *comp0 = krb5_principal_get_comp_string(context, wanted, 0);
1268 const char *comp1 = krb5_principal_get_comp_string(context, wanted, 1);
1269 const char *comp2 = krb5_principal_get_comp_string(context, wanted, 2);
1270 char * const *svcs = db->virtual_hostbased_princ_svcs;
1271 size_t i;
1273 *namespace = NULL;
1274 if (comp0 == NULL || comp1 == NULL)
1275 return EINVAL;
1276 if (strcmp(comp0, "krbtgt") == 0)
1277 return 0;
1279 for (i = 0; svcs && svcs[i]; i++) {
1280 if (strcmp(comp0, svcs[i]) == 0) {
1281 comp0 = svcs[i];
1282 break;
1285 if (!svcs || !svcs[i])
1286 comp0 = "_";
1288 /* First go around, need a namespace princ. Make it! */
1289 ret = krb5_build_principal(context, namespace, strlen(realm),
1290 realm, "WELLKNOWN",
1291 HDB_WK_NAMESPACE, comp0, NULL);
1292 if (ret == 0)
1293 ret = krb5_principal_set_comp_string(context, *namespace, 3, comp1);
1294 if (ret == 0 && comp2)
1295 /* Support domain-based names */
1296 ret = krb5_principal_set_comp_string(context, *namespace, 4, comp2);
1297 /* Caller frees `*namespace' on error */
1298 return ret;
1301 /* Wrapper around db->hdb_fetch_kvno() that implements virtual princs/keys */
1302 static krb5_error_code
1303 fetch_it(krb5_context context,
1304 HDB *db,
1305 krb5_const_principal princ,
1306 unsigned flags,
1307 krb5_timestamp t,
1308 krb5int32 etype,
1309 krb5uint32 kvno,
1310 hdb_entry_ex *ent)
1312 krb5_const_principal tmpprinc = princ;
1313 krb5_principal baseprinc = NULL;
1314 krb5_error_code ret = 0;
1315 const char *comp0 = krb5_principal_get_comp_string(context, princ, 0);
1316 const char *comp1 = krb5_principal_get_comp_string(context, princ, 1);
1317 const char *tmp;
1318 size_t mindots = db->virtual_hostbased_princ_ndots;
1319 size_t maxdots = db->virtual_hostbased_princ_maxdots;
1320 size_t hdots = 0;
1321 char *host = NULL;
1322 int do_search = 0;
1324 if (db->enable_virtual_hostbased_princs && comp1 &&
1325 strcmp("krbtgt", comp0) != 0 && strcmp("WELLKNOWN", comp0) != 0) {
1326 char *htmp;
1328 if ((host = strdup(comp1)) == NULL)
1329 return krb5_enomem(context);
1331 /* Strip out any :port */
1332 htmp = strchr(host, ':');
1333 if (htmp) {
1334 if (strchr(htmp + 1, ':')) {
1335 /* Extra ':'s? No virtualization for you! */
1336 free(host);
1337 host = NULL;
1338 htmp = NULL;
1339 } else {
1340 *htmp = '\0';
1343 /* Count dots in `host' */
1344 for (hdots = 0, htmp = host; htmp && *htmp; htmp++)
1345 if (*htmp == '.')
1346 hdots++;
1348 do_search = 1;
1351 tmp = host ? host : comp1;
1352 for (ret = HDB_ERR_NOENTRY; ret == HDB_ERR_NOENTRY; tmpprinc = baseprinc) {
1353 krb5_error_code ret2 = 0;
1356 * We break out of this loop with ret == 0 only if we found the HDB
1357 * entry we were looking for or the HDB entry for a matching namespace.
1359 * Otherwise we break out with ret != 0, typically HDB_ERR_NOENTRY.
1361 * First time through we lookup the principal as given.
1363 * Next we lookup a namespace principal, stripping off hostname labels
1364 * from the left until we find one or get tired of looking or run out
1365 * of labels.
1367 ret = db->hdb_fetch_kvno(context, db, tmpprinc, flags, kvno, ent);
1368 if (ret != HDB_ERR_NOENTRY || hdots == 0 || hdots < mindots || !tmp ||
1369 !do_search)
1370 break;
1373 * Breadcrumb:
1375 * - if we found a concrete principal, but it's been marked
1376 * as now-virtual, then we must keep going
1378 * But this will be coded in the future.
1380 * Maybe we can take attributes from the concrete principal...
1384 * The namespace's hostname will not have more labels than maxdots + 1.
1385 * Thus we truncate immediately down to maxdots + 1 if we haven't yet.
1387 * Example: with maxdots == 3,
1388 * foo.bar.baz.app.blah.example -> baz.app.blah.example
1390 while (maxdots && hdots > maxdots && tmp) {
1391 tmp = strchr(tmp, '.');
1392 /* tmp != NULL because maxdots > 0 */
1393 tmp++;
1394 hdots--;
1397 if (baseprinc == NULL)
1398 /* First go around, need a namespace princ. Make it! */
1399 ret2 = make_namespace_princ(context, db, tmpprinc, &baseprinc);
1400 /* Update the hostname component */
1401 if (ret2 == 0)
1402 ret2 = krb5_principal_set_comp_string(context, baseprinc, 3, tmp);
1403 if (ret2)
1404 ret = ret2;
1406 if (tmp) {
1407 /* Strip off left-most label for the next go-around */
1408 if ((tmp = strchr(tmp, '.')))
1409 tmp++;
1410 hdots--;
1411 } /* else we'll break out after the next db->hdb_fetch_kvno() call */
1415 * If unencrypted keys were requested, derive them. There may not be any
1416 * key derivation to do, but that's decided in derive_keys().
1418 if (ret == 0) {
1419 ret = derive_keys(context, flags, princ, !!baseprinc, t, etype, kvno,
1420 ent);
1421 if (ret == 0)
1422 ret = fix_keys(context, db, flags, t, kvno, ent);
1423 if (ret)
1424 hdb_free_entry(context, ent);
1426 krb5_free_principal(context, baseprinc);
1427 free(host);
1428 return ret;
1432 * Fetch a principal's HDB entry, possibly generating virtual keys from base
1433 * keys according to strict key rotation schedules. If a time is given, other
1434 * than HDB I/O, this function is pure, thus usable for testing.
1436 * HDB writers should use `db->hdb_fetch_kvno()' to avoid materializing virtual
1437 * principals.
1439 * HDB readers should use this function rather than `db->hdb_fetch_kvno()'
1440 * unless they only want to see concrete principals and not bother generating
1441 * any virtual keys.
1443 * @param context Context
1444 * @param db HDB
1445 * @param principal Principal name
1446 * @param flags Fetch flags
1447 * @param t For virtual keys, use this as the point in time (use zero to mean "now")
1448 * @param etype Key enctype (use KRB5_ENCTYPE_NULL to mean "preferred")
1449 * @param kvno Key version number (use zero to mean "current")
1450 * @param h Output HDB entry
1452 * @return Zero on success, an error code otherwise.
1454 krb5_error_code
1455 hdb_fetch_kvno(krb5_context context,
1456 HDB *db,
1457 krb5_const_principal principal,
1458 unsigned int flags,
1459 krb5_timestamp t,
1460 krb5int32 etype,
1461 krb5uint32 kvno,
1462 hdb_entry_ex *h)
1464 krb5_error_code ret = HDB_ERR_NOENTRY;
1466 flags |= kvno ? HDB_F_KVNO_SPECIFIED : 0; /* XXX is this needed */
1467 if (t == 0)
1468 krb5_timeofday(context, &t);
1469 ret = fetch_it(context, db, principal, flags, t, etype, kvno, h);
1470 if (ret == HDB_ERR_NOENTRY)
1471 krb5_set_error_message(context, ret, "no such entry found in hdb");
1472 return ret;
1475 size_t ASN1CALL
1476 length_hdb_keyset(HDB_keyset *data)
1478 return length_HDB_keyset(data);
1481 size_t ASN1CALL
1482 length_hdb_entry(HDB_entry *data)
1484 return length_HDB_entry(data);
1487 size_t ASN1CALL
1488 length_hdb_entry_alias(HDB_entry_alias *data)
1490 return length_HDB_entry_alias(data);
1493 void ASN1CALL
1494 free_hdb_keyset(HDB_keyset *data)
1496 free_HDB_keyset(data);
1499 void ASN1CALL
1500 free_hdb_entry(HDB_entry *data)
1502 free_HDB_entry(data);
1505 void ASN1CALL
1506 free_hdb_entry_alias(HDB_entry_alias *data)
1508 free_HDB_entry_alias(data);
1511 size_t ASN1CALL
1512 copy_hdb_keyset(const HDB_keyset *from, HDB_keyset *to)
1514 return copy_HDB_keyset(from, to);
1517 size_t ASN1CALL
1518 copy_hdb_entry(const HDB_entry *from, HDB_entry *to)
1520 return copy_HDB_entry(from, to);
1523 size_t ASN1CALL
1524 copy_hdb_entry_alias(const HDB_entry_alias *from, HDB_entry_alias *to)
1526 return copy_HDB_entry_alias(from, to);
1529 int ASN1CALL
1530 decode_hdb_keyset(const unsigned char *p,
1531 size_t len,
1532 HDB_keyset *data,
1533 size_t *size)
1535 return decode_HDB_keyset(p, len, data, size);
1538 int ASN1CALL
1539 decode_hdb_entry(const unsigned char *p,
1540 size_t len,
1541 HDB_entry *data,
1542 size_t *size)
1544 return decode_HDB_entry(p, len, data, size);
1547 int ASN1CALL
1548 decode_hdb_entry_alias(const unsigned char *p,
1549 size_t len,
1550 HDB_entry_alias *data,
1551 size_t *size)
1553 return decode_HDB_entry_alias(p, len, data, size);
1556 int ASN1CALL
1557 encode_hdb_keyset(unsigned char *p,
1558 size_t len,
1559 const HDB_keyset *data,
1560 size_t *size)
1562 return encode_HDB_keyset(p, len, data, size);
1565 int ASN1CALL
1566 encode_hdb_entry(unsigned char *p,
1567 size_t len,
1568 const HDB_entry *data,
1569 size_t *size)
1571 return encode_HDB_entry(p, len, data, size);
1574 int ASN1CALL
1575 encode_hdb_entry_alias(unsigned char *p,
1576 size_t len,
1577 const HDB_entry_alias *data,
1578 size_t *size)
1580 return encode_HDB_entry_alias(p, len, data, size);