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