1 /* 2 * Copyright (c) 1997 - 2006 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 21610 2007-07-17 07:10:45Z lha $"); 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->hdb_db; 52 DBC *dbcp = (DBC*)db->hdb_dbc; 53 54 (*dbcp->c_close)(dbcp); 55 db->hdb_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->hdb_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->hdb_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->hdb_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_ex *entry, int flag) 95 { 96 DBT key, value; 97 DBC *dbcp = db->hdb_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->hdb_lock)(context, db, HDB_RLOCK)) 104 return HDB_ERR_DB_INUSE; 105 code = (*dbcp->c_get)(dbcp, &key, &value, flag); 106 (*db->hdb_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 memset(entry, 0, sizeof(*entry)); 117 if (hdb_value2entry(context, &data, &entry->entry)) 118 return DB_seq(context, db, flags, entry, DB_NEXT); 119 if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { 120 code = hdb_unseal_keys (context, db, &entry->entry); 121 if (code) 122 hdb_free_entry (context, entry); 123 } 124 if (entry->entry.principal == NULL) { 125 entry->entry.principal = malloc(sizeof(*entry->entry.principal)); 126 if (entry->entry.principal == NULL) { 127 hdb_free_entry (context, entry); 128 krb5_set_error_string(context, "malloc: out of memory"); 129 return ENOMEM; 130 } else { 131 hdb_key2principal(context, &key_data, entry->entry.principal); 132 } 133 } 134 return 0; 135 } 136 137 138 static krb5_error_code 139 DB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) 140 { 141 return DB_seq(context, db, flags, entry, DB_FIRST); 142 } 143 144 145 static krb5_error_code 146 DB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) 147 { 148 return DB_seq(context, db, flags, entry, DB_NEXT); 149 } 150 151 static krb5_error_code 152 DB_rename(krb5_context context, HDB *db, const char *new_name) 153 { 154 int ret; 155 char *old, *new; 156 157 asprintf(&old, "%s.db", db->hdb_name); 158 asprintf(&new, "%s.db", new_name); 159 ret = rename(old, new); 160 free(old); 161 free(new); 162 if(ret) 163 return errno; 164 165 free(db->hdb_name); 166 db->hdb_name = strdup(new_name); 167 return 0; 168 } 169 170 static krb5_error_code 171 DB__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply) 172 { 173 DB *d = (DB*)db->hdb_db; 174 DBT k, v; 175 int code; 176 177 memset(&k, 0, sizeof(DBT)); 178 memset(&v, 0, sizeof(DBT)); 179 k.data = key.data; 180 k.size = key.length; 181 k.flags = 0; 182 if ((code = (*db->hdb_lock)(context, db, HDB_RLOCK))) 183 return code; 184 code = (*d->get)(d, NULL, &k, &v, 0); 185 (*db->hdb_unlock)(context, db); 186 if(code == DB_NOTFOUND) 187 return HDB_ERR_NOENTRY; 188 if(code) 189 return code; 190 191 krb5_data_copy(reply, v.data, v.size); 192 return 0; 193 } 194 195 static krb5_error_code 196 DB__put(krb5_context context, HDB *db, int replace, 197 krb5_data key, krb5_data value) 198 { 199 DB *d = (DB*)db->hdb_db; 200 DBT k, v; 201 int code; 202 203 memset(&k, 0, sizeof(DBT)); 204 memset(&v, 0, sizeof(DBT)); 205 k.data = key.data; 206 k.size = key.length; 207 k.flags = 0; 208 v.data = value.data; 209 v.size = value.length; 210 v.flags = 0; 211 if ((code = (*db->hdb_lock)(context, db, HDB_WLOCK))) 212 return code; 213 code = (*d->put)(d, NULL, &k, &v, replace ? 0 : DB_NOOVERWRITE); 214 (*db->hdb_unlock)(context, db); 215 if(code == DB_KEYEXIST) 216 return HDB_ERR_EXISTS; 217 if(code) 218 return errno; 219 return 0; 220 } 221 222 static krb5_error_code 223 DB__del(krb5_context context, HDB *db, krb5_data key) 224 { 225 DB *d = (DB*)db->hdb_db; 226 DBT k; 227 krb5_error_code code; 228 memset(&k, 0, sizeof(DBT)); 229 k.data = key.data; 230 k.size = key.length; 231 k.flags = 0; 232 code = (*db->hdb_lock)(context, db, HDB_WLOCK); 233 if(code) 234 return code; 235 code = (*d->del)(d, NULL, &k, 0); 236 (*db->hdb_unlock)(context, db); 237 if(code == DB_NOTFOUND) 238 return HDB_ERR_NOENTRY; 239 if(code) 240 return code; 241 return 0; 242 } 243 244 static krb5_error_code 245 DB_open(krb5_context context, HDB *db, int flags, mode_t mode) 246 { 247 DBC *dbc = NULL; 248 char *fn; 249 krb5_error_code ret; 250 DB *d; 251 int myflags = 0; 252 253 if (flags & O_CREAT) 254 myflags |= DB_CREATE; 255 256 if (flags & O_EXCL) 257 myflags |= DB_EXCL; 258 259 if((flags & O_ACCMODE) == O_RDONLY) 260 myflags |= DB_RDONLY; 261 262 if (flags & O_TRUNC) 263 myflags |= DB_TRUNCATE; 264 265 asprintf(&fn, "%s.db", db->hdb_name); 266 if (fn == NULL) { 267 krb5_set_error_string(context, "malloc: out of memory"); 268 return ENOMEM; 269 } 270 db_create(&d, NULL, 0); 271 db->hdb_db = d; 272 273 #if (DB_VERSION_MAJOR >= 4) && (DB_VERSION_MINOR >= 1) 274 ret = (*d->open)(db->hdb_db, NULL, fn, NULL, DB_BTREE, myflags, mode); 275 #else 276 ret = (*d->open)(db->hdb_db, fn, NULL, DB_BTREE, myflags, mode); 277 #endif 278 279 if (ret == ENOENT) { 280 /* try to open without .db extension */ 281 #if (DB_VERSION_MAJOR >= 4) && (DB_VERSION_MINOR >= 1) 282 ret = (*d->open)(db->hdb_db, NULL, db->hdb_name, NULL, DB_BTREE, 283 myflags, mode); 284 #else 285 ret = (*d->open)(db->hdb_db, db->hdb_name, NULL, DB_BTREE, 286 myflags, mode); 287 #endif 288 } 289 290 if (ret) { 291 free(fn); 292 krb5_set_error_string(context, "opening %s: %s", 293 db->hdb_name, strerror(ret)); 294 return ret; 295 } 296 free(fn); 297 298 ret = (*d->cursor)(d, NULL, &dbc, 0); 299 if (ret) { 300 krb5_set_error_string(context, "d->cursor: %s", strerror(ret)); 301 return ret; 302 } 303 db->hdb_dbc = dbc; 304 305 if((flags & O_ACCMODE) == O_RDONLY) 306 ret = hdb_check_db_format(context, db); 307 else 308 ret = hdb_init_db(context, db); 309 if(ret == HDB_ERR_NOENTRY) 310 return 0; 311 if (ret) { 312 DB_close(context, db); 313 krb5_set_error_string(context, "hdb_open: failed %s database %s", 314 (flags & O_ACCMODE) == O_RDONLY ? 315 "checking format of" : "initialize", 316 db->hdb_name); 317 } 318 319 return ret; 320 } 321 322 krb5_error_code 323 hdb_db_create(krb5_context context, HDB **db, 324 const char *filename) 325 { 326 *db = calloc(1, sizeof(**db)); 327 if (*db == NULL) { 328 krb5_set_error_string(context, "malloc: out of memory"); 329 return ENOMEM; 330 } 331 332 (*db)->hdb_db = NULL; 333 (*db)->hdb_name = strdup(filename); 334 if ((*db)->hdb_name == NULL) { 335 krb5_set_error_string(context, "malloc: out of memory"); 336 free(*db); 337 *db = NULL; 338 return ENOMEM; 339 } 340 (*db)->hdb_master_key_set = 0; 341 (*db)->hdb_openp = 0; 342 (*db)->hdb_open = DB_open; 343 (*db)->hdb_close = DB_close; 344 (*db)->hdb_fetch = _hdb_fetch; 345 (*db)->hdb_store = _hdb_store; 346 (*db)->hdb_remove = _hdb_remove; 347 (*db)->hdb_firstkey = DB_firstkey; 348 (*db)->hdb_nextkey= DB_nextkey; 349 (*db)->hdb_lock = DB_lock; 350 (*db)->hdb_unlock = DB_unlock; 351 (*db)->hdb_rename = DB_rename; 352 (*db)->hdb__get = DB__get; 353 (*db)->hdb__put = DB__put; 354 (*db)->hdb__del = DB__del; 355 (*db)->hdb_destroy = DB_destroy; 356 return 0; 357 } 358 #endif /* HAVE_DB3 */ 359