172445Sassar/* 2233294Sstas * Copyright (c) 1997 - 2006 Kungliga Tekniska H��gskolan 3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4233294Sstas * All rights reserved. 572445Sassar * 6233294Sstas * Redistribution and use in source and binary forms, with or without 7233294Sstas * modification, are permitted provided that the following conditions 8233294Sstas * are met: 972445Sassar * 10233294Sstas * 1. Redistributions of source code must retain the above copyright 11233294Sstas * notice, this list of conditions and the following disclaimer. 1272445Sassar * 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. 1672445Sassar * 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. 2072445Sassar * 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. 3272445Sassar */ 3372445Sassar 3472445Sassar#include "hdb_locl.h" 3572445Sassar 3690926Snectar#if HAVE_DB3 3790926Snectar 38233294Sstas#ifdef HAVE_DBHEADER 39233294Sstas#include <db.h> 40233294Sstas#elif HAVE_DB5_DB_H 41233294Sstas#include <db5/db.h> 42233294Sstas#elif HAVE_DB4_DB_H 43127808Snectar#include <db4/db.h> 44233294Sstas#elif HAVE_DB3_DB_H 45127808Snectar#include <db3/db.h> 46127808Snectar#else 4790926Snectar#include <db.h> 48127808Snectar#endif 4990926Snectar 5072445Sassarstatic krb5_error_code 5172445SassarDB_close(krb5_context context, HDB *db) 5272445Sassar{ 53178825Sdfr DB *d = (DB*)db->hdb_db; 54178825Sdfr DBC *dbcp = (DBC*)db->hdb_dbc; 5572445Sassar 56178825Sdfr (*dbcp->c_close)(dbcp); 57178825Sdfr db->hdb_dbc = 0; 58178825Sdfr (*d->close)(d, 0); 5972445Sassar return 0; 6072445Sassar} 6172445Sassar 6272445Sassarstatic krb5_error_code 6372445SassarDB_destroy(krb5_context context, HDB *db) 6472445Sassar{ 6572445Sassar krb5_error_code ret; 6672445Sassar 6772445Sassar ret = hdb_clear_master_key (context, db); 68178825Sdfr free(db->hdb_name); 6972445Sassar free(db); 7072445Sassar return ret; 7172445Sassar} 7272445Sassar 7372445Sassarstatic krb5_error_code 7472445SassarDB_lock(krb5_context context, HDB *db, int operation) 7572445Sassar{ 76178825Sdfr DB *d = (DB*)db->hdb_db; 7772445Sassar int fd; 7872445Sassar if ((*d->fd)(d, &fd)) 7972445Sassar return HDB_ERR_CANT_LOCK_DB; 8072445Sassar return hdb_lock(fd, operation); 8172445Sassar} 8272445Sassar 8372445Sassarstatic krb5_error_code 8472445SassarDB_unlock(krb5_context context, HDB *db) 8572445Sassar{ 86178825Sdfr DB *d = (DB*)db->hdb_db; 8772445Sassar int fd; 8872445Sassar if ((*d->fd)(d, &fd)) 8972445Sassar return HDB_ERR_CANT_LOCK_DB; 9072445Sassar return hdb_unlock(fd); 9172445Sassar} 9272445Sassar 9372445Sassar 9472445Sassarstatic krb5_error_code 9572445SassarDB_seq(krb5_context context, HDB *db, 96178825Sdfr unsigned flags, hdb_entry_ex *entry, int flag) 9772445Sassar{ 9872445Sassar DBT key, value; 99178825Sdfr DBC *dbcp = db->hdb_dbc; 10072445Sassar krb5_data key_data, data; 10172445Sassar int code; 10272445Sassar 10372445Sassar memset(&key, 0, sizeof(DBT)); 10472445Sassar memset(&value, 0, sizeof(DBT)); 105178825Sdfr if ((*db->hdb_lock)(context, db, HDB_RLOCK)) 10672445Sassar return HDB_ERR_DB_INUSE; 107178825Sdfr code = (*dbcp->c_get)(dbcp, &key, &value, flag); 108178825Sdfr (*db->hdb_unlock)(context, db); /* XXX check value */ 10972445Sassar if (code == DB_NOTFOUND) 11072445Sassar return HDB_ERR_NOENTRY; 11172445Sassar if (code) 11272445Sassar return code; 11372445Sassar 11472445Sassar key_data.data = key.data; 11572445Sassar key_data.length = key.size; 11672445Sassar data.data = value.data; 11772445Sassar data.length = value.size; 118178825Sdfr memset(entry, 0, sizeof(*entry)); 119178825Sdfr if (hdb_value2entry(context, &data, &entry->entry)) 12072445Sassar return DB_seq(context, db, flags, entry, DB_NEXT); 121178825Sdfr if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { 122178825Sdfr code = hdb_unseal_keys (context, db, &entry->entry); 12372445Sassar if (code) 12472445Sassar hdb_free_entry (context, entry); 12572445Sassar } 126178825Sdfr if (entry->entry.principal == NULL) { 127178825Sdfr entry->entry.principal = malloc(sizeof(*entry->entry.principal)); 128178825Sdfr if (entry->entry.principal == NULL) { 12972445Sassar hdb_free_entry (context, entry); 130233294Sstas krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 13190926Snectar return ENOMEM; 13272445Sassar } else { 133178825Sdfr hdb_key2principal(context, &key_data, entry->entry.principal); 13472445Sassar } 13572445Sassar } 13672445Sassar return 0; 13772445Sassar} 13872445Sassar 13972445Sassar 14072445Sassarstatic krb5_error_code 141178825SdfrDB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) 14272445Sassar{ 14372445Sassar return DB_seq(context, db, flags, entry, DB_FIRST); 14472445Sassar} 14572445Sassar 14672445Sassar 14772445Sassarstatic krb5_error_code 148178825SdfrDB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) 14972445Sassar{ 15072445Sassar return DB_seq(context, db, flags, entry, DB_NEXT); 15172445Sassar} 15272445Sassar 15372445Sassarstatic krb5_error_code 15472445SassarDB_rename(krb5_context context, HDB *db, const char *new_name) 15572445Sassar{ 15672445Sassar int ret; 15772445Sassar char *old, *new; 15872445Sassar 159178825Sdfr asprintf(&old, "%s.db", db->hdb_name); 16072445Sassar asprintf(&new, "%s.db", new_name); 16172445Sassar ret = rename(old, new); 16272445Sassar free(old); 16372445Sassar free(new); 16472445Sassar if(ret) 16572445Sassar return errno; 166233294Sstas 167178825Sdfr free(db->hdb_name); 168178825Sdfr db->hdb_name = strdup(new_name); 16972445Sassar return 0; 17072445Sassar} 17172445Sassar 17272445Sassarstatic krb5_error_code 17372445SassarDB__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply) 17472445Sassar{ 175178825Sdfr DB *d = (DB*)db->hdb_db; 17672445Sassar DBT k, v; 17772445Sassar int code; 17872445Sassar 17972445Sassar memset(&k, 0, sizeof(DBT)); 18072445Sassar memset(&v, 0, sizeof(DBT)); 18172445Sassar k.data = key.data; 18272445Sassar k.size = key.length; 18372445Sassar k.flags = 0; 184178825Sdfr if ((code = (*db->hdb_lock)(context, db, HDB_RLOCK))) 18572445Sassar return code; 186178825Sdfr code = (*d->get)(d, NULL, &k, &v, 0); 187178825Sdfr (*db->hdb_unlock)(context, db); 18872445Sassar if(code == DB_NOTFOUND) 18972445Sassar return HDB_ERR_NOENTRY; 19072445Sassar if(code) 19172445Sassar return code; 19272445Sassar 19372445Sassar krb5_data_copy(reply, v.data, v.size); 19472445Sassar return 0; 19572445Sassar} 19672445Sassar 19772445Sassarstatic krb5_error_code 198233294SstasDB__put(krb5_context context, HDB *db, int replace, 19972445Sassar krb5_data key, krb5_data value) 20072445Sassar{ 201178825Sdfr DB *d = (DB*)db->hdb_db; 20272445Sassar DBT k, v; 20372445Sassar int code; 20472445Sassar 20572445Sassar memset(&k, 0, sizeof(DBT)); 20672445Sassar memset(&v, 0, sizeof(DBT)); 20772445Sassar k.data = key.data; 20872445Sassar k.size = key.length; 20972445Sassar k.flags = 0; 21072445Sassar v.data = value.data; 21172445Sassar v.size = value.length; 21272445Sassar v.flags = 0; 213178825Sdfr if ((code = (*db->hdb_lock)(context, db, HDB_WLOCK))) 21472445Sassar return code; 215178825Sdfr code = (*d->put)(d, NULL, &k, &v, replace ? 0 : DB_NOOVERWRITE); 216178825Sdfr (*db->hdb_unlock)(context, db); 21772445Sassar if(code == DB_KEYEXIST) 21872445Sassar return HDB_ERR_EXISTS; 21972445Sassar if(code) 22072445Sassar return errno; 22172445Sassar return 0; 22272445Sassar} 22372445Sassar 22472445Sassarstatic krb5_error_code 22572445SassarDB__del(krb5_context context, HDB *db, krb5_data key) 22672445Sassar{ 227178825Sdfr DB *d = (DB*)db->hdb_db; 22872445Sassar DBT k; 22972445Sassar krb5_error_code code; 23072445Sassar memset(&k, 0, sizeof(DBT)); 23172445Sassar k.data = key.data; 23272445Sassar k.size = key.length; 23372445Sassar k.flags = 0; 234178825Sdfr code = (*db->hdb_lock)(context, db, HDB_WLOCK); 23572445Sassar if(code) 23672445Sassar return code; 237178825Sdfr code = (*d->del)(d, NULL, &k, 0); 238178825Sdfr (*db->hdb_unlock)(context, db); 23972445Sassar if(code == DB_NOTFOUND) 24072445Sassar return HDB_ERR_NOENTRY; 24172445Sassar if(code) 24272445Sassar return code; 24372445Sassar return 0; 24472445Sassar} 24572445Sassar 24672445Sassarstatic krb5_error_code 24772445SassarDB_open(krb5_context context, HDB *db, int flags, mode_t mode) 24872445Sassar{ 249178825Sdfr DBC *dbc = NULL; 25072445Sassar char *fn; 25172445Sassar krb5_error_code ret; 25272445Sassar DB *d; 25372445Sassar int myflags = 0; 25472445Sassar 25572445Sassar if (flags & O_CREAT) 25672445Sassar myflags |= DB_CREATE; 25772445Sassar 25872445Sassar if (flags & O_EXCL) 25972445Sassar myflags |= DB_EXCL; 26072445Sassar 261178825Sdfr if((flags & O_ACCMODE) == O_RDONLY) 26272445Sassar myflags |= DB_RDONLY; 26372445Sassar 26472445Sassar if (flags & O_TRUNC) 26572445Sassar myflags |= DB_TRUNCATE; 26672445Sassar 267178825Sdfr asprintf(&fn, "%s.db", db->hdb_name); 26890926Snectar if (fn == NULL) { 269233294Sstas krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 27072445Sassar return ENOMEM; 27190926Snectar } 272233294Sstas if (db_create(&d, NULL, 0) != 0) { 273233294Sstas free(fn); 274233294Sstas krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 275233294Sstas return ENOMEM; 276233294Sstas } 277178825Sdfr db->hdb_db = d; 278178825Sdfr 279178825Sdfr#if (DB_VERSION_MAJOR >= 4) && (DB_VERSION_MINOR >= 1) 280178825Sdfr ret = (*d->open)(db->hdb_db, NULL, fn, NULL, DB_BTREE, myflags, mode); 281127808Snectar#else 282178825Sdfr ret = (*d->open)(db->hdb_db, fn, NULL, DB_BTREE, myflags, mode); 283127808Snectar#endif 284178825Sdfr 285178825Sdfr if (ret == ENOENT) { 28672445Sassar /* try to open without .db extension */ 287178825Sdfr#if (DB_VERSION_MAJOR >= 4) && (DB_VERSION_MINOR >= 1) 288178825Sdfr ret = (*d->open)(db->hdb_db, NULL, db->hdb_name, NULL, DB_BTREE, 289178825Sdfr myflags, mode); 290127808Snectar#else 291233294Sstas ret = (*d->open)(db->hdb_db, db->hdb_name, NULL, DB_BTREE, 292178825Sdfr myflags, mode); 293127808Snectar#endif 29472445Sassar } 295178825Sdfr 296178825Sdfr if (ret) { 297178825Sdfr free(fn); 298233294Sstas krb5_set_error_message(context, ret, "opening %s: %s", 299178825Sdfr db->hdb_name, strerror(ret)); 300178825Sdfr return ret; 301178825Sdfr } 30272445Sassar free(fn); 30372445Sassar 304178825Sdfr ret = (*d->cursor)(d, NULL, &dbc, 0); 30590926Snectar if (ret) { 306233294Sstas krb5_set_error_message(context, ret, "d->cursor: %s", strerror(ret)); 30772445Sassar return ret; 30890926Snectar } 309178825Sdfr db->hdb_dbc = dbc; 31072445Sassar 31172445Sassar if((flags & O_ACCMODE) == O_RDONLY) 31272445Sassar ret = hdb_check_db_format(context, db); 31372445Sassar else 31472445Sassar ret = hdb_init_db(context, db); 31572445Sassar if(ret == HDB_ERR_NOENTRY) 31672445Sassar return 0; 317178825Sdfr if (ret) { 318178825Sdfr DB_close(context, db); 319233294Sstas krb5_set_error_message(context, ret, "hdb_open: failed %s database %s", 320233294Sstas (flags & O_ACCMODE) == O_RDONLY ? 321233294Sstas "checking format of" : "initialize", 322233294Sstas db->hdb_name); 323178825Sdfr } 324178825Sdfr 32572445Sassar return ret; 32672445Sassar} 32772445Sassar 32872445Sassarkrb5_error_code 329233294Sstashdb_db_create(krb5_context context, HDB **db, 33072445Sassar const char *filename) 33172445Sassar{ 332178825Sdfr *db = calloc(1, sizeof(**db)); 33390926Snectar if (*db == NULL) { 334233294Sstas krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 33572445Sassar return ENOMEM; 33690926Snectar } 33772445Sassar 338178825Sdfr (*db)->hdb_db = NULL; 339178825Sdfr (*db)->hdb_name = strdup(filename); 340178825Sdfr if ((*db)->hdb_name == NULL) { 34190926Snectar free(*db); 34290926Snectar *db = NULL; 343233294Sstas krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 34490926Snectar return ENOMEM; 34590926Snectar } 346178825Sdfr (*db)->hdb_master_key_set = 0; 347178825Sdfr (*db)->hdb_openp = 0; 348233294Sstas (*db)->hdb_capability_flags = HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL; 349178825Sdfr (*db)->hdb_open = DB_open; 350178825Sdfr (*db)->hdb_close = DB_close; 351233294Sstas (*db)->hdb_fetch_kvno = _hdb_fetch_kvno; 352178825Sdfr (*db)->hdb_store = _hdb_store; 353178825Sdfr (*db)->hdb_remove = _hdb_remove; 354178825Sdfr (*db)->hdb_firstkey = DB_firstkey; 355178825Sdfr (*db)->hdb_nextkey= DB_nextkey; 356178825Sdfr (*db)->hdb_lock = DB_lock; 357178825Sdfr (*db)->hdb_unlock = DB_unlock; 358178825Sdfr (*db)->hdb_rename = DB_rename; 359178825Sdfr (*db)->hdb__get = DB__get; 360178825Sdfr (*db)->hdb__put = DB__put; 361178825Sdfr (*db)->hdb__del = DB__del; 362178825Sdfr (*db)->hdb_destroy = DB_destroy; 36372445Sassar return 0; 36472445Sassar} 36590926Snectar#endif /* HAVE_DB3 */ 366