1 /* 2 * Copyright (c) 1997 - 2001 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.30 2001/01/30 01:24:00 assar Exp $"); 37 38 #if defined(HAVE_NDBM_H) || defined(HAVE_GDBM_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 = 0; 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 ret = hdb_unseal_keys (context, db, entry); 98 if (ret) 99 hdb_free_entry (context, entry); 100 } 101 if (entry->principal == NULL) { 102 entry->principal = malloc (sizeof(*entry->principal)); 103 if (entry->principal == NULL) { 104 ret = ENOMEM; 105 hdb_free_entry (context, entry); 106 } else { 107 hdb_key2principal (context, &key_data, entry->principal); 108 } 109 } 110 return ret; 111 } 112 113 114 static krb5_error_code 115 NDBM_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) 116 { 117 return NDBM_seq(context, db, flags, entry, 1); 118 } 119 120 121 static krb5_error_code 122 NDBM_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) 123 { 124 return NDBM_seq(context, db, flags, entry, 0); 125 } 126 127 static krb5_error_code 128 NDBM_rename(krb5_context context, HDB *db, const char *new_name) 129 { 130 /* XXX this function will break */ 131 struct ndbm_db *d = db->db; 132 133 int ret; 134 char *old_dir, *old_pag, *new_dir, *new_pag; 135 char *new_lock; 136 int lock_fd; 137 138 /* lock old and new databases */ 139 ret = db->lock(context, db, HDB_WLOCK); 140 if(ret) return ret; 141 asprintf(&new_lock, "%s.lock", new_name); 142 lock_fd = open(new_lock, O_RDWR | O_CREAT, 0600); 143 free(new_lock); 144 if(lock_fd < 0) { 145 ret = errno; 146 db->unlock(context, db); 147 return ret; 148 } 149 ret = hdb_lock(lock_fd, HDB_WLOCK); 150 if(ret) { 151 db->unlock(context, db); 152 close(lock_fd); 153 return ret; 154 } 155 156 asprintf(&old_dir, "%s.dir", db->name); 157 asprintf(&old_pag, "%s.pag", db->name); 158 asprintf(&new_dir, "%s.dir", new_name); 159 asprintf(&new_pag, "%s.pag", new_name); 160 161 ret = rename(old_dir, new_dir) || rename(old_pag, new_pag); 162 free(old_dir); 163 free(old_pag); 164 free(new_dir); 165 free(new_pag); 166 hdb_unlock(lock_fd); 167 db->unlock(context, db); 168 169 if(ret) { 170 close(lock_fd); 171 return errno; 172 } 173 174 close(d->lock_fd); 175 d->lock_fd = lock_fd; 176 177 free(db->name); 178 db->name = strdup(new_name); 179 return 0; 180 } 181 182 static krb5_error_code 183 NDBM__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply) 184 { 185 struct ndbm_db *d = (struct ndbm_db *)db->db; 186 datum k, v; 187 int code; 188 189 k.dptr = key.data; 190 k.dsize = key.length; 191 code = db->lock(context, db, HDB_RLOCK); 192 if(code) 193 return code; 194 v = dbm_fetch(d->db, k); 195 db->unlock(context, db); 196 if(v.dptr == NULL) 197 return HDB_ERR_NOENTRY; 198 199 krb5_data_copy(reply, v.dptr, v.dsize); 200 return 0; 201 } 202 203 static krb5_error_code 204 NDBM__put(krb5_context context, HDB *db, int replace, 205 krb5_data key, krb5_data value) 206 { 207 struct ndbm_db *d = (struct ndbm_db *)db->db; 208 datum k, v; 209 int code; 210 211 k.dptr = key.data; 212 k.dsize = key.length; 213 v.dptr = value.data; 214 v.dsize = value.length; 215 216 code = db->lock(context, db, HDB_WLOCK); 217 if(code) 218 return code; 219 code = dbm_store(d->db, k, v, replace ? DBM_REPLACE : DBM_INSERT); 220 db->unlock(context, db); 221 if(code == 1) 222 return HDB_ERR_EXISTS; 223 if (code < 0) 224 return code; 225 return 0; 226 } 227 228 static krb5_error_code 229 NDBM__del(krb5_context context, HDB *db, krb5_data key) 230 { 231 struct ndbm_db *d = (struct ndbm_db *)db->db; 232 datum k; 233 int code; 234 krb5_error_code ret; 235 236 k.dptr = key.data; 237 k.dsize = key.length; 238 ret = db->lock(context, db, HDB_WLOCK); 239 if(ret) return ret; 240 code = dbm_delete(d->db, k); 241 db->unlock(context, db); 242 if(code < 0) 243 return errno; 244 return 0; 245 } 246 247 static krb5_error_code 248 NDBM_open(krb5_context context, HDB *db, int flags, mode_t mode) 249 { 250 krb5_error_code ret; 251 struct ndbm_db *d = malloc(sizeof(*d)); 252 char *lock_file; 253 254 if(d == NULL) 255 return ENOMEM; 256 asprintf(&lock_file, "%s.lock", (char*)db->name); 257 if(lock_file == NULL) { 258 free(d); 259 return ENOMEM; 260 } 261 d->db = dbm_open((char*)db->name, flags, mode); 262 if(d->db == NULL){ 263 free(d); 264 free(lock_file); 265 return errno; 266 } 267 d->lock_fd = open(lock_file, O_RDWR | O_CREAT, 0600); 268 free(lock_file); 269 if(d->lock_fd < 0){ 270 dbm_close(d->db); 271 free(d); 272 return errno; 273 } 274 db->db = d; 275 if((flags & O_ACCMODE) == O_RDONLY) 276 ret = hdb_check_db_format(context, db); 277 else 278 ret = hdb_init_db(context, db); 279 if(ret == HDB_ERR_NOENTRY) 280 return 0; 281 return ret; 282 } 283 284 static krb5_error_code 285 NDBM_close(krb5_context context, HDB *db) 286 { 287 struct ndbm_db *d = db->db; 288 dbm_close(d->db); 289 close(d->lock_fd); 290 free(d); 291 return 0; 292 } 293 294 krb5_error_code 295 hdb_ndbm_create(krb5_context context, HDB **db, 296 const char *filename) 297 { 298 *db = malloc(sizeof(**db)); 299 if (*db == NULL) 300 return ENOMEM; 301 302 (*db)->db = NULL; 303 (*db)->name = strdup(filename); 304 (*db)->master_key_set = 0; 305 (*db)->openp = 0; 306 (*db)->open = NDBM_open; 307 (*db)->close = NDBM_close; 308 (*db)->fetch = _hdb_fetch; 309 (*db)->store = _hdb_store; 310 (*db)->remove = _hdb_remove; 311 (*db)->firstkey = NDBM_firstkey; 312 (*db)->nextkey= NDBM_nextkey; 313 (*db)->lock = NDBM_lock; 314 (*db)->unlock = NDBM_unlock; 315 (*db)->rename = NDBM_rename; 316 (*db)->_get = NDBM__get; 317 (*db)->_put = NDBM__put; 318 (*db)->_del = NDBM__del; 319 (*db)->destroy = NDBM_destroy; 320 return 0; 321 } 322 323 #endif 324