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_NDBM 3755682Smarkm 3890926Snectar#if defined(HAVE_GDBM_NDBM_H) 3990926Snectar#include <gdbm/ndbm.h> 40233294Sstas#define WRITE_SUPPORT 1 4190926Snectar#elif defined(HAVE_NDBM_H) 4290926Snectar#include <ndbm.h> 4390926Snectar#elif defined(HAVE_DBM_H) 44233294Sstas#define WRITE_SUPPORT 1 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{ 56233294Sstas hdb_clear_master_key (context, db); 57178825Sdfr free(db->hdb_name); 5855682Smarkm free(db); 5955682Smarkm return 0; 6055682Smarkm} 6155682Smarkm 6255682Smarkmstatic krb5_error_code 6355682SmarkmNDBM_lock(krb5_context context, HDB *db, int operation) 6455682Smarkm{ 65178825Sdfr struct ndbm_db *d = db->hdb_db; 6655682Smarkm return hdb_lock(d->lock_fd, operation); 6755682Smarkm} 6855682Smarkm 6955682Smarkmstatic krb5_error_code 7055682SmarkmNDBM_unlock(krb5_context context, HDB *db) 7155682Smarkm{ 72178825Sdfr struct ndbm_db *d = db->hdb_db; 7355682Smarkm return hdb_unlock(d->lock_fd); 7455682Smarkm} 7555682Smarkm 7655682Smarkmstatic krb5_error_code 77233294SstasNDBM_seq(krb5_context context, HDB *db, 78178825Sdfr unsigned flags, hdb_entry_ex *entry, int first) 7955682Smarkm 8055682Smarkm{ 81178825Sdfr struct ndbm_db *d = (struct ndbm_db *)db->hdb_db; 8255682Smarkm datum key, value; 8355682Smarkm krb5_data key_data, data; 8472445Sassar krb5_error_code ret = 0; 8555682Smarkm 8655682Smarkm if(first) 8755682Smarkm key = dbm_firstkey(d->db); 8855682Smarkm else 8955682Smarkm key = dbm_nextkey(d->db); 9055682Smarkm if(key.dptr == NULL) 9155682Smarkm return HDB_ERR_NOENTRY; 9255682Smarkm key_data.data = key.dptr; 9355682Smarkm key_data.length = key.dsize; 94178825Sdfr ret = db->hdb_lock(context, db, HDB_RLOCK); 9555682Smarkm if(ret) return ret; 9655682Smarkm value = dbm_fetch(d->db, key); 97178825Sdfr db->hdb_unlock(context, db); 9855682Smarkm data.data = value.dptr; 9955682Smarkm data.length = value.dsize; 100178825Sdfr memset(entry, 0, sizeof(*entry)); 101178825Sdfr if(hdb_value2entry(context, &data, &entry->entry)) 10255682Smarkm return NDBM_seq(context, db, flags, entry, 0); 103178825Sdfr if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { 104178825Sdfr ret = hdb_unseal_keys (context, db, &entry->entry); 10572445Sassar if (ret) 10672445Sassar hdb_free_entry (context, entry); 10772445Sassar } 108178825Sdfr if (ret == 0 && entry->entry.principal == NULL) { 109178825Sdfr entry->entry.principal = malloc (sizeof(*entry->entry.principal)); 110178825Sdfr if (entry->entry.principal == NULL) { 111233294Sstas hdb_free_entry (context, entry); 11272445Sassar ret = ENOMEM; 113233294Sstas krb5_set_error_message(context, ret, "malloc: out of memory"); 11472445Sassar } else { 115178825Sdfr hdb_key2principal (context, &key_data, entry->entry.principal); 11672445Sassar } 11755682Smarkm } 11872445Sassar return ret; 11955682Smarkm} 12055682Smarkm 12155682Smarkm 12255682Smarkmstatic krb5_error_code 123178825SdfrNDBM_firstkey(krb5_context context, HDB *db,unsigned flags,hdb_entry_ex *entry) 12455682Smarkm{ 12555682Smarkm return NDBM_seq(context, db, flags, entry, 1); 12655682Smarkm} 12755682Smarkm 12855682Smarkm 12955682Smarkmstatic krb5_error_code 130178825SdfrNDBM_nextkey(krb5_context context, HDB *db, unsigned flags,hdb_entry_ex *entry) 13155682Smarkm{ 13255682Smarkm return NDBM_seq(context, db, flags, entry, 0); 13355682Smarkm} 13455682Smarkm 13555682Smarkmstatic krb5_error_code 136233294Sstasopen_lock_file(krb5_context context, const char *db_name, int *fd) 137233294Sstas{ 138233294Sstas char *lock_file; 139233294Sstas 140233294Sstas /* lock old and new databases */ 141233294Sstas asprintf(&lock_file, "%s.lock", db_name); 142233294Sstas if(lock_file == NULL) { 143233294Sstas krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 144233294Sstas return ENOMEM; 145233294Sstas } 146233294Sstas 147233294Sstas *fd = open(lock_file, O_RDWR | O_CREAT, 0600); 148233294Sstas free(lock_file); 149233294Sstas if(*fd < 0) { 150233294Sstas int ret = errno; 151233294Sstas krb5_set_error_message(context, ret, "open(%s): %s", lock_file, 152233294Sstas strerror(ret)); 153233294Sstas return ret; 154233294Sstas } 155233294Sstas return 0; 156233294Sstas} 157233294Sstas 158233294Sstas 159233294Sstasstatic krb5_error_code 16055682SmarkmNDBM_rename(krb5_context context, HDB *db, const char *new_name) 16155682Smarkm{ 16255682Smarkm int ret; 16355682Smarkm char *old_dir, *old_pag, *new_dir, *new_pag; 164233294Sstas int old_lock_fd, new_lock_fd; 16555682Smarkm 16655682Smarkm /* lock old and new databases */ 167233294Sstas ret = open_lock_file(context, db->hdb_name, &old_lock_fd); 168233294Sstas if (ret) 16990926Snectar return ret; 170233294Sstas 171233294Sstas ret = hdb_lock(old_lock_fd, HDB_WLOCK); 172233294Sstas if(ret) { 173233294Sstas close(old_lock_fd); 174233294Sstas return ret; 17590926Snectar } 176233294Sstas 177233294Sstas ret = open_lock_file(context, new_name, &new_lock_fd); 178233294Sstas if (ret) { 179233294Sstas hdb_unlock(old_lock_fd); 180233294Sstas close(old_lock_fd); 18155682Smarkm return ret; 18255682Smarkm } 183233294Sstas 184233294Sstas ret = hdb_lock(new_lock_fd, HDB_WLOCK); 18555682Smarkm if(ret) { 186233294Sstas hdb_unlock(old_lock_fd); 187233294Sstas close(old_lock_fd); 188233294Sstas close(new_lock_fd); 18955682Smarkm return ret; 19055682Smarkm } 19155682Smarkm 192178825Sdfr asprintf(&old_dir, "%s.dir", db->hdb_name); 193178825Sdfr asprintf(&old_pag, "%s.pag", db->hdb_name); 19455682Smarkm asprintf(&new_dir, "%s.dir", new_name); 19555682Smarkm asprintf(&new_pag, "%s.pag", new_name); 19655682Smarkm 19755682Smarkm ret = rename(old_dir, new_dir) || rename(old_pag, new_pag); 198233294Sstas if (ret) { 199233294Sstas ret = errno; 200233294Sstas if (ret == 0) 201233294Sstas ret = EPERM; 202233294Sstas krb5_set_error_message(context, ret, "rename: %s", strerror(ret)); 203233294Sstas } 204233294Sstas 20555682Smarkm free(old_dir); 20655682Smarkm free(old_pag); 20755682Smarkm free(new_dir); 20855682Smarkm free(new_pag); 20955682Smarkm 210233294Sstas hdb_unlock(new_lock_fd); 211233294Sstas hdb_unlock(old_lock_fd); 212233294Sstas close(new_lock_fd); 213233294Sstas close(old_lock_fd); 214233294Sstas 215233294Sstas if(ret) 21690926Snectar return ret; 21755682Smarkm 218178825Sdfr free(db->hdb_name); 219178825Sdfr db->hdb_name = strdup(new_name); 22055682Smarkm return 0; 22155682Smarkm} 22255682Smarkm 22355682Smarkmstatic krb5_error_code 22455682SmarkmNDBM__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply) 22555682Smarkm{ 226178825Sdfr struct ndbm_db *d = (struct ndbm_db *)db->hdb_db; 22755682Smarkm datum k, v; 22855682Smarkm int code; 22955682Smarkm 23055682Smarkm k.dptr = key.data; 23155682Smarkm k.dsize = key.length; 232178825Sdfr code = db->hdb_lock(context, db, HDB_RLOCK); 23355682Smarkm if(code) 23455682Smarkm return code; 23555682Smarkm v = dbm_fetch(d->db, k); 236178825Sdfr db->hdb_unlock(context, db); 23755682Smarkm if(v.dptr == NULL) 23855682Smarkm return HDB_ERR_NOENTRY; 23955682Smarkm 24055682Smarkm krb5_data_copy(reply, v.dptr, v.dsize); 24155682Smarkm return 0; 24255682Smarkm} 24355682Smarkm 24455682Smarkmstatic krb5_error_code 245233294SstasNDBM__put(krb5_context context, HDB *db, int replace, 24655682Smarkm krb5_data key, krb5_data value) 24755682Smarkm{ 248233294Sstas#ifdef WRITE_SUPPORT 249178825Sdfr struct ndbm_db *d = (struct ndbm_db *)db->hdb_db; 25055682Smarkm datum k, v; 25155682Smarkm int code; 25255682Smarkm 25355682Smarkm k.dptr = key.data; 25455682Smarkm k.dsize = key.length; 25555682Smarkm v.dptr = value.data; 25655682Smarkm v.dsize = value.length; 25755682Smarkm 258178825Sdfr code = db->hdb_lock(context, db, HDB_WLOCK); 25955682Smarkm if(code) 26055682Smarkm return code; 26155682Smarkm code = dbm_store(d->db, k, v, replace ? DBM_REPLACE : DBM_INSERT); 262178825Sdfr db->hdb_unlock(context, db); 26355682Smarkm if(code == 1) 26455682Smarkm return HDB_ERR_EXISTS; 26555682Smarkm if (code < 0) 26655682Smarkm return code; 26755682Smarkm return 0; 268233294Sstas#else 269233294Sstas return HDB_ERR_NO_WRITE_SUPPORT; 270233294Sstas#endif 27155682Smarkm} 27255682Smarkm 27355682Smarkmstatic krb5_error_code 27455682SmarkmNDBM__del(krb5_context context, HDB *db, krb5_data key) 27555682Smarkm{ 276178825Sdfr struct ndbm_db *d = (struct ndbm_db *)db->hdb_db; 27755682Smarkm datum k; 27855682Smarkm int code; 27955682Smarkm krb5_error_code ret; 28055682Smarkm 28155682Smarkm k.dptr = key.data; 28255682Smarkm k.dsize = key.length; 283178825Sdfr ret = db->hdb_lock(context, db, HDB_WLOCK); 28455682Smarkm if(ret) return ret; 28555682Smarkm code = dbm_delete(d->db, k); 286178825Sdfr db->hdb_unlock(context, db); 28755682Smarkm if(code < 0) 28855682Smarkm return errno; 28955682Smarkm return 0; 29055682Smarkm} 29155682Smarkm 292178825Sdfr 29355682Smarkmstatic krb5_error_code 294178825SdfrNDBM_close(krb5_context context, HDB *db) 295178825Sdfr{ 296178825Sdfr struct ndbm_db *d = db->hdb_db; 297178825Sdfr dbm_close(d->db); 298178825Sdfr close(d->lock_fd); 299178825Sdfr free(d); 300178825Sdfr return 0; 301178825Sdfr} 302178825Sdfr 303178825Sdfrstatic krb5_error_code 30455682SmarkmNDBM_open(krb5_context context, HDB *db, int flags, mode_t mode) 30555682Smarkm{ 30655682Smarkm krb5_error_code ret; 30755682Smarkm struct ndbm_db *d = malloc(sizeof(*d)); 30855682Smarkm 30990926Snectar if(d == NULL) { 310233294Sstas krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 31155682Smarkm return ENOMEM; 31290926Snectar } 313233294Sstas 314178825Sdfr d->db = dbm_open((char*)db->hdb_name, flags, mode); 31555682Smarkm if(d->db == NULL){ 31690926Snectar ret = errno; 31755682Smarkm free(d); 318233294Sstas krb5_set_error_message(context, ret, "dbm_open(%s): %s", db->hdb_name, 319233294Sstas strerror(ret)); 32090926Snectar return ret; 32155682Smarkm } 322233294Sstas 323233294Sstas ret = open_lock_file(context, db->hdb_name, &d->lock_fd); 324233294Sstas if (ret) { 32590926Snectar ret = errno; 32655682Smarkm dbm_close(d->db); 32755682Smarkm free(d); 328233294Sstas krb5_set_error_message(context, ret, "open(lock file): %s", 329233294Sstas strerror(ret)); 33090926Snectar return ret; 33155682Smarkm } 332233294Sstas 333178825Sdfr db->hdb_db = d; 33455682Smarkm if((flags & O_ACCMODE) == O_RDONLY) 33555682Smarkm ret = hdb_check_db_format(context, db); 33655682Smarkm else 33755682Smarkm ret = hdb_init_db(context, db); 33855682Smarkm if(ret == HDB_ERR_NOENTRY) 33955682Smarkm return 0; 340178825Sdfr if (ret) { 341178825Sdfr NDBM_close(context, db); 342233294Sstas krb5_set_error_message(context, ret, "hdb_open: failed %s database %s", 343233294Sstas (flags & O_ACCMODE) == O_RDONLY ? 344233294Sstas "checking format of" : "initialize", 345233294Sstas db->hdb_name); 346178825Sdfr } 34755682Smarkm return ret; 34855682Smarkm} 34955682Smarkm 35055682Smarkmkrb5_error_code 351233294Sstashdb_ndbm_create(krb5_context context, HDB **db, 35255682Smarkm const char *filename) 35355682Smarkm{ 354178825Sdfr *db = calloc(1, sizeof(**db)); 35590926Snectar if (*db == NULL) { 356233294Sstas krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 35755682Smarkm return ENOMEM; 35890926Snectar } 35955682Smarkm 360178825Sdfr (*db)->hdb_db = NULL; 361178825Sdfr (*db)->hdb_name = strdup(filename); 362178825Sdfr if ((*db)->hdb_name == NULL) { 36390926Snectar free(*db); 36490926Snectar *db = NULL; 365233294Sstas krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 36690926Snectar return ENOMEM; 36790926Snectar } 368178825Sdfr (*db)->hdb_master_key_set = 0; 369178825Sdfr (*db)->hdb_openp = 0; 370233294Sstas (*db)->hdb_capability_flags = HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL; 371178825Sdfr (*db)->hdb_open = NDBM_open; 372178825Sdfr (*db)->hdb_close = NDBM_close; 373233294Sstas (*db)->hdb_fetch_kvno = _hdb_fetch_kvno; 374178825Sdfr (*db)->hdb_store = _hdb_store; 375178825Sdfr (*db)->hdb_remove = _hdb_remove; 376178825Sdfr (*db)->hdb_firstkey = NDBM_firstkey; 377178825Sdfr (*db)->hdb_nextkey= NDBM_nextkey; 378178825Sdfr (*db)->hdb_lock = NDBM_lock; 379178825Sdfr (*db)->hdb_unlock = NDBM_unlock; 380178825Sdfr (*db)->hdb_rename = NDBM_rename; 381178825Sdfr (*db)->hdb__get = NDBM__get; 382178825Sdfr (*db)->hdb__put = NDBM__put; 383178825Sdfr (*db)->hdb__del = NDBM__del; 384178825Sdfr (*db)->hdb_destroy = NDBM_destroy; 38555682Smarkm return 0; 38655682Smarkm} 38755682Smarkm 38890926Snectar#endif /* HAVE_NDBM */ 389