172445Sassar/* 2178825Sdfr * Copyright (c) 1997 - 2006 Kungliga Tekniska H�gskolan 372445Sassar * (Royal Institute of Technology, Stockholm, Sweden). 472445Sassar * All rights reserved. 572445Sassar * 672445Sassar * Redistribution and use in source and binary forms, with or without 772445Sassar * modification, are permitted provided that the following conditions 872445Sassar * are met: 972445Sassar * 1072445Sassar * 1. Redistributions of source code must retain the above copyright 1172445Sassar * notice, this list of conditions and the following disclaimer. 1272445Sassar * 1372445Sassar * 2. Redistributions in binary form must reproduce the above copyright 1472445Sassar * notice, this list of conditions and the following disclaimer in the 1572445Sassar * documentation and/or other materials provided with the distribution. 1672445Sassar * 1772445Sassar * 3. Neither the name of the Institute nor the names of its contributors 1872445Sassar * may be used to endorse or promote products derived from this software 1972445Sassar * without specific prior written permission. 2072445Sassar * 2172445Sassar * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 2272445Sassar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2372445Sassar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2472445Sassar * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 2572445Sassar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2672445Sassar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2772445Sassar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2872445Sassar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2972445Sassar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3072445Sassar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3172445Sassar * SUCH DAMAGE. 3272445Sassar */ 3372445Sassar 3472445Sassar#include "hdb_locl.h" 3572445Sassar 36178825SdfrRCSID("$Id: db3.c 21610 2007-07-17 07:10:45Z lha $"); 3772445Sassar 3890926Snectar#if HAVE_DB3 3990926Snectar 40127808Snectar#ifdef HAVE_DB4_DB_H 41127808Snectar#include <db4/db.h> 42127808Snectar#elif defined(HAVE_DB3_DB_H) 43127808Snectar#include <db3/db.h> 44127808Snectar#else 4590926Snectar#include <db.h> 46127808Snectar#endif 4790926Snectar 4872445Sassarstatic krb5_error_code 4972445SassarDB_close(krb5_context context, HDB *db) 5072445Sassar{ 51178825Sdfr DB *d = (DB*)db->hdb_db; 52178825Sdfr DBC *dbcp = (DBC*)db->hdb_dbc; 5372445Sassar 54178825Sdfr (*dbcp->c_close)(dbcp); 55178825Sdfr db->hdb_dbc = 0; 56178825Sdfr (*d->close)(d, 0); 5772445Sassar return 0; 5872445Sassar} 5972445Sassar 6072445Sassarstatic krb5_error_code 6172445SassarDB_destroy(krb5_context context, HDB *db) 6272445Sassar{ 6372445Sassar krb5_error_code ret; 6472445Sassar 6572445Sassar ret = hdb_clear_master_key (context, db); 66178825Sdfr free(db->hdb_name); 6772445Sassar free(db); 6872445Sassar return ret; 6972445Sassar} 7072445Sassar 7172445Sassarstatic krb5_error_code 7272445SassarDB_lock(krb5_context context, HDB *db, int operation) 7372445Sassar{ 74178825Sdfr DB *d = (DB*)db->hdb_db; 7572445Sassar int fd; 7672445Sassar if ((*d->fd)(d, &fd)) 7772445Sassar return HDB_ERR_CANT_LOCK_DB; 7872445Sassar return hdb_lock(fd, operation); 7972445Sassar} 8072445Sassar 8172445Sassarstatic krb5_error_code 8272445SassarDB_unlock(krb5_context context, HDB *db) 8372445Sassar{ 84178825Sdfr DB *d = (DB*)db->hdb_db; 8572445Sassar int fd; 8672445Sassar if ((*d->fd)(d, &fd)) 8772445Sassar return HDB_ERR_CANT_LOCK_DB; 8872445Sassar return hdb_unlock(fd); 8972445Sassar} 9072445Sassar 9172445Sassar 9272445Sassarstatic krb5_error_code 9372445SassarDB_seq(krb5_context context, HDB *db, 94178825Sdfr unsigned flags, hdb_entry_ex *entry, int flag) 9572445Sassar{ 9672445Sassar DBT key, value; 97178825Sdfr DBC *dbcp = db->hdb_dbc; 9872445Sassar krb5_data key_data, data; 9972445Sassar int code; 10072445Sassar 10172445Sassar memset(&key, 0, sizeof(DBT)); 10272445Sassar memset(&value, 0, sizeof(DBT)); 103178825Sdfr if ((*db->hdb_lock)(context, db, HDB_RLOCK)) 10472445Sassar return HDB_ERR_DB_INUSE; 105178825Sdfr code = (*dbcp->c_get)(dbcp, &key, &value, flag); 106178825Sdfr (*db->hdb_unlock)(context, db); /* XXX check value */ 10772445Sassar if (code == DB_NOTFOUND) 10872445Sassar return HDB_ERR_NOENTRY; 10972445Sassar if (code) 11072445Sassar return code; 11172445Sassar 11272445Sassar key_data.data = key.data; 11372445Sassar key_data.length = key.size; 11472445Sassar data.data = value.data; 11572445Sassar data.length = value.size; 116178825Sdfr memset(entry, 0, sizeof(*entry)); 117178825Sdfr if (hdb_value2entry(context, &data, &entry->entry)) 11872445Sassar return DB_seq(context, db, flags, entry, DB_NEXT); 119178825Sdfr if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { 120178825Sdfr code = hdb_unseal_keys (context, db, &entry->entry); 12172445Sassar if (code) 12272445Sassar hdb_free_entry (context, entry); 12372445Sassar } 124178825Sdfr if (entry->entry.principal == NULL) { 125178825Sdfr entry->entry.principal = malloc(sizeof(*entry->entry.principal)); 126178825Sdfr if (entry->entry.principal == NULL) { 12772445Sassar hdb_free_entry (context, entry); 12890926Snectar krb5_set_error_string(context, "malloc: out of memory"); 12990926Snectar return ENOMEM; 13072445Sassar } else { 131178825Sdfr hdb_key2principal(context, &key_data, entry->entry.principal); 13272445Sassar } 13372445Sassar } 13472445Sassar return 0; 13572445Sassar} 13672445Sassar 13772445Sassar 13872445Sassarstatic krb5_error_code 139178825SdfrDB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) 14072445Sassar{ 14172445Sassar return DB_seq(context, db, flags, entry, DB_FIRST); 14272445Sassar} 14372445Sassar 14472445Sassar 14572445Sassarstatic krb5_error_code 146178825SdfrDB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) 14772445Sassar{ 14872445Sassar return DB_seq(context, db, flags, entry, DB_NEXT); 14972445Sassar} 15072445Sassar 15172445Sassarstatic krb5_error_code 15272445SassarDB_rename(krb5_context context, HDB *db, const char *new_name) 15372445Sassar{ 15472445Sassar int ret; 15572445Sassar char *old, *new; 15672445Sassar 157178825Sdfr asprintf(&old, "%s.db", db->hdb_name); 15872445Sassar asprintf(&new, "%s.db", new_name); 15972445Sassar ret = rename(old, new); 16072445Sassar free(old); 16172445Sassar free(new); 16272445Sassar if(ret) 16372445Sassar return errno; 16472445Sassar 165178825Sdfr free(db->hdb_name); 166178825Sdfr db->hdb_name = strdup(new_name); 16772445Sassar return 0; 16872445Sassar} 16972445Sassar 17072445Sassarstatic krb5_error_code 17172445SassarDB__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply) 17272445Sassar{ 173178825Sdfr DB *d = (DB*)db->hdb_db; 17472445Sassar DBT k, v; 17572445Sassar int code; 17672445Sassar 17772445Sassar memset(&k, 0, sizeof(DBT)); 17872445Sassar memset(&v, 0, sizeof(DBT)); 17972445Sassar k.data = key.data; 18072445Sassar k.size = key.length; 18172445Sassar k.flags = 0; 182178825Sdfr if ((code = (*db->hdb_lock)(context, db, HDB_RLOCK))) 18372445Sassar return code; 184178825Sdfr code = (*d->get)(d, NULL, &k, &v, 0); 185178825Sdfr (*db->hdb_unlock)(context, db); 18672445Sassar if(code == DB_NOTFOUND) 18772445Sassar return HDB_ERR_NOENTRY; 18872445Sassar if(code) 18972445Sassar return code; 19072445Sassar 19172445Sassar krb5_data_copy(reply, v.data, v.size); 19272445Sassar return 0; 19372445Sassar} 19472445Sassar 19572445Sassarstatic krb5_error_code 19672445SassarDB__put(krb5_context context, HDB *db, int replace, 19772445Sassar krb5_data key, krb5_data value) 19872445Sassar{ 199178825Sdfr DB *d = (DB*)db->hdb_db; 20072445Sassar DBT k, v; 20172445Sassar int code; 20272445Sassar 20372445Sassar memset(&k, 0, sizeof(DBT)); 20472445Sassar memset(&v, 0, sizeof(DBT)); 20572445Sassar k.data = key.data; 20672445Sassar k.size = key.length; 20772445Sassar k.flags = 0; 20872445Sassar v.data = value.data; 20972445Sassar v.size = value.length; 21072445Sassar v.flags = 0; 211178825Sdfr if ((code = (*db->hdb_lock)(context, db, HDB_WLOCK))) 21272445Sassar return code; 213178825Sdfr code = (*d->put)(d, NULL, &k, &v, replace ? 0 : DB_NOOVERWRITE); 214178825Sdfr (*db->hdb_unlock)(context, db); 21572445Sassar if(code == DB_KEYEXIST) 21672445Sassar return HDB_ERR_EXISTS; 21772445Sassar if(code) 21872445Sassar return errno; 21972445Sassar return 0; 22072445Sassar} 22172445Sassar 22272445Sassarstatic krb5_error_code 22372445SassarDB__del(krb5_context context, HDB *db, krb5_data key) 22472445Sassar{ 225178825Sdfr DB *d = (DB*)db->hdb_db; 22672445Sassar DBT k; 22772445Sassar krb5_error_code code; 22872445Sassar memset(&k, 0, sizeof(DBT)); 22972445Sassar k.data = key.data; 23072445Sassar k.size = key.length; 23172445Sassar k.flags = 0; 232178825Sdfr code = (*db->hdb_lock)(context, db, HDB_WLOCK); 23372445Sassar if(code) 23472445Sassar return code; 235178825Sdfr code = (*d->del)(d, NULL, &k, 0); 236178825Sdfr (*db->hdb_unlock)(context, db); 23772445Sassar if(code == DB_NOTFOUND) 23872445Sassar return HDB_ERR_NOENTRY; 23972445Sassar if(code) 24072445Sassar return code; 24172445Sassar return 0; 24272445Sassar} 24372445Sassar 24472445Sassarstatic krb5_error_code 24572445SassarDB_open(krb5_context context, HDB *db, int flags, mode_t mode) 24672445Sassar{ 247178825Sdfr DBC *dbc = NULL; 24872445Sassar char *fn; 24972445Sassar krb5_error_code ret; 25072445Sassar DB *d; 25172445Sassar int myflags = 0; 25272445Sassar 25372445Sassar if (flags & O_CREAT) 25472445Sassar myflags |= DB_CREATE; 25572445Sassar 25672445Sassar if (flags & O_EXCL) 25772445Sassar myflags |= DB_EXCL; 25872445Sassar 259178825Sdfr if((flags & O_ACCMODE) == O_RDONLY) 26072445Sassar myflags |= DB_RDONLY; 26172445Sassar 26272445Sassar if (flags & O_TRUNC) 26372445Sassar myflags |= DB_TRUNCATE; 26472445Sassar 265178825Sdfr asprintf(&fn, "%s.db", db->hdb_name); 26690926Snectar if (fn == NULL) { 26790926Snectar krb5_set_error_string(context, "malloc: out of memory"); 26872445Sassar return ENOMEM; 26990926Snectar } 27072445Sassar db_create(&d, NULL, 0); 271178825Sdfr db->hdb_db = d; 272178825Sdfr 273178825Sdfr#if (DB_VERSION_MAJOR >= 4) && (DB_VERSION_MINOR >= 1) 274178825Sdfr ret = (*d->open)(db->hdb_db, NULL, fn, NULL, DB_BTREE, myflags, mode); 275127808Snectar#else 276178825Sdfr ret = (*d->open)(db->hdb_db, fn, NULL, DB_BTREE, myflags, mode); 277127808Snectar#endif 278178825Sdfr 279178825Sdfr if (ret == ENOENT) { 28072445Sassar /* try to open without .db extension */ 281178825Sdfr#if (DB_VERSION_MAJOR >= 4) && (DB_VERSION_MINOR >= 1) 282178825Sdfr ret = (*d->open)(db->hdb_db, NULL, db->hdb_name, NULL, DB_BTREE, 283178825Sdfr myflags, mode); 284127808Snectar#else 285178825Sdfr ret = (*d->open)(db->hdb_db, db->hdb_name, NULL, DB_BTREE, 286178825Sdfr myflags, mode); 287127808Snectar#endif 28872445Sassar } 289178825Sdfr 290178825Sdfr if (ret) { 291178825Sdfr free(fn); 292178825Sdfr krb5_set_error_string(context, "opening %s: %s", 293178825Sdfr db->hdb_name, strerror(ret)); 294178825Sdfr return ret; 295178825Sdfr } 29672445Sassar free(fn); 29772445Sassar 298178825Sdfr ret = (*d->cursor)(d, NULL, &dbc, 0); 29990926Snectar if (ret) { 30090926Snectar krb5_set_error_string(context, "d->cursor: %s", strerror(ret)); 30172445Sassar return ret; 30290926Snectar } 303178825Sdfr db->hdb_dbc = dbc; 30472445Sassar 30572445Sassar if((flags & O_ACCMODE) == O_RDONLY) 30672445Sassar ret = hdb_check_db_format(context, db); 30772445Sassar else 30872445Sassar ret = hdb_init_db(context, db); 30972445Sassar if(ret == HDB_ERR_NOENTRY) 31072445Sassar return 0; 311178825Sdfr if (ret) { 312178825Sdfr DB_close(context, db); 313178825Sdfr krb5_set_error_string(context, "hdb_open: failed %s database %s", 314178825Sdfr (flags & O_ACCMODE) == O_RDONLY ? 315178825Sdfr "checking format of" : "initialize", 316178825Sdfr db->hdb_name); 317178825Sdfr } 318178825Sdfr 31972445Sassar return ret; 32072445Sassar} 32172445Sassar 32272445Sassarkrb5_error_code 32372445Sassarhdb_db_create(krb5_context context, HDB **db, 32472445Sassar const char *filename) 32572445Sassar{ 326178825Sdfr *db = calloc(1, sizeof(**db)); 32790926Snectar if (*db == NULL) { 32890926Snectar krb5_set_error_string(context, "malloc: out of memory"); 32972445Sassar return ENOMEM; 33090926Snectar } 33172445Sassar 332178825Sdfr (*db)->hdb_db = NULL; 333178825Sdfr (*db)->hdb_name = strdup(filename); 334178825Sdfr if ((*db)->hdb_name == NULL) { 33590926Snectar krb5_set_error_string(context, "malloc: out of memory"); 33690926Snectar free(*db); 33790926Snectar *db = NULL; 33890926Snectar return ENOMEM; 33990926Snectar } 340178825Sdfr (*db)->hdb_master_key_set = 0; 341178825Sdfr (*db)->hdb_openp = 0; 342178825Sdfr (*db)->hdb_open = DB_open; 343178825Sdfr (*db)->hdb_close = DB_close; 344178825Sdfr (*db)->hdb_fetch = _hdb_fetch; 345178825Sdfr (*db)->hdb_store = _hdb_store; 346178825Sdfr (*db)->hdb_remove = _hdb_remove; 347178825Sdfr (*db)->hdb_firstkey = DB_firstkey; 348178825Sdfr (*db)->hdb_nextkey= DB_nextkey; 349178825Sdfr (*db)->hdb_lock = DB_lock; 350178825Sdfr (*db)->hdb_unlock = DB_unlock; 351178825Sdfr (*db)->hdb_rename = DB_rename; 352178825Sdfr (*db)->hdb__get = DB__get; 353178825Sdfr (*db)->hdb__put = DB__put; 354178825Sdfr (*db)->hdb__del = DB__del; 355178825Sdfr (*db)->hdb_destroy = DB_destroy; 35672445Sassar return 0; 35772445Sassar} 35890926Snectar#endif /* HAVE_DB3 */ 359