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 364137ff4cSJacques Vidrine RCSID("$Id: ndbm.c,v 1.33 2001/09/03 05:03:01 assar Exp $"); 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); 59b528cefcSMark Murray free(db->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 { 67b528cefcSMark Murray struct ndbm_db *d = db->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 { 74b528cefcSMark Murray struct ndbm_db *d = db->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, 80b528cefcSMark Murray unsigned flags, hdb_entry *entry, int first) 81b528cefcSMark Murray 82b528cefcSMark Murray { 83b528cefcSMark Murray struct ndbm_db *d = (struct ndbm_db *)db->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; 96b528cefcSMark Murray ret = db->lock(context, db, HDB_RLOCK); 97b528cefcSMark Murray if(ret) return ret; 98b528cefcSMark Murray value = dbm_fetch(d->db, key); 99b528cefcSMark Murray db->unlock(context, db); 100b528cefcSMark Murray data.data = value.dptr; 101b528cefcSMark Murray data.length = value.dsize; 102b528cefcSMark Murray if(hdb_value2entry(context, &data, entry)) 103b528cefcSMark Murray return NDBM_seq(context, db, flags, entry, 0); 1045e9cd1aeSAssar Westerlund if (db->master_key_set && (flags & HDB_F_DECRYPT)) { 1055e9cd1aeSAssar Westerlund ret = hdb_unseal_keys (context, db, entry); 1065e9cd1aeSAssar Westerlund if (ret) 1075e9cd1aeSAssar Westerlund hdb_free_entry (context, entry); 1085e9cd1aeSAssar Westerlund } 109b528cefcSMark Murray if (entry->principal == NULL) { 110b528cefcSMark Murray entry->principal = malloc (sizeof(*entry->principal)); 1115e9cd1aeSAssar Westerlund if (entry->principal == NULL) { 1125e9cd1aeSAssar Westerlund ret = ENOMEM; 1135e9cd1aeSAssar Westerlund hdb_free_entry (context, entry); 1144137ff4cSJacques Vidrine krb5_set_error_string(context, "malloc: out of memory"); 1155e9cd1aeSAssar Westerlund } else { 116b528cefcSMark Murray hdb_key2principal (context, &key_data, entry->principal); 117b528cefcSMark Murray } 1185e9cd1aeSAssar Westerlund } 1195e9cd1aeSAssar Westerlund return ret; 120b528cefcSMark Murray } 121b528cefcSMark Murray 122b528cefcSMark Murray 123b528cefcSMark Murray static krb5_error_code 124b528cefcSMark Murray NDBM_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) 125b528cefcSMark Murray { 126b528cefcSMark Murray return NDBM_seq(context, db, flags, entry, 1); 127b528cefcSMark Murray } 128b528cefcSMark Murray 129b528cefcSMark Murray 130b528cefcSMark Murray static krb5_error_code 131b528cefcSMark Murray NDBM_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) 132b528cefcSMark Murray { 133b528cefcSMark Murray return NDBM_seq(context, db, flags, entry, 0); 134b528cefcSMark Murray } 135b528cefcSMark Murray 136b528cefcSMark Murray static krb5_error_code 137b528cefcSMark Murray NDBM_rename(krb5_context context, HDB *db, const char *new_name) 138b528cefcSMark Murray { 139b528cefcSMark Murray /* XXX this function will break */ 140b528cefcSMark Murray struct ndbm_db *d = db->db; 141b528cefcSMark Murray 142b528cefcSMark Murray int ret; 143b528cefcSMark Murray char *old_dir, *old_pag, *new_dir, *new_pag; 144b528cefcSMark Murray char *new_lock; 145b528cefcSMark Murray int lock_fd; 146b528cefcSMark Murray 147b528cefcSMark Murray /* lock old and new databases */ 148b528cefcSMark Murray ret = db->lock(context, db, HDB_WLOCK); 1494137ff4cSJacques Vidrine if(ret) 1504137ff4cSJacques Vidrine return ret; 151b528cefcSMark Murray asprintf(&new_lock, "%s.lock", new_name); 1524137ff4cSJacques Vidrine if(new_lock == NULL) { 1534137ff4cSJacques Vidrine db->unlock(context, db); 1544137ff4cSJacques Vidrine krb5_set_error_string(context, "malloc: out of memory"); 1554137ff4cSJacques Vidrine return ENOMEM; 1564137ff4cSJacques Vidrine } 157b528cefcSMark Murray lock_fd = open(new_lock, O_RDWR | O_CREAT, 0600); 158b528cefcSMark Murray if(lock_fd < 0) { 159b528cefcSMark Murray ret = errno; 160b528cefcSMark Murray db->unlock(context, db); 1614137ff4cSJacques Vidrine krb5_set_error_string(context, "open(%s): %s", new_lock, 1624137ff4cSJacques Vidrine strerror(ret)); 1634137ff4cSJacques Vidrine free(new_lock); 164b528cefcSMark Murray return ret; 165b528cefcSMark Murray } 1664137ff4cSJacques Vidrine free(new_lock); 167b528cefcSMark Murray ret = hdb_lock(lock_fd, HDB_WLOCK); 168b528cefcSMark Murray if(ret) { 169b528cefcSMark Murray db->unlock(context, db); 170b528cefcSMark Murray close(lock_fd); 171b528cefcSMark Murray return ret; 172b528cefcSMark Murray } 173b528cefcSMark Murray 174b528cefcSMark Murray asprintf(&old_dir, "%s.dir", db->name); 175b528cefcSMark Murray asprintf(&old_pag, "%s.pag", db->name); 176b528cefcSMark Murray asprintf(&new_dir, "%s.dir", new_name); 177b528cefcSMark Murray asprintf(&new_pag, "%s.pag", new_name); 178b528cefcSMark Murray 179b528cefcSMark Murray ret = rename(old_dir, new_dir) || rename(old_pag, new_pag); 180b528cefcSMark Murray free(old_dir); 181b528cefcSMark Murray free(old_pag); 182b528cefcSMark Murray free(new_dir); 183b528cefcSMark Murray free(new_pag); 184b528cefcSMark Murray hdb_unlock(lock_fd); 185b528cefcSMark Murray db->unlock(context, db); 186b528cefcSMark Murray 187b528cefcSMark Murray if(ret) { 1884137ff4cSJacques Vidrine ret = errno; 189b528cefcSMark Murray close(lock_fd); 1904137ff4cSJacques Vidrine krb5_set_error_string(context, "rename: %s", strerror(ret)); 1914137ff4cSJacques Vidrine return ret; 192b528cefcSMark Murray } 193b528cefcSMark Murray 194b528cefcSMark Murray close(d->lock_fd); 195b528cefcSMark Murray d->lock_fd = lock_fd; 196b528cefcSMark Murray 197b528cefcSMark Murray free(db->name); 198b528cefcSMark Murray db->name = strdup(new_name); 199b528cefcSMark Murray return 0; 200b528cefcSMark Murray } 201b528cefcSMark Murray 202b528cefcSMark Murray static krb5_error_code 203b528cefcSMark Murray NDBM__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply) 204b528cefcSMark Murray { 205b528cefcSMark Murray struct ndbm_db *d = (struct ndbm_db *)db->db; 206b528cefcSMark Murray datum k, v; 207b528cefcSMark Murray int code; 208b528cefcSMark Murray 209b528cefcSMark Murray k.dptr = key.data; 210b528cefcSMark Murray k.dsize = key.length; 211b528cefcSMark Murray code = db->lock(context, db, HDB_RLOCK); 212b528cefcSMark Murray if(code) 213b528cefcSMark Murray return code; 214b528cefcSMark Murray v = dbm_fetch(d->db, k); 215b528cefcSMark Murray db->unlock(context, db); 216b528cefcSMark Murray if(v.dptr == NULL) 217b528cefcSMark Murray return HDB_ERR_NOENTRY; 218b528cefcSMark Murray 219b528cefcSMark Murray krb5_data_copy(reply, v.dptr, v.dsize); 220b528cefcSMark Murray return 0; 221b528cefcSMark Murray } 222b528cefcSMark Murray 223b528cefcSMark Murray static krb5_error_code 224b528cefcSMark Murray NDBM__put(krb5_context context, HDB *db, int replace, 225b528cefcSMark Murray krb5_data key, krb5_data value) 226b528cefcSMark Murray { 227b528cefcSMark Murray struct ndbm_db *d = (struct ndbm_db *)db->db; 228b528cefcSMark Murray datum k, v; 229b528cefcSMark Murray int code; 230b528cefcSMark Murray 231b528cefcSMark Murray k.dptr = key.data; 232b528cefcSMark Murray k.dsize = key.length; 233b528cefcSMark Murray v.dptr = value.data; 234b528cefcSMark Murray v.dsize = value.length; 235b528cefcSMark Murray 236b528cefcSMark Murray code = db->lock(context, db, HDB_WLOCK); 237b528cefcSMark Murray if(code) 238b528cefcSMark Murray return code; 239b528cefcSMark Murray code = dbm_store(d->db, k, v, replace ? DBM_REPLACE : DBM_INSERT); 240b528cefcSMark Murray db->unlock(context, db); 241b528cefcSMark Murray if(code == 1) 242b528cefcSMark Murray return HDB_ERR_EXISTS; 243b528cefcSMark Murray if (code < 0) 244b528cefcSMark Murray return code; 245b528cefcSMark Murray return 0; 246b528cefcSMark Murray } 247b528cefcSMark Murray 248b528cefcSMark Murray static krb5_error_code 249b528cefcSMark Murray NDBM__del(krb5_context context, HDB *db, krb5_data key) 250b528cefcSMark Murray { 251b528cefcSMark Murray struct ndbm_db *d = (struct ndbm_db *)db->db; 252b528cefcSMark Murray datum k; 253b528cefcSMark Murray int code; 254b528cefcSMark Murray krb5_error_code ret; 255b528cefcSMark Murray 256b528cefcSMark Murray k.dptr = key.data; 257b528cefcSMark Murray k.dsize = key.length; 258b528cefcSMark Murray ret = db->lock(context, db, HDB_WLOCK); 259b528cefcSMark Murray if(ret) return ret; 260b528cefcSMark Murray code = dbm_delete(d->db, k); 261b528cefcSMark Murray db->unlock(context, db); 262b528cefcSMark Murray if(code < 0) 263b528cefcSMark Murray return errno; 264b528cefcSMark Murray return 0; 265b528cefcSMark Murray } 266b528cefcSMark Murray 267b528cefcSMark Murray static krb5_error_code 268b528cefcSMark Murray NDBM_open(krb5_context context, HDB *db, int flags, mode_t mode) 269b528cefcSMark Murray { 270b528cefcSMark Murray krb5_error_code ret; 271b528cefcSMark Murray struct ndbm_db *d = malloc(sizeof(*d)); 272b528cefcSMark Murray char *lock_file; 273b528cefcSMark Murray 2744137ff4cSJacques Vidrine if(d == NULL) { 2754137ff4cSJacques Vidrine krb5_set_error_string(context, "malloc: out of memory"); 276b528cefcSMark Murray return ENOMEM; 2774137ff4cSJacques Vidrine } 278b528cefcSMark Murray asprintf(&lock_file, "%s.lock", (char*)db->name); 279b528cefcSMark Murray if(lock_file == NULL) { 280b528cefcSMark Murray free(d); 2814137ff4cSJacques Vidrine krb5_set_error_string(context, "malloc: out of memory"); 282b528cefcSMark Murray return ENOMEM; 283b528cefcSMark Murray } 284b528cefcSMark Murray d->db = dbm_open((char*)db->name, flags, mode); 285b528cefcSMark Murray if(d->db == NULL){ 2864137ff4cSJacques Vidrine ret = errno; 287b528cefcSMark Murray free(d); 288b528cefcSMark Murray free(lock_file); 2894137ff4cSJacques Vidrine krb5_set_error_string(context, "dbm_open(%s): %s", db->name, 2904137ff4cSJacques Vidrine strerror(ret)); 2914137ff4cSJacques Vidrine return ret; 292b528cefcSMark Murray } 293b528cefcSMark Murray d->lock_fd = open(lock_file, O_RDWR | O_CREAT, 0600); 294b528cefcSMark Murray if(d->lock_fd < 0){ 2954137ff4cSJacques Vidrine ret = errno; 296b528cefcSMark Murray dbm_close(d->db); 297b528cefcSMark Murray free(d); 2984137ff4cSJacques Vidrine krb5_set_error_string(context, "open(%s): %s", lock_file, 2994137ff4cSJacques Vidrine strerror(ret)); 3004137ff4cSJacques Vidrine free(lock_file); 3014137ff4cSJacques Vidrine return ret; 302b528cefcSMark Murray } 3034137ff4cSJacques Vidrine free(lock_file); 304b528cefcSMark Murray db->db = d; 305b528cefcSMark Murray if((flags & O_ACCMODE) == O_RDONLY) 306b528cefcSMark Murray ret = hdb_check_db_format(context, db); 307b528cefcSMark Murray else 308b528cefcSMark Murray ret = hdb_init_db(context, db); 309b528cefcSMark Murray if(ret == HDB_ERR_NOENTRY) 310b528cefcSMark Murray return 0; 311b528cefcSMark Murray return ret; 312b528cefcSMark Murray } 313b528cefcSMark Murray 314b528cefcSMark Murray static krb5_error_code 315b528cefcSMark Murray NDBM_close(krb5_context context, HDB *db) 316b528cefcSMark Murray { 317b528cefcSMark Murray struct ndbm_db *d = db->db; 318b528cefcSMark Murray dbm_close(d->db); 319b528cefcSMark Murray close(d->lock_fd); 320b528cefcSMark Murray free(d); 321b528cefcSMark Murray return 0; 322b528cefcSMark Murray } 323b528cefcSMark Murray 324b528cefcSMark Murray krb5_error_code 325b528cefcSMark Murray hdb_ndbm_create(krb5_context context, HDB **db, 326b528cefcSMark Murray const char *filename) 327b528cefcSMark Murray { 328b528cefcSMark Murray *db = malloc(sizeof(**db)); 3294137ff4cSJacques Vidrine if (*db == NULL) { 3304137ff4cSJacques Vidrine krb5_set_error_string(context, "malloc: out of memory"); 331b528cefcSMark Murray return ENOMEM; 3324137ff4cSJacques Vidrine } 333b528cefcSMark Murray 334b528cefcSMark Murray (*db)->db = NULL; 335b528cefcSMark Murray (*db)->name = strdup(filename); 3364137ff4cSJacques Vidrine if ((*db)->name == NULL) { 3374137ff4cSJacques Vidrine krb5_set_error_string(context, "malloc: out of memory"); 3384137ff4cSJacques Vidrine free(*db); 3394137ff4cSJacques Vidrine *db = NULL; 3404137ff4cSJacques Vidrine return ENOMEM; 3414137ff4cSJacques Vidrine } 342b528cefcSMark Murray (*db)->master_key_set = 0; 343b528cefcSMark Murray (*db)->openp = 0; 344b528cefcSMark Murray (*db)->open = NDBM_open; 345b528cefcSMark Murray (*db)->close = NDBM_close; 346b528cefcSMark Murray (*db)->fetch = _hdb_fetch; 347b528cefcSMark Murray (*db)->store = _hdb_store; 348b528cefcSMark Murray (*db)->remove = _hdb_remove; 349b528cefcSMark Murray (*db)->firstkey = NDBM_firstkey; 350b528cefcSMark Murray (*db)->nextkey= NDBM_nextkey; 351b528cefcSMark Murray (*db)->lock = NDBM_lock; 352b528cefcSMark Murray (*db)->unlock = NDBM_unlock; 353b528cefcSMark Murray (*db)->rename = NDBM_rename; 354b528cefcSMark Murray (*db)->_get = NDBM__get; 355b528cefcSMark Murray (*db)->_put = NDBM__put; 356b528cefcSMark Murray (*db)->_del = NDBM__del; 357b528cefcSMark Murray (*db)->destroy = NDBM_destroy; 358b528cefcSMark Murray return 0; 359b528cefcSMark Murray } 360b528cefcSMark Murray 3614137ff4cSJacques Vidrine #endif /* HAVE_NDBM */ 362