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