1 /* 2 * Copyright (c) 1997, 1998, 1999 Kungliga Tekniska H�gskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include "hdb_locl.h" 35 36 RCSID("$Id: ndbm.c,v 1.26 1999/12/02 17:05:05 joda Exp $"); 37 38 #ifdef HAVE_NDBM_H 39 40 struct ndbm_db { 41 DBM *db; 42 int lock_fd; 43 }; 44 45 static krb5_error_code 46 NDBM_destroy(krb5_context context, HDB *db) 47 { 48 krb5_error_code ret; 49 50 ret = hdb_clear_master_key (context, db); 51 free(db->name); 52 free(db); 53 return 0; 54 } 55 56 static krb5_error_code 57 NDBM_lock(krb5_context context, HDB *db, int operation) 58 { 59 struct ndbm_db *d = db->db; 60 return hdb_lock(d->lock_fd, operation); 61 } 62 63 static krb5_error_code 64 NDBM_unlock(krb5_context context, HDB *db) 65 { 66 struct ndbm_db *d = db->db; 67 return hdb_unlock(d->lock_fd); 68 } 69 70 static krb5_error_code 71 NDBM_seq(krb5_context context, HDB *db, 72 unsigned flags, hdb_entry *entry, int first) 73 74 { 75 struct ndbm_db *d = (struct ndbm_db *)db->db; 76 datum key, value; 77 krb5_data key_data, data; 78 krb5_error_code ret; 79 80 if(first) 81 key = dbm_firstkey(d->db); 82 else 83 key = dbm_nextkey(d->db); 84 if(key.dptr == NULL) 85 return HDB_ERR_NOENTRY; 86 key_data.data = key.dptr; 87 key_data.length = key.dsize; 88 ret = db->lock(context, db, HDB_RLOCK); 89 if(ret) return ret; 90 value = dbm_fetch(d->db, key); 91 db->unlock(context, db); 92 data.data = value.dptr; 93 data.length = value.dsize; 94 if(hdb_value2entry(context, &data, entry)) 95 return NDBM_seq(context, db, flags, entry, 0); 96 if (db->master_key_set && (flags & HDB_F_DECRYPT)) 97 hdb_unseal_keys (db, entry); 98 if (entry->principal == NULL) { 99 entry->principal = malloc (sizeof(*entry->principal)); 100 hdb_key2principal (context, &key_data, entry->principal); 101 } 102 return 0; 103 } 104 105 106 static krb5_error_code 107 NDBM_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) 108 { 109 return NDBM_seq(context, db, flags, entry, 1); 110 } 111 112 113 static krb5_error_code 114 NDBM_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) 115 { 116 return NDBM_seq(context, db, flags, entry, 0); 117 } 118 119 static krb5_error_code 120 NDBM_rename(krb5_context context, HDB *db, const char *new_name) 121 { 122 /* XXX this function will break */ 123 struct ndbm_db *d = db->db; 124 125 int ret; 126 char *old_dir, *old_pag, *new_dir, *new_pag; 127 char *new_lock; 128 int lock_fd; 129 130 /* lock old and new databases */ 131 ret = db->lock(context, db, HDB_WLOCK); 132 if(ret) return ret; 133 asprintf(&new_lock, "%s.lock", new_name); 134 lock_fd = open(new_lock, O_RDWR | O_CREAT, 0600); 135 free(new_lock); 136 if(lock_fd < 0) { 137 ret = errno; 138 db->unlock(context, db); 139 return ret; 140 } 141 ret = hdb_lock(lock_fd, HDB_WLOCK); 142 if(ret) { 143 db->unlock(context, db); 144 close(lock_fd); 145 return ret; 146 } 147 148 asprintf(&old_dir, "%s.dir", db->name); 149 asprintf(&old_pag, "%s.pag", db->name); 150 asprintf(&new_dir, "%s.dir", new_name); 151 asprintf(&new_pag, "%s.pag", new_name); 152 153 ret = rename(old_dir, new_dir) || rename(old_pag, new_pag); 154 free(old_dir); 155 free(old_pag); 156 free(new_dir); 157 free(new_pag); 158 hdb_unlock(lock_fd); 159 db->unlock(context, db); 160 161 if(ret) { 162 close(lock_fd); 163 return errno; 164 } 165 166 close(d->lock_fd); 167 d->lock_fd = lock_fd; 168 169 free(db->name); 170 db->name = strdup(new_name); 171 return 0; 172 } 173 174 static krb5_error_code 175 NDBM__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply) 176 { 177 struct ndbm_db *d = (struct ndbm_db *)db->db; 178 datum k, v; 179 int code; 180 181 k.dptr = key.data; 182 k.dsize = key.length; 183 code = db->lock(context, db, HDB_RLOCK); 184 if(code) 185 return code; 186 v = dbm_fetch(d->db, k); 187 db->unlock(context, db); 188 if(v.dptr == NULL) 189 return HDB_ERR_NOENTRY; 190 191 krb5_data_copy(reply, v.dptr, v.dsize); 192 return 0; 193 } 194 195 static krb5_error_code 196 NDBM__put(krb5_context context, HDB *db, int replace, 197 krb5_data key, krb5_data value) 198 { 199 struct ndbm_db *d = (struct ndbm_db *)db->db; 200 datum k, v; 201 int code; 202 203 k.dptr = key.data; 204 k.dsize = key.length; 205 v.dptr = value.data; 206 v.dsize = value.length; 207 208 code = db->lock(context, db, HDB_WLOCK); 209 if(code) 210 return code; 211 code = dbm_store(d->db, k, v, replace ? DBM_REPLACE : DBM_INSERT); 212 db->unlock(context, db); 213 if(code == 1) 214 return HDB_ERR_EXISTS; 215 if (code < 0) 216 return code; 217 return 0; 218 } 219 220 static krb5_error_code 221 NDBM__del(krb5_context context, HDB *db, krb5_data key) 222 { 223 struct ndbm_db *d = (struct ndbm_db *)db->db; 224 datum k; 225 int code; 226 krb5_error_code ret; 227 228 k.dptr = key.data; 229 k.dsize = key.length; 230 ret = db->lock(context, db, HDB_WLOCK); 231 if(ret) return ret; 232 code = dbm_delete(d->db, k); 233 db->unlock(context, db); 234 if(code < 0) 235 return errno; 236 return 0; 237 } 238 239 static krb5_error_code 240 NDBM_open(krb5_context context, HDB *db, int flags, mode_t mode) 241 { 242 krb5_error_code ret; 243 struct ndbm_db *d = malloc(sizeof(*d)); 244 char *lock_file; 245 246 if(d == NULL) 247 return ENOMEM; 248 asprintf(&lock_file, "%s.lock", (char*)db->name); 249 if(lock_file == NULL) { 250 free(d); 251 return ENOMEM; 252 } 253 d->db = dbm_open((char*)db->name, flags, mode); 254 if(d->db == NULL){ 255 free(d); 256 free(lock_file); 257 return errno; 258 } 259 d->lock_fd = open(lock_file, O_RDWR | O_CREAT, 0600); 260 free(lock_file); 261 if(d->lock_fd < 0){ 262 dbm_close(d->db); 263 free(d); 264 return errno; 265 } 266 db->db = d; 267 if((flags & O_ACCMODE) == O_RDONLY) 268 ret = hdb_check_db_format(context, db); 269 else 270 ret = hdb_init_db(context, db); 271 if(ret == HDB_ERR_NOENTRY) 272 return 0; 273 return ret; 274 } 275 276 static krb5_error_code 277 NDBM_close(krb5_context context, HDB *db) 278 { 279 struct ndbm_db *d = db->db; 280 dbm_close(d->db); 281 close(d->lock_fd); 282 free(d); 283 return 0; 284 } 285 286 krb5_error_code 287 hdb_ndbm_create(krb5_context context, HDB **db, 288 const char *filename) 289 { 290 *db = malloc(sizeof(**db)); 291 if (*db == NULL) 292 return ENOMEM; 293 294 (*db)->db = NULL; 295 (*db)->name = strdup(filename); 296 (*db)->master_key_set = 0; 297 (*db)->openp = 0; 298 (*db)->open = NDBM_open; 299 (*db)->close = NDBM_close; 300 (*db)->fetch = _hdb_fetch; 301 (*db)->store = _hdb_store; 302 (*db)->remove = _hdb_remove; 303 (*db)->firstkey = NDBM_firstkey; 304 (*db)->nextkey= NDBM_nextkey; 305 (*db)->lock = NDBM_lock; 306 (*db)->unlock = NDBM_unlock; 307 (*db)->rename = NDBM_rename; 308 (*db)->_get = NDBM__get; 309 (*db)->_put = NDBM__put; 310 (*db)->_del = NDBM__del; 311 (*db)->destroy = NDBM_destroy; 312 return 0; 313 } 314 315 316 #endif 317