155682Smarkm/* 2233294Sstas * Copyright (c) 1997 - 2001 Kungliga Tekniska H��gskolan 3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4233294Sstas * All rights reserved. 555682Smarkm * 6233294Sstas * Redistribution and use in source and binary forms, with or without 7233294Sstas * modification, are permitted provided that the following conditions 8233294Sstas * are met: 955682Smarkm * 10233294Sstas * 1. Redistributions of source code must retain the above copyright 11233294Sstas * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright 14233294Sstas * notice, this list of conditions and the following disclaimer in the 15233294Sstas * documentation and/or other materials provided with the distribution. 1655682Smarkm * 17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors 18233294Sstas * may be used to endorse or promote products derived from this software 19233294Sstas * without specific prior written permission. 2055682Smarkm * 21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24233294Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31233294Sstas * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm#include "hdb_locl.h" 3555682Smarkm 3690926Snectar#if HAVE_DB1 3755682Smarkm 3890926Snectar#if defined(HAVE_DB_185_H) 3990926Snectar#include <db_185.h> 4090926Snectar#elif defined(HAVE_DB_H) 4190926Snectar#include <db.h> 4290926Snectar#endif 4390926Snectar 4455682Smarkmstatic krb5_error_code 4555682SmarkmDB_close(krb5_context context, HDB *db) 4655682Smarkm{ 47178825Sdfr DB *d = (DB*)db->hdb_db; 48178825Sdfr (*d->close)(d); 4955682Smarkm return 0; 5055682Smarkm} 5155682Smarkm 5255682Smarkmstatic krb5_error_code 5355682SmarkmDB_destroy(krb5_context context, HDB *db) 5455682Smarkm{ 5555682Smarkm krb5_error_code ret; 5655682Smarkm 5755682Smarkm ret = hdb_clear_master_key (context, db); 58178825Sdfr free(db->hdb_name); 5955682Smarkm free(db); 6055682Smarkm return ret; 6155682Smarkm} 6255682Smarkm 6355682Smarkmstatic krb5_error_code 6455682SmarkmDB_lock(krb5_context context, HDB *db, int operation) 6555682Smarkm{ 66178825Sdfr DB *d = (DB*)db->hdb_db; 6755682Smarkm int fd = (*d->fd)(d); 68178825Sdfr if(fd < 0) { 69233294Sstas krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB, 70233294Sstas "Can't lock database: %s", db->hdb_name); 7155682Smarkm return HDB_ERR_CANT_LOCK_DB; 72178825Sdfr } 7355682Smarkm return hdb_lock(fd, operation); 7455682Smarkm} 7555682Smarkm 7655682Smarkmstatic krb5_error_code 7755682SmarkmDB_unlock(krb5_context context, HDB *db) 7855682Smarkm{ 79178825Sdfr DB *d = (DB*)db->hdb_db; 8055682Smarkm int fd = (*d->fd)(d); 81178825Sdfr if(fd < 0) { 82233294Sstas krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB, 83233294Sstas "Can't unlock database: %s", db->hdb_name); 8455682Smarkm return HDB_ERR_CANT_LOCK_DB; 85178825Sdfr } 8655682Smarkm return hdb_unlock(fd); 8755682Smarkm} 8855682Smarkm 8955682Smarkm 9055682Smarkmstatic krb5_error_code 9155682SmarkmDB_seq(krb5_context context, HDB *db, 92178825Sdfr unsigned flags, hdb_entry_ex *entry, int flag) 9355682Smarkm{ 94178825Sdfr DB *d = (DB*)db->hdb_db; 9555682Smarkm DBT key, value; 9655682Smarkm krb5_data key_data, data; 9755682Smarkm int code; 9855682Smarkm 99178825Sdfr code = db->hdb_lock(context, db, HDB_RLOCK); 100178825Sdfr if(code == -1) { 101233294Sstas krb5_set_error_message(context, HDB_ERR_DB_INUSE, "Database %s in use", db->hdb_name); 10255682Smarkm return HDB_ERR_DB_INUSE; 103178825Sdfr } 104178825Sdfr code = (*d->seq)(d, &key, &value, flag); 105178825Sdfr db->hdb_unlock(context, db); /* XXX check value */ 106178825Sdfr if(code == -1) { 107178825Sdfr code = errno; 108233294Sstas krb5_set_error_message(context, code, "Database %s seq error: %s", 109233294Sstas db->hdb_name, strerror(code)); 110178825Sdfr return code; 111178825Sdfr } 112178825Sdfr if(code == 1) { 113233294Sstas krb5_clear_error_message(context); 11455682Smarkm return HDB_ERR_NOENTRY; 115178825Sdfr } 11655682Smarkm 11755682Smarkm key_data.data = key.data; 11855682Smarkm key_data.length = key.size; 11955682Smarkm data.data = value.data; 12055682Smarkm data.length = value.size; 121178825Sdfr memset(entry, 0, sizeof(*entry)); 122178825Sdfr if (hdb_value2entry(context, &data, &entry->entry)) 12355682Smarkm return DB_seq(context, db, flags, entry, R_NEXT); 124178825Sdfr if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { 125178825Sdfr code = hdb_unseal_keys (context, db, &entry->entry); 12672445Sassar if (code) 12772445Sassar hdb_free_entry (context, entry); 12872445Sassar } 129178825Sdfr if (code == 0 && entry->entry.principal == NULL) { 130178825Sdfr entry->entry.principal = malloc(sizeof(*entry->entry.principal)); 131178825Sdfr if (entry->entry.principal == NULL) { 13272445Sassar code = ENOMEM; 133233294Sstas krb5_set_error_message(context, code, "malloc: out of memory"); 13472445Sassar hdb_free_entry (context, entry); 13572445Sassar } else { 136178825Sdfr hdb_key2principal(context, &key_data, entry->entry.principal); 13772445Sassar } 13855682Smarkm } 13972445Sassar return code; 14055682Smarkm} 14155682Smarkm 14255682Smarkm 14355682Smarkmstatic krb5_error_code 144178825SdfrDB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) 14555682Smarkm{ 14655682Smarkm return DB_seq(context, db, flags, entry, R_FIRST); 14755682Smarkm} 14855682Smarkm 14955682Smarkm 15055682Smarkmstatic krb5_error_code 151178825SdfrDB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) 15255682Smarkm{ 15355682Smarkm return DB_seq(context, db, flags, entry, R_NEXT); 15455682Smarkm} 15555682Smarkm 15655682Smarkmstatic krb5_error_code 15755682SmarkmDB_rename(krb5_context context, HDB *db, const char *new_name) 15855682Smarkm{ 15955682Smarkm int ret; 16055682Smarkm char *old, *new; 16155682Smarkm 162178825Sdfr asprintf(&old, "%s.db", db->hdb_name); 16355682Smarkm asprintf(&new, "%s.db", new_name); 16455682Smarkm ret = rename(old, new); 16555682Smarkm free(old); 16655682Smarkm free(new); 16755682Smarkm if(ret) 16855682Smarkm return errno; 169233294Sstas 170178825Sdfr free(db->hdb_name); 171178825Sdfr db->hdb_name = strdup(new_name); 17255682Smarkm return 0; 17355682Smarkm} 17455682Smarkm 17555682Smarkmstatic krb5_error_code 17655682SmarkmDB__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply) 17755682Smarkm{ 178178825Sdfr DB *d = (DB*)db->hdb_db; 17955682Smarkm DBT k, v; 18055682Smarkm int code; 18155682Smarkm 18255682Smarkm k.data = key.data; 18355682Smarkm k.size = key.length; 184178825Sdfr code = db->hdb_lock(context, db, HDB_RLOCK); 18555682Smarkm if(code) 18655682Smarkm return code; 187178825Sdfr code = (*d->get)(d, &k, &v, 0); 188178825Sdfr db->hdb_unlock(context, db); 189178825Sdfr if(code < 0) { 190178825Sdfr code = errno; 191233294Sstas krb5_set_error_message(context, code, "Database %s get error: %s", 192233294Sstas db->hdb_name, strerror(code)); 193178825Sdfr return code; 194178825Sdfr } 195178825Sdfr if(code == 1) { 196233294Sstas krb5_clear_error_message(context); 19755682Smarkm return HDB_ERR_NOENTRY; 198178825Sdfr } 199233294Sstas 20055682Smarkm krb5_data_copy(reply, v.data, v.size); 20155682Smarkm return 0; 20255682Smarkm} 20355682Smarkm 20455682Smarkmstatic krb5_error_code 205233294SstasDB__put(krb5_context context, HDB *db, int replace, 20655682Smarkm krb5_data key, krb5_data value) 20755682Smarkm{ 208178825Sdfr DB *d = (DB*)db->hdb_db; 20955682Smarkm DBT k, v; 21055682Smarkm int code; 21155682Smarkm 21255682Smarkm k.data = key.data; 21355682Smarkm k.size = key.length; 21455682Smarkm v.data = value.data; 21555682Smarkm v.size = value.length; 216178825Sdfr code = db->hdb_lock(context, db, HDB_WLOCK); 21755682Smarkm if(code) 21855682Smarkm return code; 219178825Sdfr code = (*d->put)(d, &k, &v, replace ? 0 : R_NOOVERWRITE); 220178825Sdfr db->hdb_unlock(context, db); 221178825Sdfr if(code < 0) { 222178825Sdfr code = errno; 223233294Sstas krb5_set_error_message(context, code, "Database %s put error: %s", 224233294Sstas db->hdb_name, strerror(code)); 225178825Sdfr return code; 226178825Sdfr } 227178825Sdfr if(code == 1) { 228233294Sstas krb5_clear_error_message(context); 22955682Smarkm return HDB_ERR_EXISTS; 230178825Sdfr } 23155682Smarkm return 0; 23255682Smarkm} 23355682Smarkm 23455682Smarkmstatic krb5_error_code 23555682SmarkmDB__del(krb5_context context, HDB *db, krb5_data key) 23655682Smarkm{ 237178825Sdfr DB *d = (DB*)db->hdb_db; 23855682Smarkm DBT k; 23955682Smarkm krb5_error_code code; 24055682Smarkm k.data = key.data; 24155682Smarkm k.size = key.length; 242178825Sdfr code = db->hdb_lock(context, db, HDB_WLOCK); 24355682Smarkm if(code) 24455682Smarkm return code; 245178825Sdfr code = (*d->del)(d, &k, 0); 246178825Sdfr db->hdb_unlock(context, db); 247178825Sdfr if(code == 1) { 248178825Sdfr code = errno; 249233294Sstas krb5_set_error_message(context, code, "Database %s put error: %s", 250233294Sstas db->hdb_name, strerror(code)); 251178825Sdfr return code; 252178825Sdfr } 25355682Smarkm if(code < 0) 25455682Smarkm return errno; 25555682Smarkm return 0; 25655682Smarkm} 25755682Smarkm 25855682Smarkmstatic krb5_error_code 25955682SmarkmDB_open(krb5_context context, HDB *db, int flags, mode_t mode) 26055682Smarkm{ 26155682Smarkm char *fn; 26255682Smarkm krb5_error_code ret; 26355682Smarkm 264178825Sdfr asprintf(&fn, "%s.db", db->hdb_name); 26590926Snectar if (fn == NULL) { 266233294Sstas krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 26755682Smarkm return ENOMEM; 26890926Snectar } 269178825Sdfr db->hdb_db = dbopen(fn, flags, mode, DB_BTREE, NULL); 27055682Smarkm free(fn); 27155682Smarkm /* try to open without .db extension */ 272178825Sdfr if(db->hdb_db == NULL && errno == ENOENT) 273178825Sdfr db->hdb_db = dbopen(db->hdb_name, flags, mode, DB_BTREE, NULL); 274178825Sdfr if(db->hdb_db == NULL) { 27590926Snectar ret = errno; 276233294Sstas krb5_set_error_message(context, ret, "dbopen (%s): %s", 277178825Sdfr db->hdb_name, strerror(ret)); 27890926Snectar return ret; 27990926Snectar } 28055682Smarkm if((flags & O_ACCMODE) == O_RDONLY) 28155682Smarkm ret = hdb_check_db_format(context, db); 28255682Smarkm else 28355682Smarkm ret = hdb_init_db(context, db); 28490926Snectar if(ret == HDB_ERR_NOENTRY) { 285233294Sstas krb5_clear_error_message(context); 28655682Smarkm return 0; 28790926Snectar } 288178825Sdfr if (ret) { 289178825Sdfr DB_close(context, db); 290233294Sstas krb5_set_error_message(context, ret, "hdb_open: failed %s database %s", 291233294Sstas (flags & O_ACCMODE) == O_RDONLY ? 292233294Sstas "checking format of" : "initialize", 293178825Sdfr db->hdb_name); 294178825Sdfr } 29555682Smarkm return ret; 29655682Smarkm} 29755682Smarkm 29855682Smarkmkrb5_error_code 299233294Sstashdb_db_create(krb5_context context, HDB **db, 30055682Smarkm const char *filename) 30155682Smarkm{ 302178825Sdfr *db = calloc(1, sizeof(**db)); 30390926Snectar if (*db == NULL) { 304233294Sstas krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 30555682Smarkm return ENOMEM; 30690926Snectar } 30755682Smarkm 308178825Sdfr (*db)->hdb_db = NULL; 309178825Sdfr (*db)->hdb_name = strdup(filename); 310178825Sdfr if ((*db)->hdb_name == NULL) { 31190926Snectar free(*db); 31290926Snectar *db = NULL; 313233294Sstas krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 31490926Snectar return ENOMEM; 31590926Snectar } 316178825Sdfr (*db)->hdb_master_key_set = 0; 317178825Sdfr (*db)->hdb_openp = 0; 318233294Sstas (*db)->hdb_capability_flags = HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL; 319178825Sdfr (*db)->hdb_open = DB_open; 320178825Sdfr (*db)->hdb_close = DB_close; 321233294Sstas (*db)->hdb_fetch_kvno = _hdb_fetch_kvno; 322178825Sdfr (*db)->hdb_store = _hdb_store; 323178825Sdfr (*db)->hdb_remove = _hdb_remove; 324178825Sdfr (*db)->hdb_firstkey = DB_firstkey; 325178825Sdfr (*db)->hdb_nextkey= DB_nextkey; 326178825Sdfr (*db)->hdb_lock = DB_lock; 327178825Sdfr (*db)->hdb_unlock = DB_unlock; 328178825Sdfr (*db)->hdb_rename = DB_rename; 329178825Sdfr (*db)->hdb__get = DB__get; 330178825Sdfr (*db)->hdb__put = DB__put; 331178825Sdfr (*db)->hdb__del = DB__del; 332178825Sdfr (*db)->hdb_destroy = DB_destroy; 33355682Smarkm return 0; 33455682Smarkm} 33555682Smarkm 33690926Snectar#endif /* HAVE_DB1 */ 337