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.30 2001/08/09 08:41:48 assar Exp $"); 37 38 #if HAVE_DB1 39 40 #if defined(HAVE_DB_185_H) 41 #include <db_185.h> 42 #elif defined(HAVE_DB_H) 43 #include <db.h> 44 #endif 45 46 static krb5_error_code 47 DB_close(krb5_context context, HDB *db) 48 { 49 DB *d = (DB*)db->db; 50 d->close(d); 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 = (*d->fd)(d); 70 if(fd < 0) 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 = (*d->fd)(d); 80 if(fd < 0) 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 krb5_data key_data, data; 93 int code; 94 95 code = db->lock(context, db, HDB_RLOCK); 96 if(code == -1) 97 return HDB_ERR_DB_INUSE; 98 code = d->seq(d, &key, &value, flag); 99 db->unlock(context, db); /* XXX check value */ 100 if(code == -1) 101 return errno; 102 if(code == 1) 103 return HDB_ERR_NOENTRY; 104 105 key_data.data = key.data; 106 key_data.length = key.size; 107 data.data = value.data; 108 data.length = value.size; 109 if (hdb_value2entry(context, &data, entry)) 110 return DB_seq(context, db, flags, entry, R_NEXT); 111 if (db->master_key_set && (flags & HDB_F_DECRYPT)) { 112 code = hdb_unseal_keys (context, db, entry); 113 if (code) 114 hdb_free_entry (context, entry); 115 } 116 if (code == 0 && entry->principal == NULL) { 117 entry->principal = malloc(sizeof(*entry->principal)); 118 if (entry->principal == NULL) { 119 krb5_set_error_string(context, "malloc: out of memory"); 120 code = ENOMEM; 121 hdb_free_entry (context, entry); 122 } else { 123 hdb_key2principal(context, &key_data, entry->principal); 124 } 125 } 126 return code; 127 } 128 129 130 static krb5_error_code 131 DB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) 132 { 133 return DB_seq(context, db, flags, entry, R_FIRST); 134 } 135 136 137 static krb5_error_code 138 DB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) 139 { 140 return DB_seq(context, db, flags, entry, R_NEXT); 141 } 142 143 static krb5_error_code 144 DB_rename(krb5_context context, HDB *db, const char *new_name) 145 { 146 int ret; 147 char *old, *new; 148 149 asprintf(&old, "%s.db", db->name); 150 asprintf(&new, "%s.db", new_name); 151 ret = rename(old, new); 152 free(old); 153 free(new); 154 if(ret) 155 return errno; 156 157 free(db->name); 158 db->name = strdup(new_name); 159 return 0; 160 } 161 162 static krb5_error_code 163 DB__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply) 164 { 165 DB *d = (DB*)db->db; 166 DBT k, v; 167 int code; 168 169 k.data = key.data; 170 k.size = key.length; 171 code = db->lock(context, db, HDB_RLOCK); 172 if(code) 173 return code; 174 code = d->get(d, &k, &v, 0); 175 db->unlock(context, db); 176 if(code < 0) 177 return errno; 178 if(code == 1) 179 return HDB_ERR_NOENTRY; 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 k.data = key.data; 194 k.size = key.length; 195 v.data = value.data; 196 v.size = value.length; 197 code = db->lock(context, db, HDB_WLOCK); 198 if(code) 199 return code; 200 code = d->put(d, &k, &v, replace ? 0 : R_NOOVERWRITE); 201 db->unlock(context, db); 202 if(code < 0) 203 return errno; 204 if(code == 1) 205 return HDB_ERR_EXISTS; 206 return 0; 207 } 208 209 static krb5_error_code 210 DB__del(krb5_context context, HDB *db, krb5_data key) 211 { 212 DB *d = (DB*)db->db; 213 DBT k; 214 krb5_error_code code; 215 k.data = key.data; 216 k.size = key.length; 217 code = db->lock(context, db, HDB_WLOCK); 218 if(code) 219 return code; 220 code = d->del(d, &k, 0); 221 db->unlock(context, db); 222 if(code == 1) 223 return HDB_ERR_NOENTRY; 224 if(code < 0) 225 return errno; 226 return 0; 227 } 228 229 static krb5_error_code 230 DB_open(krb5_context context, HDB *db, int flags, mode_t mode) 231 { 232 char *fn; 233 krb5_error_code ret; 234 235 asprintf(&fn, "%s.db", db->name); 236 if (fn == NULL) { 237 krb5_set_error_string(context, "malloc: out of memory"); 238 return ENOMEM; 239 } 240 db->db = dbopen(fn, flags, mode, DB_BTREE, NULL); 241 free(fn); 242 /* try to open without .db extension */ 243 if(db->db == NULL && errno == ENOENT) 244 db->db = dbopen(db->name, flags, mode, DB_BTREE, NULL); 245 if(db->db == NULL) { 246 ret = errno; 247 krb5_set_error_string(context, "dbopen (%s): %s", 248 db->name, strerror(ret)); 249 return ret; 250 } 251 if((flags & O_ACCMODE) == O_RDONLY) 252 ret = hdb_check_db_format(context, db); 253 else 254 ret = hdb_init_db(context, db); 255 if(ret == HDB_ERR_NOENTRY) { 256 krb5_clear_error_string(context); 257 return 0; 258 } 259 return ret; 260 } 261 262 krb5_error_code 263 hdb_db_create(krb5_context context, HDB **db, 264 const char *filename) 265 { 266 *db = malloc(sizeof(**db)); 267 if (*db == NULL) { 268 krb5_set_error_string(context, "malloc: out of memory"); 269 return ENOMEM; 270 } 271 272 (*db)->db = NULL; 273 (*db)->name = strdup(filename); 274 if ((*db)->name == NULL) { 275 krb5_set_error_string(context, "malloc: out of memory"); 276 free(*db); 277 *db = NULL; 278 return ENOMEM; 279 } 280 (*db)->master_key_set = 0; 281 (*db)->openp = 0; 282 (*db)->open = DB_open; 283 (*db)->close = DB_close; 284 (*db)->fetch = _hdb_fetch; 285 (*db)->store = _hdb_store; 286 (*db)->remove = _hdb_remove; 287 (*db)->firstkey = DB_firstkey; 288 (*db)->nextkey= DB_nextkey; 289 (*db)->lock = DB_lock; 290 (*db)->unlock = DB_unlock; 291 (*db)->rename = DB_rename; 292 (*db)->_get = DB__get; 293 (*db)->_put = DB__put; 294 (*db)->_del = DB__del; 295 (*db)->destroy = DB_destroy; 296 return 0; 297 } 298 299 #endif /* HAVE_DB1 */ 300