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: db3.c,v 1.8.6.1 2003/08/29 16:59:39 lha Exp $"); 37 38 #if HAVE_DB3 39 40 #ifdef HAVE_DB4_DB_H 41 #include <db4/db.h> 42 #elif defined(HAVE_DB3_DB_H) 43 #include <db3/db.h> 44 #else 45 #include <db.h> 46 #endif 47 48 static krb5_error_code 49 DB_close(krb5_context context, HDB *db) 50 { 51 DB *d = (DB*)db->db; 52 DBC *dbcp = (DBC*)db->dbc; 53 54 dbcp->c_close(dbcp); 55 db->dbc = 0; 56 d->close(d, 0); 57 return 0; 58 } 59 60 static krb5_error_code 61 DB_destroy(krb5_context context, HDB *db) 62 { 63 krb5_error_code ret; 64 65 ret = hdb_clear_master_key (context, db); 66 free(db->name); 67 free(db); 68 return ret; 69 } 70 71 static krb5_error_code 72 DB_lock(krb5_context context, HDB *db, int operation) 73 { 74 DB *d = (DB*)db->db; 75 int fd; 76 if ((*d->fd)(d, &fd)) 77 return HDB_ERR_CANT_LOCK_DB; 78 return hdb_lock(fd, operation); 79 } 80 81 static krb5_error_code 82 DB_unlock(krb5_context context, HDB *db) 83 { 84 DB *d = (DB*)db->db; 85 int fd; 86 if ((*d->fd)(d, &fd)) 87 return HDB_ERR_CANT_LOCK_DB; 88 return hdb_unlock(fd); 89 } 90 91 92 static krb5_error_code 93 DB_seq(krb5_context context, HDB *db, 94 unsigned flags, hdb_entry *entry, int flag) 95 { 96 DBT key, value; 97 DBC *dbcp = db->dbc; 98 krb5_data key_data, data; 99 int code; 100 101 memset(&key, 0, sizeof(DBT)); 102 memset(&value, 0, sizeof(DBT)); 103 if (db->lock(context, db, HDB_RLOCK)) 104 return HDB_ERR_DB_INUSE; 105 code = dbcp->c_get(dbcp, &key, &value, flag); 106 db->unlock(context, db); /* XXX check value */ 107 if (code == DB_NOTFOUND) 108 return HDB_ERR_NOENTRY; 109 if (code) 110 return code; 111 112 key_data.data = key.data; 113 key_data.length = key.size; 114 data.data = value.data; 115 data.length = value.size; 116 if (hdb_value2entry(context, &data, entry)) 117 return DB_seq(context, db, flags, entry, DB_NEXT); 118 if (db->master_key_set && (flags & HDB_F_DECRYPT)) { 119 code = hdb_unseal_keys (context, db, entry); 120 if (code) 121 hdb_free_entry (context, entry); 122 } 123 if (entry->principal == NULL) { 124 entry->principal = malloc(sizeof(*entry->principal)); 125 if (entry->principal == NULL) { 126 hdb_free_entry (context, entry); 127 krb5_set_error_string(context, "malloc: out of memory"); 128 return ENOMEM; 129 } else { 130 hdb_key2principal(context, &key_data, entry->principal); 131 } 132 } 133 return 0; 134 } 135 136 137 static krb5_error_code 138 DB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) 139 { 140 return DB_seq(context, db, flags, entry, DB_FIRST); 141 } 142 143 144 static krb5_error_code 145 DB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) 146 { 147 return DB_seq(context, db, flags, entry, DB_NEXT); 148 } 149 150 static krb5_error_code 151 DB_rename(krb5_context context, HDB *db, const char *new_name) 152 { 153 int ret; 154 char *old, *new; 155 156 asprintf(&old, "%s.db", db->name); 157 asprintf(&new, "%s.db", new_name); 158 ret = rename(old, new); 159 free(old); 160 free(new); 161 if(ret) 162 return errno; 163 164 free(db->name); 165 db->name = strdup(new_name); 166 return 0; 167 } 168 169 static krb5_error_code 170 DB__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply) 171 { 172 DB *d = (DB*)db->db; 173 DBT k, v; 174 int code; 175 176 memset(&k, 0, sizeof(DBT)); 177 memset(&v, 0, sizeof(DBT)); 178 k.data = key.data; 179 k.size = key.length; 180 k.flags = 0; 181 if ((code = db->lock(context, db, HDB_RLOCK))) 182 return code; 183 code = d->get(d, NULL, &k, &v, 0); 184 db->unlock(context, db); 185 if(code == DB_NOTFOUND) 186 return HDB_ERR_NOENTRY; 187 if(code) 188 return code; 189 190 krb5_data_copy(reply, v.data, v.size); 191 return 0; 192 } 193 194 static krb5_error_code 195 DB__put(krb5_context context, HDB *db, int replace, 196 krb5_data key, krb5_data value) 197 { 198 DB *d = (DB*)db->db; 199 DBT k, v; 200 int code; 201 202 memset(&k, 0, sizeof(DBT)); 203 memset(&v, 0, sizeof(DBT)); 204 k.data = key.data; 205 k.size = key.length; 206 k.flags = 0; 207 v.data = value.data; 208 v.size = value.length; 209 v.flags = 0; 210 if ((code = db->lock(context, db, HDB_WLOCK))) 211 return code; 212 code = d->put(d, NULL, &k, &v, replace ? 0 : DB_NOOVERWRITE); 213 db->unlock(context, db); 214 if(code == DB_KEYEXIST) 215 return HDB_ERR_EXISTS; 216 if(code) 217 return errno; 218 return 0; 219 } 220 221 static krb5_error_code 222 DB__del(krb5_context context, HDB *db, krb5_data key) 223 { 224 DB *d = (DB*)db->db; 225 DBT k; 226 krb5_error_code code; 227 memset(&k, 0, sizeof(DBT)); 228 k.data = key.data; 229 k.size = key.length; 230 k.flags = 0; 231 code = db->lock(context, db, HDB_WLOCK); 232 if(code) 233 return code; 234 code = d->del(d, NULL, &k, 0); 235 db->unlock(context, db); 236 if(code == DB_NOTFOUND) 237 return HDB_ERR_NOENTRY; 238 if(code) 239 return code; 240 return 0; 241 } 242 243 static krb5_error_code 244 DB_open(krb5_context context, HDB *db, int flags, mode_t mode) 245 { 246 char *fn; 247 krb5_error_code ret; 248 DB *d; 249 int myflags = 0; 250 251 if (flags & O_CREAT) 252 myflags |= DB_CREATE; 253 254 if (flags & O_EXCL) 255 myflags |= DB_EXCL; 256 257 if (flags & O_RDONLY) 258 myflags |= DB_RDONLY; 259 260 if (flags & O_TRUNC) 261 myflags |= DB_TRUNCATE; 262 263 asprintf(&fn, "%s.db", db->name); 264 if (fn == NULL) { 265 krb5_set_error_string(context, "malloc: out of memory"); 266 return ENOMEM; 267 } 268 db_create(&d, NULL, 0); 269 db->db = d; 270 #if (DB_VERSION_MAJOR > 3) && (DB_VERSION_MINOR > 0) 271 if ((ret = d->open(db->db, NULL, fn, NULL, DB_BTREE, myflags, mode))) { 272 #else 273 if ((ret = d->open(db->db, fn, NULL, DB_BTREE, myflags, mode))) { 274 #endif 275 if(ret == ENOENT) 276 /* try to open without .db extension */ 277 #if (DB_VERSION_MAJOR > 3) && (DB_VERSION_MINOR > 0) 278 if (d->open(db->db, NULL, db->name, NULL, DB_BTREE, myflags, mode)) { 279 #else 280 if (d->open(db->db, db->name, NULL, DB_BTREE, myflags, mode)) { 281 #endif 282 free(fn); 283 krb5_set_error_string(context, "opening %s: %s", 284 db->name, strerror(ret)); 285 return ret; 286 } 287 } 288 free(fn); 289 290 ret = d->cursor(d, NULL, (DBC **)&db->dbc, 0); 291 if (ret) { 292 krb5_set_error_string(context, "d->cursor: %s", strerror(ret)); 293 return ret; 294 } 295 296 if((flags & O_ACCMODE) == O_RDONLY) 297 ret = hdb_check_db_format(context, db); 298 else 299 ret = hdb_init_db(context, db); 300 if(ret == HDB_ERR_NOENTRY) 301 return 0; 302 return ret; 303 } 304 305 krb5_error_code 306 hdb_db_create(krb5_context context, HDB **db, 307 const char *filename) 308 { 309 *db = malloc(sizeof(**db)); 310 if (*db == NULL) { 311 krb5_set_error_string(context, "malloc: out of memory"); 312 return ENOMEM; 313 } 314 315 (*db)->db = NULL; 316 (*db)->name = strdup(filename); 317 if ((*db)->name == NULL) { 318 krb5_set_error_string(context, "malloc: out of memory"); 319 free(*db); 320 *db = NULL; 321 return ENOMEM; 322 } 323 (*db)->master_key_set = 0; 324 (*db)->openp = 0; 325 (*db)->open = DB_open; 326 (*db)->close = DB_close; 327 (*db)->fetch = _hdb_fetch; 328 (*db)->store = _hdb_store; 329 (*db)->remove = _hdb_remove; 330 (*db)->firstkey = DB_firstkey; 331 (*db)->nextkey= DB_nextkey; 332 (*db)->lock = DB_lock; 333 (*db)->unlock = DB_unlock; 334 (*db)->rename = DB_rename; 335 (*db)->_get = DB__get; 336 (*db)->_put = DB__put; 337 (*db)->_del = DB__del; 338 (*db)->destroy = DB_destroy; 339 return 0; 340 } 341 #endif /* HAVE_DB3 */ 342