1b528cefcSMark Murray /* 25e9cd1aeSAssar Westerlund * Copyright (c) 1997 - 2001 Kungliga Tekniska H�gskolan 3b528cefcSMark Murray * (Royal Institute of Technology, Stockholm, Sweden). 4b528cefcSMark Murray * All rights reserved. 5b528cefcSMark Murray * 6b528cefcSMark Murray * Redistribution and use in source and binary forms, with or without 7b528cefcSMark Murray * modification, are permitted provided that the following conditions 8b528cefcSMark Murray * are met: 9b528cefcSMark Murray * 10b528cefcSMark Murray * 1. Redistributions of source code must retain the above copyright 11b528cefcSMark Murray * notice, this list of conditions and the following disclaimer. 12b528cefcSMark Murray * 13b528cefcSMark Murray * 2. Redistributions in binary form must reproduce the above copyright 14b528cefcSMark Murray * notice, this list of conditions and the following disclaimer in the 15b528cefcSMark Murray * documentation and/or other materials provided with the distribution. 16b528cefcSMark Murray * 17b528cefcSMark Murray * 3. Neither the name of the Institute nor the names of its contributors 18b528cefcSMark Murray * may be used to endorse or promote products derived from this software 19b528cefcSMark Murray * without specific prior written permission. 20b528cefcSMark Murray * 21b528cefcSMark Murray * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22b528cefcSMark Murray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23b528cefcSMark Murray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24b528cefcSMark Murray * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25b528cefcSMark Murray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26b528cefcSMark Murray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27b528cefcSMark Murray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28b528cefcSMark Murray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29b528cefcSMark Murray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30b528cefcSMark Murray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31b528cefcSMark Murray * SUCH DAMAGE. 32b528cefcSMark Murray */ 33b528cefcSMark Murray 34b528cefcSMark Murray #include "hdb_locl.h" 35b528cefcSMark Murray 36c19800e8SDoug Rabson RCSID("$Id: ndbm.c 16395 2005-12-13 11:54:10Z lha $"); 37b528cefcSMark Murray 384137ff4cSJacques Vidrine #if HAVE_NDBM 394137ff4cSJacques Vidrine 404137ff4cSJacques Vidrine #if defined(HAVE_GDBM_NDBM_H) 414137ff4cSJacques Vidrine #include <gdbm/ndbm.h> 424137ff4cSJacques Vidrine #elif defined(HAVE_NDBM_H) 434137ff4cSJacques Vidrine #include <ndbm.h> 444137ff4cSJacques Vidrine #elif defined(HAVE_DBM_H) 454137ff4cSJacques Vidrine #include <dbm.h> 464137ff4cSJacques Vidrine #endif 47b528cefcSMark Murray 48b528cefcSMark Murray struct ndbm_db { 49b528cefcSMark Murray DBM *db; 50b528cefcSMark Murray int lock_fd; 51b528cefcSMark Murray }; 52b528cefcSMark Murray 53b528cefcSMark Murray static krb5_error_code 54b528cefcSMark Murray NDBM_destroy(krb5_context context, HDB *db) 55b528cefcSMark Murray { 56b528cefcSMark Murray krb5_error_code ret; 57b528cefcSMark Murray 58b528cefcSMark Murray ret = hdb_clear_master_key (context, db); 59c19800e8SDoug Rabson free(db->hdb_name); 60b528cefcSMark Murray free(db); 61b528cefcSMark Murray return 0; 62b528cefcSMark Murray } 63b528cefcSMark Murray 64b528cefcSMark Murray static krb5_error_code 65b528cefcSMark Murray NDBM_lock(krb5_context context, HDB *db, int operation) 66b528cefcSMark Murray { 67c19800e8SDoug Rabson struct ndbm_db *d = db->hdb_db; 68b528cefcSMark Murray return hdb_lock(d->lock_fd, operation); 69b528cefcSMark Murray } 70b528cefcSMark Murray 71b528cefcSMark Murray static krb5_error_code 72b528cefcSMark Murray NDBM_unlock(krb5_context context, HDB *db) 73b528cefcSMark Murray { 74c19800e8SDoug Rabson struct ndbm_db *d = db->hdb_db; 75b528cefcSMark Murray return hdb_unlock(d->lock_fd); 76b528cefcSMark Murray } 77b528cefcSMark Murray 78b528cefcSMark Murray static krb5_error_code 79b528cefcSMark Murray NDBM_seq(krb5_context context, HDB *db, 80c19800e8SDoug Rabson unsigned flags, hdb_entry_ex *entry, int first) 81b528cefcSMark Murray 82b528cefcSMark Murray { 83c19800e8SDoug Rabson struct ndbm_db *d = (struct ndbm_db *)db->hdb_db; 84b528cefcSMark Murray datum key, value; 85b528cefcSMark Murray krb5_data key_data, data; 865e9cd1aeSAssar Westerlund krb5_error_code ret = 0; 87b528cefcSMark Murray 88b528cefcSMark Murray if(first) 89b528cefcSMark Murray key = dbm_firstkey(d->db); 90b528cefcSMark Murray else 91b528cefcSMark Murray key = dbm_nextkey(d->db); 92b528cefcSMark Murray if(key.dptr == NULL) 93b528cefcSMark Murray return HDB_ERR_NOENTRY; 94b528cefcSMark Murray key_data.data = key.dptr; 95b528cefcSMark Murray key_data.length = key.dsize; 96c19800e8SDoug Rabson ret = db->hdb_lock(context, db, HDB_RLOCK); 97b528cefcSMark Murray if(ret) return ret; 98b528cefcSMark Murray value = dbm_fetch(d->db, key); 99c19800e8SDoug Rabson db->hdb_unlock(context, db); 100b528cefcSMark Murray data.data = value.dptr; 101b528cefcSMark Murray data.length = value.dsize; 102c19800e8SDoug Rabson memset(entry, 0, sizeof(*entry)); 103c19800e8SDoug Rabson if(hdb_value2entry(context, &data, &entry->entry)) 104b528cefcSMark Murray return NDBM_seq(context, db, flags, entry, 0); 105c19800e8SDoug Rabson if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { 106c19800e8SDoug Rabson ret = hdb_unseal_keys (context, db, &entry->entry); 1075e9cd1aeSAssar Westerlund if (ret) 1085e9cd1aeSAssar Westerlund hdb_free_entry (context, entry); 1095e9cd1aeSAssar Westerlund } 110c19800e8SDoug Rabson if (ret == 0 && entry->entry.principal == NULL) { 111c19800e8SDoug Rabson entry->entry.principal = malloc (sizeof(*entry->entry.principal)); 112c19800e8SDoug Rabson if (entry->entry.principal == NULL) { 1135e9cd1aeSAssar Westerlund ret = ENOMEM; 1145e9cd1aeSAssar Westerlund hdb_free_entry (context, entry); 1154137ff4cSJacques Vidrine krb5_set_error_string(context, "malloc: out of memory"); 1165e9cd1aeSAssar Westerlund } else { 117c19800e8SDoug Rabson hdb_key2principal (context, &key_data, entry->entry.principal); 118b528cefcSMark Murray } 1195e9cd1aeSAssar Westerlund } 1205e9cd1aeSAssar Westerlund return ret; 121b528cefcSMark Murray } 122b528cefcSMark Murray 123b528cefcSMark Murray 124b528cefcSMark Murray static krb5_error_code 125c19800e8SDoug Rabson NDBM_firstkey(krb5_context context, HDB *db,unsigned flags,hdb_entry_ex *entry) 126b528cefcSMark Murray { 127b528cefcSMark Murray return NDBM_seq(context, db, flags, entry, 1); 128b528cefcSMark Murray } 129b528cefcSMark Murray 130b528cefcSMark Murray 131b528cefcSMark Murray static krb5_error_code 132c19800e8SDoug Rabson NDBM_nextkey(krb5_context context, HDB *db, unsigned flags,hdb_entry_ex *entry) 133b528cefcSMark Murray { 134b528cefcSMark Murray return NDBM_seq(context, db, flags, entry, 0); 135b528cefcSMark Murray } 136b528cefcSMark Murray 137b528cefcSMark Murray static krb5_error_code 138b528cefcSMark Murray NDBM_rename(krb5_context context, HDB *db, const char *new_name) 139b528cefcSMark Murray { 140b528cefcSMark Murray /* XXX this function will break */ 141c19800e8SDoug Rabson struct ndbm_db *d = db->hdb_db; 142b528cefcSMark Murray 143b528cefcSMark Murray int ret; 144b528cefcSMark Murray char *old_dir, *old_pag, *new_dir, *new_pag; 145b528cefcSMark Murray char *new_lock; 146b528cefcSMark Murray int lock_fd; 147b528cefcSMark Murray 148b528cefcSMark Murray /* lock old and new databases */ 149c19800e8SDoug Rabson ret = db->hdb_lock(context, db, HDB_WLOCK); 1504137ff4cSJacques Vidrine if(ret) 1514137ff4cSJacques Vidrine return ret; 152b528cefcSMark Murray asprintf(&new_lock, "%s.lock", new_name); 1534137ff4cSJacques Vidrine if(new_lock == NULL) { 154c19800e8SDoug Rabson db->hdb_unlock(context, db); 1554137ff4cSJacques Vidrine krb5_set_error_string(context, "malloc: out of memory"); 1564137ff4cSJacques Vidrine return ENOMEM; 1574137ff4cSJacques Vidrine } 158b528cefcSMark Murray lock_fd = open(new_lock, O_RDWR | O_CREAT, 0600); 159b528cefcSMark Murray if(lock_fd < 0) { 160b528cefcSMark Murray ret = errno; 161c19800e8SDoug Rabson db->hdb_unlock(context, db); 1624137ff4cSJacques Vidrine krb5_set_error_string(context, "open(%s): %s", new_lock, 1634137ff4cSJacques Vidrine strerror(ret)); 1644137ff4cSJacques Vidrine free(new_lock); 165b528cefcSMark Murray return ret; 166b528cefcSMark Murray } 1674137ff4cSJacques Vidrine free(new_lock); 168b528cefcSMark Murray ret = hdb_lock(lock_fd, HDB_WLOCK); 169b528cefcSMark Murray if(ret) { 170c19800e8SDoug Rabson db->hdb_unlock(context, db); 171b528cefcSMark Murray close(lock_fd); 172b528cefcSMark Murray return ret; 173b528cefcSMark Murray } 174b528cefcSMark Murray 175c19800e8SDoug Rabson asprintf(&old_dir, "%s.dir", db->hdb_name); 176c19800e8SDoug Rabson asprintf(&old_pag, "%s.pag", db->hdb_name); 177b528cefcSMark Murray asprintf(&new_dir, "%s.dir", new_name); 178b528cefcSMark Murray asprintf(&new_pag, "%s.pag", new_name); 179b528cefcSMark Murray 180b528cefcSMark Murray ret = rename(old_dir, new_dir) || rename(old_pag, new_pag); 181b528cefcSMark Murray free(old_dir); 182b528cefcSMark Murray free(old_pag); 183b528cefcSMark Murray free(new_dir); 184b528cefcSMark Murray free(new_pag); 185b528cefcSMark Murray hdb_unlock(lock_fd); 186c19800e8SDoug Rabson db->hdb_unlock(context, db); 187b528cefcSMark Murray 188b528cefcSMark Murray if(ret) { 1894137ff4cSJacques Vidrine ret = errno; 190b528cefcSMark Murray close(lock_fd); 1914137ff4cSJacques Vidrine krb5_set_error_string(context, "rename: %s", strerror(ret)); 1924137ff4cSJacques Vidrine return ret; 193b528cefcSMark Murray } 194b528cefcSMark Murray 195b528cefcSMark Murray close(d->lock_fd); 196b528cefcSMark Murray d->lock_fd = lock_fd; 197b528cefcSMark Murray 198c19800e8SDoug Rabson free(db->hdb_name); 199c19800e8SDoug Rabson db->hdb_name = strdup(new_name); 200b528cefcSMark Murray return 0; 201b528cefcSMark Murray } 202b528cefcSMark Murray 203b528cefcSMark Murray static krb5_error_code 204b528cefcSMark Murray NDBM__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply) 205b528cefcSMark Murray { 206c19800e8SDoug Rabson struct ndbm_db *d = (struct ndbm_db *)db->hdb_db; 207b528cefcSMark Murray datum k, v; 208b528cefcSMark Murray int code; 209b528cefcSMark Murray 210b528cefcSMark Murray k.dptr = key.data; 211b528cefcSMark Murray k.dsize = key.length; 212c19800e8SDoug Rabson code = db->hdb_lock(context, db, HDB_RLOCK); 213b528cefcSMark Murray if(code) 214b528cefcSMark Murray return code; 215b528cefcSMark Murray v = dbm_fetch(d->db, k); 216c19800e8SDoug Rabson db->hdb_unlock(context, db); 217b528cefcSMark Murray if(v.dptr == NULL) 218b528cefcSMark Murray return HDB_ERR_NOENTRY; 219b528cefcSMark Murray 220b528cefcSMark Murray krb5_data_copy(reply, v.dptr, v.dsize); 221b528cefcSMark Murray return 0; 222b528cefcSMark Murray } 223b528cefcSMark Murray 224b528cefcSMark Murray static krb5_error_code 225b528cefcSMark Murray NDBM__put(krb5_context context, HDB *db, int replace, 226b528cefcSMark Murray krb5_data key, krb5_data value) 227b528cefcSMark Murray { 228c19800e8SDoug Rabson struct ndbm_db *d = (struct ndbm_db *)db->hdb_db; 229b528cefcSMark Murray datum k, v; 230b528cefcSMark Murray int code; 231b528cefcSMark Murray 232b528cefcSMark Murray k.dptr = key.data; 233b528cefcSMark Murray k.dsize = key.length; 234b528cefcSMark Murray v.dptr = value.data; 235b528cefcSMark Murray v.dsize = value.length; 236b528cefcSMark Murray 237c19800e8SDoug Rabson code = db->hdb_lock(context, db, HDB_WLOCK); 238b528cefcSMark Murray if(code) 239b528cefcSMark Murray return code; 240b528cefcSMark Murray code = dbm_store(d->db, k, v, replace ? DBM_REPLACE : DBM_INSERT); 241c19800e8SDoug Rabson db->hdb_unlock(context, db); 242b528cefcSMark Murray if(code == 1) 243b528cefcSMark Murray return HDB_ERR_EXISTS; 244b528cefcSMark Murray if (code < 0) 245b528cefcSMark Murray return code; 246b528cefcSMark Murray return 0; 247b528cefcSMark Murray } 248b528cefcSMark Murray 249b528cefcSMark Murray static krb5_error_code 250b528cefcSMark Murray NDBM__del(krb5_context context, HDB *db, krb5_data key) 251b528cefcSMark Murray { 252c19800e8SDoug Rabson struct ndbm_db *d = (struct ndbm_db *)db->hdb_db; 253b528cefcSMark Murray datum k; 254b528cefcSMark Murray int code; 255b528cefcSMark Murray krb5_error_code ret; 256b528cefcSMark Murray 257b528cefcSMark Murray k.dptr = key.data; 258b528cefcSMark Murray k.dsize = key.length; 259c19800e8SDoug Rabson ret = db->hdb_lock(context, db, HDB_WLOCK); 260b528cefcSMark Murray if(ret) return ret; 261b528cefcSMark Murray code = dbm_delete(d->db, k); 262c19800e8SDoug Rabson db->hdb_unlock(context, db); 263b528cefcSMark Murray if(code < 0) 264b528cefcSMark Murray return errno; 265b528cefcSMark Murray return 0; 266b528cefcSMark Murray } 267b528cefcSMark Murray 268c19800e8SDoug Rabson 269c19800e8SDoug Rabson static krb5_error_code 270c19800e8SDoug Rabson NDBM_close(krb5_context context, HDB *db) 271c19800e8SDoug Rabson { 272c19800e8SDoug Rabson struct ndbm_db *d = db->hdb_db; 273c19800e8SDoug Rabson dbm_close(d->db); 274c19800e8SDoug Rabson close(d->lock_fd); 275c19800e8SDoug Rabson free(d); 276c19800e8SDoug Rabson return 0; 277c19800e8SDoug Rabson } 278c19800e8SDoug Rabson 279b528cefcSMark Murray static krb5_error_code 280b528cefcSMark Murray NDBM_open(krb5_context context, HDB *db, int flags, mode_t mode) 281b528cefcSMark Murray { 282b528cefcSMark Murray krb5_error_code ret; 283b528cefcSMark Murray struct ndbm_db *d = malloc(sizeof(*d)); 284b528cefcSMark Murray char *lock_file; 285b528cefcSMark Murray 2864137ff4cSJacques Vidrine if(d == NULL) { 2874137ff4cSJacques Vidrine krb5_set_error_string(context, "malloc: out of memory"); 288b528cefcSMark Murray return ENOMEM; 2894137ff4cSJacques Vidrine } 290c19800e8SDoug Rabson asprintf(&lock_file, "%s.lock", (char*)db->hdb_name); 291b528cefcSMark Murray if(lock_file == NULL) { 292b528cefcSMark Murray free(d); 2934137ff4cSJacques Vidrine krb5_set_error_string(context, "malloc: out of memory"); 294b528cefcSMark Murray return ENOMEM; 295b528cefcSMark Murray } 296c19800e8SDoug Rabson d->db = dbm_open((char*)db->hdb_name, flags, mode); 297b528cefcSMark Murray if(d->db == NULL){ 2984137ff4cSJacques Vidrine ret = errno; 299b528cefcSMark Murray free(d); 300b528cefcSMark Murray free(lock_file); 301c19800e8SDoug Rabson krb5_set_error_string(context, "dbm_open(%s): %s", db->hdb_name, 3024137ff4cSJacques Vidrine strerror(ret)); 3034137ff4cSJacques Vidrine return ret; 304b528cefcSMark Murray } 305b528cefcSMark Murray d->lock_fd = open(lock_file, O_RDWR | O_CREAT, 0600); 306b528cefcSMark Murray if(d->lock_fd < 0){ 3074137ff4cSJacques Vidrine ret = errno; 308b528cefcSMark Murray dbm_close(d->db); 309b528cefcSMark Murray free(d); 3104137ff4cSJacques Vidrine krb5_set_error_string(context, "open(%s): %s", lock_file, 3114137ff4cSJacques Vidrine strerror(ret)); 3124137ff4cSJacques Vidrine free(lock_file); 3134137ff4cSJacques Vidrine return ret; 314b528cefcSMark Murray } 3154137ff4cSJacques Vidrine free(lock_file); 316c19800e8SDoug Rabson db->hdb_db = d; 317b528cefcSMark Murray if((flags & O_ACCMODE) == O_RDONLY) 318b528cefcSMark Murray ret = hdb_check_db_format(context, db); 319b528cefcSMark Murray else 320b528cefcSMark Murray ret = hdb_init_db(context, db); 321b528cefcSMark Murray if(ret == HDB_ERR_NOENTRY) 322b528cefcSMark Murray return 0; 323c19800e8SDoug Rabson if (ret) { 324c19800e8SDoug Rabson NDBM_close(context, db); 325c19800e8SDoug Rabson krb5_set_error_string(context, "hdb_open: failed %s database %s", 326c19800e8SDoug Rabson (flags & O_ACCMODE) == O_RDONLY ? 327c19800e8SDoug Rabson "checking format of" : "initialize", 328c19800e8SDoug Rabson db->hdb_name); 329b528cefcSMark Murray } 330c19800e8SDoug Rabson return ret; 331b528cefcSMark Murray } 332b528cefcSMark Murray 333b528cefcSMark Murray krb5_error_code 334b528cefcSMark Murray hdb_ndbm_create(krb5_context context, HDB **db, 335b528cefcSMark Murray const char *filename) 336b528cefcSMark Murray { 337c19800e8SDoug Rabson *db = calloc(1, sizeof(**db)); 3384137ff4cSJacques Vidrine if (*db == NULL) { 3394137ff4cSJacques Vidrine krb5_set_error_string(context, "malloc: out of memory"); 340b528cefcSMark Murray return ENOMEM; 3414137ff4cSJacques Vidrine } 342b528cefcSMark Murray 343c19800e8SDoug Rabson (*db)->hdb_db = NULL; 344c19800e8SDoug Rabson (*db)->hdb_name = strdup(filename); 345c19800e8SDoug Rabson if ((*db)->hdb_name == NULL) { 3464137ff4cSJacques Vidrine krb5_set_error_string(context, "malloc: out of memory"); 3474137ff4cSJacques Vidrine free(*db); 3484137ff4cSJacques Vidrine *db = NULL; 3494137ff4cSJacques Vidrine return ENOMEM; 3504137ff4cSJacques Vidrine } 351c19800e8SDoug Rabson (*db)->hdb_master_key_set = 0; 352c19800e8SDoug Rabson (*db)->hdb_openp = 0; 353c19800e8SDoug Rabson (*db)->hdb_open = NDBM_open; 354c19800e8SDoug Rabson (*db)->hdb_close = NDBM_close; 355c19800e8SDoug Rabson (*db)->hdb_fetch = _hdb_fetch; 356c19800e8SDoug Rabson (*db)->hdb_store = _hdb_store; 357c19800e8SDoug Rabson (*db)->hdb_remove = _hdb_remove; 358c19800e8SDoug Rabson (*db)->hdb_firstkey = NDBM_firstkey; 359c19800e8SDoug Rabson (*db)->hdb_nextkey= NDBM_nextkey; 360c19800e8SDoug Rabson (*db)->hdb_lock = NDBM_lock; 361c19800e8SDoug Rabson (*db)->hdb_unlock = NDBM_unlock; 362c19800e8SDoug Rabson (*db)->hdb_rename = NDBM_rename; 363c19800e8SDoug Rabson (*db)->hdb__get = NDBM__get; 364c19800e8SDoug Rabson (*db)->hdb__put = NDBM__put; 365c19800e8SDoug Rabson (*db)->hdb__del = NDBM__del; 366c19800e8SDoug Rabson (*db)->hdb_destroy = NDBM_destroy; 367b528cefcSMark Murray return 0; 368b528cefcSMark Murray } 369b528cefcSMark Murray 3704137ff4cSJacques Vidrine #endif /* HAVE_NDBM */ 371