LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/hdb - common.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 59 682 8.7 %
Date: 2024-06-13 04:01:37 Functions: 5 44 11.4 %

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

Generated by: LCOV version 1.13