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 #if HAVE_NDBM 37 38 #if defined(HAVE_GDBM_NDBM_H) 39 #include <gdbm/ndbm.h> 40 #define WRITE_SUPPORT 1 41 #elif defined(HAVE_NDBM_H) 42 #include <ndbm.h> 43 #elif defined(HAVE_DBM_H) 44 #define WRITE_SUPPORT 1 45 #include <dbm.h> 46 #endif 47 48 struct ndbm_db { 49 DBM *db; 50 int lock_fd; 51 }; 52 53 static krb5_error_code 54 NDBM_destroy(krb5_context context, HDB *db) 55 { 56 hdb_clear_master_key (context, db); 57 free(db->hdb_name); 58 free(db); 59 return 0; 60 } 61 62 static krb5_error_code 63 NDBM_lock(krb5_context context, HDB *db, int operation) 64 { 65 struct ndbm_db *d = db->hdb_db; 66 return hdb_lock(d->lock_fd, operation); 67 } 68 69 static krb5_error_code 70 NDBM_unlock(krb5_context context, HDB *db) 71 { 72 struct ndbm_db *d = db->hdb_db; 73 return hdb_unlock(d->lock_fd); 74 } 75 76 static krb5_error_code 77 NDBM_seq(krb5_context context, HDB *db, 78 unsigned flags, hdb_entry_ex *entry, int first) 79 80 { 81 struct ndbm_db *d = (struct ndbm_db *)db->hdb_db; 82 datum key, value; 83 krb5_data key_data, data; 84 krb5_error_code ret = 0; 85 86 if(first) 87 key = dbm_firstkey(d->db); 88 else 89 key = dbm_nextkey(d->db); 90 if(key.dptr == NULL) 91 return HDB_ERR_NOENTRY; 92 key_data.data = key.dptr; 93 key_data.length = key.dsize; 94 ret = db->hdb_lock(context, db, HDB_RLOCK); 95 if(ret) return ret; 96 value = dbm_fetch(d->db, key); 97 db->hdb_unlock(context, db); 98 data.data = value.dptr; 99 data.length = value.dsize; 100 memset(entry, 0, sizeof(*entry)); 101 if(hdb_value2entry(context, &data, &entry->entry)) 102 return NDBM_seq(context, db, flags, entry, 0); 103 if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { 104 ret = hdb_unseal_keys (context, db, &entry->entry); 105 if (ret) 106 hdb_free_entry (context, entry); 107 } 108 if (ret == 0 && entry->entry.principal == NULL) { 109 entry->entry.principal = malloc (sizeof(*entry->entry.principal)); 110 if (entry->entry.principal == NULL) { 111 hdb_free_entry (context, entry); 112 ret = ENOMEM; 113 krb5_set_error_message(context, ret, "malloc: out of memory"); 114 } else { 115 hdb_key2principal (context, &key_data, entry->entry.principal); 116 } 117 } 118 return ret; 119 } 120 121 122 static krb5_error_code 123 NDBM_firstkey(krb5_context context, HDB *db,unsigned flags,hdb_entry_ex *entry) 124 { 125 return NDBM_seq(context, db, flags, entry, 1); 126 } 127 128 129 static krb5_error_code 130 NDBM_nextkey(krb5_context context, HDB *db, unsigned flags,hdb_entry_ex *entry) 131 { 132 return NDBM_seq(context, db, flags, entry, 0); 133 } 134 135 static krb5_error_code 136 open_lock_file(krb5_context context, const char *db_name, int *fd) 137 { 138 char *lock_file; 139 140 /* lock old and new databases */ 141 asprintf(&lock_file, "%s.lock", db_name); 142 if(lock_file == NULL) { 143 krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 144 return ENOMEM; 145 } 146 147 *fd = open(lock_file, O_RDWR | O_CREAT, 0600); 148 free(lock_file); 149 if(*fd < 0) { 150 int ret = errno; 151 krb5_set_error_message(context, ret, "open(%s): %s", lock_file, 152 strerror(ret)); 153 return ret; 154 } 155 return 0; 156 } 157 158 159 static krb5_error_code 160 NDBM_rename(krb5_context context, HDB *db, const char *new_name) 161 { 162 int ret; 163 char *old_dir, *old_pag, *new_dir, *new_pag; 164 int old_lock_fd, new_lock_fd; 165 166 /* lock old and new databases */ 167 ret = open_lock_file(context, db->hdb_name, &old_lock_fd); 168 if (ret) 169 return ret; 170 171 ret = hdb_lock(old_lock_fd, HDB_WLOCK); 172 if(ret) { 173 close(old_lock_fd); 174 return ret; 175 } 176 177 ret = open_lock_file(context, new_name, &new_lock_fd); 178 if (ret) { 179 hdb_unlock(old_lock_fd); 180 close(old_lock_fd); 181 return ret; 182 } 183 184 ret = hdb_lock(new_lock_fd, HDB_WLOCK); 185 if(ret) { 186 hdb_unlock(old_lock_fd); 187 close(old_lock_fd); 188 close(new_lock_fd); 189 return ret; 190 } 191 192 asprintf(&old_dir, "%s.dir", db->hdb_name); 193 asprintf(&old_pag, "%s.pag", db->hdb_name); 194 asprintf(&new_dir, "%s.dir", new_name); 195 asprintf(&new_pag, "%s.pag", new_name); 196 197 ret = rename(old_dir, new_dir) || rename(old_pag, new_pag); 198 if (ret) { 199 ret = errno; 200 if (ret == 0) 201 ret = EPERM; 202 krb5_set_error_message(context, ret, "rename: %s", strerror(ret)); 203 } 204 205 free(old_dir); 206 free(old_pag); 207 free(new_dir); 208 free(new_pag); 209 210 hdb_unlock(new_lock_fd); 211 hdb_unlock(old_lock_fd); 212 close(new_lock_fd); 213 close(old_lock_fd); 214 215 if(ret) 216 return ret; 217 218 free(db->hdb_name); 219 db->hdb_name = strdup(new_name); 220 return 0; 221 } 222 223 static krb5_error_code 224 NDBM__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply) 225 { 226 struct ndbm_db *d = (struct ndbm_db *)db->hdb_db; 227 datum k, v; 228 int code; 229 230 k.dptr = key.data; 231 k.dsize = key.length; 232 code = db->hdb_lock(context, db, HDB_RLOCK); 233 if(code) 234 return code; 235 v = dbm_fetch(d->db, k); 236 db->hdb_unlock(context, db); 237 if(v.dptr == NULL) 238 return HDB_ERR_NOENTRY; 239 240 krb5_data_copy(reply, v.dptr, v.dsize); 241 return 0; 242 } 243 244 static krb5_error_code 245 NDBM__put(krb5_context context, HDB *db, int replace, 246 krb5_data key, krb5_data value) 247 { 248 #ifdef WRITE_SUPPORT 249 struct ndbm_db *d = (struct ndbm_db *)db->hdb_db; 250 datum k, v; 251 int code; 252 253 k.dptr = key.data; 254 k.dsize = key.length; 255 v.dptr = value.data; 256 v.dsize = value.length; 257 258 code = db->hdb_lock(context, db, HDB_WLOCK); 259 if(code) 260 return code; 261 code = dbm_store(d->db, k, v, replace ? DBM_REPLACE : DBM_INSERT); 262 db->hdb_unlock(context, db); 263 if(code == 1) 264 return HDB_ERR_EXISTS; 265 if (code < 0) 266 return code; 267 return 0; 268 #else 269 return HDB_ERR_NO_WRITE_SUPPORT; 270 #endif 271 } 272 273 static krb5_error_code 274 NDBM__del(krb5_context context, HDB *db, krb5_data key) 275 { 276 struct ndbm_db *d = (struct ndbm_db *)db->hdb_db; 277 datum k; 278 int code; 279 krb5_error_code ret; 280 281 k.dptr = key.data; 282 k.dsize = key.length; 283 ret = db->hdb_lock(context, db, HDB_WLOCK); 284 if(ret) return ret; 285 code = dbm_delete(d->db, k); 286 db->hdb_unlock(context, db); 287 if(code < 0) 288 return errno; 289 return 0; 290 } 291 292 293 static krb5_error_code 294 NDBM_close(krb5_context context, HDB *db) 295 { 296 struct ndbm_db *d = db->hdb_db; 297 dbm_close(d->db); 298 close(d->lock_fd); 299 free(d); 300 return 0; 301 } 302 303 static krb5_error_code 304 NDBM_open(krb5_context context, HDB *db, int flags, mode_t mode) 305 { 306 krb5_error_code ret; 307 struct ndbm_db *d = malloc(sizeof(*d)); 308 309 if(d == NULL) { 310 krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 311 return ENOMEM; 312 } 313 314 d->db = dbm_open((char*)db->hdb_name, flags, mode); 315 if(d->db == NULL){ 316 ret = errno; 317 free(d); 318 krb5_set_error_message(context, ret, "dbm_open(%s): %s", db->hdb_name, 319 strerror(ret)); 320 return ret; 321 } 322 323 ret = open_lock_file(context, db->hdb_name, &d->lock_fd); 324 if (ret) { 325 ret = errno; 326 dbm_close(d->db); 327 free(d); 328 krb5_set_error_message(context, ret, "open(lock file): %s", 329 strerror(ret)); 330 return ret; 331 } 332 333 db->hdb_db = d; 334 if((flags & O_ACCMODE) == O_RDONLY) 335 ret = hdb_check_db_format(context, db); 336 else 337 ret = hdb_init_db(context, db); 338 if(ret == HDB_ERR_NOENTRY) 339 return 0; 340 if (ret) { 341 NDBM_close(context, db); 342 krb5_set_error_message(context, ret, "hdb_open: failed %s database %s", 343 (flags & O_ACCMODE) == O_RDONLY ? 344 "checking format of" : "initialize", 345 db->hdb_name); 346 } 347 return ret; 348 } 349 350 krb5_error_code 351 hdb_ndbm_create(krb5_context context, HDB **db, 352 const char *filename) 353 { 354 *db = calloc(1, sizeof(**db)); 355 if (*db == NULL) { 356 krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 357 return ENOMEM; 358 } 359 360 (*db)->hdb_db = NULL; 361 (*db)->hdb_name = strdup(filename); 362 if ((*db)->hdb_name == NULL) { 363 free(*db); 364 *db = NULL; 365 krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 366 return ENOMEM; 367 } 368 (*db)->hdb_master_key_set = 0; 369 (*db)->hdb_openp = 0; 370 (*db)->hdb_capability_flags = HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL; 371 (*db)->hdb_open = NDBM_open; 372 (*db)->hdb_close = NDBM_close; 373 (*db)->hdb_fetch_kvno = _hdb_fetch_kvno; 374 (*db)->hdb_store = _hdb_store; 375 (*db)->hdb_remove = _hdb_remove; 376 (*db)->hdb_firstkey = NDBM_firstkey; 377 (*db)->hdb_nextkey= NDBM_nextkey; 378 (*db)->hdb_lock = NDBM_lock; 379 (*db)->hdb_unlock = NDBM_unlock; 380 (*db)->hdb_rename = NDBM_rename; 381 (*db)->hdb__get = NDBM__get; 382 (*db)->hdb__put = NDBM__put; 383 (*db)->hdb__del = NDBM__del; 384 (*db)->hdb_destroy = NDBM_destroy; 385 return 0; 386 } 387 388 #endif /* HAVE_NDBM */ 389