1 /* 2 * Copyright (c) 1997, 1998, 1999 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.25 1999/12/02 17:05:04 joda Exp $"); 37 38 #ifdef HAVE_DB_H 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 hdb_unseal_keys (db, entry); 107 if (entry->principal == NULL) { 108 entry->principal = malloc(sizeof(*entry->principal)); 109 hdb_key2principal(context, &key_data, entry->principal); 110 } 111 return 0; 112 } 113 114 115 static krb5_error_code 116 DB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) 117 { 118 return DB_seq(context, db, flags, entry, R_FIRST); 119 } 120 121 122 static krb5_error_code 123 DB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) 124 { 125 return DB_seq(context, db, flags, entry, R_NEXT); 126 } 127 128 static krb5_error_code 129 DB_rename(krb5_context context, HDB *db, const char *new_name) 130 { 131 int ret; 132 char *old, *new; 133 134 asprintf(&old, "%s.db", db->name); 135 asprintf(&new, "%s.db", new_name); 136 ret = rename(old, new); 137 free(old); 138 free(new); 139 if(ret) 140 return errno; 141 142 free(db->name); 143 db->name = strdup(new_name); 144 return 0; 145 } 146 147 static krb5_error_code 148 DB__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply) 149 { 150 DB *d = (DB*)db->db; 151 DBT k, v; 152 int code; 153 154 k.data = key.data; 155 k.size = key.length; 156 code = db->lock(context, db, HDB_RLOCK); 157 if(code) 158 return code; 159 code = d->get(d, &k, &v, 0); 160 db->unlock(context, db); 161 if(code < 0) 162 return errno; 163 if(code == 1) 164 return HDB_ERR_NOENTRY; 165 166 krb5_data_copy(reply, v.data, v.size); 167 return 0; 168 } 169 170 static krb5_error_code 171 DB__put(krb5_context context, HDB *db, int replace, 172 krb5_data key, krb5_data value) 173 { 174 DB *d = (DB*)db->db; 175 DBT k, v; 176 int code; 177 178 k.data = key.data; 179 k.size = key.length; 180 v.data = value.data; 181 v.size = value.length; 182 code = db->lock(context, db, HDB_WLOCK); 183 if(code) 184 return code; 185 code = d->put(d, &k, &v, replace ? 0 : R_NOOVERWRITE); 186 db->unlock(context, db); 187 if(code < 0) 188 return errno; 189 if(code == 1) 190 return HDB_ERR_EXISTS; 191 return 0; 192 } 193 194 static krb5_error_code 195 DB__del(krb5_context context, HDB *db, krb5_data key) 196 { 197 DB *d = (DB*)db->db; 198 DBT k; 199 krb5_error_code code; 200 k.data = key.data; 201 k.size = key.length; 202 code = db->lock(context, db, HDB_WLOCK); 203 if(code) 204 return code; 205 code = d->del(d, &k, 0); 206 db->unlock(context, db); 207 if(code == 1) 208 return HDB_ERR_NOENTRY; 209 if(code < 0) 210 return errno; 211 return 0; 212 } 213 214 static krb5_error_code 215 DB_open(krb5_context context, HDB *db, int flags, mode_t mode) 216 { 217 char *fn; 218 krb5_error_code ret; 219 220 asprintf(&fn, "%s.db", db->name); 221 if (fn == NULL) 222 return ENOMEM; 223 db->db = dbopen(fn, flags, mode, DB_BTREE, NULL); 224 free(fn); 225 /* try to open without .db extension */ 226 if(db->db == NULL && errno == ENOENT) 227 db->db = dbopen(db->name, flags, mode, DB_BTREE, NULL); 228 if(db->db == NULL) 229 return errno; 230 if((flags & O_ACCMODE) == O_RDONLY) 231 ret = hdb_check_db_format(context, db); 232 else 233 ret = hdb_init_db(context, db); 234 if(ret == HDB_ERR_NOENTRY) 235 return 0; 236 return ret; 237 } 238 239 krb5_error_code 240 hdb_db_create(krb5_context context, HDB **db, 241 const char *filename) 242 { 243 *db = malloc(sizeof(**db)); 244 if (*db == NULL) 245 return ENOMEM; 246 247 (*db)->db = NULL; 248 (*db)->name = strdup(filename); 249 (*db)->master_key_set = 0; 250 (*db)->openp = 0; 251 (*db)->open = DB_open; 252 (*db)->close = DB_close; 253 (*db)->fetch = _hdb_fetch; 254 (*db)->store = _hdb_store; 255 (*db)->remove = _hdb_remove; 256 (*db)->firstkey = DB_firstkey; 257 (*db)->nextkey= DB_nextkey; 258 (*db)->lock = DB_lock; 259 (*db)->unlock = DB_unlock; 260 (*db)->rename = DB_rename; 261 (*db)->_get = DB__get; 262 (*db)->_put = DB__put; 263 (*db)->_del = DB__del; 264 (*db)->destroy = DB_destroy; 265 return 0; 266 } 267 268 #endif 269