155682Smarkm/* 272445Sassar * Copyright (c) 1997 - 2001 Kungliga Tekniska H�gskolan 355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden). 455682Smarkm * All rights reserved. 555682Smarkm * 655682Smarkm * Redistribution and use in source and binary forms, with or without 755682Smarkm * modification, are permitted provided that the following conditions 855682Smarkm * are met: 955682Smarkm * 1055682Smarkm * 1. Redistributions of source code must retain the above copyright 1155682Smarkm * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1455682Smarkm * notice, this list of conditions and the following disclaimer in the 1555682Smarkm * documentation and/or other materials provided with the distribution. 1655682Smarkm * 1755682Smarkm * 3. Neither the name of the Institute nor the names of its contributors 1855682Smarkm * may be used to endorse or promote products derived from this software 1955682Smarkm * without specific prior written permission. 2055682Smarkm * 2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2455682Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3155682Smarkm * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm#include "hdb_locl.h" 3555682Smarkm 36178825SdfrRCSID("$Id: ndbm.c 16395 2005-12-13 11:54:10Z lha $"); 3755682Smarkm 3890926Snectar#if HAVE_NDBM 3955682Smarkm 4090926Snectar#if defined(HAVE_GDBM_NDBM_H) 4190926Snectar#include <gdbm/ndbm.h> 4290926Snectar#elif defined(HAVE_NDBM_H) 4390926Snectar#include <ndbm.h> 4490926Snectar#elif defined(HAVE_DBM_H) 4590926Snectar#include <dbm.h> 4690926Snectar#endif 4790926Snectar 4855682Smarkmstruct ndbm_db { 4955682Smarkm DBM *db; 5055682Smarkm int lock_fd; 5155682Smarkm}; 5255682Smarkm 5355682Smarkmstatic krb5_error_code 5455682SmarkmNDBM_destroy(krb5_context context, HDB *db) 5555682Smarkm{ 5655682Smarkm krb5_error_code ret; 5755682Smarkm 5855682Smarkm ret = hdb_clear_master_key (context, db); 59178825Sdfr free(db->hdb_name); 6055682Smarkm free(db); 6155682Smarkm return 0; 6255682Smarkm} 6355682Smarkm 6455682Smarkmstatic krb5_error_code 6555682SmarkmNDBM_lock(krb5_context context, HDB *db, int operation) 6655682Smarkm{ 67178825Sdfr struct ndbm_db *d = db->hdb_db; 6855682Smarkm return hdb_lock(d->lock_fd, operation); 6955682Smarkm} 7055682Smarkm 7155682Smarkmstatic krb5_error_code 7255682SmarkmNDBM_unlock(krb5_context context, HDB *db) 7355682Smarkm{ 74178825Sdfr struct ndbm_db *d = db->hdb_db; 7555682Smarkm return hdb_unlock(d->lock_fd); 7655682Smarkm} 7755682Smarkm 7855682Smarkmstatic krb5_error_code 7955682SmarkmNDBM_seq(krb5_context context, HDB *db, 80178825Sdfr unsigned flags, hdb_entry_ex *entry, int first) 8155682Smarkm 8255682Smarkm{ 83178825Sdfr struct ndbm_db *d = (struct ndbm_db *)db->hdb_db; 8455682Smarkm datum key, value; 8555682Smarkm krb5_data key_data, data; 8672445Sassar krb5_error_code ret = 0; 8755682Smarkm 8855682Smarkm if(first) 8955682Smarkm key = dbm_firstkey(d->db); 9055682Smarkm else 9155682Smarkm key = dbm_nextkey(d->db); 9255682Smarkm if(key.dptr == NULL) 9355682Smarkm return HDB_ERR_NOENTRY; 9455682Smarkm key_data.data = key.dptr; 9555682Smarkm key_data.length = key.dsize; 96178825Sdfr ret = db->hdb_lock(context, db, HDB_RLOCK); 9755682Smarkm if(ret) return ret; 9855682Smarkm value = dbm_fetch(d->db, key); 99178825Sdfr db->hdb_unlock(context, db); 10055682Smarkm data.data = value.dptr; 10155682Smarkm data.length = value.dsize; 102178825Sdfr memset(entry, 0, sizeof(*entry)); 103178825Sdfr if(hdb_value2entry(context, &data, &entry->entry)) 10455682Smarkm return NDBM_seq(context, db, flags, entry, 0); 105178825Sdfr if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { 106178825Sdfr ret = hdb_unseal_keys (context, db, &entry->entry); 10772445Sassar if (ret) 10872445Sassar hdb_free_entry (context, entry); 10972445Sassar } 110178825Sdfr if (ret == 0 && entry->entry.principal == NULL) { 111178825Sdfr entry->entry.principal = malloc (sizeof(*entry->entry.principal)); 112178825Sdfr if (entry->entry.principal == NULL) { 11372445Sassar ret = ENOMEM; 11472445Sassar hdb_free_entry (context, entry); 11590926Snectar krb5_set_error_string(context, "malloc: out of memory"); 11672445Sassar } else { 117178825Sdfr hdb_key2principal (context, &key_data, entry->entry.principal); 11872445Sassar } 11955682Smarkm } 12072445Sassar return ret; 12155682Smarkm} 12255682Smarkm 12355682Smarkm 12455682Smarkmstatic krb5_error_code 125178825SdfrNDBM_firstkey(krb5_context context, HDB *db,unsigned flags,hdb_entry_ex *entry) 12655682Smarkm{ 12755682Smarkm return NDBM_seq(context, db, flags, entry, 1); 12855682Smarkm} 12955682Smarkm 13055682Smarkm 13155682Smarkmstatic krb5_error_code 132178825SdfrNDBM_nextkey(krb5_context context, HDB *db, unsigned flags,hdb_entry_ex *entry) 13355682Smarkm{ 13455682Smarkm return NDBM_seq(context, db, flags, entry, 0); 13555682Smarkm} 13655682Smarkm 13755682Smarkmstatic krb5_error_code 13855682SmarkmNDBM_rename(krb5_context context, HDB *db, const char *new_name) 13955682Smarkm{ 14055682Smarkm /* XXX this function will break */ 141178825Sdfr struct ndbm_db *d = db->hdb_db; 14255682Smarkm 14355682Smarkm int ret; 14455682Smarkm char *old_dir, *old_pag, *new_dir, *new_pag; 14555682Smarkm char *new_lock; 14655682Smarkm int lock_fd; 14755682Smarkm 14855682Smarkm /* lock old and new databases */ 149178825Sdfr ret = db->hdb_lock(context, db, HDB_WLOCK); 15090926Snectar if(ret) 15190926Snectar return ret; 15255682Smarkm asprintf(&new_lock, "%s.lock", new_name); 15390926Snectar if(new_lock == NULL) { 154178825Sdfr db->hdb_unlock(context, db); 15590926Snectar krb5_set_error_string(context, "malloc: out of memory"); 15690926Snectar return ENOMEM; 15790926Snectar } 15855682Smarkm lock_fd = open(new_lock, O_RDWR | O_CREAT, 0600); 15955682Smarkm if(lock_fd < 0) { 16055682Smarkm ret = errno; 161178825Sdfr db->hdb_unlock(context, db); 16290926Snectar krb5_set_error_string(context, "open(%s): %s", new_lock, 16390926Snectar strerror(ret)); 16490926Snectar free(new_lock); 16555682Smarkm return ret; 16655682Smarkm } 16790926Snectar free(new_lock); 16855682Smarkm ret = hdb_lock(lock_fd, HDB_WLOCK); 16955682Smarkm if(ret) { 170178825Sdfr db->hdb_unlock(context, db); 17155682Smarkm close(lock_fd); 17255682Smarkm return ret; 17355682Smarkm } 17455682Smarkm 175178825Sdfr asprintf(&old_dir, "%s.dir", db->hdb_name); 176178825Sdfr asprintf(&old_pag, "%s.pag", db->hdb_name); 17755682Smarkm asprintf(&new_dir, "%s.dir", new_name); 17855682Smarkm asprintf(&new_pag, "%s.pag", new_name); 17955682Smarkm 18055682Smarkm ret = rename(old_dir, new_dir) || rename(old_pag, new_pag); 18155682Smarkm free(old_dir); 18255682Smarkm free(old_pag); 18355682Smarkm free(new_dir); 18455682Smarkm free(new_pag); 18555682Smarkm hdb_unlock(lock_fd); 186178825Sdfr db->hdb_unlock(context, db); 18755682Smarkm 18855682Smarkm if(ret) { 18990926Snectar ret = errno; 19055682Smarkm close(lock_fd); 19190926Snectar krb5_set_error_string(context, "rename: %s", strerror(ret)); 19290926Snectar return ret; 19355682Smarkm } 19455682Smarkm 19555682Smarkm close(d->lock_fd); 19655682Smarkm d->lock_fd = lock_fd; 19755682Smarkm 198178825Sdfr free(db->hdb_name); 199178825Sdfr db->hdb_name = strdup(new_name); 20055682Smarkm return 0; 20155682Smarkm} 20255682Smarkm 20355682Smarkmstatic krb5_error_code 20455682SmarkmNDBM__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply) 20555682Smarkm{ 206178825Sdfr struct ndbm_db *d = (struct ndbm_db *)db->hdb_db; 20755682Smarkm datum k, v; 20855682Smarkm int code; 20955682Smarkm 21055682Smarkm k.dptr = key.data; 21155682Smarkm k.dsize = key.length; 212178825Sdfr code = db->hdb_lock(context, db, HDB_RLOCK); 21355682Smarkm if(code) 21455682Smarkm return code; 21555682Smarkm v = dbm_fetch(d->db, k); 216178825Sdfr db->hdb_unlock(context, db); 21755682Smarkm if(v.dptr == NULL) 21855682Smarkm return HDB_ERR_NOENTRY; 21955682Smarkm 22055682Smarkm krb5_data_copy(reply, v.dptr, v.dsize); 22155682Smarkm return 0; 22255682Smarkm} 22355682Smarkm 22455682Smarkmstatic krb5_error_code 22555682SmarkmNDBM__put(krb5_context context, HDB *db, int replace, 22655682Smarkm krb5_data key, krb5_data value) 22755682Smarkm{ 228178825Sdfr struct ndbm_db *d = (struct ndbm_db *)db->hdb_db; 22955682Smarkm datum k, v; 23055682Smarkm int code; 23155682Smarkm 23255682Smarkm k.dptr = key.data; 23355682Smarkm k.dsize = key.length; 23455682Smarkm v.dptr = value.data; 23555682Smarkm v.dsize = value.length; 23655682Smarkm 237178825Sdfr code = db->hdb_lock(context, db, HDB_WLOCK); 23855682Smarkm if(code) 23955682Smarkm return code; 24055682Smarkm code = dbm_store(d->db, k, v, replace ? DBM_REPLACE : DBM_INSERT); 241178825Sdfr db->hdb_unlock(context, db); 24255682Smarkm if(code == 1) 24355682Smarkm return HDB_ERR_EXISTS; 24455682Smarkm if (code < 0) 24555682Smarkm return code; 24655682Smarkm return 0; 24755682Smarkm} 24855682Smarkm 24955682Smarkmstatic krb5_error_code 25055682SmarkmNDBM__del(krb5_context context, HDB *db, krb5_data key) 25155682Smarkm{ 252178825Sdfr struct ndbm_db *d = (struct ndbm_db *)db->hdb_db; 25355682Smarkm datum k; 25455682Smarkm int code; 25555682Smarkm krb5_error_code ret; 25655682Smarkm 25755682Smarkm k.dptr = key.data; 25855682Smarkm k.dsize = key.length; 259178825Sdfr ret = db->hdb_lock(context, db, HDB_WLOCK); 26055682Smarkm if(ret) return ret; 26155682Smarkm code = dbm_delete(d->db, k); 262178825Sdfr db->hdb_unlock(context, db); 26355682Smarkm if(code < 0) 26455682Smarkm return errno; 26555682Smarkm return 0; 26655682Smarkm} 26755682Smarkm 268178825Sdfr 26955682Smarkmstatic krb5_error_code 270178825SdfrNDBM_close(krb5_context context, HDB *db) 271178825Sdfr{ 272178825Sdfr struct ndbm_db *d = db->hdb_db; 273178825Sdfr dbm_close(d->db); 274178825Sdfr close(d->lock_fd); 275178825Sdfr free(d); 276178825Sdfr return 0; 277178825Sdfr} 278178825Sdfr 279178825Sdfrstatic krb5_error_code 28055682SmarkmNDBM_open(krb5_context context, HDB *db, int flags, mode_t mode) 28155682Smarkm{ 28255682Smarkm krb5_error_code ret; 28355682Smarkm struct ndbm_db *d = malloc(sizeof(*d)); 28455682Smarkm char *lock_file; 28555682Smarkm 28690926Snectar if(d == NULL) { 28790926Snectar krb5_set_error_string(context, "malloc: out of memory"); 28855682Smarkm return ENOMEM; 28990926Snectar } 290178825Sdfr asprintf(&lock_file, "%s.lock", (char*)db->hdb_name); 29155682Smarkm if(lock_file == NULL) { 29255682Smarkm free(d); 29390926Snectar krb5_set_error_string(context, "malloc: out of memory"); 29455682Smarkm return ENOMEM; 29555682Smarkm } 296178825Sdfr d->db = dbm_open((char*)db->hdb_name, flags, mode); 29755682Smarkm if(d->db == NULL){ 29890926Snectar ret = errno; 29955682Smarkm free(d); 30055682Smarkm free(lock_file); 301178825Sdfr krb5_set_error_string(context, "dbm_open(%s): %s", db->hdb_name, 30290926Snectar strerror(ret)); 30390926Snectar return ret; 30455682Smarkm } 30555682Smarkm d->lock_fd = open(lock_file, O_RDWR | O_CREAT, 0600); 30655682Smarkm if(d->lock_fd < 0){ 30790926Snectar ret = errno; 30855682Smarkm dbm_close(d->db); 30955682Smarkm free(d); 31090926Snectar krb5_set_error_string(context, "open(%s): %s", lock_file, 31190926Snectar strerror(ret)); 31290926Snectar free(lock_file); 31390926Snectar return ret; 31455682Smarkm } 31590926Snectar free(lock_file); 316178825Sdfr db->hdb_db = d; 31755682Smarkm if((flags & O_ACCMODE) == O_RDONLY) 31855682Smarkm ret = hdb_check_db_format(context, db); 31955682Smarkm else 32055682Smarkm ret = hdb_init_db(context, db); 32155682Smarkm if(ret == HDB_ERR_NOENTRY) 32255682Smarkm return 0; 323178825Sdfr if (ret) { 324178825Sdfr NDBM_close(context, db); 325178825Sdfr krb5_set_error_string(context, "hdb_open: failed %s database %s", 326178825Sdfr (flags & O_ACCMODE) == O_RDONLY ? 327178825Sdfr "checking format of" : "initialize", 328178825Sdfr db->hdb_name); 329178825Sdfr } 33055682Smarkm return ret; 33155682Smarkm} 33255682Smarkm 33355682Smarkmkrb5_error_code 33455682Smarkmhdb_ndbm_create(krb5_context context, HDB **db, 33555682Smarkm const char *filename) 33655682Smarkm{ 337178825Sdfr *db = calloc(1, sizeof(**db)); 33890926Snectar if (*db == NULL) { 33990926Snectar krb5_set_error_string(context, "malloc: out of memory"); 34055682Smarkm return ENOMEM; 34190926Snectar } 34255682Smarkm 343178825Sdfr (*db)->hdb_db = NULL; 344178825Sdfr (*db)->hdb_name = strdup(filename); 345178825Sdfr if ((*db)->hdb_name == NULL) { 34690926Snectar krb5_set_error_string(context, "malloc: out of memory"); 34790926Snectar free(*db); 34890926Snectar *db = NULL; 34990926Snectar return ENOMEM; 35090926Snectar } 351178825Sdfr (*db)->hdb_master_key_set = 0; 352178825Sdfr (*db)->hdb_openp = 0; 353178825Sdfr (*db)->hdb_open = NDBM_open; 354178825Sdfr (*db)->hdb_close = NDBM_close; 355178825Sdfr (*db)->hdb_fetch = _hdb_fetch; 356178825Sdfr (*db)->hdb_store = _hdb_store; 357178825Sdfr (*db)->hdb_remove = _hdb_remove; 358178825Sdfr (*db)->hdb_firstkey = NDBM_firstkey; 359178825Sdfr (*db)->hdb_nextkey= NDBM_nextkey; 360178825Sdfr (*db)->hdb_lock = NDBM_lock; 361178825Sdfr (*db)->hdb_unlock = NDBM_unlock; 362178825Sdfr (*db)->hdb_rename = NDBM_rename; 363178825Sdfr (*db)->hdb__get = NDBM__get; 364178825Sdfr (*db)->hdb__put = NDBM__put; 365178825Sdfr (*db)->hdb__del = NDBM__del; 366178825Sdfr (*db)->hdb_destroy = NDBM_destroy; 36755682Smarkm return 0; 36855682Smarkm} 36955682Smarkm 37090926Snectar#endif /* HAVE_NDBM */ 371