1272850Shrs/* 2272850Shrs * Copyright (c) 1997 - 2001 Kungliga Tekniska H��gskolan 3272850Shrs * (Royal Institute of Technology, Stockholm, Sweden). 4272850Shrs * All rights reserved. 5272850Shrs * 6272850Shrs * Redistribution and use in source and binary forms, with or without 7272850Shrs * modification, are permitted provided that the following conditions 8272850Shrs * are met: 9272850Shrs * 10272850Shrs * 1. Redistributions of source code must retain the above copyright 11272850Shrs * notice, this list of conditions and the following disclaimer. 12272850Shrs * 13272850Shrs * 2. Redistributions in binary form must reproduce the above copyright 14272850Shrs * notice, this list of conditions and the following disclaimer in the 15272850Shrs * documentation and/or other materials provided with the distribution. 16272850Shrs * 17272850Shrs * 3. Neither the name of the Institute nor the names of its contributors 18272850Shrs * may be used to endorse or promote products derived from this software 19272850Shrs * without specific prior written permission. 20272850Shrs * 21272850Shrs * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22272850Shrs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23272850Shrs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24272850Shrs * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25272850Shrs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26272850Shrs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27272850Shrs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28272850Shrs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29272850Shrs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301832Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311832Swollman * SUCH DAMAGE. 321832Swollman */ 331832Swollman 341832Swollman#include "hdb_locl.h" 351832Swollman 361832Swollman#if HAVE_DB1 371832Swollman 381832Swollman#if defined(HAVE_DB_185_H) 391832Swollman#include <db_185.h> 401832Swollman#elif defined(HAVE_DB_H) 41114629Sobrien#include <db.h> 42114629Sobrien#endif 431832Swollman 441832Swollmanstatic krb5_error_code 451832SwollmanDB_close(krb5_context context, HDB *db) 461832Swollman{ 471832Swollman DB *d = (DB*)db->hdb_db; 4825000Sdfr (*d->close)(d); 4925000Sdfr return 0; 5025000Sdfr} 511832Swollman 521832Swollmanstatic krb5_error_code 531832SwollmanDB_destroy(krb5_context context, HDB *db) 541832Swollman{ 551832Swollman krb5_error_code ret; 561832Swollman 571832Swollman ret = hdb_clear_master_key (context, db); 581832Swollman free(db->hdb_name); 5925000Sdfr free(db); 6025000Sdfr return ret; 6125000Sdfr} 621832Swollman 631832Swollmanstatic krb5_error_code 641832SwollmanDB_lock(krb5_context context, HDB *db, int operation) 651832Swollman{ 661832Swollman DB *d = (DB*)db->hdb_db; 671832Swollman int fd = (*d->fd)(d); 681832Swollman if(fd < 0) { 691832Swollman krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB, 701832Swollman "Can't lock database: %s", db->hdb_name); 711832Swollman return HDB_ERR_CANT_LOCK_DB; 721832Swollman } 731832Swollman return hdb_lock(fd, operation); 741832Swollman} 7525000Sdfr 761832Swollmanstatic krb5_error_code 7725000SdfrDB_unlock(krb5_context context, HDB *db) 7825000Sdfr{ 7925000Sdfr DB *d = (DB*)db->hdb_db; 8025000Sdfr int fd = (*d->fd)(d); 8125000Sdfr if(fd < 0) { 8225000Sdfr krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB, 8325000Sdfr "Can't unlock database: %s", db->hdb_name); 8425000Sdfr return HDB_ERR_CANT_LOCK_DB; 8525000Sdfr } 8625000Sdfr return hdb_unlock(fd); 8725000Sdfr} 8825000Sdfr 8925000Sdfr 9025000Sdfrstatic krb5_error_code 9125000SdfrDB_seq(krb5_context context, HDB *db, 9225000Sdfr unsigned flags, hdb_entry_ex *entry, int flag) 9325000Sdfr{ 9425000Sdfr DB *d = (DB*)db->hdb_db; 9525000Sdfr DBT key, value; 9625000Sdfr krb5_data key_data, data; 9725000Sdfr int code; 9825000Sdfr 9925000Sdfr code = db->hdb_lock(context, db, HDB_RLOCK); 10025000Sdfr if(code == -1) { 10125000Sdfr krb5_set_error_message(context, HDB_ERR_DB_INUSE, "Database %s in use", db->hdb_name); 10225000Sdfr return HDB_ERR_DB_INUSE; 10325000Sdfr } 10425000Sdfr code = (*d->seq)(d, &key, &value, flag); 10525000Sdfr db->hdb_unlock(context, db); /* XXX check value */ 1061832Swollman if(code == -1) { 1071832Swollman code = errno; 1081832Swollman krb5_set_error_message(context, code, "Database %s seq error: %s", 1091832Swollman db->hdb_name, strerror(code)); 1101832Swollman return code; 1111832Swollman } 1121832Swollman if(code == 1) { 1131832Swollman krb5_clear_error_message(context); 1141832Swollman return HDB_ERR_NOENTRY; 1151832Swollman } 1161832Swollman 1171832Swollman key_data.data = key.data; 1181832Swollman key_data.length = key.size; 1191832Swollman data.data = value.data; 1201832Swollman data.length = value.size; 1211832Swollman memset(entry, 0, sizeof(*entry)); 1221832Swollman if (hdb_value2entry(context, &data, &entry->entry)) 1231832Swollman return DB_seq(context, db, flags, entry, R_NEXT); 1241832Swollman if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { 1251832Swollman code = hdb_unseal_keys (context, db, &entry->entry); 1261832Swollman if (code) 1271832Swollman hdb_free_entry (context, entry); 1281832Swollman } 1291832Swollman if (code == 0 && entry->entry.principal == NULL) { 1301832Swollman entry->entry.principal = malloc(sizeof(*entry->entry.principal)); 1311832Swollman if (entry->entry.principal == NULL) { 1321832Swollman code = ENOMEM; 1331832Swollman krb5_set_error_message(context, code, "malloc: out of memory"); 1341832Swollman hdb_free_entry (context, entry); 1351832Swollman } else { 1361832Swollman hdb_key2principal(context, &key_data, entry->entry.principal); 1371832Swollman } 1381832Swollman } 1391832Swollman return code; 1401832Swollman} 1411832Swollman 1421832Swollman 1431832Swollmanstatic krb5_error_code 1441832SwollmanDB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) 1451832Swollman{ 1461832Swollman return DB_seq(context, db, flags, entry, R_FIRST); 14725000Sdfr} 14825000Sdfr 14925000Sdfr 15025000Sdfrstatic krb5_error_code 1511832SwollmanDB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) 1521832Swollman{ 1531832Swollman return DB_seq(context, db, flags, entry, R_NEXT); 1541832Swollman} 155229781Suqs 1561832Swollmanstatic krb5_error_code 1571832SwollmanDB_rename(krb5_context context, HDB *db, const char *new_name) 1581832Swollman{ 1591832Swollman int ret; 1601832Swollman char *old, *new; 1611832Swollman 1621832Swollman asprintf(&old, "%s.db", db->hdb_name); 1631832Swollman asprintf(&new, "%s.db", new_name); 1641832Swollman ret = rename(old, new); 1651832Swollman free(old); 1661832Swollman free(new); 1671832Swollman if(ret) 1681832Swollman return errno; 1691832Swollman 1701832Swollman free(db->hdb_name); 1711832Swollman db->hdb_name = strdup(new_name); 1721832Swollman return 0; 1731832Swollman} 1741832Swollman 1751832Swollmanstatic krb5_error_code 1761832SwollmanDB__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply) 1771832Swollman{ 1781832Swollman DB *d = (DB*)db->hdb_db; 1791832Swollman DBT k, v; 1801832Swollman int code; 1811832Swollman 1821832Swollman k.data = key.data; 1831832Swollman k.size = key.length; 1841832Swollman code = db->hdb_lock(context, db, HDB_RLOCK); 1851832Swollman if(code) 1861832Swollman return code; 1871832Swollman code = (*d->get)(d, &k, &v, 0); 1881832Swollman db->hdb_unlock(context, db); 1891832Swollman if(code < 0) { 1901832Swollman code = errno; 1911832Swollman krb5_set_error_message(context, code, "Database %s get error: %s", 1921832Swollman db->hdb_name, strerror(code)); 1931832Swollman return code; 1941832Swollman } 1951832Swollman if(code == 1) { 1961832Swollman krb5_clear_error_message(context); 1971832Swollman return HDB_ERR_NOENTRY; 1981832Swollman } 1991832Swollman 2001832Swollman krb5_data_copy(reply, v.data, v.size); 2011832Swollman return 0; 2021832Swollman} 2031832Swollman 2041832Swollmanstatic krb5_error_code 2051832SwollmanDB__put(krb5_context context, HDB *db, int replace, 20625000Sdfr krb5_data key, krb5_data value) 20725000Sdfr{ 20825000Sdfr DB *d = (DB*)db->hdb_db; 20925000Sdfr DBT k, v; 210229781Suqs int code; 21125000Sdfr 21225000Sdfr k.data = key.data; 21325000Sdfr k.size = key.length; 21425000Sdfr v.data = value.data; 21525000Sdfr v.size = value.length; 21625000Sdfr code = db->hdb_lock(context, db, HDB_WLOCK); 21725000Sdfr if(code) 21825000Sdfr return code; 21925000Sdfr code = (*d->put)(d, &k, &v, replace ? 0 : R_NOOVERWRITE); 22025000Sdfr db->hdb_unlock(context, db); 22125000Sdfr if(code < 0) { 22225000Sdfr code = errno; 22325000Sdfr krb5_set_error_message(context, code, "Database %s put error: %s", 22425000Sdfr db->hdb_name, strerror(code)); 22525000Sdfr return code; 22625000Sdfr } 22725000Sdfr if(code == 1) { 22825000Sdfr krb5_clear_error_message(context); 22925000Sdfr return HDB_ERR_EXISTS; 23025000Sdfr } 23125000Sdfr return 0; 23225000Sdfr} 23325000Sdfr 23425000Sdfrstatic krb5_error_code 23525000SdfrDB__del(krb5_context context, HDB *db, krb5_data key) 23625000Sdfr{ 23725000Sdfr DB *d = (DB*)db->hdb_db; 23825000Sdfr DBT k; 23925000Sdfr krb5_error_code code; 24025000Sdfr k.data = key.data; 24125000Sdfr k.size = key.length; 24225000Sdfr code = db->hdb_lock(context, db, HDB_WLOCK); 24325000Sdfr if(code) 24425000Sdfr return code; 24525000Sdfr code = (*d->del)(d, &k, 0); 24625000Sdfr db->hdb_unlock(context, db); 24725000Sdfr if(code == 1) { 24825000Sdfr code = errno; 24925000Sdfr krb5_set_error_message(context, code, "Database %s put error: %s", 25025000Sdfr db->hdb_name, strerror(code)); 25125000Sdfr return code; 25225000Sdfr } 25325000Sdfr if(code < 0) 25425000Sdfr return errno; 25525000Sdfr return 0; 25625000Sdfr} 25725000Sdfr 25825000Sdfrstatic krb5_error_code 2591832SwollmanDB_open(krb5_context context, HDB *db, int flags, mode_t mode) 260{ 261 char *fn; 262 krb5_error_code ret; 263 264 asprintf(&fn, "%s.db", db->hdb_name); 265 if (fn == NULL) { 266 krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 267 return ENOMEM; 268 } 269 db->hdb_db = dbopen(fn, flags, mode, DB_BTREE, NULL); 270 free(fn); 271 /* try to open without .db extension */ 272 if(db->hdb_db == NULL && errno == ENOENT) 273 db->hdb_db = dbopen(db->hdb_name, flags, mode, DB_BTREE, NULL); 274 if(db->hdb_db == NULL) { 275 ret = errno; 276 krb5_set_error_message(context, ret, "dbopen (%s): %s", 277 db->hdb_name, strerror(ret)); 278 return ret; 279 } 280 if((flags & O_ACCMODE) == O_RDONLY) 281 ret = hdb_check_db_format(context, db); 282 else 283 ret = hdb_init_db(context, db); 284 if(ret == HDB_ERR_NOENTRY) { 285 krb5_clear_error_message(context); 286 return 0; 287 } 288 if (ret) { 289 DB_close(context, db); 290 krb5_set_error_message(context, ret, "hdb_open: failed %s database %s", 291 (flags & O_ACCMODE) == O_RDONLY ? 292 "checking format of" : "initialize", 293 db->hdb_name); 294 } 295 return ret; 296} 297 298krb5_error_code 299hdb_db_create(krb5_context context, HDB **db, 300 const char *filename) 301{ 302 *db = calloc(1, sizeof(**db)); 303 if (*db == NULL) { 304 krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 305 return ENOMEM; 306 } 307 308 (*db)->hdb_db = NULL; 309 (*db)->hdb_name = strdup(filename); 310 if ((*db)->hdb_name == NULL) { 311 free(*db); 312 *db = NULL; 313 krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 314 return ENOMEM; 315 } 316 (*db)->hdb_master_key_set = 0; 317 (*db)->hdb_openp = 0; 318 (*db)->hdb_capability_flags = HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL; 319 (*db)->hdb_open = DB_open; 320 (*db)->hdb_close = DB_close; 321 (*db)->hdb_fetch_kvno = _hdb_fetch_kvno; 322 (*db)->hdb_store = _hdb_store; 323 (*db)->hdb_remove = _hdb_remove; 324 (*db)->hdb_firstkey = DB_firstkey; 325 (*db)->hdb_nextkey= DB_nextkey; 326 (*db)->hdb_lock = DB_lock; 327 (*db)->hdb_unlock = DB_unlock; 328 (*db)->hdb_rename = DB_rename; 329 (*db)->hdb__get = DB__get; 330 (*db)->hdb__put = DB__put; 331 (*db)->hdb__del = DB__del; 332 (*db)->hdb_destroy = DB_destroy; 333 return 0; 334} 335 336#endif /* HAVE_DB1 */ 337