Path: blob/main/crypto/heimdal/lib/hdb/hdb-mitdb.c
34907 views
/*1* Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan2* (Royal Institute of Technology, Stockholm, Sweden).3* All rights reserved.4*5* Portions Copyright (c) 2009 Apple Inc. All rights reserved.6*7* Redistribution and use in source and binary forms, with or without8* modification, are permitted provided that the following conditions9* are met:10*11* 1. Redistributions of source code must retain the above copyright12* notice, this list of conditions and the following disclaimer.13*14* 2. Redistributions in binary form must reproduce the above copyright15* notice, this list of conditions and the following disclaimer in the16* documentation and/or other materials provided with the distribution.17*18* 3. Neither the name of the Institute nor the names of its contributors19* may be used to endorse or promote products derived from this software20* without specific prior written permission.21*22* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND23* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE24* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE25* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE26* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL27* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS28* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)29* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT30* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY31* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF32* SUCH DAMAGE.33*/3435#define KRB5_KDB_DISALLOW_POSTDATED 0x0000000136#define KRB5_KDB_DISALLOW_FORWARDABLE 0x0000000237#define KRB5_KDB_DISALLOW_TGT_BASED 0x0000000438#define KRB5_KDB_DISALLOW_RENEWABLE 0x0000000839#define KRB5_KDB_DISALLOW_PROXIABLE 0x0000001040#define KRB5_KDB_DISALLOW_DUP_SKEY 0x0000002041#define KRB5_KDB_DISALLOW_ALL_TIX 0x0000004042#define KRB5_KDB_REQUIRES_PRE_AUTH 0x0000008043#define KRB5_KDB_REQUIRES_HW_AUTH 0x0000010044#define KRB5_KDB_REQUIRES_PWCHANGE 0x0000020045#define KRB5_KDB_DISALLOW_SVR 0x0000100046#define KRB5_KDB_PWCHANGE_SERVICE 0x0000200047#define KRB5_KDB_SUPPORT_DESMD5 0x0000400048#define KRB5_KDB_NEW_PRINC 0x000080004950/*5152key: krb5_unparse_name + NUL535416: baselength5532: attributes5632: max time5732: max renewable time5832: client expire5932: passwd expire6032: last successful passwd6132: last failed attempt6232: num of failed attempts6316: num tl data6416: num data data6516: principal length66length: principal67for num tl data times6816: tl data type6916: tl data length70length: length71for num key data times7216: version (num keyblocks)7316: kvno74for version times:7516: type7616: length77length: keydata787980key_data_contents[0]8182int16: length83read-of-data: key-encrypted, key-usage 0, master-key8485salt:86version2 = salt in key_data->key_data_contents[1]87else default salt.8889*/9091#include "hdb_locl.h"9293#define KDB_V1_BASE_LENGTH 389495#if HAVE_DB19697#if defined(HAVE_DB_185_H)98#include <db_185.h>99#elif defined(HAVE_DB_H)100#include <db.h>101#endif102103#define CHECK(x) do { if ((x)) goto out; } while(0)104105static krb5_error_code106mdb_principal2key(krb5_context context,107krb5_const_principal principal,108krb5_data *key)109{110krb5_error_code ret;111char *str;112113ret = krb5_unparse_name(context, principal, &str);114if (ret)115return ret;116key->data = str;117key->length = strlen(str) + 1;118return 0;119}120121#define KRB5_KDB_SALTTYPE_NORMAL 0122#define KRB5_KDB_SALTTYPE_V4 1123#define KRB5_KDB_SALTTYPE_NOREALM 2124#define KRB5_KDB_SALTTYPE_ONLYREALM 3125#define KRB5_KDB_SALTTYPE_SPECIAL 4126#define KRB5_KDB_SALTTYPE_AFS3 5127#define KRB5_KDB_SALTTYPE_CERTHASH 6128129static krb5_error_code130fix_salt(krb5_context context, hdb_entry *ent, int key_num)131{132krb5_error_code ret;133Salt *salt = ent->keys.val[key_num].salt;134/* fix salt type */135switch((int)salt->type) {136case KRB5_KDB_SALTTYPE_NORMAL:137salt->type = KRB5_PADATA_PW_SALT;138break;139case KRB5_KDB_SALTTYPE_V4:140krb5_data_free(&salt->salt);141salt->type = KRB5_PADATA_PW_SALT;142break;143case KRB5_KDB_SALTTYPE_NOREALM:144{145size_t len;146size_t i;147char *p;148149len = 0;150for (i = 0; i < ent->principal->name.name_string.len; ++i)151len += strlen(ent->principal->name.name_string.val[i]);152ret = krb5_data_alloc (&salt->salt, len);153if (ret)154return ret;155p = salt->salt.data;156for (i = 0; i < ent->principal->name.name_string.len; ++i) {157memcpy (p,158ent->principal->name.name_string.val[i],159strlen(ent->principal->name.name_string.val[i]));160p += strlen(ent->principal->name.name_string.val[i]);161}162163salt->type = KRB5_PADATA_PW_SALT;164break;165}166case KRB5_KDB_SALTTYPE_ONLYREALM:167krb5_data_free(&salt->salt);168ret = krb5_data_copy(&salt->salt,169ent->principal->realm,170strlen(ent->principal->realm));171if(ret)172return ret;173salt->type = KRB5_PADATA_PW_SALT;174break;175case KRB5_KDB_SALTTYPE_SPECIAL:176salt->type = KRB5_PADATA_PW_SALT;177break;178case KRB5_KDB_SALTTYPE_AFS3:179krb5_data_free(&salt->salt);180ret = krb5_data_copy(&salt->salt,181ent->principal->realm,182strlen(ent->principal->realm));183if(ret)184return ret;185salt->type = KRB5_PADATA_AFS3_SALT;186break;187case KRB5_KDB_SALTTYPE_CERTHASH:188krb5_data_free(&salt->salt);189free(ent->keys.val[key_num].salt);190ent->keys.val[key_num].salt = NULL;191break;192default:193abort();194}195return 0;196}197198199static krb5_error_code200mdb_value2entry(krb5_context context, krb5_data *data, krb5_kvno kvno, hdb_entry *entry)201{202krb5_error_code ret;203krb5_storage *sp;204uint32_t u32;205uint16_t u16, num_keys, num_tl;206size_t i, j;207char *p;208209sp = krb5_storage_from_data(data);210if (sp == NULL) {211krb5_set_error_message(context, ENOMEM, "out of memory");212return ENOMEM;213}214215krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE);216217/*218* 16: baselength219*220* The story here is that these 16 bits have to be a constant:221* KDB_V1_BASE_LENGTH. Once upon a time a different value here222* would have been used to indicate the presence of "extra data"223* between the "base" contents and the {principal name, TL data,224* keys} that follow it. Nothing supports such "extra data"225* nowadays, so neither do we here.226*227* XXX But... surely we ought to log about this extra data, or skip228* it, or something, in case anyone has MIT KDBs with ancient229* entries in them... Logging would allow the admin to know which230* entries to dump with MIT krb5's kdb5_util.231*/232CHECK(ret = krb5_ret_uint16(sp, &u16));233if (u16 != KDB_V1_BASE_LENGTH) { ret = EINVAL; goto out; }234/* 32: attributes */235CHECK(ret = krb5_ret_uint32(sp, &u32));236entry->flags.postdate = !(u32 & KRB5_KDB_DISALLOW_POSTDATED);237entry->flags.forwardable = !(u32 & KRB5_KDB_DISALLOW_FORWARDABLE);238entry->flags.initial = !!(u32 & KRB5_KDB_DISALLOW_TGT_BASED);239entry->flags.renewable = !(u32 & KRB5_KDB_DISALLOW_RENEWABLE);240entry->flags.proxiable = !(u32 & KRB5_KDB_DISALLOW_PROXIABLE);241/* DUP_SKEY */242entry->flags.invalid = !!(u32 & KRB5_KDB_DISALLOW_ALL_TIX);243entry->flags.require_preauth =!!(u32 & KRB5_KDB_REQUIRES_PRE_AUTH);244entry->flags.require_hwauth =!!(u32 & KRB5_KDB_REQUIRES_HW_AUTH);245entry->flags.server = !(u32 & KRB5_KDB_DISALLOW_SVR);246entry->flags.change_pw = !!(u32 & KRB5_KDB_PWCHANGE_SERVICE);247entry->flags.client = 1; /* XXX */248249/* 32: max time */250CHECK(ret = krb5_ret_uint32(sp, &u32));251if (u32) {252entry->max_life = malloc(sizeof(*entry->max_life));253*entry->max_life = u32;254}255/* 32: max renewable time */256CHECK(ret = krb5_ret_uint32(sp, &u32));257if (u32) {258entry->max_renew = malloc(sizeof(*entry->max_renew));259*entry->max_renew = u32;260}261/* 32: client expire */262CHECK(ret = krb5_ret_uint32(sp, &u32));263if (u32) {264entry->valid_end = malloc(sizeof(*entry->valid_end));265*entry->valid_end = u32;266}267/* 32: passwd expire */268CHECK(ret = krb5_ret_uint32(sp, &u32));269if (u32) {270entry->pw_end = malloc(sizeof(*entry->pw_end));271*entry->pw_end = u32;272}273/* 32: last successful passwd */274CHECK(ret = krb5_ret_uint32(sp, &u32));275/* 32: last failed attempt */276CHECK(ret = krb5_ret_uint32(sp, &u32));277/* 32: num of failed attempts */278CHECK(ret = krb5_ret_uint32(sp, &u32));279/* 16: num tl data */280CHECK(ret = krb5_ret_uint16(sp, &u16));281num_tl = u16;282/* 16: num key data */283CHECK(ret = krb5_ret_uint16(sp, &u16));284num_keys = u16;285/* 16: principal length */286CHECK(ret = krb5_ret_uint16(sp, &u16));287/* length: principal */288{289/*290* Note that the principal name includes the NUL in the entry,291* but we don't want to take chances, so we add an extra NUL.292*/293p = malloc(u16 + 1);294if (p == NULL) {295ret = ENOMEM;296goto out;297}298krb5_storage_read(sp, p, u16);299p[u16] = '\0';300CHECK(ret = krb5_parse_name(context, p, &entry->principal));301free(p);302}303/* for num tl data times30416: tl data type30516: tl data length306length: length */307for (i = 0; i < num_tl; i++) {308/* 16: TL data type */309CHECK(ret = krb5_ret_uint16(sp, &u16));310/* 16: TL data length */311CHECK(ret = krb5_ret_uint16(sp, &u16));312krb5_storage_seek(sp, u16, SEEK_CUR);313}314/*315* for num key data times316* 16: "version"317* 16: kvno318* for version times:319* 16: type320* 16: length321* length: keydata322*323* "version" here is really 1 or 2, the first meaning there's only324* keys for this kvno, the second meaning there's keys and salt[s?].325* That's right... hold that gag reflex, you can do it.326*/327for (i = 0; i < num_keys; i++) {328int keep = 0;329uint16_t version;330void *ptr;331332CHECK(ret = krb5_ret_uint16(sp, &u16));333version = u16;334CHECK(ret = krb5_ret_uint16(sp, &u16));335336/*337* First time through, and until we find one matching key,338* entry->kvno == 0.339*/340if ((entry->kvno < u16) && (kvno == 0 || kvno == u16)) {341keep = 1;342entry->kvno = u16;343/*344* Found a higher kvno than earlier, so free the old highest345* kvno keys.346*347* XXX Of course, we actually want to extract the old kvnos348* as well, for some of the kadm5 APIs. We shouldn't free349* these keys, but keep them elsewhere.350*/351for (j = 0; j < entry->keys.len; j++)352free_Key(&entry->keys.val[j]);353free(entry->keys.val);354entry->keys.len = 0;355entry->keys.val = NULL;356} else if (entry->kvno == u16)357/* Accumulate keys */358keep = 1;359360if (keep) {361Key *k;362363ptr = realloc(entry->keys.val, sizeof(entry->keys.val[0]) * (entry->keys.len + 1));364if (ptr == NULL) {365ret = ENOMEM;366goto out;367}368entry->keys.val = ptr;369370/* k points to current Key */371k = &entry->keys.val[entry->keys.len];372373memset(k, 0, sizeof(*k));374entry->keys.len += 1;375376k->mkvno = malloc(sizeof(*k->mkvno));377if (k->mkvno == NULL) {378ret = ENOMEM;379goto out;380}381*k->mkvno = 1;382383for (j = 0; j < version; j++) {384uint16_t type;385CHECK(ret = krb5_ret_uint16(sp, &type));386CHECK(ret = krb5_ret_uint16(sp, &u16));387if (j == 0) {388/* This "version" means we have a key */389k->key.keytype = type;390if (u16 < 2) {391ret = EINVAL;392goto out;393}394/*395* MIT stores keys encrypted keys as {16-bit length396* of plaintext key, {encrypted key}}. The reason397* for this is that the Kerberos cryptosystem is not398* length-preserving. Heimdal's approach is to399* truncate the plaintext to the expected length of400* the key given its enctype, so we ignore this401* 16-bit length-of-plaintext-key field.402*/403krb5_storage_seek(sp, 2, SEEK_CUR); /* skip real length */404k->key.keyvalue.length = u16 - 2; /* adjust cipher len */405k->key.keyvalue.data = malloc(k->key.keyvalue.length);406krb5_storage_read(sp, k->key.keyvalue.data,407k->key.keyvalue.length);408} else if (j == 1) {409/* This "version" means we have a salt */410k->salt = calloc(1, sizeof(*k->salt));411if (k->salt == NULL) {412ret = ENOMEM;413goto out;414}415k->salt->type = type;416if (u16 != 0) {417k->salt->salt.data = malloc(u16);418if (k->salt->salt.data == NULL) {419ret = ENOMEM;420goto out;421}422k->salt->salt.length = u16;423krb5_storage_read(sp, k->salt->salt.data, k->salt->salt.length);424}425fix_salt(context, entry, entry->keys.len - 1);426} else {427/*428* Whatever this "version" might be, we skip it429*430* XXX A krb5.conf parameter requesting that we log431* about strangeness like this, or return an error432* from here, might be nice.433*/434krb5_storage_seek(sp, u16, SEEK_CUR);435}436}437} else {438/*439* XXX For now we skip older kvnos, but we should extract440* them...441*/442for (j = 0; j < version; j++) {443/* enctype */444CHECK(ret = krb5_ret_uint16(sp, &u16));445/* encrypted key (or plaintext salt) */446CHECK(ret = krb5_ret_uint16(sp, &u16));447krb5_storage_seek(sp, u16, SEEK_CUR);448}449}450}451452if (entry->kvno == 0 && kvno != 0) {453ret = HDB_ERR_NOT_FOUND_HERE;454goto out;455}456457return 0;458out:459if (ret == HEIM_ERR_EOF)460/* Better error code than "end of file" */461ret = HEIM_ERR_BAD_HDBENT_ENCODING;462return ret;463}464465#if 0466static krb5_error_code467mdb_entry2value(krb5_context context, hdb_entry *entry, krb5_data *data)468{469return EINVAL;470}471#endif472473474static krb5_error_code475mdb_close(krb5_context context, HDB *db)476{477DB *d = (DB*)db->hdb_db;478(*d->close)(d);479return 0;480}481482static krb5_error_code483mdb_destroy(krb5_context context, HDB *db)484{485krb5_error_code ret;486487ret = hdb_clear_master_key (context, db);488free(db->hdb_name);489free(db);490return ret;491}492493static krb5_error_code494mdb_lock(krb5_context context, HDB *db, int operation)495{496DB *d = (DB*)db->hdb_db;497int fd = (*d->fd)(d);498if(fd < 0) {499krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB,500"Can't lock database: %s", db->hdb_name);501return HDB_ERR_CANT_LOCK_DB;502}503return hdb_lock(fd, operation);504}505506static krb5_error_code507mdb_unlock(krb5_context context, HDB *db)508{509DB *d = (DB*)db->hdb_db;510int fd = (*d->fd)(d);511if(fd < 0) {512krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB,513"Can't unlock database: %s", db->hdb_name);514return HDB_ERR_CANT_LOCK_DB;515}516return hdb_unlock(fd);517}518519520static krb5_error_code521mdb_seq(krb5_context context, HDB *db,522unsigned flags, hdb_entry_ex *entry, int flag)523{524DB *d = (DB*)db->hdb_db;525DBT key, value;526krb5_data key_data, data;527int code;528529code = db->hdb_lock(context, db, HDB_RLOCK);530if(code == -1) {531krb5_set_error_message(context, HDB_ERR_DB_INUSE, "Database %s in use", db->hdb_name);532return HDB_ERR_DB_INUSE;533}534code = (*d->seq)(d, &key, &value, flag);535db->hdb_unlock(context, db); /* XXX check value */536if(code == -1) {537code = errno;538krb5_set_error_message(context, code, "Database %s seq error: %s",539db->hdb_name, strerror(code));540return code;541}542if(code == 1) {543krb5_clear_error_message(context);544return HDB_ERR_NOENTRY;545}546547key_data.data = key.data;548key_data.length = key.size;549data.data = value.data;550data.length = value.size;551memset(entry, 0, sizeof(*entry));552553if (mdb_value2entry(context, &data, 0, &entry->entry))554return mdb_seq(context, db, flags, entry, R_NEXT);555556if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {557code = hdb_unseal_keys (context, db, &entry->entry);558if (code)559hdb_free_entry (context, entry);560}561562return code;563}564565566static krb5_error_code567mdb_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)568{569return mdb_seq(context, db, flags, entry, R_FIRST);570}571572573static krb5_error_code574mdb_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)575{576return mdb_seq(context, db, flags, entry, R_NEXT);577}578579static krb5_error_code580mdb_rename(krb5_context context, HDB *db, const char *new_name)581{582int ret;583char *old, *new;584585asprintf(&old, "%s.db", db->hdb_name);586asprintf(&new, "%s.db", new_name);587ret = rename(old, new);588free(old);589free(new);590if(ret)591return errno;592593free(db->hdb_name);594db->hdb_name = strdup(new_name);595return 0;596}597598static krb5_error_code599mdb__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply)600{601DB *d = (DB*)db->hdb_db;602DBT k, v;603int code;604605k.data = key.data;606k.size = key.length;607code = db->hdb_lock(context, db, HDB_RLOCK);608if(code)609return code;610code = (*d->get)(d, &k, &v, 0);611db->hdb_unlock(context, db);612if(code < 0) {613code = errno;614krb5_set_error_message(context, code, "Database %s get error: %s",615db->hdb_name, strerror(code));616return code;617}618if(code == 1) {619krb5_clear_error_message(context);620return HDB_ERR_NOENTRY;621}622623krb5_data_copy(reply, v.data, v.size);624return 0;625}626627static krb5_error_code628mdb__put(krb5_context context, HDB *db, int replace,629krb5_data key, krb5_data value)630{631DB *d = (DB*)db->hdb_db;632DBT k, v;633int code;634635k.data = key.data;636k.size = key.length;637v.data = value.data;638v.size = value.length;639code = db->hdb_lock(context, db, HDB_WLOCK);640if(code)641return code;642code = (*d->put)(d, &k, &v, replace ? 0 : R_NOOVERWRITE);643db->hdb_unlock(context, db);644if(code < 0) {645code = errno;646krb5_set_error_message(context, code, "Database %s put error: %s",647db->hdb_name, strerror(code));648return code;649}650if(code == 1) {651krb5_clear_error_message(context);652return HDB_ERR_EXISTS;653}654return 0;655}656657static krb5_error_code658mdb__del(krb5_context context, HDB *db, krb5_data key)659{660DB *d = (DB*)db->hdb_db;661DBT k;662krb5_error_code code;663k.data = key.data;664k.size = key.length;665code = db->hdb_lock(context, db, HDB_WLOCK);666if(code)667return code;668code = (*d->del)(d, &k, 0);669db->hdb_unlock(context, db);670if(code == 1) {671code = errno;672krb5_set_error_message(context, code, "Database %s put error: %s",673db->hdb_name, strerror(code));674return code;675}676if(code < 0)677return errno;678return 0;679}680681static krb5_error_code682mdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal,683unsigned flags, krb5_kvno kvno, hdb_entry_ex *entry)684{685krb5_data key, value;686krb5_error_code code;687688code = mdb_principal2key(context, principal, &key);689if (code)690return code;691code = db->hdb__get(context, db, key, &value);692krb5_data_free(&key);693if(code)694return code;695code = mdb_value2entry(context, &value, kvno, &entry->entry);696krb5_data_free(&value);697if (code)698return code;699700if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {701code = hdb_unseal_keys (context, db, &entry->entry);702if (code)703hdb_free_entry(context, entry);704}705706return 0;707}708709static krb5_error_code710mdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)711{712krb5_set_error_message(context, EINVAL, "can't set principal in mdb");713return EINVAL;714}715716static krb5_error_code717mdb_remove(krb5_context context, HDB *db, krb5_const_principal principal)718{719krb5_error_code code;720krb5_data key;721722code = db->hdb__del(context, db, key);723krb5_data_free(&key);724return code;725}726727static krb5_error_code728mdb_open(krb5_context context, HDB *db, int flags, mode_t mode)729{730char *fn;731krb5_error_code ret;732733asprintf(&fn, "%s.db", db->hdb_name);734if (fn == NULL) {735krb5_set_error_message(context, ENOMEM, "malloc: out of memory");736return ENOMEM;737}738db->hdb_db = dbopen(fn, flags, mode, DB_BTREE, NULL);739free(fn);740741if (db->hdb_db == NULL) {742switch (errno) {743#ifdef EFTYPE744case EFTYPE:745#endif746case EINVAL:747db->hdb_db = dbopen(fn, flags, mode, DB_BTREE, NULL);748}749}750751/* try to open without .db extension */752if(db->hdb_db == NULL && errno == ENOENT)753db->hdb_db = dbopen(db->hdb_name, flags, mode, DB_BTREE, NULL);754if(db->hdb_db == NULL) {755ret = errno;756krb5_set_error_message(context, ret, "dbopen (%s): %s",757db->hdb_name, strerror(ret));758return ret;759}760if((flags & O_ACCMODE) == O_RDONLY)761ret = hdb_check_db_format(context, db);762else763ret = hdb_init_db(context, db);764if(ret == HDB_ERR_NOENTRY) {765krb5_clear_error_message(context);766return 0;767}768if (ret) {769mdb_close(context, db);770krb5_set_error_message(context, ret, "hdb_open: failed %s database %s",771(flags & O_ACCMODE) == O_RDONLY ?772"checking format of" : "initialize",773db->hdb_name);774}775return ret;776}777778krb5_error_code779hdb_mdb_create(krb5_context context, HDB **db,780const char *filename)781{782*db = calloc(1, sizeof(**db));783if (*db == NULL) {784krb5_set_error_message(context, ENOMEM, "malloc: out of memory");785return ENOMEM;786}787788(*db)->hdb_db = NULL;789(*db)->hdb_name = strdup(filename);790if ((*db)->hdb_name == NULL) {791free(*db);792*db = NULL;793krb5_set_error_message(context, ENOMEM, "malloc: out of memory");794return ENOMEM;795}796(*db)->hdb_master_key_set = 0;797(*db)->hdb_openp = 0;798(*db)->hdb_capability_flags = 0;799(*db)->hdb_open = mdb_open;800(*db)->hdb_close = mdb_close;801(*db)->hdb_fetch_kvno = mdb_fetch_kvno;802(*db)->hdb_store = mdb_store;803(*db)->hdb_remove = mdb_remove;804(*db)->hdb_firstkey = mdb_firstkey;805(*db)->hdb_nextkey= mdb_nextkey;806(*db)->hdb_lock = mdb_lock;807(*db)->hdb_unlock = mdb_unlock;808(*db)->hdb_rename = mdb_rename;809(*db)->hdb__get = mdb__get;810(*db)->hdb__put = mdb__put;811(*db)->hdb__del = mdb__del;812(*db)->hdb_destroy = mdb_destroy;813return 0;814}815816#endif /* HAVE_DB1 */817818819