Line data Source code
1 : /*
2 : * Copyright (c) 1997-2002 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 "krb5_locl.h"
35 : #include "hdb_locl.h"
36 :
37 : int
38 0 : hdb_principal2key(krb5_context context, krb5_const_principal p, krb5_data *key)
39 : {
40 0 : Principal new;
41 0 : size_t len = 0;
42 0 : int ret;
43 :
44 0 : ret = copy_Principal(p, &new);
45 0 : if(ret)
46 0 : return ret;
47 0 : new.name.name_type = 0;
48 :
49 0 : ASN1_MALLOC_ENCODE(Principal, key->data, key->length, &new, &len, ret);
50 0 : if (ret == 0 && key->length != len)
51 0 : krb5_abortx(context, "internal asn.1 encoder error");
52 0 : free_Principal(&new);
53 0 : return ret;
54 : }
55 :
56 : int
57 0 : hdb_key2principal(krb5_context context, krb5_data *key, krb5_principal p)
58 : {
59 0 : return decode_Principal(key->data, key->length, p, NULL);
60 : }
61 :
62 : int
63 0 : hdb_entry2value(krb5_context context, const hdb_entry *ent, krb5_data *value)
64 : {
65 0 : size_t len = 0;
66 0 : int ret;
67 :
68 0 : ASN1_MALLOC_ENCODE(HDB_entry, value->data, value->length, ent, &len, ret);
69 0 : if (ret == 0 && value->length != len)
70 0 : krb5_abortx(context, "internal asn.1 encoder error");
71 0 : return ret;
72 : }
73 :
74 : int
75 0 : hdb_value2entry(krb5_context context, krb5_data *value, hdb_entry *ent)
76 : {
77 0 : return decode_HDB_entry(value->data, value->length, ent, NULL);
78 : }
79 :
80 : int
81 0 : hdb_entry_alias2value(krb5_context context,
82 : const hdb_entry_alias *alias,
83 : krb5_data *value)
84 : {
85 0 : size_t len = 0;
86 0 : int ret;
87 :
88 0 : ASN1_MALLOC_ENCODE(HDB_entry_alias, value->data, value->length,
89 : alias, &len, ret);
90 0 : if (ret == 0 && value->length != len)
91 0 : krb5_abortx(context, "internal asn.1 encoder error");
92 0 : return ret;
93 : }
94 :
95 : int
96 0 : hdb_value2entry_alias(krb5_context context, krb5_data *value,
97 : hdb_entry_alias *ent)
98 : {
99 0 : return decode_HDB_entry_alias(value->data, value->length, ent, NULL);
100 : }
101 :
102 : /*
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.
107 : */
108 : static krb5_error_code
109 0 : add_default_salts(krb5_context context, HDB *db, hdb_entry *entry)
110 : {
111 0 : krb5_error_code ret;
112 0 : size_t i;
113 0 : krb5_salt pwsalt;
114 :
115 0 : ret = krb5_get_pw_salt(context, entry->principal, &pwsalt);
116 0 : if (ret)
117 0 : return ret;
118 :
119 0 : for (i = 0; i < entry->keys.len; i++) {
120 0 : Key *key = &entry->keys.val[i];
121 :
122 0 : if (key->salt != NULL ||
123 0 : _krb5_enctype_requires_random_salt(context, key->key.keytype))
124 0 : continue;
125 :
126 0 : key->salt = calloc(1, sizeof(*key->salt));
127 0 : if (key->salt == NULL) {
128 0 : ret = krb5_enomem(context);
129 0 : break;
130 : }
131 :
132 0 : key->salt->type = KRB5_PADATA_PW_SALT;
133 :
134 0 : ret = krb5_data_copy(&key->salt->salt,
135 0 : pwsalt.saltvalue.data,
136 : pwsalt.saltvalue.length);
137 0 : if (ret)
138 0 : break;
139 : }
140 :
141 0 : krb5_free_salt(context, pwsalt);
142 :
143 0 : return ret;
144 : }
145 :
146 : static krb5_error_code
147 0 : fetch_entry_or_alias(krb5_context context,
148 : HDB *db,
149 : krb5_const_principal principal,
150 : unsigned flags,
151 : hdb_entry *entry)
152 : {
153 0 : HDB_EntryOrAlias eoa;
154 0 : krb5_principal enterprise_principal = NULL;
155 0 : krb5_data key, value;
156 0 : krb5_error_code ret;
157 :
158 0 : value.length = 0;
159 0 : value.data = 0;
160 0 : key = value;
161 :
162 0 : if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
163 0 : if (principal->name.name_string.len != 1) {
164 0 : ret = KRB5_PARSE_MALFORMED;
165 0 : krb5_set_error_message(context, ret, "malformed principal: "
166 : "enterprise name with %d name components",
167 0 : principal->name.name_string.len);
168 0 : return ret;
169 : }
170 0 : ret = krb5_parse_name(context, principal->name.name_string.val[0],
171 : &enterprise_principal);
172 0 : if (ret)
173 0 : return ret;
174 0 : principal = enterprise_principal;
175 : }
176 :
177 0 : ret = hdb_principal2key(context, principal, &key);
178 0 : if (ret == 0)
179 0 : ret = db->hdb__get(context, db, key, &value);
180 0 : if (ret == 0)
181 0 : ret = decode_HDB_EntryOrAlias(value.data, value.length, &eoa, NULL);
182 0 : if (ret == 0 && eoa.element == choice_HDB_EntryOrAlias_entry) {
183 0 : *entry = eoa.u.entry;
184 0 : entry->aliased = 0;
185 0 : } else if (ret == 0 && eoa.element == choice_HDB_EntryOrAlias_alias) {
186 0 : krb5_data_free(&key);
187 0 : ret = hdb_principal2key(context, eoa.u.alias.principal, &key);
188 0 : if (ret == 0) {
189 0 : krb5_data_free(&value);
190 0 : ret = db->hdb__get(context, db, key, &value);
191 : }
192 0 : if (ret == 0)
193 : /* No alias chaining */
194 0 : ret = hdb_value2entry(context, &value, entry);
195 0 : krb5_free_principal(context, eoa.u.alias.principal);
196 0 : entry->aliased = 1;
197 0 : } else if (ret == 0)
198 0 : ret = ENOTSUP;
199 0 : if (ret == 0 && enterprise_principal) {
200 : /*
201 : * Whilst Windows does not canonicalize enterprise principal names if
202 : * the canonicalize flag is unset, the original specification in
203 : * draft-ietf-krb-wg-kerberos-referrals-03.txt says we should.
204 : */
205 0 : entry->flags.force_canonicalize = 1;
206 : }
207 :
208 : #if 0
209 : /* HDB_F_GET_ANY indicates request originated from KDC (not kadmin) */
210 : if (ret == 0 && eoa.element == choice_HDB_EntryOrAlias_alias &&
211 : (flags & (HDB_F_CANON|HDB_F_GET_ANY)) == 0) {
212 :
213 : /* `principal' was alias but canon not req'd */
214 : free_HDB_entry(entry);
215 : ret = HDB_ERR_NOENTRY;
216 : }
217 : #endif
218 :
219 0 : krb5_free_principal(context, enterprise_principal);
220 0 : krb5_data_free(&value);
221 0 : krb5_data_free(&key);
222 0 : principal = enterprise_principal = NULL;
223 0 : return ret;
224 : }
225 :
226 : /*
227 : * We have only one type of aliases in our HDB entries, but we really need two:
228 : * hard and soft.
229 : *
230 : * Hard aliases should be treated as if they were distinct principals with the
231 : * same keys.
232 : *
233 : * Soft aliases should be treated as configuration to issue referrals, and they
234 : * can only result in referrals to other realms.
235 : *
236 : * Rather than add a type of aliases, we'll use a convention where the form of
237 : * the target of the alias indicates whether the alias is hard or soft.
238 : *
239 : * TODO We could also use an attribute of the aliased entry.
240 : */
241 : static int
242 0 : is_soft_alias_p(krb5_context context,
243 : krb5_const_principal principal,
244 : unsigned int flags,
245 : hdb_entry *h)
246 : {
247 : /* Target is a WELLKNOWN/REFERRALS/TARGET/... -> soft alias */
248 0 : if (krb5_principal_get_num_comp(context, h->principal) >= 3 &&
249 0 : strcmp(krb5_principal_get_comp_string(context, h->principal, 0),
250 0 : KRB5_WELLKNOWN_NAME) == 0 &&
251 0 : strcmp(krb5_principal_get_comp_string(context, h->principal, 1),
252 0 : "REFERRALS") == 0 &&
253 0 : strcmp(krb5_principal_get_comp_string(context, h->principal, 2),
254 : "TARGET") == 0)
255 0 : return 1;
256 :
257 : /*
258 : * Pre-8.0 we had only soft aliases for a while, and one site used aliases
259 : * of referrals-targetNN@TARGET-REALM.
260 : */
261 0 : if (krb5_principal_get_num_comp(context, h->principal) == 1 &&
262 0 : strncmp("referrals-target",
263 0 : krb5_principal_get_comp_string(context, h->principal, 0),
264 : sizeof("referrals-target") - 1) == 0)
265 0 : return 1;
266 :
267 : /* All other cases are hard aliases */
268 0 : return 0;
269 : }
270 :
271 : krb5_error_code
272 0 : _hdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal,
273 : unsigned flags, krb5_kvno kvno, hdb_entry *entry)
274 : {
275 0 : krb5_error_code ret;
276 0 : int soft_aliased = 0;
277 0 : int same_realm;
278 :
279 0 : ret = fetch_entry_or_alias(context, db, principal, flags, entry);
280 0 : if (ret)
281 0 : return ret;
282 :
283 0 : if ((flags & HDB_F_DECRYPT) && (flags & HDB_F_ALL_KVNOS)) {
284 : /* Decrypt the current keys */
285 0 : ret = hdb_unseal_keys(context, db, entry);
286 0 : if (ret) {
287 0 : hdb_free_entry(context, db, entry);
288 0 : return ret;
289 : }
290 : /* Decrypt the key history too */
291 0 : ret = hdb_unseal_keys_kvno(context, db, 0, flags, entry);
292 0 : if (ret) {
293 0 : hdb_free_entry(context, db, entry);
294 0 : return ret;
295 : }
296 0 : } else if ((flags & HDB_F_DECRYPT)) {
297 0 : if ((flags & HDB_F_KVNO_SPECIFIED) == 0 || kvno == entry->kvno) {
298 : /* Decrypt the current keys */
299 0 : ret = hdb_unseal_keys(context, db, entry);
300 0 : if (ret) {
301 0 : hdb_free_entry(context, db, entry);
302 0 : return ret;
303 : }
304 : } else {
305 0 : if ((flags & HDB_F_ALL_KVNOS))
306 0 : kvno = 0;
307 : /*
308 : * Find and decrypt the keys from the history that we want,
309 : * and swap them with the current keys
310 : */
311 0 : ret = hdb_unseal_keys_kvno(context, db, kvno, flags, entry);
312 0 : if (ret) {
313 0 : hdb_free_entry(context, db, entry);
314 0 : return ret;
315 : }
316 : }
317 : }
318 0 : if ((flags & HDB_F_FOR_AS_REQ) && (flags & HDB_F_GET_CLIENT)) {
319 : /*
320 : * Generate default salt for any principals missing one; note such
321 : * principals could include those for which a random (non-password)
322 : * key was generated, but given the salt will be ignored by a keytab
323 : * client it doesn't hurt to include the default salt.
324 : */
325 0 : ret = add_default_salts(context, db, entry);
326 0 : if (ret) {
327 0 : hdb_free_entry(context, db, entry);
328 0 : return ret;
329 : }
330 : }
331 :
332 0 : if (!entry->aliased)
333 0 : return 0;
334 :
335 0 : soft_aliased = is_soft_alias_p(context, principal, flags, entry);
336 :
337 : /* Never return HDB_ERR_WRONG_REALM to kadm5 or other non-KDC callers */
338 0 : if ((flags & HDB_F_ADMIN_DATA))
339 0 : return 0;
340 :
341 0 : same_realm = krb5_realm_compare(context, principal, entry->principal);
342 :
343 0 : if (entry->aliased && !soft_aliased) {
344 : /*
345 : * This is a hard alias. We'll make the entry's name be the same as
346 : * the alias.
347 : *
348 : * Except, we allow for disabling this for same-realm aliases, mainly
349 : * for our tests.
350 : */
351 0 : if (same_realm &&
352 0 : krb5_config_get_bool_default(context, NULL, FALSE, "hdb",
353 : "same_realm_aliases_are_soft", NULL))
354 0 : return 0;
355 :
356 : /* EPNs are always soft */
357 0 : if (principal->name.name_type != KRB5_NT_ENTERPRISE_PRINCIPAL) {
358 0 : krb5_free_principal(context, entry->principal);
359 0 : ret = krb5_copy_principal(context, principal, &entry->principal);
360 0 : if (ret) {
361 0 : hdb_free_entry(context, db, entry);
362 0 : return ret;
363 : }
364 : }
365 0 : return 0;
366 : }
367 :
368 : /* Same realm -> not a referral, therefore this is a hard alias */
369 0 : if (same_realm) {
370 0 : if (soft_aliased) {
371 : /* Soft alias to the same realm?! No. */
372 0 : hdb_free_entry(context, db, entry);
373 0 : return HDB_ERR_NOENTRY;
374 : }
375 0 : return 0;
376 : }
377 :
378 : /* Not same realm && not hard alias */
379 0 : return HDB_ERR_WRONG_REALM;
380 : }
381 :
382 : static krb5_error_code
383 0 : hdb_remove_aliases(krb5_context context, HDB *db, krb5_data *key)
384 : {
385 0 : const HDB_Ext_Aliases *aliases;
386 0 : krb5_error_code code;
387 0 : hdb_entry oldentry;
388 0 : krb5_data value;
389 0 : size_t i;
390 :
391 0 : code = db->hdb__get(context, db, *key, &value);
392 0 : if (code == HDB_ERR_NOENTRY)
393 0 : return 0;
394 0 : else if (code)
395 0 : return code;
396 :
397 0 : code = hdb_value2entry(context, &value, &oldentry);
398 0 : krb5_data_free(&value);
399 0 : if (code)
400 0 : return code;
401 :
402 0 : code = hdb_entry_get_aliases(&oldentry, &aliases);
403 0 : if (code || aliases == NULL) {
404 0 : free_HDB_entry(&oldentry);
405 0 : return code;
406 : }
407 0 : for (i = 0; i < aliases->aliases.len; i++) {
408 0 : krb5_data akey;
409 :
410 0 : code = hdb_principal2key(context, &aliases->aliases.val[i], &akey);
411 0 : if (code == 0) {
412 0 : code = db->hdb__del(context, db, akey);
413 0 : krb5_data_free(&akey);
414 0 : if (code == HDB_ERR_NOENTRY)
415 0 : code = 0;
416 : }
417 0 : if (code) {
418 0 : free_HDB_entry(&oldentry);
419 0 : return code;
420 : }
421 : }
422 0 : free_HDB_entry(&oldentry);
423 0 : return 0;
424 : }
425 :
426 : static krb5_error_code
427 0 : hdb_add_aliases(krb5_context context, HDB *db,
428 : unsigned flags, hdb_entry *entry)
429 : {
430 0 : const HDB_Ext_Aliases *aliases;
431 0 : krb5_error_code code;
432 0 : krb5_data key, value;
433 0 : size_t i;
434 :
435 0 : code = hdb_entry_get_aliases(entry, &aliases);
436 0 : if (code || aliases == NULL)
437 0 : return code;
438 :
439 0 : for (i = 0; i < aliases->aliases.len; i++) {
440 0 : hdb_entry_alias entryalias;
441 0 : entryalias.principal = entry->principal;
442 :
443 0 : code = hdb_entry_alias2value(context, &entryalias, &value);
444 0 : if (code)
445 0 : return code;
446 :
447 0 : code = hdb_principal2key(context, &aliases->aliases.val[i], &key);
448 0 : if (code == 0) {
449 0 : code = db->hdb__put(context, db, flags, key, value);
450 0 : krb5_data_free(&key);
451 0 : if (code == HDB_ERR_EXISTS)
452 : /*
453 : * Assuming hdb_check_aliases() was called, this must be a
454 : * duplicate in the alias list.
455 : */
456 0 : code = 0;
457 : }
458 0 : krb5_data_free(&value);
459 0 : if (code)
460 0 : return code;
461 : }
462 0 : return 0;
463 : }
464 :
465 : /* Check if new aliases are already used for other entries */
466 : static krb5_error_code
467 0 : hdb_check_aliases(krb5_context context, HDB *db, hdb_entry *entry)
468 : {
469 0 : const HDB_Ext_Aliases *aliases = NULL;
470 0 : HDB_EntryOrAlias eoa;
471 0 : krb5_data akey, value;
472 0 : size_t i;
473 0 : int ret;
474 :
475 0 : memset(&eoa, 0, sizeof(eoa));
476 0 : krb5_data_zero(&value);
477 0 : akey = value;
478 :
479 0 : ret = hdb_entry_get_aliases(entry, &aliases);
480 0 : for (i = 0; ret == 0 && aliases && i < aliases->aliases.len; i++) {
481 0 : ret = hdb_principal2key(context, &aliases->aliases.val[i], &akey);
482 0 : if (ret == 0)
483 0 : ret = db->hdb__get(context, db, akey, &value);
484 0 : if (ret == 0)
485 0 : ret = decode_HDB_EntryOrAlias(value.data, value.length, &eoa, NULL);
486 0 : if (ret == 0 && eoa.element != choice_HDB_EntryOrAlias_entry &&
487 0 : eoa.element != choice_HDB_EntryOrAlias_alias)
488 0 : ret = ENOTSUP;
489 0 : if (ret == 0 && eoa.element == choice_HDB_EntryOrAlias_entry)
490 : /* New alias names an existing non-alias entry in the HDB */
491 0 : ret = HDB_ERR_EXISTS;
492 0 : if (ret == 0 && eoa.element == choice_HDB_EntryOrAlias_alias &&
493 0 : !krb5_principal_compare(context, eoa.u.alias.principal,
494 0 : entry->principal))
495 : /* New alias names an existing alias of a different entry */
496 0 : ret = HDB_ERR_EXISTS;
497 0 : if (ret == HDB_ERR_NOENTRY) /* from db->hdb__get */
498 : /* New alias is a name that doesn't exist in the HDB */
499 0 : ret = 0;
500 :
501 0 : free_HDB_EntryOrAlias(&eoa);
502 0 : krb5_data_free(&value);
503 0 : krb5_data_free(&akey);
504 : }
505 0 : return ret;
506 : }
507 :
508 : /*
509 : * Many HDB entries don't have `etypes' setup. Historically we use the
510 : * enctypes of the selected keyset as the entry's supported enctypes, but that
511 : * is problematic. By doing this at store time and, if need be, at fetch time,
512 : * we can make sure to stop deriving supported etypes from keys in the long
513 : * run. We also need kadm5/kadmin support for etypes. We'll use this function
514 : * there to derive etypes when using a kadm5_principal_ent_t that lacks the new
515 : * TL data for etypes.
516 : */
517 : krb5_error_code
518 0 : hdb_derive_etypes(krb5_context context, hdb_entry *e, HDB_Ext_KeySet *base_keys)
519 : {
520 0 : krb5_error_code ret = 0;
521 0 : size_t i, k, netypes;
522 0 : HDB_extension *ext;
523 :
524 0 : if (!base_keys &&
525 0 : (ext = hdb_find_extension(e, choice_HDB_extension_data_hist_keys)))
526 0 : base_keys = &ext->data.u.hist_keys;
527 :
528 0 : netypes = e->keys.len;
529 0 : if (netypes == 0 && base_keys) {
530 : /* There's no way that base_keys->val[i].keys.len == 0, but hey */
531 0 : for (i = 0; netypes == 0 && i < base_keys->len; i++)
532 0 : netypes = base_keys->val[i].keys.len;
533 : }
534 :
535 0 : if (netypes == 0)
536 0 : return 0;
537 :
538 0 : if (e->etypes != NULL) {
539 0 : free(e->etypes->val);
540 0 : e->etypes->len = 0;
541 0 : e->etypes->val = 0;
542 0 : } else if ((e->etypes = calloc(1, sizeof(e->etypes[0]))) == NULL) {
543 0 : ret = krb5_enomem(context);
544 : }
545 0 : if (ret == 0 &&
546 0 : (e->etypes->val = calloc(netypes, sizeof(e->etypes->val[0]))) == NULL)
547 0 : ret = krb5_enomem(context);
548 0 : if (ret) {
549 0 : free(e->etypes);
550 0 : e->etypes = 0;
551 0 : return ret;
552 : }
553 0 : e->etypes->len = netypes;
554 0 : for (i = 0; i < e->keys.len && i < netypes; i++)
555 0 : e->etypes->val[i] = e->keys.val[i].key.keytype;
556 0 : if (!base_keys || i)
557 0 : return 0;
558 0 : for (k = 0; i == 0 && k < base_keys->len; k++) {
559 0 : if (!base_keys->val[k].keys.len)
560 0 : continue;
561 0 : for (; i < base_keys->val[k].keys.len; i++)
562 0 : e->etypes->val[i] = base_keys->val[k].keys.val[i].key.keytype;
563 : }
564 0 : return 0;
565 : }
566 :
567 : krb5_error_code
568 0 : _hdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
569 : {
570 0 : krb5_data key, value;
571 0 : int code;
572 :
573 0 : if (entry->flags.do_not_store ||
574 : entry->flags.force_canonicalize)
575 0 : return HDB_ERR_MISUSE;
576 : /* check if new aliases already is used */
577 0 : code = hdb_check_aliases(context, db, entry);
578 0 : if (code)
579 0 : return code;
580 :
581 0 : if ((flags & HDB_F_PRECHECK) && (flags & HDB_F_REPLACE))
582 0 : return 0;
583 :
584 0 : if ((flags & HDB_F_PRECHECK)) {
585 0 : code = hdb_principal2key(context, entry->principal, &key);
586 0 : if (code)
587 0 : return code;
588 0 : code = db->hdb__get(context, db, key, &value);
589 0 : krb5_data_free(&key);
590 0 : if (code == 0)
591 0 : krb5_data_free(&value);
592 0 : if (code == HDB_ERR_NOENTRY)
593 0 : return 0;
594 0 : return code ? code : HDB_ERR_EXISTS;
595 : }
596 :
597 0 : if ((entry->etypes == NULL || entry->etypes->len == 0) &&
598 0 : (code = hdb_derive_etypes(context, entry, NULL)))
599 0 : return code;
600 :
601 0 : if (entry->generation == NULL) {
602 0 : struct timeval t;
603 0 : entry->generation = malloc(sizeof(*entry->generation));
604 0 : if(entry->generation == NULL) {
605 0 : krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
606 0 : return ENOMEM;
607 : }
608 0 : gettimeofday(&t, NULL);
609 0 : entry->generation->time = t.tv_sec;
610 0 : entry->generation->usec = t.tv_usec;
611 0 : entry->generation->gen = 0;
612 : } else
613 0 : entry->generation->gen++;
614 :
615 0 : code = hdb_seal_keys(context, db, entry);
616 0 : if (code)
617 0 : return code;
618 :
619 0 : code = hdb_principal2key(context, entry->principal, &key);
620 0 : if (code)
621 0 : return code;
622 :
623 : /* remove aliases */
624 0 : code = hdb_remove_aliases(context, db, &key);
625 0 : if (code) {
626 0 : krb5_data_free(&key);
627 0 : return code;
628 : }
629 0 : code = hdb_entry2value(context, entry, &value);
630 0 : if (code == 0)
631 0 : code = db->hdb__put(context, db, flags & HDB_F_REPLACE, key, value);
632 0 : krb5_data_free(&value);
633 0 : krb5_data_free(&key);
634 0 : if (code)
635 0 : return code;
636 :
637 0 : code = hdb_add_aliases(context, db, flags, entry);
638 :
639 0 : return code;
640 : }
641 :
642 : krb5_error_code
643 0 : _hdb_remove(krb5_context context, HDB *db,
644 : unsigned flags, krb5_const_principal principal)
645 : {
646 0 : krb5_data key, value;
647 0 : HDB_EntryOrAlias eoa;
648 0 : int is_alias = -1;
649 0 : int code;
650 :
651 : /*
652 : * We only allow deletion of entries by canonical name. To remove an
653 : * alias use kadm5_modify_principal().
654 : *
655 : * We need to determine if this is an alias. We decode as a
656 : * HDB_EntryOrAlias, which is expensive -- we could decode as a
657 : * HDB_entry_alias instead and assume it's an entry if decoding fails...
658 : */
659 :
660 0 : code = hdb_principal2key(context, principal, &key);
661 0 : if (code == 0)
662 0 : code = db->hdb__get(context, db, key, &value);
663 0 : if (code == 0) {
664 0 : code = decode_HDB_EntryOrAlias(value.data, value.length, &eoa, NULL);
665 0 : krb5_data_free(&value);
666 : }
667 0 : if (code == 0) {
668 0 : is_alias = eoa.element == choice_HDB_EntryOrAlias_entry ? 0 : 1;
669 0 : free_HDB_EntryOrAlias(&eoa);
670 : }
671 :
672 0 : if ((flags & HDB_F_PRECHECK)) {
673 0 : if (code == 0 && is_alias)
674 0 : krb5_set_error_message(context, code = HDB_ERR_NOENTRY,
675 : "Cannot delete alias of principal");
676 0 : krb5_data_free(&key);
677 0 : return code;
678 : }
679 :
680 0 : if (code == 0)
681 0 : code = hdb_remove_aliases(context, db, &key);
682 0 : if (code == 0)
683 0 : code = db->hdb__del(context, db, key);
684 0 : krb5_data_free(&key);
685 0 : return code;
686 : }
687 :
688 : /* PRF+(K_base, pad, keylen(etype)) */
689 : static krb5_error_code
690 0 : derive_Key1(krb5_context context,
691 : krb5_data *pad,
692 : EncryptionKey *base,
693 : krb5int32 etype,
694 : EncryptionKey *nk)
695 : {
696 0 : krb5_error_code ret;
697 0 : krb5_crypto crypto = NULL;
698 0 : krb5_data out;
699 0 : size_t len;
700 :
701 0 : out.data = 0;
702 0 : out.length = 0;
703 :
704 0 : ret = krb5_enctype_keysize(context, base->keytype, &len);
705 0 : if (ret == 0)
706 0 : ret = krb5_crypto_init(context, base, 0, &crypto);
707 0 : if (ret == 0)
708 0 : ret = krb5_crypto_prfplus(context, crypto, pad, len, &out);
709 0 : if (crypto)
710 0 : krb5_crypto_destroy(context, crypto);
711 0 : if (ret == 0)
712 0 : ret = krb5_random_to_key(context, etype, out.data, out.length, nk);
713 0 : krb5_data_free(&out);
714 0 : return ret;
715 : }
716 :
717 : /* PRF+(PRF+(K_base, princ, keylen(etype)), kvno, keylen(etype)) */
718 : /* XXX Make it PRF+(PRF+(K_base, princ, keylen(K_base.etype)), and lift it, kvno, keylen(etype)) */
719 : static krb5_error_code
720 0 : derive_Key(krb5_context context,
721 : const char *princ,
722 : krb5uint32 kvno,
723 : EncryptionKey *base,
724 : krb5int32 etype,
725 : Key *nk)
726 : {
727 0 : krb5_error_code ret = 0;
728 0 : EncryptionKey intermediate;
729 0 : krb5_data pad;
730 :
731 0 : nk->salt = NULL;
732 0 : nk->mkvno = NULL;
733 0 : nk->key.keytype = 0;
734 0 : nk->key.keyvalue.data = 0;
735 0 : nk->key.keyvalue.length = 0;
736 :
737 0 : intermediate.keytype = 0;
738 0 : intermediate.keyvalue.data = 0;
739 0 : intermediate.keyvalue.length = 0;
740 0 : if (princ) {
741 : /* Derive intermediate key for the given principal */
742 : /* XXX Lift to optimize? */
743 0 : pad.data = (void *)(uintptr_t)princ;
744 0 : pad.length = strlen(princ);
745 0 : ret = derive_Key1(context, &pad, base, etype, &intermediate);
746 0 : if (ret == 0)
747 0 : base = &intermediate;
748 : } /* else `base' is already an intermediate key for the desired princ */
749 :
750 : /* Derive final key for `kvno' from intermediate key */
751 0 : kvno = htonl(kvno);
752 0 : pad.data = &kvno;
753 0 : pad.length = sizeof(kvno);
754 0 : if (ret == 0)
755 0 : ret = derive_Key1(context, &pad, base, etype, &nk->key);
756 0 : free_EncryptionKey(&intermediate);
757 0 : return ret;
758 : }
759 :
760 : /*
761 : * PRF+(PRF+(K_base, princ, keylen(etype)), kvno, keylen(etype)) for one
762 : * enctype.
763 : */
764 : static krb5_error_code
765 0 : derive_Keys(krb5_context context,
766 : const char *princ,
767 : krb5uint32 kvno,
768 : krb5int32 etype,
769 : const Keys *base,
770 : Keys *dk)
771 :
772 : {
773 0 : krb5_error_code ret = 0;
774 0 : size_t i;
775 0 : Key nk;
776 :
777 0 : dk->len = 0;
778 0 : dk->val = 0;
779 :
780 : /*
781 : * The enctypes of the base keys is the list of enctypes to derive keys
782 : * for. Still, we derive all keys from the first base key.
783 : */
784 0 : for (i = 0; ret == 0 && i < base->len; i++) {
785 0 : if (etype != KRB5_ENCTYPE_NULL && etype != base->val[i].key.keytype)
786 0 : continue;
787 0 : ret = derive_Key(context, princ, kvno, &base->val[0].key,
788 0 : base->val[i].key.keytype, &nk);
789 0 : if (ret)
790 0 : break;
791 0 : ret = add_Keys(dk, &nk);
792 0 : free_Key(&nk);
793 : /*
794 : * FIXME We need to finish kdc/kadm5/kadmin support for the `etypes' so
795 : * we can reduce the number of keys in keytabs to just those in current
796 : * use and only of *one* enctype.
797 : *
798 : * What we could do is derive *one* key and for the others output a
799 : * one-byte key of the intended enctype (which will never work).
800 : *
801 : * We'll never need any keys but the first one...
802 : */
803 : }
804 :
805 0 : if (ret)
806 0 : free_Keys(dk);
807 0 : return ret;
808 : }
809 :
810 : /* Helper for derive_keys_for_kr() */
811 : static krb5_error_code
812 0 : derive_keyset(krb5_context context,
813 : const Keys *base_keys,
814 : const char *princ,
815 : krb5int32 etype,
816 : krb5uint32 kvno,
817 : KerberosTime set_time, /* "now" */
818 : hdb_keyset *dks)
819 : {
820 0 : dks->kvno = kvno;
821 0 : dks->keys.val = 0;
822 0 : dks->set_time = malloc(sizeof(*(dks->set_time)));
823 0 : if (dks->set_time == NULL)
824 0 : return krb5_enomem(context);
825 0 : *dks->set_time = set_time;
826 0 : return derive_Keys(context, princ, kvno, etype, base_keys, &dks->keys);
827 : }
828 :
829 : /* Possibly derive and install in `h' a keyset identified by `t' */
830 : static krb5_error_code
831 0 : derive_keys_for_kr(krb5_context context,
832 : hdb_entry *h,
833 : HDB_Ext_KeySet *base_keys,
834 : int is_current_keyset,
835 : int rotation_period_offset,
836 : const char *princ,
837 : krb5int32 etype,
838 : krb5uint32 kvno_wanted,
839 : KerberosTime t,
840 : struct KeyRotation *krp)
841 : {
842 0 : krb5_error_code ret;
843 0 : hdb_keyset dks;
844 0 : KerberosTime set_time, n;
845 0 : krb5uint32 kvno;
846 0 : size_t i;
847 :
848 0 : if (rotation_period_offset < -1 || rotation_period_offset > 1)
849 0 : return EINVAL; /* wat */
850 :
851 : /*
852 : * Compute `kvno' and `set_time' given `t' and `krp'.
853 : *
854 : * There be signed 32-bit time_t dragons here.
855 : *
856 : * (t - krp->epoch < 0) is better than (krp->epoch < t), making us more
857 : * tolerant of signed 32-bit time_t here near 2038. Of course, we have
858 : * signed 32-bit time_t dragons elsewhere.
859 : *
860 : * We don't need to check for n == 0 && rotation_period_offset < 0 because
861 : * only derive_keys_for_current_kr() calls us with non-zero rotation period
862 : * offsets, and it will never call us in that case.
863 : */
864 0 : if (t - krp->epoch < 0)
865 0 : return 0; /* This KR is not relevant yet */
866 0 : n = (t - krp->epoch) / krp->period;
867 0 : n += rotation_period_offset;
868 0 : set_time = krp->epoch + krp->period * n;
869 0 : kvno = krp->base_kvno + n;
870 :
871 : /*
872 : * Since this principal is virtual, or has virtual keys, we're going to
873 : * derive a "password expiration time" for it in order to help httpkadmind
874 : * and other tools figure out when to request keys again.
875 : *
876 : * The kadm5 representation of principals does not include the set_time of
877 : * keys/keysets, so we can't have httpkadmind derive a Cache-Control from
878 : * that without adding yet another "TL data". Since adding TL data is a
879 : * huge pain, we'll just use the `pw_end' field of `HDB_entry' to
880 : * communicate when this principal's keys will change next.
881 : */
882 0 : if (h->pw_end[0] == 0) {
883 0 : KerberosTime used = (t - krp->epoch) % krp->period;
884 0 : KerberosTime left = krp->period - used;
885 :
886 : /*
887 : * If `h->pw_end[0]' == 0 then this must be the current period of the
888 : * current KR we're deriving keys for. See upstairs.
889 : *
890 : * If there's more than a quarter of this time period left, then we'll
891 : * set `h->pw_end[0]' to one quarter before the end of this time
892 : * period. Else we'll set it to 1/4 after (we'll be including the next
893 : * set of derived keys, so there's no harm in waiting that long to
894 : * refetch).
895 : */
896 0 : if (left > krp->period >> 2)
897 0 : h->pw_end[0] = set_time + krp->period - (krp->period >> 2);
898 : else
899 0 : h->pw_end[0] = set_time + krp->period + (krp->period >> 2);
900 : }
901 :
902 :
903 : /*
904 : * Do not waste cycles computing keys not wanted or needed.
905 : * A past kvno is too old if its set_time + rotation period is in the past
906 : * by more than half a rotation period, since then no service ticket
907 : * encrypted with keys of that kvno can still be extant.
908 : *
909 : * A future kvno is not coming up soon enough if we're more than a quarter
910 : * of the rotation period away from it.
911 : *
912 : * Recall: the assumption for virtually-keyed principals is that services
913 : * fetch their future keys frequently enough that they'll never miss having
914 : * the keys they need.
915 : */
916 0 : if (!is_current_keyset || rotation_period_offset != 0) {
917 0 : if ((kvno_wanted && kvno != kvno_wanted) ||
918 0 : t - (set_time + krp->period + (krp->period >> 1)) > 0 ||
919 0 : (set_time - t > 0 && (set_time - t) > (krp->period >> 2)))
920 0 : return 0;
921 : }
922 :
923 0 : for (i = 0; i < base_keys->len; i++) {
924 0 : if (base_keys->val[i].kvno == krp->base_key_kvno)
925 0 : break;
926 : }
927 0 : if (i == base_keys->len) {
928 : /* Base key not found! */
929 0 : if (kvno_wanted || is_current_keyset) {
930 0 : krb5_set_error_message(context, ret = HDB_ERR_KVNO_NOT_FOUND,
931 : "Base key version %u not found for %s",
932 : krp->base_key_kvno, princ);
933 0 : return ret;
934 : }
935 0 : return 0;
936 : }
937 :
938 0 : ret = derive_keyset(context, &base_keys->val[i].keys, princ, etype, kvno,
939 : set_time, &dks);
940 0 : if (ret == 0)
941 0 : ret = hdb_install_keyset(context, h, is_current_keyset, &dks);
942 :
943 0 : free_HDB_keyset(&dks);
944 0 : return ret;
945 : }
946 :
947 : /* Derive and install current keys, and possibly preceding or next keys */
948 : static krb5_error_code
949 0 : derive_keys_for_current_kr(krb5_context context,
950 : hdb_entry *h,
951 : HDB_Ext_KeySet *base_keys,
952 : const char *princ,
953 : unsigned int flags,
954 : krb5int32 etype,
955 : krb5uint32 kvno_wanted,
956 : KerberosTime t,
957 : struct KeyRotation *krp,
958 : KerberosTime future_epoch)
959 : {
960 0 : krb5_error_code ret;
961 :
962 : /* derive_keys_for_kr() for current kvno and install as the current keys */
963 0 : ret = derive_keys_for_kr(context, h, base_keys, 1, 0, princ, etype,
964 : kvno_wanted, t, krp);
965 0 : if (!(flags & HDB_F_ALL_KVNOS))
966 0 : return ret;
967 :
968 : /* */
969 :
970 :
971 : /*
972 : * derive_keys_for_kr() for prev kvno if still needed -- it can only be
973 : * needed if the prev kvno's start time is within this KR's epoch.
974 : *
975 : * Note that derive_keys_for_kr() can return without doing anything if this
976 : * is isn't the current keyset. So these conditions need not be
977 : * sufficiently narrow.
978 : */
979 0 : if (ret == 0 && t - krp->epoch >= krp->period)
980 0 : ret = derive_keys_for_kr(context, h, base_keys, 0, -1, princ, etype,
981 : kvno_wanted, t, krp);
982 : /*
983 : * derive_keys_for_kr() for next kvno if near enough, but only if it
984 : * doesn't start after the next KR's epoch.
985 : */
986 0 : if (future_epoch &&
987 0 : t - krp->epoch >= 0 /* We know! Hint to the compiler */) {
988 0 : KerberosTime next_kvno_start, n;
989 :
990 0 : n = (t - krp->epoch) / krp->period;
991 0 : next_kvno_start = krp->epoch + krp->period * (n + 1);
992 0 : if (future_epoch - next_kvno_start <= 0)
993 0 : return ret;
994 : }
995 0 : if (ret == 0)
996 0 : ret = derive_keys_for_kr(context, h, base_keys, 0, 1, princ, etype,
997 : kvno_wanted, t, krp);
998 0 : return ret;
999 : }
1000 :
1001 : /*
1002 : * Derive and install all keysets in `h' that `princ' needs at time `now'.
1003 : *
1004 : * This mutates the entry `h' to
1005 : *
1006 : * a) not have base keys,
1007 : * b) have keys derived from the base keys according to
1008 : * c) the key rotation periods for the base principal (possibly the same
1009 : * principal if it's a concrete principal with virtual keys), and the
1010 : * requested time, enctype, and kvno (all of which are optional, with zero
1011 : * implying some default).
1012 : *
1013 : * Arguments:
1014 : *
1015 : * - `flags' is the flags passed to `hdb_fetch_kvno()'
1016 : * - `princ' is the name of the principal we'll end up with in `entry'
1017 : * - `h_is_namespace' indicates whether `h' is for a namespace or a concrete
1018 : * principal (that might nonetheless have virtual/derived keys)
1019 : * - `t' is the time such that the derived keys are for kvnos needed at `t'
1020 : * - `etype' indicates what enctype to derive keys for (0 for all enctypes in
1021 : * `entry->etypes')
1022 : * - `kvno' requests a particular kvno, or all if zero
1023 : *
1024 : * The caller doesn't know if the principal needs key derivation -- we make
1025 : * that determination in this function.
1026 : *
1027 : * Note that this function is fully deterministic for any given set of
1028 : * arguments and HDB contents.
1029 : *
1030 : * Definitions:
1031 : *
1032 : * - A keyset is a set of keys for a single kvno.
1033 : * - A keyset is relevant IFF:
1034 : * - it is the keyset for a time period identified by `t' in a
1035 : * corresponding KR
1036 : * - it is a keyset for a past time period for which there may be extant,
1037 : * not-yet-expired tickets that a service may need to decrypt
1038 : * - it is a keyset for an upcoming time period that a service will need to
1039 : * fetch before that time period becomes current, that way the service
1040 : * can have keytab entries for those keys in time for when the KDC starts
1041 : * encrypting service tickets to those keys
1042 : *
1043 : * This function derives the keyset(s) for the current KR first. The idea is
1044 : * to optimize the order of resulting keytabs so that the most likely keys to
1045 : * be used come first.
1046 : *
1047 : * Invariants:
1048 : *
1049 : * - KR metadata is sane because sanity is checked for when storing HDB
1050 : * entries
1051 : * - KRs are sorted by epoch in descending order; KR #0's epoch is the most
1052 : * recent
1053 : * - KR periods are non-zero (we divide by period)
1054 : * - kvnos are numerically ordered and correspond to time periods
1055 : * - within each KR, the kvnos for larger times are larger than (or equal
1056 : * to) the kvnos of earlier times
1057 : * - at KR boundaries, the first kvno of the newer boundary is larger than
1058 : * the kvno of the last time period of the previous KR
1059 : * - the time `t' must fall into exactly one KR period
1060 : * - the time `t' must fall into exactly one period within a KR period
1061 : * - at most two kvnos will be relevant from the KR that `t' falls into
1062 : * (the current kvno for `t', and possibly either the preceding, or the
1063 : * next)
1064 : * - at most one kvno from non-current KRs will be derived: possibly one for a
1065 : * preceding KR, and possibly one from an upcoming KR
1066 : *
1067 : * There can be:
1068 : *
1069 : * - no KR extension (not a namespace principal, and no virtual keys)
1070 : * - 1, 2, or 3 KRs (see above)
1071 : * - the newest KR may have the `deleted' flag, meaning "does not exist after
1072 : * this epoch"
1073 : *
1074 : * Note that the last time period in any older KR can be partial.
1075 : *
1076 : * Timeline diagram:
1077 : *
1078 : * .......|--+--+...+--|---+---+---+...+--|----+...
1079 : * T20 T10 T11 RT12 T1n T01
1080 : * ^ ^ ^ ^ ^ ^ ^ T00
1081 : * | | | T22 T2n | | ^
1082 : * ^ | T21 | | |
1083 : * princ | | epoch of | epoch of
1084 : * did | | middle KR | newest epoch
1085 : * not | | |
1086 : * exist! | start of Note that T1n
1087 : * | second kvno is shown as shorter
1088 : * | in 1st epoch than preceding periods
1089 : * |
1090 : * ^
1091 : * first KR's
1092 : * epoch, and start
1093 : * of its first kvno
1094 : *
1095 : * Tmn == the start of the Mth KR's Nth time period.
1096 : * (higher M -> older KR; lower M -> newer KR)
1097 : * (N is the reverse: lower N -> older time period in KR)
1098 : * T20 == start of oldest KR -- no keys before this time will be derived.
1099 : * T2n == last time period in oldest KR
1100 : * T10 == start of middle KR
1101 : * T1n == last time period in middle KR
1102 : * T00 == start of newest KR
1103 : * T0n == current time period in newest KR for wall clock time
1104 : */
1105 : static krb5_error_code
1106 309171 : derive_keys(krb5_context context,
1107 : unsigned flags,
1108 : krb5_const_principal princ,
1109 : int h_is_namespace,
1110 : krb5_timestamp t,
1111 : krb5int32 etype,
1112 : krb5uint32 kvno,
1113 : hdb_entry *h)
1114 : {
1115 10142 : HDB_Ext_KeyRotation kr;
1116 10142 : HDB_Ext_KeySet base_keys;
1117 309171 : krb5_error_code ret = 0;
1118 10142 : size_t current_kr, future_kr, past_kr, i;
1119 309171 : char *p = NULL;
1120 309171 : int valid = 1;
1121 :
1122 309171 : if (!h_is_namespace && !h->flags.virtual_keys)
1123 299029 : return 0;
1124 0 : h->flags.virtual = 1;
1125 :
1126 0 : kr.len = 0;
1127 0 : kr.val = 0;
1128 0 : if (ret == 0) {
1129 0 : const HDB_Ext_KeyRotation *ckr;
1130 :
1131 : /* Installing keys invalidates `ckr', so we copy it */
1132 0 : ret = hdb_entry_get_key_rotation(context, h, &ckr);
1133 0 : if (!ckr)
1134 0 : return ret;
1135 0 : if (ret == 0)
1136 0 : ret = copy_HDB_Ext_KeyRotation(ckr, &kr);
1137 : }
1138 :
1139 : /* Get the base keys from the entry, and remove them */
1140 0 : base_keys.val = 0;
1141 0 : base_keys.len = 0;
1142 0 : if (ret == 0)
1143 0 : ret = _hdb_remove_base_keys(context, h, &base_keys, &kr);
1144 :
1145 : /* Make sure we have h->etypes */
1146 0 : if (ret == 0 && !h->etypes)
1147 0 : ret = hdb_derive_etypes(context, h, &base_keys);
1148 :
1149 : /* Keys not desired? Don't derive them! */
1150 0 : if (ret || !(flags & HDB_F_DECRYPT)) {
1151 0 : free_HDB_Ext_KeyRotation(&kr);
1152 0 : free_HDB_Ext_KeySet(&base_keys);
1153 0 : return ret;
1154 : }
1155 :
1156 : /* The principal name will be used in key derivation and error messages */
1157 0 : if (ret == 0)
1158 0 : ret = krb5_unparse_name(context, princ, &p);
1159 :
1160 : /* Sanity check key rotations, determine current & last kr */
1161 0 : if (ret == 0 && kr.len < 1)
1162 0 : krb5_set_error_message(context, ret = HDB_ERR_NOENTRY,
1163 : "no key rotation periods for %s", p);
1164 0 : if (ret == 0)
1165 0 : current_kr = future_kr = past_kr = kr.len;
1166 : else
1167 0 : current_kr = future_kr = past_kr = 1;
1168 :
1169 : /*
1170 : * Identify a current, next, and previous KRs if there are any.
1171 : *
1172 : * There can be up to three KRs, ordered by epoch, descending, making up a
1173 : * timeline like:
1174 : *
1175 : * ...|---------|--------|------>
1176 : * ^ | | |
1177 : * | | | |
1178 : * | | | Newest KR (kr.val[0])
1179 : * | | Middle KR (kr.val[1])
1180 : * | Oldest (last) KR (kr.val[2])
1181 : * |
1182 : * Before the begging of time for this namespace
1183 : *
1184 : * We step through these from future towards past looking for the best
1185 : * future, current, and past KRs. The best current KR is one that has its
1186 : * epoch nearest to `t' but in the past of `t'.
1187 : *
1188 : * We validate KRs before storing HDB entries with the KR extension, so we
1189 : * can assume they are valid here. However, we do some validity checking,
1190 : * and if they're not valid, we pick the best current KR and ignore the
1191 : * others.
1192 : *
1193 : * In principle there cannot be two future KRs, but this function is
1194 : * deterministic and takes a time value, so it should not enforce this just
1195 : * so we can test. Enforcement of such rules should be done at store time.
1196 : */
1197 0 : for (i = 0; ret == 0 && i < kr.len; i++) {
1198 : /* Minimal validation: order and period */
1199 0 : if (i && kr.val[i - 1].epoch - kr.val[i].epoch <= 0) {
1200 0 : future_kr = past_kr = kr.len;
1201 0 : valid = 0;
1202 : }
1203 0 : if (!kr.val[i].period) {
1204 0 : future_kr = past_kr = kr.len;
1205 0 : valid = 0;
1206 0 : continue;
1207 : }
1208 0 : if (t - kr.val[i].epoch >= 0) {
1209 : /*
1210 : * `t' is in the future of this KR's epoch, so it's a candidate for
1211 : * either current or past KR.
1212 : */
1213 0 : if (current_kr == kr.len)
1214 0 : current_kr = i; /* First curr KR candidate; should be best */
1215 0 : else if (kr.val[current_kr].epoch - kr.val[i].epoch < 0)
1216 0 : current_kr = i; /* Invalid KRs, but better curr KR cand. */
1217 0 : else if (valid && past_kr == kr.len)
1218 0 : past_kr = i;
1219 0 : } else if (valid) {
1220 : /* This KR is in the future of `t', a candidate for next KR */
1221 0 : future_kr = i;
1222 : }
1223 : }
1224 0 : if (ret == 0 && current_kr == kr.len)
1225 : /* No current KR -> too soon */
1226 0 : krb5_set_error_message(context, ret = HDB_ERR_NOENTRY,
1227 : "Too soon for virtual principal to exist");
1228 :
1229 : /* Check that the principal has not been marked deleted */
1230 0 : if (ret == 0 && current_kr < kr.len && kr.val[current_kr].flags.deleted)
1231 0 : krb5_set_error_message(context, ret = HDB_ERR_NOENTRY,
1232 : "virtual principal %s does not exist "
1233 : "because last key rotation period "
1234 : "marks deletion", p);
1235 :
1236 : /* See `derive_keys_for_kr()' */
1237 0 : if (h->pw_end == NULL &&
1238 0 : (h->pw_end = calloc(1, sizeof(h->pw_end[0]))) == NULL)
1239 0 : ret = krb5_enomem(context);
1240 :
1241 : /*
1242 : * Derive and set in `h' its current kvno and current keys.
1243 : *
1244 : * This will set h->kvno as well.
1245 : *
1246 : * This may set up to TWO keysets for the current key rotation period:
1247 : * - current keys (h->keys and h->kvno)
1248 : * - possibly one future
1249 : * OR
1250 : * possibly one past keyset in hist_keys for the current_kr
1251 : */
1252 0 : if (ret == 0 && current_kr < kr.len)
1253 0 : ret = derive_keys_for_current_kr(context, h, &base_keys, p, flags,
1254 0 : etype, kvno, t, &kr.val[current_kr],
1255 0 : current_kr ? kr.val[0].epoch : 0);
1256 :
1257 : /*
1258 : * Derive and set in `h' its future keys for next KR if it is soon to be
1259 : * current.
1260 : *
1261 : * We want to derive keys for the first kvno of the next (future) KR if
1262 : * it's sufficiently close to `t', meaning within 1 period of the current
1263 : * KR, but we want these keys to be available sooner, so 1.5 of the current
1264 : * period.
1265 : */
1266 0 : if (ret == 0 && future_kr < kr.len && (flags & HDB_F_ALL_KVNOS))
1267 0 : ret = derive_keys_for_kr(context, h, &base_keys, 0, 0, p, etype, kvno,
1268 0 : kr.val[future_kr].epoch, &kr.val[future_kr]);
1269 :
1270 : /*
1271 : * Derive and set in `h' its past keys for the previous KR if its last time
1272 : * period could still have extant, unexpired service tickets encrypted in
1273 : * its keys.
1274 : */
1275 0 : if (ret == 0 && past_kr < kr.len && (flags & HDB_F_ALL_KVNOS))
1276 0 : ret = derive_keys_for_kr(context, h, &base_keys, 0, 0, p, etype, kvno,
1277 0 : kr.val[current_kr].epoch - 1, &kr.val[past_kr]);
1278 :
1279 : /*
1280 : * Impose a bound on h->max_life so that [when the KDC is the caller]
1281 : * the KDC won't issue tickets longer lived than this.
1282 : */
1283 0 : if (ret == 0 && !h->max_life &&
1284 0 : (h->max_life = calloc(1, sizeof(h->max_life[0]))) == NULL)
1285 0 : ret = krb5_enomem(context);
1286 0 : if (ret == 0 && *h->max_life > kr.val[current_kr].period >> 1)
1287 0 : *h->max_life = kr.val[current_kr].period >> 1;
1288 :
1289 0 : if (ret == 0 && h->pw_end[0] == 0)
1290 : /* Shouldn't happen */
1291 0 : h->pw_end[0] = kr.val[current_kr].epoch +
1292 0 : kr.val[current_kr].period *
1293 0 : (1 + (t - kr.val[current_kr].epoch) / kr.val[current_kr].period);
1294 :
1295 0 : free_HDB_Ext_KeyRotation(&kr);
1296 0 : free_HDB_Ext_KeySet(&base_keys);
1297 0 : free(p);
1298 0 : return ret;
1299 : }
1300 :
1301 : /*
1302 : * Pick a best kvno for the given principal at the given time.
1303 : *
1304 : * Implements the [hdb] new_service_key_delay configuration parameter.
1305 : *
1306 : * In order for disparate keytab provisioning systems such as OSKT and our own
1307 : * kadmin ext_keytab and httpkadmind's get-keys to coexist, we need to be able
1308 : * to force keys set by the former to not become current keys until users of
1309 : * the latter have had a chance to fetch those keys into their keytabs. To do
1310 : * this we have to search the list of keys in the entry looking for the newest
1311 : * keys older than `now - db->new_service_key_delay'.
1312 : *
1313 : * The context is that OSKT's krb5_keytab is very happy to change keys in a way
1314 : * that requires all members of a cluster to rekey together. If one also
1315 : * wishes to have cluster members that opt out of this and just fetch current,
1316 : * past, and future keys periodically, then the keys set by OSKT must not come
1317 : * into effect until all the opt-out members have had a chance to fetch the new
1318 : * keys.
1319 : *
1320 : * The assumption is that services will fetch new keys periodically, say, every
1321 : * four hours. Then one can set `[hdb] new_service_key_delay = 8h' in the
1322 : * configuration and new keys set by OSKT will not be used until 8h after they
1323 : * are set.
1324 : *
1325 : * Naturally, this applies only to concrete principals with concrete keys.
1326 : */
1327 : static krb5_error_code
1328 309171 : pick_kvno(krb5_context context,
1329 : HDB *db,
1330 : unsigned flags,
1331 : krb5_timestamp now,
1332 : krb5uint32 kvno,
1333 : hdb_entry *h)
1334 : {
1335 10142 : HDB_extension *ext;
1336 10142 : HDB_Ext_KeySet keys;
1337 309171 : time_t current = 0;
1338 10142 : time_t best;
1339 10142 : size_t i;
1340 :
1341 : /*
1342 : * If we want a specific kvno, or if the caller doesn't want new keys
1343 : * delayed, or if there's no new-key delay configured, or we're not
1344 : * fetching for use as a service principal, then we're out.
1345 : */
1346 309171 : if (!(flags & HDB_F_DELAY_NEW_KEYS) || kvno || h->flags.virtual ||
1347 100809 : h->flags.virtual_keys || db->new_service_key_delay <= 0)
1348 299029 : return 0;
1349 :
1350 : /* No history -> current keyset is the only one and therefore the best */
1351 0 : ext = hdb_find_extension(h, choice_HDB_extension_data_hist_keys);
1352 0 : if (!ext)
1353 0 : return 0;
1354 :
1355 : /* Assume the current keyset is the best to start with */
1356 0 : (void) hdb_entry_get_pw_change_time(h, ¤t);
1357 0 : if (current == 0 && h->modified_by)
1358 0 : current = h->modified_by->time;
1359 0 : if (current == 0)
1360 0 : current = h->created_by.time;
1361 :
1362 : /* Current keyset starts out as best */
1363 0 : best = current;
1364 0 : kvno = h->kvno;
1365 :
1366 : /* Look for a better keyset in the history */
1367 0 : keys = ext->data.u.hist_keys;
1368 0 : for (i = 0; i < keys.len; i++) {
1369 : /* No set_time? Ignore. Too new? Ignore */
1370 0 : if (!keys.val[i].set_time ||
1371 0 : keys.val[i].set_time[0] + db->new_service_key_delay > now)
1372 0 : continue;
1373 :
1374 : /*
1375 : * Ignore the keyset with kvno 1 when the entry has better kvnos
1376 : * because kadmin's `ank -r' command immediately changes the keys.
1377 : */
1378 0 : if (kvno > 1 && keys.val[i].kvno == 1)
1379 0 : continue;
1380 :
1381 : /*
1382 : * This keyset's set_time older than the previous best? Ignore.
1383 : * However, if the current best is the entry's current and that one
1384 : * is too new, then don't ignore this one.
1385 : */
1386 0 : if (keys.val[i].set_time[0] < best &&
1387 0 : (best != current || current + db->new_service_key_delay < now))
1388 0 : continue;
1389 :
1390 : /*
1391 : * If two good enough keysets have the same set_time, take the keyset
1392 : * with the highest kvno.
1393 : */
1394 0 : if (keys.val[i].set_time[0] == best && keys.val[i].kvno <= kvno)
1395 0 : continue;
1396 :
1397 : /*
1398 : * This keyset is clearly more current than the previous best keyset
1399 : * but still old enough to use for encrypting tickets with.
1400 : */
1401 0 : best = keys.val[i].set_time[0];
1402 0 : kvno = keys.val[i].kvno;
1403 : }
1404 0 : return hdb_change_kvno(context, kvno, h);
1405 : }
1406 :
1407 : /*
1408 : * Make a WELLKNOWN/HOSTBASED-NAMESPACE/${svc}/${hostname} or
1409 : * WELLKNOWN/HOSTBASED-NAMESPACE/${svc}/${hostname}/${domainname} principal
1410 : * object, with the service and hostname components take from `wanted', but if
1411 : * the service name is not in the list `db->virtual_hostbased_princ_svcs[]'
1412 : * then use "_" (wildcard) instead. This way we can have different attributes
1413 : * for different services in the same namespaces.
1414 : *
1415 : * For example, virtual hostbased service names for the "host" service might
1416 : * have ok-as-delegate set, but ones for the "HTTP" service might not.
1417 : */
1418 : static krb5_error_code
1419 0 : make_namespace_princ(krb5_context context,
1420 : HDB *db,
1421 : krb5_const_principal wanted,
1422 : krb5_principal *namespace)
1423 : {
1424 0 : krb5_error_code ret = 0;
1425 0 : const char *realm = krb5_principal_get_realm(context, wanted);
1426 0 : const char *comp0 = krb5_principal_get_comp_string(context, wanted, 0);
1427 0 : const char *comp1 = krb5_principal_get_comp_string(context, wanted, 1);
1428 0 : const char *comp2 = krb5_principal_get_comp_string(context, wanted, 2);
1429 0 : char * const *svcs = db->virtual_hostbased_princ_svcs;
1430 0 : size_t i;
1431 :
1432 0 : *namespace = NULL;
1433 0 : if (comp0 == NULL || comp1 == NULL)
1434 0 : return EINVAL;
1435 0 : if (strcmp(comp0, "krbtgt") == 0)
1436 0 : return 0;
1437 :
1438 0 : for (i = 0; svcs && svcs[i]; i++) {
1439 0 : if (strcmp(comp0, svcs[i]) == 0) {
1440 0 : comp0 = svcs[i];
1441 0 : break;
1442 : }
1443 : }
1444 0 : if (!svcs || !svcs[i])
1445 0 : comp0 = "_";
1446 :
1447 : /* First go around, need a namespace princ. Make it! */
1448 0 : ret = krb5_build_principal(context, namespace, strlen(realm),
1449 : realm, KRB5_WELLKNOWN_NAME,
1450 : HDB_WK_NAMESPACE, comp0, NULL);
1451 0 : if (ret == 0)
1452 0 : ret = krb5_principal_set_comp_string(context, *namespace, 3, comp1);
1453 0 : if (ret == 0 && comp2)
1454 : /* Support domain-based names */
1455 0 : ret = krb5_principal_set_comp_string(context, *namespace, 4, comp2);
1456 : /* Caller frees `*namespace' on error */
1457 0 : return ret;
1458 : }
1459 :
1460 : static int
1461 0 : is_namespace_princ_p(krb5_context context,
1462 : krb5_const_principal princ)
1463 : {
1464 0 : return
1465 0 : krb5_principal_get_num_comp(context, princ) >= 4
1466 0 : && strcmp(krb5_principal_get_comp_string(context, princ, 0),
1467 : KRB5_WELLKNOWN_NAME) == 0
1468 0 : && strcmp(krb5_principal_get_comp_string(context, princ, 1),
1469 : HDB_WK_NAMESPACE) == 0;
1470 : }
1471 :
1472 : /* See call site */
1473 : static krb5_error_code
1474 0 : rewrite_hostname(krb5_context context,
1475 : krb5_const_principal wanted_princ,
1476 : krb5_const_principal ns_princ,
1477 : krb5_const_principal found_ns_princ,
1478 : char **s)
1479 : {
1480 0 : const char *ns_host_part, *wanted_host_part, *found_host_part;
1481 0 : const char *p, *r;
1482 0 : size_t ns_host_part_len, wanted_host_part_len;
1483 :
1484 0 : wanted_host_part = krb5_principal_get_comp_string(context, wanted_princ, 1);
1485 0 : wanted_host_part_len = strlen(wanted_host_part);
1486 0 : if (wanted_host_part_len > 256) {
1487 0 : krb5_set_error_message(context, HDB_ERR_NOENTRY,
1488 : "Aliases of host-based principals longer than "
1489 : "256 bytes not supported");
1490 0 : return HDB_ERR_NOENTRY;
1491 : }
1492 :
1493 0 : ns_host_part = krb5_principal_get_comp_string(context, ns_princ, 3);
1494 0 : ns_host_part_len = strlen(ns_host_part);
1495 :
1496 : /* Find `ns_host_part' as the tail of `wanted_host_part' */
1497 0 : for (r = p = strstr(wanted_host_part, ns_host_part);
1498 0 : r && strnlen(r, ns_host_part_len + 1) > ns_host_part_len;
1499 0 : p = (r = strstr(r, ns_host_part)) ? r : p)
1500 : ;
1501 0 : if (!p || strnlen(p, ns_host_part_len + 1) != ns_host_part_len)
1502 0 : return HDB_ERR_NOENTRY; /* Can't happen */
1503 0 : if (p == wanted_host_part || p[-1] != '.')
1504 0 : return HDB_ERR_NOENTRY;
1505 :
1506 0 : found_host_part =
1507 0 : krb5_principal_get_comp_string(context, found_ns_princ, 3);
1508 0 : return
1509 0 : asprintf(s, "%.*s%s", (int)(p - wanted_host_part), wanted_host_part,
1510 0 : found_host_part) < 0 ||
1511 0 : *s == NULL ? krb5_enomem(context) : 0;
1512 : }
1513 :
1514 : /*
1515 : * Fix `h->principal' to match the desired `princ' in the namespace
1516 : * `nsprinc' (which is either the same as `h->principal' or an alias
1517 : * of it).
1518 : */
1519 : static krb5_error_code
1520 309171 : fix_princ_name(krb5_context context,
1521 : krb5_const_principal princ,
1522 : krb5_const_principal nsprinc,
1523 : hdb_entry *h)
1524 : {
1525 309171 : krb5_error_code ret = 0;
1526 309171 : char *s = NULL;
1527 :
1528 309171 : if (!nsprinc)
1529 299029 : return 0;
1530 0 : if (krb5_principal_get_num_comp(context, princ) < 2)
1531 0 : return HDB_ERR_NOENTRY;
1532 :
1533 : /* `nsprinc' must be a namespace principal */
1534 :
1535 0 : if (krb5_principal_compare(context, nsprinc, h->principal)) {
1536 : /*
1537 : * `h' is the HDB entry for `nsprinc', and `nsprinc' is its canonical
1538 : * name.
1539 : *
1540 : * Set the entry's principal name to the desired name. The keys will
1541 : * be fixed next (upstairs, but don't forget to!).
1542 : */
1543 0 : free_Principal(h->principal);
1544 0 : return copy_Principal(princ, h->principal);
1545 : }
1546 :
1547 0 : if (!is_namespace_princ_p(context, h->principal)) {
1548 : /*
1549 : * The alias is a namespace, but the canonical name is not. WAT.
1550 : *
1551 : * Well, the KDC will just issue a referral anyways, so we can leave
1552 : * `h->principal' as is...
1553 : *
1554 : * Remove all of `h's keys just in case, and leave
1555 : * `h->principal' as-is.
1556 : */
1557 0 : free_Keys(&h->keys);
1558 0 : (void) hdb_entry_clear_password(context, h);
1559 0 : return hdb_clear_extension(context, h,
1560 : choice_HDB_extension_data_hist_keys);
1561 : }
1562 :
1563 : /*
1564 : * A namespace alias of a namespace entry.
1565 : *
1566 : * We'll want to rewrite the original principal accordingly.
1567 : *
1568 : * E.g., if the caller wanted host/foo.ns.test.h5l.se and we
1569 : * found WELLKNOWN/HOSTBASED-NAMESPACE/ns.test.h5l.se is an
1570 : * alias of WELLKNOWN/HOSTBASED-NAMESPACE/ns.example.org, then
1571 : * we'll want to treat host/foo.ns.test.h5l.se as an alias of
1572 : * host/foo.ns.example.org.
1573 : */
1574 0 : if (krb5_principal_get_num_comp(context, h->principal) !=
1575 0 : 2 + krb5_principal_get_num_comp(context, princ))
1576 0 : ret = HDB_ERR_NOENTRY; /* Only host-based services for now */
1577 0 : if (ret == 0)
1578 0 : ret = rewrite_hostname(context, princ, nsprinc, h->principal, &s);
1579 0 : if (ret == 0) {
1580 0 : krb5_free_principal(context, h->principal);
1581 0 : h->principal = NULL;
1582 0 : ret = krb5_make_principal(context, &h->principal,
1583 : krb5_principal_get_realm(context, princ),
1584 : krb5_principal_get_comp_string(context,
1585 : princ, 0),
1586 : s,
1587 : NULL);
1588 : }
1589 0 : free(s);
1590 0 : return ret;
1591 : }
1592 :
1593 : /* Wrapper around db->hdb_fetch_kvno() that implements virtual princs/keys */
1594 : static krb5_error_code
1595 313941 : fetch_it(krb5_context context,
1596 : HDB *db,
1597 : krb5_const_principal princ,
1598 : unsigned flags,
1599 : krb5_timestamp t,
1600 : krb5int32 etype,
1601 : krb5uint32 kvno,
1602 : hdb_entry *ent)
1603 : {
1604 313941 : krb5_const_principal tmpprinc = princ;
1605 313941 : krb5_principal nsprinc = NULL;
1606 313941 : krb5_error_code ret = 0;
1607 313941 : const char *comp0 = krb5_principal_get_comp_string(context, princ, 0);
1608 313941 : const char *comp1 = krb5_principal_get_comp_string(context, princ, 1);
1609 10142 : const char *tmp;
1610 313941 : size_t mindots = db->virtual_hostbased_princ_ndots;
1611 313941 : size_t maxdots = db->virtual_hostbased_princ_maxdots;
1612 313941 : size_t hdots = 0;
1613 313941 : char *host = NULL;
1614 313941 : int do_search = 0;
1615 :
1616 313941 : if (!db->enable_virtual_hostbased_princs)
1617 313941 : maxdots = mindots = 0;
1618 313941 : if (db->enable_virtual_hostbased_princs && comp1 &&
1619 0 : (comp0 == NULL || (strcmp("krbtgt", comp0) != 0 && strcmp(KRB5_WELLKNOWN_NAME, comp0) != 0))) {
1620 0 : char *htmp;
1621 :
1622 0 : if ((host = strdup(comp1)) == NULL)
1623 0 : return krb5_enomem(context);
1624 :
1625 : /* Strip out any :port */
1626 0 : htmp = strchr(host, ':');
1627 0 : if (htmp) {
1628 0 : if (strchr(htmp + 1, ':')) {
1629 : /* Extra ':'s? No virtualization for you! */
1630 0 : free(host);
1631 0 : host = NULL;
1632 : } else {
1633 0 : *htmp = '\0';
1634 : }
1635 : }
1636 : /* Count dots in `host' */
1637 0 : for (hdots = 0, htmp = host; htmp && *htmp; htmp++)
1638 0 : if (*htmp == '.')
1639 0 : hdots++;
1640 :
1641 0 : do_search = 1;
1642 : }
1643 :
1644 313941 : tmp = host ? host : comp1;
1645 313941 : for (ret = HDB_ERR_NOENTRY; ret == HDB_ERR_NOENTRY; tmpprinc = nsprinc) {
1646 313941 : krb5_error_code ret2 = 0;
1647 :
1648 : /*
1649 : * We break out of this loop with ret == 0 only if we found the HDB
1650 : * entry we were looking for or the HDB entry for a matching namespace.
1651 : *
1652 : * Otherwise we break out with ret != 0, typically HDB_ERR_NOENTRY.
1653 : *
1654 : * First time through we lookup the principal as given.
1655 : *
1656 : * Next we lookup a namespace principal, stripping off hostname labels
1657 : * from the left until we find one or get tired of looking or run out
1658 : * of labels.
1659 : */
1660 313941 : ret = db->hdb_fetch_kvno(context, db, tmpprinc, flags, kvno, ent);
1661 313941 : if (ret == 0 && nsprinc && ent->flags.invalid) {
1662 0 : free_HDB_entry(ent);
1663 0 : ret = HDB_ERR_NOENTRY;
1664 : }
1665 313941 : if (ret != HDB_ERR_NOENTRY || hdots == 0 || hdots < mindots || !tmp ||
1666 : !do_search)
1667 : break;
1668 :
1669 : /*
1670 : * Breadcrumb:
1671 : *
1672 : * - if we found a concrete principal, but it's been marked
1673 : * as now-virtual, then we must keep going
1674 : *
1675 : * But this will be coded in the future.
1676 : *
1677 : * Maybe we can take attributes from the concrete principal...
1678 : */
1679 :
1680 : /*
1681 : * The namespace's hostname will not have more labels than maxdots + 1.
1682 : * Thus we truncate immediately down to maxdots + 1 if we haven't yet.
1683 : *
1684 : * Example: with maxdots == 3,
1685 : * foo.bar.baz.app.blah.example -> baz.app.blah.example
1686 : */
1687 0 : while (maxdots && hdots > maxdots && tmp) {
1688 0 : tmp = strchr(tmp, '.');
1689 : /* tmp != NULL because maxdots > 0; we check to quiet linters */
1690 0 : if (tmp == NULL) {
1691 0 : ret = HDB_ERR_NOENTRY;
1692 0 : goto out;
1693 : }
1694 0 : tmp++;
1695 0 : hdots--;
1696 : }
1697 :
1698 0 : if (nsprinc == NULL)
1699 : /* First go around, need a namespace princ. Make it! */
1700 0 : ret2 = make_namespace_princ(context, db, tmpprinc, &nsprinc);
1701 :
1702 : /* Update the hostname component of the namespace principal */
1703 0 : if (ret2 == 0)
1704 0 : ret2 = krb5_principal_set_comp_string(context, nsprinc, 3, tmp);
1705 0 : if (ret2)
1706 0 : ret = ret2;
1707 :
1708 0 : if (tmp) {
1709 : /* Strip off left-most label for the next go-around */
1710 0 : if ((tmp = strchr(tmp, '.')))
1711 0 : tmp++;
1712 0 : hdots--;
1713 : } /* else we'll break out after the next db->hdb_fetch_kvno() call */
1714 : }
1715 :
1716 : /*
1717 : * If unencrypted keys were requested, derive them. There may not be any
1718 : * key derivation to do, but that's decided in derive_keys().
1719 : */
1720 313941 : if (ret == 0 || ret == HDB_ERR_WRONG_REALM) {
1721 309171 : krb5_error_code save_ret = ret;
1722 :
1723 : /* Fix the principal name if namespaced */
1724 309171 : ret = fix_princ_name(context, princ, nsprinc, ent);
1725 :
1726 : /* Derive keys if namespaced or virtual */
1727 309171 : if (ret == 0)
1728 309171 : ret = derive_keys(context, flags, princ, !!nsprinc, t, etype, kvno,
1729 : ent);
1730 : /* Pick the best kvno for this principal at the given time */
1731 309171 : if (ret == 0)
1732 309171 : ret = pick_kvno(context, db, flags, t, kvno, ent);
1733 309171 : if (ret == 0)
1734 309171 : ret = save_ret;
1735 : }
1736 :
1737 4770 : out:
1738 313941 : if (ret != 0 && ret != HDB_ERR_WRONG_REALM)
1739 4770 : hdb_free_entry(context, db, ent);
1740 313941 : krb5_free_principal(context, nsprinc);
1741 313941 : free(host);
1742 313941 : return ret;
1743 : }
1744 :
1745 : /**
1746 : * Fetch a principal's HDB entry, possibly generating virtual keys from base
1747 : * keys according to strict key rotation schedules. If a time is given, other
1748 : * than HDB I/O, this function is pure, thus usable for testing.
1749 : *
1750 : * HDB writers should use `db->hdb_fetch_kvno()' to avoid materializing virtual
1751 : * principals.
1752 : *
1753 : * HDB readers should use this function rather than `db->hdb_fetch_kvno()'
1754 : * unless they only want to see concrete principals and not bother generating
1755 : * any virtual keys.
1756 : *
1757 : * @param context Context
1758 : * @param db HDB
1759 : * @param principal Principal name
1760 : * @param flags Fetch flags
1761 : * @param t For virtual keys, use this as the point in time (use zero to mean "now")
1762 : * @param etype Key enctype (use KRB5_ENCTYPE_NULL to mean "preferred")
1763 : * @param kvno Key version number (use zero to mean "current")
1764 : * @param h Output HDB entry
1765 : *
1766 : * @return Zero or HDB_ERR_WRONG_REALM on success, an error code otherwise.
1767 : */
1768 : krb5_error_code
1769 313941 : hdb_fetch_kvno(krb5_context context,
1770 : HDB *db,
1771 : krb5_const_principal principal,
1772 : unsigned int flags,
1773 : krb5_timestamp t,
1774 : krb5int32 etype,
1775 : krb5uint32 kvno,
1776 : hdb_entry *h)
1777 : {
1778 10142 : krb5_error_code ret;
1779 10142 : krb5_timestamp now;
1780 :
1781 313941 : krb5_timeofday(context, &now);
1782 :
1783 313941 : flags |= kvno ? HDB_F_KVNO_SPECIFIED : 0; /* XXX is this needed */
1784 313941 : ret = fetch_it(context, db, principal, flags, t ? t : now, etype, kvno, h);
1785 313941 : if (ret == 0 && t == 0 && h->flags.virtual &&
1786 0 : h->pw_end && h->pw_end[0] < now) {
1787 : /*
1788 : * This shouldn't happen!
1789 : *
1790 : * Do not allow h->pw_end[0] to be in the past for virtual principals
1791 : * outside testing. This is just to prevent the AS/TGS from failing.
1792 : */
1793 0 : h->pw_end[0] = now + 3600;
1794 : }
1795 313941 : if (ret == HDB_ERR_NOENTRY)
1796 1750 : krb5_set_error_message(context, ret, "no such entry found in hdb");
1797 313941 : return ret;
1798 : }
1799 :
1800 : size_t ASN1CALL
1801 0 : length_hdb_keyset(HDB_keyset *data)
1802 : {
1803 0 : return length_HDB_keyset(data);
1804 : }
1805 :
1806 : size_t ASN1CALL
1807 0 : length_hdb_entry(HDB_entry *data)
1808 : {
1809 0 : return length_HDB_entry(data);
1810 : }
1811 :
1812 : size_t ASN1CALL
1813 0 : length_hdb_entry_alias(HDB_entry_alias *data)
1814 : {
1815 0 : return length_HDB_entry_alias(data);
1816 : }
1817 :
1818 : void ASN1CALL
1819 0 : free_hdb_keyset(HDB_keyset *data)
1820 : {
1821 0 : free_HDB_keyset(data);
1822 0 : }
1823 :
1824 : void ASN1CALL
1825 0 : free_hdb_entry(HDB_entry *data)
1826 : {
1827 0 : free_HDB_entry(data);
1828 0 : }
1829 :
1830 : void ASN1CALL
1831 0 : free_hdb_entry_alias(HDB_entry_alias *data)
1832 : {
1833 0 : free_HDB_entry_alias(data);
1834 0 : }
1835 :
1836 : size_t ASN1CALL
1837 0 : copy_hdb_keyset(const HDB_keyset *from, HDB_keyset *to)
1838 : {
1839 0 : return copy_HDB_keyset(from, to);
1840 : }
1841 :
1842 : size_t ASN1CALL
1843 0 : copy_hdb_entry(const HDB_entry *from, HDB_entry *to)
1844 : {
1845 0 : return copy_HDB_entry(from, to);
1846 : }
1847 :
1848 : size_t ASN1CALL
1849 0 : copy_hdb_entry_alias(const HDB_entry_alias *from, HDB_entry_alias *to)
1850 : {
1851 0 : return copy_HDB_entry_alias(from, to);
1852 : }
1853 :
1854 : int ASN1CALL
1855 0 : decode_hdb_keyset(const unsigned char *p,
1856 : size_t len,
1857 : HDB_keyset *data,
1858 : size_t *size)
1859 : {
1860 0 : return decode_HDB_keyset(p, len, data, size);
1861 : }
1862 :
1863 : int ASN1CALL
1864 0 : decode_hdb_entry(const unsigned char *p,
1865 : size_t len,
1866 : HDB_entry *data,
1867 : size_t *size)
1868 : {
1869 0 : return decode_HDB_entry(p, len, data, size);
1870 : }
1871 :
1872 : int ASN1CALL
1873 0 : decode_hdb_entry_alias(const unsigned char *p,
1874 : size_t len,
1875 : HDB_entry_alias *data,
1876 : size_t *size)
1877 : {
1878 0 : return decode_HDB_entry_alias(p, len, data, size);
1879 : }
1880 :
1881 : int ASN1CALL
1882 0 : encode_hdb_keyset(unsigned char *p,
1883 : size_t len,
1884 : const HDB_keyset *data,
1885 : size_t *size)
1886 : {
1887 0 : return encode_HDB_keyset(p, len, data, size);
1888 : }
1889 :
1890 : int ASN1CALL
1891 0 : encode_hdb_entry(unsigned char *p,
1892 : size_t len,
1893 : const HDB_entry *data,
1894 : size_t *size)
1895 : {
1896 0 : return encode_HDB_entry(p, len, data, size);
1897 : }
1898 :
1899 : int ASN1CALL
1900 0 : encode_hdb_entry_alias(unsigned char *p,
1901 : size_t len,
1902 : const HDB_entry_alias *data,
1903 : size_t *size)
1904 : {
1905 0 : return encode_HDB_entry_alias(p, len, data, size);
1906 : }
|