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