LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/hdb - hdb.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 99 366 27.0 %
Date: 2024-04-21 15:09:00 Functions: 10 24 41.7 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
       3             :  * (Royal Institute of Technology, Stockholm, Sweden).
       4             :  * All rights reserved.
       5             :  *
       6             :  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
       7             :  *
       8             :  * Redistribution and use in source and binary forms, with or without
       9             :  * modification, are permitted provided that the following conditions
      10             :  * are met:
      11             :  *
      12             :  * 1. Redistributions of source code must retain the above copyright
      13             :  *    notice, this list of conditions and the following disclaimer.
      14             :  *
      15             :  * 2. Redistributions in binary form must reproduce the above copyright
      16             :  *    notice, this list of conditions and the following disclaimer in the
      17             :  *    documentation and/or other materials provided with the distribution.
      18             :  *
      19             :  * 3. Neither the name of the Institute nor the names of its contributors
      20             :  *    may be used to endorse or promote products derived from this software
      21             :  *    without specific prior written permission.
      22             :  *
      23             :  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
      24             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      25             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      26             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
      27             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      28             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      29             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      30             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      31             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      32             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      33             :  * SUCH DAMAGE.
      34             :  */
      35             : 
      36             : #include "krb5_locl.h"
      37             : #include "hdb_locl.h"
      38             : 
      39             : #ifdef HAVE_DLFCN_H
      40             : #include <dlfcn.h>
      41             : #endif
      42             : 
      43             : /*! @mainpage Heimdal database backend library
      44             :  *
      45             :  * @section intro Introduction
      46             :  *
      47             :  * Heimdal libhdb library provides the backend support for Heimdal kdc
      48             :  * and kadmind. Its here where plugins for diffrent database engines
      49             :  * can be pluged in and extend support for here Heimdal get the
      50             :  * principal and policy data from.
      51             :  *
      52             :  * Example of Heimdal backend are:
      53             :  * - Berkeley DB 1.85
      54             :  * - Berkeley DB 3.0
      55             :  * - Berkeley DB 4.0
      56             :  * - New Berkeley DB
      57             :  * - LDAP
      58             :  *
      59             :  *
      60             :  * The project web page: http://www.h5l.org/
      61             :  *
      62             :  */
      63             : 
      64             : const int hdb_interface_version = HDB_INTERFACE_VERSION;
      65             : 
      66             : static struct hdb_method methods[] = {
      67             :     /* "db:" should be db3 if we have db3, or db1 if we have db1 */
      68             : #if HAVE_DB3
      69             :     { HDB_INTERFACE_VERSION, NULL, NULL, 1 /*is_file_based*/, 1 /*can_taste*/,
      70             :                                                "db:", hdb_db3_create},
      71             : #elif HAVE_DB1
      72             :     { HDB_INTERFACE_VERSION, NULL, NULL, 1, 1, "db:", hdb_db1_create},
      73             : #endif
      74             : #if HAVE_DB1
      75             :     { HDB_INTERFACE_VERSION, NULL, NULL, 1, 1, "db1:",        hdb_db1_create},
      76             : #endif
      77             : #if HAVE_DB3
      78             :     { HDB_INTERFACE_VERSION, NULL, NULL, 1, 1, "db3:",        hdb_db3_create},
      79             : #endif
      80             : #if HAVE_MITDB
      81             :     { HDB_INTERFACE_VERSION, NULL, NULL, 1, 1, "mit-db:",     hdb_mitdb_create},
      82             : #endif
      83             : #if HAVE_LMDB
      84             :     { HDB_INTERFACE_VERSION, NULL, NULL, 1, 1, "mdb:",        hdb_mdb_create},
      85             :     { HDB_INTERFACE_VERSION, NULL, NULL, 1, 1, "lmdb:",       hdb_mdb_create},
      86             : #endif
      87             : #if HAVE_NDBM
      88             :     { HDB_INTERFACE_VERSION, NULL, NULL, 1, 0, "ndbm:",       hdb_ndbm_create},
      89             : #endif
      90             : #ifdef HAVE_SQLITE3
      91             :     { HDB_INTERFACE_VERSION, NULL, NULL, 1, 1, "sqlite:", hdb_sqlite_create},
      92             : #endif
      93             :     /* The keytab interface can't use its hdb_open() method to "taste" a DB */
      94             :     { HDB_INTERFACE_VERSION, NULL, NULL, 1, 0, "keytab:",     hdb_keytab_create},
      95             :     /* The rest are not file-based */
      96             : #if defined(OPENLDAP) && !defined(OPENLDAP_MODULE)
      97             :     { HDB_INTERFACE_VERSION, NULL, NULL, 0, 0, "ldap:",       hdb_ldap_create},
      98             :     { HDB_INTERFACE_VERSION, NULL, NULL, 0, 0, "ldapi:",      hdb_ldapi_create},
      99             : #elif defined(OPENLDAP)
     100             :     { HDB_INTERFACE_VERSION, NULL, NULL, 0, 0, "ldap:",       NULL},
     101             :     { HDB_INTERFACE_VERSION, NULL, NULL, 0, 0, "ldapi:", NULL},
     102             : #endif
     103             :     { 0, NULL, NULL, 0, 0, NULL, NULL}
     104             : };
     105             : 
     106             : /**
     107             :  * Returns the Keys of `e' for `kvno', or NULL if not found.  The Keys will
     108             :  * remain valid provided that the entry is not mutated.
     109             :  *
     110             :  * @param context Context
     111             :  * @param e The HDB entry
     112             :  * @param kvno The kvno
     113             :  *
     114             :  * @return A pointer to the Keys for the requested kvno.
     115             :  */
     116             : const Keys *
     117       82431 : hdb_kvno2keys(krb5_context context,
     118             :               const hdb_entry *e,
     119             :               krb5_kvno kvno)
     120             : {
     121        2828 :     HDB_Ext_KeySet *hist_keys;
     122        2828 :     HDB_extension *extp;
     123        2828 :     size_t i;
     124             : 
     125       82431 :     if (kvno == 0 || e->kvno == kvno)
     126       82121 :         return &e->keys;
     127             : 
     128         310 :     extp = hdb_find_extension(e, choice_HDB_extension_data_hist_keys);
     129         310 :     if (extp == NULL)
     130         159 :         return 0;
     131             : 
     132         151 :     hist_keys = &extp->data.u.hist_keys;
     133         164 :     for (i = 0; i < hist_keys->len; i++) {
     134         163 :         if (hist_keys->val[i].kvno == kvno)
     135         150 :             return &hist_keys->val[i].keys;
     136             :     }
     137             : 
     138           1 :     return NULL;
     139             : }
     140             : 
     141             : /* Based on remove_HDB_Ext_KeySet(), generated by the ASN.1 compiler */
     142             : static int
     143           0 : dequeue_HDB_Ext_KeySet(HDB_Ext_KeySet *data, unsigned int element, hdb_keyset *ks)
     144             : {
     145           0 :     if (element >= data->len) {
     146           0 :         ks->kvno = 0;
     147           0 :         ks->keys.len = 0;
     148           0 :         ks->keys.val = 0;
     149           0 :         ks->set_time = 0;
     150           0 :         return ASN1_OVERRUN;
     151             :     }
     152           0 :     *ks = data->val[element];
     153           0 :     data->len--;
     154             :     /* Swap instead of memmove()... changes the order of elements */
     155           0 :     if (element < data->len)
     156           0 :         data->val[element] = data->val[data->len];
     157           0 :     if (data->len == 0) {
     158           0 :         free(data->val);
     159           0 :         data->val = 0;
     160             :     }
     161           0 :     return 0;
     162             : }
     163             : 
     164             : 
     165             : /**
     166             :  * Removes from `e' and optionally outputs the keyset for the requested `kvno'.
     167             :  *
     168             :  * @param context Context
     169             :  * @param e The HDB entry
     170             :  * @param kvno The key version number
     171             :  * @param ks A pointer to a variable of type hdb_keyset (may be NULL)
     172             :  *
     173             :  * @return Zero on success, an error code otherwise.
     174             :  */
     175             : krb5_error_code
     176           0 : hdb_remove_keys(krb5_context context,
     177             :                 hdb_entry *e,
     178             :                 krb5_kvno kvno,
     179             :                 hdb_keyset *ks)
     180             : {
     181           0 :     HDB_Ext_KeySet *hist_keys;
     182           0 :     HDB_extension *extp;
     183           0 :     size_t i;
     184             : 
     185           0 :     if (kvno == 0 || e->kvno == kvno) {
     186           0 :         if (ks) {
     187           0 :             KerberosTime t;
     188             : 
     189           0 :             (void) hdb_entry_get_pw_change_time(e, &t);
     190           0 :             if (t) {
     191           0 :                 if ((ks->set_time = malloc(sizeof(*ks->set_time))) == NULL)
     192           0 :                     return krb5_enomem(context);
     193           0 :                 *ks->set_time = t;
     194             :             }
     195           0 :             ks->kvno = e->kvno;
     196           0 :             ks->keys = e->keys;
     197           0 :             e->keys.len = 0;
     198           0 :             e->keys.val = NULL;
     199           0 :             e->kvno = 0;
     200             :         } else {
     201           0 :             free_Keys(&e->keys);
     202             :         }
     203           0 :         return 0;
     204             :     }
     205             : 
     206           0 :     if (ks) {
     207           0 :         ks->kvno = 0;
     208           0 :         ks->keys.len = 0;
     209           0 :         ks->keys.val = 0;
     210           0 :         ks->set_time = 0;
     211             :     }
     212             : 
     213           0 :     extp = hdb_find_extension(e, choice_HDB_extension_data_hist_keys);
     214           0 :     if (extp == NULL)
     215           0 :         return 0;
     216             : 
     217           0 :     hist_keys = &extp->data.u.hist_keys;
     218           0 :     for (i = 0; i < hist_keys->len; i++) {
     219           0 :         if (hist_keys->val[i].kvno != kvno)
     220           0 :             continue;
     221           0 :         if (ks)
     222           0 :             return dequeue_HDB_Ext_KeySet(hist_keys, i, ks);
     223           0 :         return remove_HDB_Ext_KeySet(hist_keys, i);
     224             :     }
     225           0 :     return HDB_ERR_NOENTRY;
     226             : }
     227             : 
     228             : /**
     229             :  * Removes from `e' and outputs all the base keys for virtual principal and/or
     230             :  * key derivation.
     231             :  *
     232             :  * @param context Context
     233             :  * @param e The HDB entry
     234             :  * @param ks A pointer to a variable of type HDB_Ext_KeySet
     235             :  * @param ckr A pointer to stable (copied) HDB_Ext_KeyRotation
     236             :  *
     237             :  * @return Zero on success, an error code otherwise.
     238             :  */
     239             : krb5_error_code
     240           0 : _hdb_remove_base_keys(krb5_context context,
     241             :                       hdb_entry *e,
     242             :                       HDB_Ext_KeySet *base_keys,
     243             :                       const HDB_Ext_KeyRotation *ckr)
     244             : {
     245           0 :     krb5_error_code ret = 0;
     246           0 :     size_t i, k;
     247             : 
     248           0 :     base_keys->len = 0;
     249           0 :     if ((base_keys->val = calloc(ckr->len, sizeof(base_keys->val[0]))) == NULL)
     250           0 :         ret = krb5_enomem(context);
     251             : 
     252           0 :     for (k = i = 0; ret == 0 && i < ckr->len; i++) {
     253           0 :         const KeyRotation *krp = &ckr->val[i];
     254             : 
     255             :         /*
     256             :          * WARNING: O(N * M) where M is number of keysets and N is the number
     257             :          *          of base keysets.
     258             :          *
     259             :          * In practice N will never be > 3 because the ASN.1 module imposes
     260             :          * that as a constraint, and M will generally be the same as N, so this
     261             :          * will be O(1) after all.
     262             :          */
     263           0 :         ret = hdb_remove_keys(context, e, krp->base_key_kvno,
     264           0 :                               &base_keys->val[k]);
     265           0 :         if (ret == 0)
     266           0 :             k++;
     267           0 :         else if (ret == HDB_ERR_NOENTRY)
     268           0 :             ret = 0;
     269             :     }
     270           0 :     if (ret == 0)
     271           0 :         base_keys->len = k;
     272             :     else
     273           0 :         free_HDB_Ext_KeySet(base_keys);
     274           0 :     return 0;
     275             : }
     276             : 
     277             : /**
     278             :  * Removes from `e' and outputs all the base keys for virtual principal and/or
     279             :  * key derivation.
     280             :  *
     281             :  * @param context Context
     282             :  * @param e The HDB entry
     283             :  * @param is_current_keyset Whether to make the keys the current keys for `e'
     284             :  * @param ks A pointer to an hdb_keyset containing the keys to set
     285             :  *
     286             :  * @return Zero on success, an error code otherwise.
     287             :  */
     288             : krb5_error_code
     289           0 : hdb_install_keyset(krb5_context context,
     290             :                    hdb_entry *e,
     291             :                    int is_current_keyset,
     292             :                    const hdb_keyset *ks)
     293             : {
     294           0 :     krb5_error_code ret = 0;
     295             : 
     296           0 :     if (is_current_keyset) {
     297           0 :         if (e->keys.len &&
     298           0 :             (ret = hdb_add_current_keys_to_history(context, e)))
     299           0 :             return ret;
     300           0 :         free_Keys(&e->keys);
     301           0 :         e->kvno = ks->kvno;
     302           0 :         if (ret == 0)
     303           0 :             ret = copy_Keys(&ks->keys, &e->keys);
     304           0 :         if (ret == 0 && ks->set_time)
     305           0 :             ret = hdb_entry_set_pw_change_time(context, e, *ks->set_time);
     306           0 :         return ret;
     307             :     }
     308           0 :     return hdb_add_history_keyset(context, e, ks);
     309             : }
     310             : 
     311             : 
     312             : krb5_error_code
     313      406322 : hdb_next_enctype2key(krb5_context context,
     314             :                      const hdb_entry *e,
     315             :                      const Keys *keyset,
     316             :                      krb5_enctype enctype,
     317             :                      Key **key)
     318             : {
     319      406322 :     const Keys *keys = keyset ? keyset : &e->keys;
     320       10742 :     Key *k;
     321             : 
     322      535598 :     for (k = *key ? (*key) + 1 : keys->val; k < keys->val + keys->len; k++) {
     323      423105 :         if(k->key.keytype == enctype){
     324      304571 :             *key = k;
     325      304571 :             return 0;
     326             :         }
     327             :     }
     328      101751 :     krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
     329             :                            "No next enctype %d for hdb-entry",
     330             :                           (int)enctype);
     331      101751 :     return KRB5_PROG_ETYPE_NOSUPP; /* XXX */
     332             : }
     333             : 
     334             : krb5_error_code
     335      367462 : hdb_enctype2key(krb5_context context,
     336             :                 const hdb_entry *e,
     337             :                 const Keys *keyset,
     338             :                 krb5_enctype enctype,
     339             :                 Key **key)
     340             : {
     341      367462 :     *key = NULL;
     342      367462 :     return hdb_next_enctype2key(context, e, keyset, enctype, key);
     343             : }
     344             : 
     345             : void
     346           0 : hdb_free_key(Key *key)
     347             : {
     348           0 :     memset_s(key->key.keyvalue.data,
     349             :              key->key.keyvalue.length,
     350             :              0,
     351             :              key->key.keyvalue.length);
     352           0 :     free_Key(key);
     353           0 :     free(key);
     354           0 : }
     355             : 
     356             : 
     357             : krb5_error_code
     358           0 : hdb_lock(int fd, int operation)
     359             : {
     360           0 :     int i, code = 0;
     361             : 
     362           0 :     for(i = 0; i < 3; i++){
     363           0 :         code = flock(fd, (operation == HDB_RLOCK ? LOCK_SH : LOCK_EX) | LOCK_NB);
     364           0 :         if(code == 0 || errno != EWOULDBLOCK)
     365             :             break;
     366           0 :         sleep(1);
     367             :     }
     368           0 :     if(code == 0)
     369           0 :         return 0;
     370           0 :     if(errno == EWOULDBLOCK)
     371           0 :         return HDB_ERR_DB_INUSE;
     372           0 :     return HDB_ERR_CANT_LOCK_DB;
     373             : }
     374             : 
     375             : krb5_error_code
     376           0 : hdb_unlock(int fd)
     377             : {
     378           0 :     int code;
     379           0 :     code = flock(fd, LOCK_UN);
     380           0 :     if(code)
     381           0 :         return 4711 /* XXX */;
     382           0 :     return 0;
     383             : }
     384             : 
     385             : void
     386      313571 : hdb_free_entry(krb5_context context, HDB *db, hdb_entry *ent)
     387             : {
     388       10142 :     Key *k;
     389       10142 :     size_t i;
     390             : 
     391      313571 :     if (db && db->hdb_free_entry_context)
     392      313571 :         db->hdb_free_entry_context(context, db, ent);
     393             : 
     394      842491 :     for(i = 0; i < ent->keys.len; i++) {
     395      528920 :         k = &ent->keys.val[i];
     396             : 
     397      528920 :         memset_s(k->key.keyvalue.data,
     398             :                  k->key.keyvalue.length,
     399             :                  0,
     400             :                  k->key.keyvalue.length);
     401             :     }
     402      313571 :     free_HDB_entry(ent);
     403      313571 : }
     404             : 
     405             : krb5_error_code
     406           0 : hdb_foreach(krb5_context context,
     407             :             HDB *db,
     408             :             unsigned flags,
     409             :             hdb_foreach_func_t func,
     410             :             void *data)
     411             : {
     412           0 :     krb5_error_code ret;
     413           0 :     hdb_entry entry;
     414           0 :     ret = db->hdb_firstkey(context, db, flags, &entry);
     415           0 :     if (ret == 0)
     416           0 :         krb5_clear_error_message(context);
     417           0 :     while(ret == 0){
     418           0 :         ret = (*func)(context, db, &entry, data);
     419           0 :         hdb_free_entry(context, db, &entry);
     420           0 :         if(ret == 0)
     421           0 :             ret = db->hdb_nextkey(context, db, flags, &entry);
     422             :     }
     423           0 :     if(ret == HDB_ERR_NOENTRY)
     424           0 :         ret = 0;
     425           0 :     return ret;
     426             : }
     427             : 
     428             : krb5_error_code
     429           0 : hdb_check_db_format(krb5_context context, HDB *db)
     430             : {
     431           0 :     krb5_data tag;
     432           0 :     krb5_data version;
     433           0 :     krb5_error_code ret, ret2;
     434           0 :     unsigned ver;
     435           0 :     int foo;
     436             : 
     437           0 :     ret = db->hdb_lock(context, db, HDB_RLOCK);
     438           0 :     if (ret)
     439           0 :         return ret;
     440             : 
     441           0 :     tag.data = (void *)(intptr_t)HDB_DB_FORMAT_ENTRY;
     442           0 :     tag.length = strlen(tag.data);
     443           0 :     ret = (*db->hdb__get)(context, db, tag, &version);
     444           0 :     ret2 = db->hdb_unlock(context, db);
     445           0 :     if(ret)
     446           0 :         return ret;
     447           0 :     if (ret2)
     448           0 :         return ret2;
     449           0 :     foo = sscanf(version.data, "%u", &ver);
     450           0 :     krb5_data_free (&version);
     451           0 :     if (foo != 1)
     452           0 :         return HDB_ERR_BADVERSION;
     453           0 :     if(ver != HDB_DB_FORMAT)
     454           0 :         return HDB_ERR_BADVERSION;
     455           0 :     return 0;
     456             : }
     457             : 
     458             : krb5_error_code
     459           0 : hdb_init_db(krb5_context context, HDB *db)
     460             : {
     461           0 :     krb5_error_code ret, ret2;
     462           0 :     krb5_data tag;
     463           0 :     krb5_data version;
     464           0 :     char ver[32];
     465             : 
     466           0 :     ret = hdb_check_db_format(context, db);
     467           0 :     if(ret != HDB_ERR_NOENTRY)
     468           0 :         return ret;
     469             : 
     470           0 :     ret = db->hdb_lock(context, db, HDB_WLOCK);
     471           0 :     if (ret)
     472           0 :         return ret;
     473             : 
     474           0 :     tag.data = (void *)(intptr_t)HDB_DB_FORMAT_ENTRY;
     475           0 :     tag.length = strlen(tag.data);
     476           0 :     snprintf(ver, sizeof(ver), "%u", HDB_DB_FORMAT);
     477           0 :     version.data = ver;
     478           0 :     version.length = strlen(version.data) + 1; /* zero terminated */
     479           0 :     ret = (*db->hdb__put)(context, db, 0, tag, version);
     480           0 :     ret2 = db->hdb_unlock(context, db);
     481           0 :     if (ret) {
     482           0 :         if (ret2)
     483           0 :             krb5_clear_error_message(context);
     484           0 :         return ret;
     485             :     }
     486           0 :     return ret2;
     487             : }
     488             : 
     489             : /*
     490             :  * `default_dbmethod' is the last resort default.
     491             :  *
     492             :  * In hdb_create() we may try all the `methods[]' until one succeeds or all
     493             :  * fail.
     494             :  */
     495             : #if defined(HAVE_LMDB)
     496             : static struct hdb_method default_dbmethod =
     497             :     { HDB_INTERFACE_VERSION, NULL, NULL, 1, 1, "", hdb_mdb_create };
     498             : #elif defined(HAVE_DB3)
     499             : static struct hdb_method default_dbmethod =
     500             :     { HDB_INTERFACE_VERSION, NULL, NULL, 1, 1, "", hdb_db3_create };
     501             : #elif defined(HAVE_DB1)
     502             : static struct hdb_method default_dbmethod =
     503             :     { HDB_INTERFACE_VERSION, NULL, NULL, 1, 1, "", hdb_db1_create };
     504             : #elif defined(HAVE_NDBM)
     505             : static struct hdb_method default_dbmethod =
     506             :     { HDB_INTERFACE_VERSION, NULL, NULL, 0, 1, "", hdb_ndbm_create };
     507             : #else
     508             : static struct hdb_method default_dbmethod =
     509             :     { 0, NULL, NULL, 0, 0, NULL, NULL};
     510             : #endif
     511             : 
     512             : static int
     513           0 : is_pathish(const char *s)
     514             : {
     515           0 :     if (s[0] == '/' ||
     516           0 :         strncmp(s, "./", sizeof("./") - 1) == 0 ||
     517           0 :         strncmp(s, "../", sizeof("../") - 1) == 0)
     518           0 :         return 1;
     519             : #ifdef WIN32
     520             :     if (s[0] == '\\' || (isalpha((unsigned char)s[0]) && s[0] == ':') ||
     521             :         strncmp(s, ".\\", sizeof(".\\") - 1) == 0 ||
     522             :         strncmp(s, "\\\\", sizeof("\\\\") - 1) == 0)
     523             :         return 1;
     524             : #endif
     525           0 :     return 0;
     526             : }
     527             : 
     528             : static const struct hdb_method *
     529          68 : has_method_prefix(const char *filename)
     530             : {
     531           0 :     const struct hdb_method *h;
     532             : 
     533         136 :     for (h = methods; h->prefix != NULL; ++h)
     534          68 :         if (strncmp(filename, h->prefix, strlen(h->prefix)) == 0)
     535           0 :             return h;
     536          68 :     return NULL;
     537             : }
     538             : 
     539             : /*
     540             :  * find the relevant method for `filename', returning a pointer to the
     541             :  * rest in `rest'.
     542             :  * return NULL if there's no such method.
     543             :  */
     544             : 
     545             : static const struct hdb_method *
     546          68 : find_method(const char *filename, const char **rest)
     547             : {
     548          68 :     const struct hdb_method *h = has_method_prefix(filename);
     549             : 
     550          68 :     *rest = h ? filename + strlen(h->prefix) : filename;
     551          68 :     return h;
     552             : }
     553             : 
     554             : struct cb_s {
     555             :     const char *residual;
     556             :     const char *filename;
     557             :     const struct hdb_method *h;
     558             : };
     559             : 
     560             : static krb5_error_code KRB5_LIB_CALL
     561          68 : callback(krb5_context context, const void *plug, void *plugctx, void *userctx)
     562             : {
     563          68 :     const struct hdb_method *h = (const struct hdb_method *)plug;
     564          68 :     struct cb_s *cb_ctx = (struct cb_s *)userctx;
     565             : 
     566          68 :     if (strncmp(cb_ctx->filename, h->prefix, strlen(h->prefix)) == 0) {
     567          68 :         cb_ctx->residual = cb_ctx->filename + strlen(h->prefix) + 1;
     568          68 :         cb_ctx->h = h;
     569          68 :         return 0;
     570             :     }
     571           0 :    return KRB5_PLUGIN_NO_HANDLE;
     572             : }
     573             : 
     574             : static char *
     575          68 : make_sym(const char *prefix)
     576             : {
     577           0 :     char *s, *sym;
     578             : 
     579          68 :     errno = 0;
     580          68 :     if (prefix == NULL || prefix[0] == '\0')
     581           0 :         return NULL;
     582          68 :     if ((s = strdup(prefix)) == NULL)
     583           0 :         return NULL;
     584          68 :     if (strchr(s, ':') != NULL)
     585          68 :         *strchr(s, ':') = '\0';
     586          68 :     if (asprintf(&sym, "hdb_%s_interface", s) == -1)
     587           0 :         sym = NULL;
     588          68 :     free(s);
     589          68 :     return sym;
     590             : }
     591             : 
     592             : static const char *hdb_plugin_deps[] = { "hdb", "krb5", NULL };
     593             : 
     594             : krb5_error_code
     595           0 : hdb_list_builtin(krb5_context context, char **list)
     596             : {
     597           0 :     const struct hdb_method *h;
     598           0 :     size_t len = 0;
     599           0 :     char *buf = NULL;
     600             : 
     601           0 :     for (h = methods; h->prefix != NULL; ++h) {
     602           0 :         if (h->prefix[0] == '\0')
     603           0 :             continue;
     604           0 :         len += strlen(h->prefix) + 2;
     605             :     }
     606             : 
     607           0 :     len += 1;
     608           0 :     buf = malloc(len);
     609           0 :     if (buf == NULL) {
     610           0 :         return krb5_enomem(context);
     611             :     }
     612           0 :     buf[0] = '\0';
     613             : 
     614           0 :     for (h = methods; h->prefix != NULL; ++h) {
     615           0 :         if (h->create == NULL) {
     616           0 :             struct cb_s cb_ctx;
     617           0 :             char *f;
     618           0 :             struct heim_plugin_data hdb_plugin_data;
     619             : 
     620           0 :             hdb_plugin_data.module = "krb5";
     621           0 :             hdb_plugin_data.min_version = HDB_INTERFACE_VERSION;
     622           0 :             hdb_plugin_data.deps = hdb_plugin_deps;
     623           0 :             hdb_plugin_data.get_instance = hdb_get_instance;
     624             : 
     625             :             /* Try loading the plugin */
     626           0 :             if (asprintf(&f, "%sfoo", h->prefix) == -1)
     627           0 :                 f = NULL;
     628           0 :             if ((hdb_plugin_data.name = make_sym(h->prefix)) == NULL) {
     629           0 :                 free(buf);
     630           0 :                 free(f);
     631           0 :                 return krb5_enomem(context);
     632             :             }
     633           0 :             cb_ctx.filename = f;
     634           0 :             cb_ctx.residual = NULL;
     635           0 :             cb_ctx.h = NULL;
     636           0 :             (void)_krb5_plugin_run_f(context, &hdb_plugin_data, 0,
     637             :                                      &cb_ctx, callback);
     638           0 :             free(f);
     639           0 :             free(rk_UNCONST(hdb_plugin_data.name));
     640           0 :             if (cb_ctx.h == NULL || cb_ctx.h->create == NULL)
     641           0 :                 continue;
     642             :         }
     643           0 :         if (h != methods)
     644           0 :             strlcat(buf, ", ", len);
     645           0 :         strlcat(buf, h->prefix, len);
     646             :     }
     647           0 :     *list = buf;
     648           0 :     return 0;
     649             : }
     650             : 
     651             : krb5_error_code
     652           0 : _hdb_keytab2hdb_entry(krb5_context context,
     653             :                       const krb5_keytab_entry *ktentry,
     654             :                       hdb_entry *entry)
     655             : {
     656           0 :     entry->kvno = ktentry->vno;
     657           0 :     entry->created_by.time = ktentry->timestamp;
     658             : 
     659           0 :     entry->keys.val = calloc(1, sizeof(entry->keys.val[0]));
     660           0 :     if (entry->keys.val == NULL)
     661           0 :         return ENOMEM;
     662           0 :     entry->keys.len = 1;
     663             : 
     664           0 :     entry->keys.val[0].mkvno = NULL;
     665           0 :     entry->keys.val[0].salt = NULL;
     666             : 
     667           0 :     return krb5_copy_keyblock_contents(context,
     668             :                                        &ktentry->keyblock,
     669           0 :                                        &entry->keys.val[0].key);
     670             : }
     671             : 
     672             : static krb5_error_code
     673          68 : load_config(krb5_context context, HDB *db)
     674             : {
     675          68 :     db->enable_virtual_hostbased_princs =
     676          68 :         krb5_config_get_bool_default(context, NULL, FALSE, "hdb",
     677             :                                      "enable_virtual_hostbased_princs",
     678             :                                      NULL);
     679          68 :     db->virtual_hostbased_princ_ndots =
     680          68 :         krb5_config_get_int_default(context, NULL, 1, "hdb",
     681             :                                     "virtual_hostbased_princ_mindots",
     682             :                                     NULL);
     683          68 :     db->virtual_hostbased_princ_maxdots =
     684          68 :         krb5_config_get_int_default(context, NULL, 0, "hdb",
     685             :                                     "virtual_hostbased_princ_maxdots",
     686             :                                     NULL);
     687          68 :     db->new_service_key_delay =
     688          68 :         krb5_config_get_time_default(context, NULL, 0, "hdb",
     689             :                                      "new_service_key_delay", NULL);
     690             :     /*
     691             :      * XXX Needs freeing in the HDB backends because we don't have a
     692             :      * first-class hdb_close() :(
     693             :      */
     694          68 :     db->virtual_hostbased_princ_svcs =
     695          68 :       krb5_config_get_strings(context, NULL, "hdb",
     696             :                               "virtual_hostbased_princ_svcs", NULL);
     697             :     /* Check for ENOMEM */
     698          68 :     if (db->virtual_hostbased_princ_svcs == NULL
     699          68 :         && krb5_config_get_string(context, NULL, "hdb",
     700             :                                   "virtual_hostbased_princ_svcs", NULL)) {
     701           0 :         return krb5_enomem(context);
     702             :     }
     703          68 :     return 0;
     704             : }
     705             : 
     706             : /**
     707             :  * Create a handle for a Kerberos database
     708             :  *
     709             :  * Create a handle for a Kerberos database backend specified by a
     710             :  * filename.  Doesn't actually create or even open an HDB file(s);
     711             :  * you have to call the hdb_open() open method of the resulting HDB
     712             :  * to open the database, and you have to use O_CREAT to create it.
     713             :  *
     714             :  * If `filename' does not have a backend type prefix, all file-based
     715             :  * backends will be tried until one succeeds or all fail, and if the
     716             :  * HDB exists for some backend, that will be used.  A build-time
     717             :  * default backend type will be used if the `filename' does not exist.
     718             :  *
     719             :  * Note that the actual filename may have a suffix added, such as
     720             :  * ".db".  Also, for backends such as "ldap:" and "ldapi:" the
     721             :  * `filename' is more like a URI.
     722             :  *
     723             :  * @param [in] context Context
     724             :  * @param [out] db HDB handle output
     725             :  * @param [in] filename The name of the HDB
     726             :  *
     727             :  * @return Zero on success else a krb5 error code.
     728             :  */
     729             : 
     730             : krb5_error_code
     731          68 : hdb_create(krb5_context context, HDB **db, const char *filename)
     732             : {
     733          68 :     krb5_error_code ret = ENOTSUP;
     734           0 :     struct cb_s cb_ctx;
     735             : 
     736          68 :     *db = NULL;
     737          68 :     if (filename == NULL)
     738           0 :         filename = hdb_default_db(context);
     739             : 
     740          68 :     cb_ctx.h = find_method(filename, &cb_ctx.residual);
     741          68 :     cb_ctx.filename = filename;
     742             : 
     743          68 :     if (cb_ctx.h == NULL || cb_ctx.h->create == NULL) {
     744           0 :         struct heim_plugin_data hdb_plugin_data;
     745             : 
     746             :         /*
     747             :          * `filename' does not start with a known HDB backend prefix.
     748             :          *
     749             :          * Try plugins.
     750             :          */
     751          68 :         hdb_plugin_data.module = "krb5";
     752          68 :         hdb_plugin_data.min_version = HDB_INTERFACE_VERSION;
     753          68 :         hdb_plugin_data.deps = hdb_plugin_deps;
     754          68 :         hdb_plugin_data.get_instance = hdb_get_instance;
     755             : 
     756          68 :         if ((hdb_plugin_data.name = make_sym(filename)) == NULL)
     757           0 :             return krb5_enomem(context);
     758             : 
     759          68 :         (void)_krb5_plugin_run_f(context, &hdb_plugin_data, 0 /* flags */,
     760             :                                  &cb_ctx, callback);
     761             : 
     762          68 :         free(rk_UNCONST(hdb_plugin_data.name));
     763             :     }
     764             : 
     765          68 :     if (cb_ctx.h == NULL || cb_ctx.h->create == NULL) {
     766           0 :         int pathish = is_pathish(filename);
     767             :         /*
     768             :          * `filename' does not start with a known HDB backend prefix and it
     769             :          * wasn't handled by any plugin.
     770             :          *
     771             :          * If it's "filename-ish", try all builtin HDB backends that are
     772             :          * local-file-ish, but use hdb_open() to see if the HDB exists and stop
     773             :          * when a backend is found for which the HDB exists.
     774             :          */
     775           0 :         if (!pathish) {
     776           0 :             krb5_set_error_message(context, ret = ENOTSUP,
     777             :                                    "No database support for %s",
     778             :                                    cb_ctx.filename);
     779           0 :             return ret;
     780             :         }
     781           0 :         for (cb_ctx.h = methods; cb_ctx.h->prefix != NULL; cb_ctx.h++) {
     782           0 :             if (cb_ctx.h->is_file_based)
     783           0 :                 continue;
     784           0 :             if (!cb_ctx.h->can_taste)
     785           0 :                 continue;
     786             :             /* Taste the file */
     787           0 :             ret = (*cb_ctx.h->create)(context, db, filename);
     788           0 :             if (ret == 0)
     789           0 :                 ret = (*db)->hdb_open(context, *db, O_RDONLY, 0);
     790           0 :             if (ret == 0) {
     791           0 :                 (void) (*db)->hdb_close(context, *db);
     792           0 :                 break;
     793             :             }
     794           0 :             if (*db)
     795           0 :                 (*db)->hdb_destroy(context, *db);
     796           0 :             *db = NULL;
     797             :         }
     798           0 :         if (cb_ctx.h->prefix == NULL)
     799           0 :             cb_ctx.h = NULL;
     800             :     }
     801             : #ifdef HDB_DEFAULT_DB_TYPE
     802             :     if (cb_ctx.h == NULL) {
     803             :         /*
     804             :          * If still we've not picked a backend, use a build configuration time
     805             :          * default.
     806             :          */
     807             :         for (cb_ctx.h = methods; cb_ctx.h->prefix != NULL; cb_ctx.h++)
     808             :             if (strcmp(cb_ctx.h->prefix, HDB_DEFAULT_DB_TYPE) == 0)
     809             :                 break;
     810             :         if (cb_ctx.h->prefix == NULL)
     811             :             cb_ctx.h = NULL;
     812             :     }
     813             : #endif
     814          68 :     if (cb_ctx.h == NULL)
     815             :         /* Last resort default */
     816           0 :         cb_ctx.h = &default_dbmethod;
     817          68 :     if (cb_ctx.h->prefix == NULL) {
     818           0 :         krb5_set_error_message(context, ENOTSUP,
     819             :                                "Could not determine default DB backend for %s",
     820             :                                filename);
     821           0 :         return ENOTSUP;
     822             :     }
     823          68 :     if (!*db) {
     824          68 :         ret = (*cb_ctx.h->create)(context, db, cb_ctx.residual);
     825          68 :         if (ret == 0)
     826          68 :             (*db)->hdb_method_name = cb_ctx.h->prefix;
     827             :     }
     828          68 :     if (ret == 0 && *db)
     829          68 :         ret = load_config(context, *db);
     830          68 :     if (ret && *db) {
     831           0 :         (*db)->hdb_destroy(context, *db);
     832           0 :         *db = NULL;
     833             :     }
     834          68 :     return ret;
     835             : }
     836             : 
     837             : uintptr_t KRB5_CALLCONV
     838           0 : hdb_get_instance(const char *libname)
     839             : {
     840           0 :     static const char *instance = "libhdb";
     841             : 
     842           0 :     if (strcmp(libname, "hdb") == 0)
     843           0 :         return (uintptr_t)instance;
     844           0 :     else if (strcmp(libname, "krb5") == 0)
     845           0 :         return krb5_get_instance(libname);
     846             : 
     847           0 :     return 0;
     848             : }

Generated by: LCOV version 1.14