LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/hdb - common.c (source / functions) Hit Total Coverage
Test: coverage report for vadcx-master-patch-75612 fe003de8 Lines: 69 807 8.6 %
Date: 2024-02-29 22:57:05 Functions: 5 45 11.1 %

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

Generated by: LCOV version 1.14