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