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