1 /* $NetBSD: ndbm.c,v 1.1.1.1 2011/04/13 18:14:42 elric Exp $ */ 2 3 /* 4 * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include "hdb_locl.h" 37 38 #if HAVE_NDBM 39 40 #if defined(HAVE_GDBM_NDBM_H) 41 #include <gdbm/ndbm.h> 42 #define WRITE_SUPPORT 1 43 #elif defined(HAVE_NDBM_H) 44 #include <ndbm.h> 45 #elif defined(HAVE_DBM_H) 46 #define WRITE_SUPPORT 1 47 #include <dbm.h> 48 #endif 49 50 struct ndbm_db { 51 DBM *db; 52 int lock_fd; 53 }; 54 55 static krb5_error_code 56 NDBM_destroy(krb5_context context, HDB *db) 57 { 58 hdb_clear_master_key (context, db); 59 free(db->hdb_name); 60 free(db); 61 return 0; 62 } 63 64 static krb5_error_code 65 NDBM_lock(krb5_context context, HDB *db, int operation) 66 { 67 struct ndbm_db *d = db->hdb_db; 68 return hdb_lock(d->lock_fd, operation); 69 } 70 71 static krb5_error_code 72 NDBM_unlock(krb5_context context, HDB *db) 73 { 74 struct ndbm_db *d = db->hdb_db; 75 return hdb_unlock(d->lock_fd); 76 } 77 78 static krb5_error_code 79 NDBM_seq(krb5_context context, HDB *db, 80 unsigned flags, hdb_entry_ex *entry, int first) 81 82 { 83 struct ndbm_db *d = (struct ndbm_db *)db->hdb_db; 84 datum key, value; 85 krb5_data key_data, data; 86 krb5_error_code ret = 0; 87 88 if(first) 89 key = dbm_firstkey(d->db); 90 else 91 key = dbm_nextkey(d->db); 92 if(key.dptr == NULL) 93 return HDB_ERR_NOENTRY; 94 key_data.data = key.dptr; 95 key_data.length = key.dsize; 96 ret = db->hdb_lock(context, db, HDB_RLOCK); 97 if(ret) return ret; 98 value = dbm_fetch(d->db, key); 99 db->hdb_unlock(context, db); 100 data.data = value.dptr; 101 data.length = value.dsize; 102 memset(entry, 0, sizeof(*entry)); 103 if(hdb_value2entry(context, &data, &entry->entry)) 104 return NDBM_seq(context, db, flags, entry, 0); 105 if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { 106 ret = hdb_unseal_keys (context, db, &entry->entry); 107 if (ret) 108 hdb_free_entry (context, entry); 109 } 110 if (ret == 0 && entry->entry.principal == NULL) { 111 entry->entry.principal = malloc (sizeof(*entry->entry.principal)); 112 if (entry->entry.principal == NULL) { 113 hdb_free_entry (context, entry); 114 ret = ENOMEM; 115 krb5_set_error_message(context, ret, "malloc: out of memory"); 116 } else { 117 hdb_key2principal (context, &key_data, entry->entry.principal); 118 } 119 } 120 return ret; 121 } 122 123 124 static krb5_error_code 125 NDBM_firstkey(krb5_context context, HDB *db,unsigned flags,hdb_entry_ex *entry) 126 { 127 return NDBM_seq(context, db, flags, entry, 1); 128 } 129 130 131 static krb5_error_code 132 NDBM_nextkey(krb5_context context, HDB *db, unsigned flags,hdb_entry_ex *entry) 133 { 134 return NDBM_seq(context, db, flags, entry, 0); 135 } 136 137 static krb5_error_code 138 open_lock_file(krb5_context context, const char *db_name, int *fd) 139 { 140 char *lock_file; 141 142 /* lock old and new databases */ 143 asprintf(&lock_file, "%s.lock", db_name); 144 if(lock_file == NULL) { 145 krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 146 return ENOMEM; 147 } 148 149 *fd = open(lock_file, O_RDWR | O_CREAT, 0600); 150 free(lock_file); 151 if(*fd < 0) { 152 int ret = errno; 153 krb5_set_error_message(context, ret, "open(%s): %s", lock_file, 154 strerror(ret)); 155 return ret; 156 } 157 return 0; 158 } 159 160 161 static krb5_error_code 162 NDBM_rename(krb5_context context, HDB *db, const char *new_name) 163 { 164 int ret; 165 char *old_dir, *old_pag, *new_dir, *new_pag; 166 int old_lock_fd, new_lock_fd; 167 168 /* lock old and new databases */ 169 ret = open_lock_file(context, db->hdb_name, &old_lock_fd); 170 if (ret) 171 return ret; 172 173 ret = hdb_lock(old_lock_fd, HDB_WLOCK); 174 if(ret) { 175 close(old_lock_fd); 176 return ret; 177 } 178 179 ret = open_lock_file(context, new_name, &new_lock_fd); 180 if (ret) { 181 hdb_unlock(old_lock_fd); 182 close(old_lock_fd); 183 return ret; 184 } 185 186 ret = hdb_lock(new_lock_fd, HDB_WLOCK); 187 if(ret) { 188 hdb_unlock(old_lock_fd); 189 close(old_lock_fd); 190 close(new_lock_fd); 191 return ret; 192 } 193 194 asprintf(&old_dir, "%s.dir", db->hdb_name); 195 asprintf(&old_pag, "%s.pag", db->hdb_name); 196 asprintf(&new_dir, "%s.dir", new_name); 197 asprintf(&new_pag, "%s.pag", new_name); 198 199 ret = rename(old_dir, new_dir) || rename(old_pag, new_pag); 200 if (ret) { 201 ret = errno; 202 if (ret == 0) 203 ret = EPERM; 204 krb5_set_error_message(context, ret, "rename: %s", strerror(ret)); 205 } 206 207 free(old_dir); 208 free(old_pag); 209 free(new_dir); 210 free(new_pag); 211 212 hdb_unlock(new_lock_fd); 213 hdb_unlock(old_lock_fd); 214 close(new_lock_fd); 215 close(old_lock_fd); 216 217 if(ret) 218 return ret; 219 220 free(db->hdb_name); 221 db->hdb_name = strdup(new_name); 222 return 0; 223 } 224 225 static krb5_error_code 226 NDBM__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply) 227 { 228 struct ndbm_db *d = (struct ndbm_db *)db->hdb_db; 229 datum k, v; 230 int code; 231 232 k.dptr = key.data; 233 k.dsize = key.length; 234 code = db->hdb_lock(context, db, HDB_RLOCK); 235 if(code) 236 return code; 237 v = dbm_fetch(d->db, k); 238 db->hdb_unlock(context, db); 239 if(v.dptr == NULL) 240 return HDB_ERR_NOENTRY; 241 242 krb5_data_copy(reply, v.dptr, v.dsize); 243 return 0; 244 } 245 246 static krb5_error_code 247 NDBM__put(krb5_context context, HDB *db, int replace, 248 krb5_data key, krb5_data value) 249 { 250 #ifdef WRITE_SUPPORT 251 struct ndbm_db *d = (struct ndbm_db *)db->hdb_db; 252 datum k, v; 253 int code; 254 255 k.dptr = key.data; 256 k.dsize = key.length; 257 v.dptr = value.data; 258 v.dsize = value.length; 259 260 code = db->hdb_lock(context, db, HDB_WLOCK); 261 if(code) 262 return code; 263 code = dbm_store(d->db, k, v, replace ? DBM_REPLACE : DBM_INSERT); 264 db->hdb_unlock(context, db); 265 if(code == 1) 266 return HDB_ERR_EXISTS; 267 if (code < 0) 268 return code; 269 return 0; 270 #else 271 return HDB_ERR_NO_WRITE_SUPPORT; 272 #endif 273 } 274 275 static krb5_error_code 276 NDBM__del(krb5_context context, HDB *db, krb5_data key) 277 { 278 struct ndbm_db *d = (struct ndbm_db *)db->hdb_db; 279 datum k; 280 int code; 281 krb5_error_code ret; 282 283 k.dptr = key.data; 284 k.dsize = key.length; 285 ret = db->hdb_lock(context, db, HDB_WLOCK); 286 if(ret) return ret; 287 code = dbm_delete(d->db, k); 288 db->hdb_unlock(context, db); 289 if(code < 0) 290 return errno; 291 return 0; 292 } 293 294 295 static krb5_error_code 296 NDBM_close(krb5_context context, HDB *db) 297 { 298 struct ndbm_db *d = db->hdb_db; 299 dbm_close(d->db); 300 close(d->lock_fd); 301 free(d); 302 return 0; 303 } 304 305 static krb5_error_code 306 NDBM_open(krb5_context context, HDB *db, int flags, mode_t mode) 307 { 308 krb5_error_code ret; 309 struct ndbm_db *d = malloc(sizeof(*d)); 310 311 if(d == NULL) { 312 krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 313 return ENOMEM; 314 } 315 316 d->db = dbm_open((char*)db->hdb_name, flags, mode); 317 if(d->db == NULL){ 318 ret = errno; 319 free(d); 320 krb5_set_error_message(context, ret, "dbm_open(%s): %s", db->hdb_name, 321 strerror(ret)); 322 return ret; 323 } 324 325 ret = open_lock_file(context, db->hdb_name, &d->lock_fd); 326 if (ret) { 327 ret = errno; 328 dbm_close(d->db); 329 free(d); 330 krb5_set_error_message(context, ret, "open(lock file): %s", 331 strerror(ret)); 332 return ret; 333 } 334 335 db->hdb_db = d; 336 if((flags & O_ACCMODE) == O_RDONLY) 337 ret = hdb_check_db_format(context, db); 338 else 339 ret = hdb_init_db(context, db); 340 if(ret == HDB_ERR_NOENTRY) 341 return 0; 342 if (ret) { 343 NDBM_close(context, db); 344 krb5_set_error_message(context, ret, "hdb_open: failed %s database %s", 345 (flags & O_ACCMODE) == O_RDONLY ? 346 "checking format of" : "initialize", 347 db->hdb_name); 348 } 349 return ret; 350 } 351 352 krb5_error_code 353 hdb_ndbm_create(krb5_context context, HDB **db, 354 const char *filename) 355 { 356 *db = calloc(1, sizeof(**db)); 357 if (*db == NULL) { 358 krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 359 return ENOMEM; 360 } 361 362 (*db)->hdb_db = NULL; 363 (*db)->hdb_name = strdup(filename); 364 if ((*db)->hdb_name == NULL) { 365 free(*db); 366 *db = NULL; 367 krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 368 return ENOMEM; 369 } 370 (*db)->hdb_master_key_set = 0; 371 (*db)->hdb_openp = 0; 372 (*db)->hdb_capability_flags = HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL; 373 (*db)->hdb_open = NDBM_open; 374 (*db)->hdb_close = NDBM_close; 375 (*db)->hdb_fetch_kvno = _hdb_fetch_kvno; 376 (*db)->hdb_store = _hdb_store; 377 (*db)->hdb_remove = _hdb_remove; 378 (*db)->hdb_firstkey = NDBM_firstkey; 379 (*db)->hdb_nextkey= NDBM_nextkey; 380 (*db)->hdb_lock = NDBM_lock; 381 (*db)->hdb_unlock = NDBM_unlock; 382 (*db)->hdb_rename = NDBM_rename; 383 (*db)->hdb__get = NDBM__get; 384 (*db)->hdb__put = NDBM__put; 385 (*db)->hdb__del = NDBM__del; 386 (*db)->hdb_destroy = NDBM_destroy; 387 return 0; 388 } 389 390 #endif /* HAVE_NDBM */ 391