15e9cd1aeSAssar Westerlund /* 25e9cd1aeSAssar Westerlund * Copyright (c) 1997 - 2001 Kungliga Tekniska H�gskolan 35e9cd1aeSAssar Westerlund * (Royal Institute of Technology, Stockholm, Sweden). 45e9cd1aeSAssar Westerlund * All rights reserved. 55e9cd1aeSAssar Westerlund * 65e9cd1aeSAssar Westerlund * Redistribution and use in source and binary forms, with or without 75e9cd1aeSAssar Westerlund * modification, are permitted provided that the following conditions 85e9cd1aeSAssar Westerlund * are met: 95e9cd1aeSAssar Westerlund * 105e9cd1aeSAssar Westerlund * 1. Redistributions of source code must retain the above copyright 115e9cd1aeSAssar Westerlund * notice, this list of conditions and the following disclaimer. 125e9cd1aeSAssar Westerlund * 135e9cd1aeSAssar Westerlund * 2. Redistributions in binary form must reproduce the above copyright 145e9cd1aeSAssar Westerlund * notice, this list of conditions and the following disclaimer in the 155e9cd1aeSAssar Westerlund * documentation and/or other materials provided with the distribution. 165e9cd1aeSAssar Westerlund * 175e9cd1aeSAssar Westerlund * 3. Neither the name of the Institute nor the names of its contributors 185e9cd1aeSAssar Westerlund * may be used to endorse or promote products derived from this software 195e9cd1aeSAssar Westerlund * without specific prior written permission. 205e9cd1aeSAssar Westerlund * 215e9cd1aeSAssar Westerlund * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 225e9cd1aeSAssar Westerlund * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 235e9cd1aeSAssar Westerlund * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 245e9cd1aeSAssar Westerlund * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 255e9cd1aeSAssar Westerlund * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 265e9cd1aeSAssar Westerlund * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 275e9cd1aeSAssar Westerlund * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 285e9cd1aeSAssar Westerlund * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 295e9cd1aeSAssar Westerlund * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 305e9cd1aeSAssar Westerlund * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 315e9cd1aeSAssar Westerlund * SUCH DAMAGE. 325e9cd1aeSAssar Westerlund */ 335e9cd1aeSAssar Westerlund 345e9cd1aeSAssar Westerlund #include "hdb_locl.h" 355e9cd1aeSAssar Westerlund 365e9cd1aeSAssar Westerlund RCSID("$Id: db3.c,v 1.6 2001/01/30 01:24:00 assar Exp $"); 375e9cd1aeSAssar Westerlund 385e9cd1aeSAssar Westerlund #if defined(HAVE_DB_H) && DB_VERSION_MAJOR == 3 395e9cd1aeSAssar Westerlund static krb5_error_code 405e9cd1aeSAssar Westerlund DB_close(krb5_context context, HDB *db) 415e9cd1aeSAssar Westerlund { 425e9cd1aeSAssar Westerlund DB *d = (DB*)db->db; 435e9cd1aeSAssar Westerlund DBC *dbcp = (DBC*)db->dbc; 445e9cd1aeSAssar Westerlund 455e9cd1aeSAssar Westerlund dbcp->c_close(dbcp); 465e9cd1aeSAssar Westerlund db->dbc = 0; 475e9cd1aeSAssar Westerlund d->close(d, 0); 485e9cd1aeSAssar Westerlund return 0; 495e9cd1aeSAssar Westerlund } 505e9cd1aeSAssar Westerlund 515e9cd1aeSAssar Westerlund static krb5_error_code 525e9cd1aeSAssar Westerlund DB_destroy(krb5_context context, HDB *db) 535e9cd1aeSAssar Westerlund { 545e9cd1aeSAssar Westerlund krb5_error_code ret; 555e9cd1aeSAssar Westerlund 565e9cd1aeSAssar Westerlund ret = hdb_clear_master_key (context, db); 575e9cd1aeSAssar Westerlund free(db->name); 585e9cd1aeSAssar Westerlund free(db); 595e9cd1aeSAssar Westerlund return ret; 605e9cd1aeSAssar Westerlund } 615e9cd1aeSAssar Westerlund 625e9cd1aeSAssar Westerlund static krb5_error_code 635e9cd1aeSAssar Westerlund DB_lock(krb5_context context, HDB *db, int operation) 645e9cd1aeSAssar Westerlund { 655e9cd1aeSAssar Westerlund DB *d = (DB*)db->db; 665e9cd1aeSAssar Westerlund int fd; 675e9cd1aeSAssar Westerlund if ((*d->fd)(d, &fd)) 685e9cd1aeSAssar Westerlund return HDB_ERR_CANT_LOCK_DB; 695e9cd1aeSAssar Westerlund return hdb_lock(fd, operation); 705e9cd1aeSAssar Westerlund } 715e9cd1aeSAssar Westerlund 725e9cd1aeSAssar Westerlund static krb5_error_code 735e9cd1aeSAssar Westerlund DB_unlock(krb5_context context, HDB *db) 745e9cd1aeSAssar Westerlund { 755e9cd1aeSAssar Westerlund DB *d = (DB*)db->db; 765e9cd1aeSAssar Westerlund int fd; 775e9cd1aeSAssar Westerlund if ((*d->fd)(d, &fd)) 785e9cd1aeSAssar Westerlund return HDB_ERR_CANT_LOCK_DB; 795e9cd1aeSAssar Westerlund return hdb_unlock(fd); 805e9cd1aeSAssar Westerlund } 815e9cd1aeSAssar Westerlund 825e9cd1aeSAssar Westerlund 835e9cd1aeSAssar Westerlund static krb5_error_code 845e9cd1aeSAssar Westerlund DB_seq(krb5_context context, HDB *db, 855e9cd1aeSAssar Westerlund unsigned flags, hdb_entry *entry, int flag) 865e9cd1aeSAssar Westerlund { 875e9cd1aeSAssar Westerlund DB *d = (DB*)db->db; 885e9cd1aeSAssar Westerlund DBT key, value; 895e9cd1aeSAssar Westerlund DBC *dbcp = db->dbc; 905e9cd1aeSAssar Westerlund krb5_data key_data, data; 915e9cd1aeSAssar Westerlund int code; 925e9cd1aeSAssar Westerlund 935e9cd1aeSAssar Westerlund memset(&key, 0, sizeof(DBT)); 945e9cd1aeSAssar Westerlund memset(&value, 0, sizeof(DBT)); 955e9cd1aeSAssar Westerlund if (db->lock(context, db, HDB_RLOCK)) 965e9cd1aeSAssar Westerlund return HDB_ERR_DB_INUSE; 975e9cd1aeSAssar Westerlund code = dbcp->c_get(dbcp, &key, &value, flag); 985e9cd1aeSAssar Westerlund db->unlock(context, db); /* XXX check value */ 995e9cd1aeSAssar Westerlund if (code == DB_NOTFOUND) 1005e9cd1aeSAssar Westerlund return HDB_ERR_NOENTRY; 1015e9cd1aeSAssar Westerlund if (code) 1025e9cd1aeSAssar Westerlund return code; 1035e9cd1aeSAssar Westerlund 1045e9cd1aeSAssar Westerlund key_data.data = key.data; 1055e9cd1aeSAssar Westerlund key_data.length = key.size; 1065e9cd1aeSAssar Westerlund data.data = value.data; 1075e9cd1aeSAssar Westerlund data.length = value.size; 1085e9cd1aeSAssar Westerlund if (hdb_value2entry(context, &data, entry)) 1095e9cd1aeSAssar Westerlund return DB_seq(context, db, flags, entry, DB_NEXT); 1105e9cd1aeSAssar Westerlund if (db->master_key_set && (flags & HDB_F_DECRYPT)) { 1115e9cd1aeSAssar Westerlund code = hdb_unseal_keys (context, db, entry); 1125e9cd1aeSAssar Westerlund if (code) 1135e9cd1aeSAssar Westerlund hdb_free_entry (context, entry); 1145e9cd1aeSAssar Westerlund } 1155e9cd1aeSAssar Westerlund if (entry->principal == NULL) { 1165e9cd1aeSAssar Westerlund entry->principal = malloc(sizeof(*entry->principal)); 1175e9cd1aeSAssar Westerlund if (entry->principal == NULL) { 1185e9cd1aeSAssar Westerlund code = ENOMEM; 1195e9cd1aeSAssar Westerlund hdb_free_entry (context, entry); 1205e9cd1aeSAssar Westerlund } else { 1215e9cd1aeSAssar Westerlund hdb_key2principal(context, &key_data, entry->principal); 1225e9cd1aeSAssar Westerlund } 1235e9cd1aeSAssar Westerlund } 1245e9cd1aeSAssar Westerlund return 0; 1255e9cd1aeSAssar Westerlund } 1265e9cd1aeSAssar Westerlund 1275e9cd1aeSAssar Westerlund 1285e9cd1aeSAssar Westerlund static krb5_error_code 1295e9cd1aeSAssar Westerlund DB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) 1305e9cd1aeSAssar Westerlund { 1315e9cd1aeSAssar Westerlund return DB_seq(context, db, flags, entry, DB_FIRST); 1325e9cd1aeSAssar Westerlund } 1335e9cd1aeSAssar Westerlund 1345e9cd1aeSAssar Westerlund 1355e9cd1aeSAssar Westerlund static krb5_error_code 1365e9cd1aeSAssar Westerlund DB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) 1375e9cd1aeSAssar Westerlund { 1385e9cd1aeSAssar Westerlund return DB_seq(context, db, flags, entry, DB_NEXT); 1395e9cd1aeSAssar Westerlund } 1405e9cd1aeSAssar Westerlund 1415e9cd1aeSAssar Westerlund static krb5_error_code 1425e9cd1aeSAssar Westerlund DB_rename(krb5_context context, HDB *db, const char *new_name) 1435e9cd1aeSAssar Westerlund { 1445e9cd1aeSAssar Westerlund int ret; 1455e9cd1aeSAssar Westerlund char *old, *new; 1465e9cd1aeSAssar Westerlund 1475e9cd1aeSAssar Westerlund asprintf(&old, "%s.db", db->name); 1485e9cd1aeSAssar Westerlund asprintf(&new, "%s.db", new_name); 1495e9cd1aeSAssar Westerlund ret = rename(old, new); 1505e9cd1aeSAssar Westerlund free(old); 1515e9cd1aeSAssar Westerlund free(new); 1525e9cd1aeSAssar Westerlund if(ret) 1535e9cd1aeSAssar Westerlund return errno; 1545e9cd1aeSAssar Westerlund 1555e9cd1aeSAssar Westerlund free(db->name); 1565e9cd1aeSAssar Westerlund db->name = strdup(new_name); 1575e9cd1aeSAssar Westerlund return 0; 1585e9cd1aeSAssar Westerlund } 1595e9cd1aeSAssar Westerlund 1605e9cd1aeSAssar Westerlund static krb5_error_code 1615e9cd1aeSAssar Westerlund DB__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply) 1625e9cd1aeSAssar Westerlund { 1635e9cd1aeSAssar Westerlund DB *d = (DB*)db->db; 1645e9cd1aeSAssar Westerlund DBT k, v; 1655e9cd1aeSAssar Westerlund int code; 1665e9cd1aeSAssar Westerlund 1675e9cd1aeSAssar Westerlund memset(&k, 0, sizeof(DBT)); 1685e9cd1aeSAssar Westerlund memset(&v, 0, sizeof(DBT)); 1695e9cd1aeSAssar Westerlund k.data = key.data; 1705e9cd1aeSAssar Westerlund k.size = key.length; 1715e9cd1aeSAssar Westerlund k.flags = 0; 1725e9cd1aeSAssar Westerlund if ((code = db->lock(context, db, HDB_RLOCK))) 1735e9cd1aeSAssar Westerlund return code; 1745e9cd1aeSAssar Westerlund code = d->get(d, NULL, &k, &v, 0); 1755e9cd1aeSAssar Westerlund db->unlock(context, db); 1765e9cd1aeSAssar Westerlund if(code == DB_NOTFOUND) 1775e9cd1aeSAssar Westerlund return HDB_ERR_NOENTRY; 1785e9cd1aeSAssar Westerlund if(code) 1795e9cd1aeSAssar Westerlund return code; 1805e9cd1aeSAssar Westerlund 1815e9cd1aeSAssar Westerlund krb5_data_copy(reply, v.data, v.size); 1825e9cd1aeSAssar Westerlund return 0; 1835e9cd1aeSAssar Westerlund } 1845e9cd1aeSAssar Westerlund 1855e9cd1aeSAssar Westerlund static krb5_error_code 1865e9cd1aeSAssar Westerlund DB__put(krb5_context context, HDB *db, int replace, 1875e9cd1aeSAssar Westerlund krb5_data key, krb5_data value) 1885e9cd1aeSAssar Westerlund { 1895e9cd1aeSAssar Westerlund DB *d = (DB*)db->db; 1905e9cd1aeSAssar Westerlund DBT k, v; 1915e9cd1aeSAssar Westerlund int code; 1925e9cd1aeSAssar Westerlund 1935e9cd1aeSAssar Westerlund memset(&k, 0, sizeof(DBT)); 1945e9cd1aeSAssar Westerlund memset(&v, 0, sizeof(DBT)); 1955e9cd1aeSAssar Westerlund k.data = key.data; 1965e9cd1aeSAssar Westerlund k.size = key.length; 1975e9cd1aeSAssar Westerlund k.flags = 0; 1985e9cd1aeSAssar Westerlund v.data = value.data; 1995e9cd1aeSAssar Westerlund v.size = value.length; 2005e9cd1aeSAssar Westerlund v.flags = 0; 2015e9cd1aeSAssar Westerlund if ((code = db->lock(context, db, HDB_WLOCK))) 2025e9cd1aeSAssar Westerlund return code; 2035e9cd1aeSAssar Westerlund code = d->put(d, NULL, &k, &v, replace ? 0 : DB_NOOVERWRITE); 2045e9cd1aeSAssar Westerlund db->unlock(context, db); 2055e9cd1aeSAssar Westerlund if(code == DB_KEYEXIST) 2065e9cd1aeSAssar Westerlund return HDB_ERR_EXISTS; 2075e9cd1aeSAssar Westerlund if(code) 2085e9cd1aeSAssar Westerlund return errno; 2095e9cd1aeSAssar Westerlund return 0; 2105e9cd1aeSAssar Westerlund } 2115e9cd1aeSAssar Westerlund 2125e9cd1aeSAssar Westerlund static krb5_error_code 2135e9cd1aeSAssar Westerlund DB__del(krb5_context context, HDB *db, krb5_data key) 2145e9cd1aeSAssar Westerlund { 2155e9cd1aeSAssar Westerlund DB *d = (DB*)db->db; 2165e9cd1aeSAssar Westerlund DBT k; 2175e9cd1aeSAssar Westerlund krb5_error_code code; 2185e9cd1aeSAssar Westerlund memset(&k, 0, sizeof(DBT)); 2195e9cd1aeSAssar Westerlund k.data = key.data; 2205e9cd1aeSAssar Westerlund k.size = key.length; 2215e9cd1aeSAssar Westerlund k.flags = 0; 2225e9cd1aeSAssar Westerlund code = db->lock(context, db, HDB_WLOCK); 2235e9cd1aeSAssar Westerlund if(code) 2245e9cd1aeSAssar Westerlund return code; 2255e9cd1aeSAssar Westerlund code = d->del(d, NULL, &k, 0); 2265e9cd1aeSAssar Westerlund db->unlock(context, db); 2275e9cd1aeSAssar Westerlund if(code == DB_NOTFOUND) 2285e9cd1aeSAssar Westerlund return HDB_ERR_NOENTRY; 2295e9cd1aeSAssar Westerlund if(code) 2305e9cd1aeSAssar Westerlund return code; 2315e9cd1aeSAssar Westerlund return 0; 2325e9cd1aeSAssar Westerlund } 2335e9cd1aeSAssar Westerlund 2345e9cd1aeSAssar Westerlund static krb5_error_code 2355e9cd1aeSAssar Westerlund DB_open(krb5_context context, HDB *db, int flags, mode_t mode) 2365e9cd1aeSAssar Westerlund { 2375e9cd1aeSAssar Westerlund char *fn; 2385e9cd1aeSAssar Westerlund krb5_error_code ret; 2395e9cd1aeSAssar Westerlund DB *d; 2405e9cd1aeSAssar Westerlund int myflags = 0; 2415e9cd1aeSAssar Westerlund 2425e9cd1aeSAssar Westerlund if (flags & O_CREAT) 2435e9cd1aeSAssar Westerlund myflags |= DB_CREATE; 2445e9cd1aeSAssar Westerlund 2455e9cd1aeSAssar Westerlund if (flags & O_EXCL) 2465e9cd1aeSAssar Westerlund myflags |= DB_EXCL; 2475e9cd1aeSAssar Westerlund 2485e9cd1aeSAssar Westerlund if (flags & O_RDONLY) 2495e9cd1aeSAssar Westerlund myflags |= DB_RDONLY; 2505e9cd1aeSAssar Westerlund 2515e9cd1aeSAssar Westerlund if (flags & O_TRUNC) 2525e9cd1aeSAssar Westerlund myflags |= DB_TRUNCATE; 2535e9cd1aeSAssar Westerlund 2545e9cd1aeSAssar Westerlund asprintf(&fn, "%s.db", db->name); 2555e9cd1aeSAssar Westerlund if (fn == NULL) 2565e9cd1aeSAssar Westerlund return ENOMEM; 2575e9cd1aeSAssar Westerlund db_create(&d, NULL, 0); 2585e9cd1aeSAssar Westerlund db->db = d; 2595e9cd1aeSAssar Westerlund if ((ret = d->open(db->db, fn, NULL, DB_BTREE, myflags, mode))) { 2605e9cd1aeSAssar Westerlund if(ret == ENOENT) 2615e9cd1aeSAssar Westerlund /* try to open without .db extension */ 2625e9cd1aeSAssar Westerlund if (d->open(db->db, db->name, NULL, DB_BTREE, myflags, mode)) { 2635e9cd1aeSAssar Westerlund free(fn); 2645e9cd1aeSAssar Westerlund return ret; 2655e9cd1aeSAssar Westerlund } 2665e9cd1aeSAssar Westerlund } 2675e9cd1aeSAssar Westerlund free(fn); 2685e9cd1aeSAssar Westerlund 2695e9cd1aeSAssar Westerlund ret = d->cursor(d, NULL, (DBC **)&db->dbc, 0); 2705e9cd1aeSAssar Westerlund if (ret) 2715e9cd1aeSAssar Westerlund return ret; 2725e9cd1aeSAssar Westerlund 2735e9cd1aeSAssar Westerlund if((flags & O_ACCMODE) == O_RDONLY) 2745e9cd1aeSAssar Westerlund ret = hdb_check_db_format(context, db); 2755e9cd1aeSAssar Westerlund else 2765e9cd1aeSAssar Westerlund ret = hdb_init_db(context, db); 2775e9cd1aeSAssar Westerlund if(ret == HDB_ERR_NOENTRY) 2785e9cd1aeSAssar Westerlund return 0; 2795e9cd1aeSAssar Westerlund return ret; 2805e9cd1aeSAssar Westerlund } 2815e9cd1aeSAssar Westerlund 2825e9cd1aeSAssar Westerlund krb5_error_code 2835e9cd1aeSAssar Westerlund hdb_db_create(krb5_context context, HDB **db, 2845e9cd1aeSAssar Westerlund const char *filename) 2855e9cd1aeSAssar Westerlund { 2865e9cd1aeSAssar Westerlund *db = malloc(sizeof(**db)); 2875e9cd1aeSAssar Westerlund if (*db == NULL) 2885e9cd1aeSAssar Westerlund return ENOMEM; 2895e9cd1aeSAssar Westerlund 2905e9cd1aeSAssar Westerlund (*db)->db = NULL; 2915e9cd1aeSAssar Westerlund (*db)->name = strdup(filename); 2925e9cd1aeSAssar Westerlund (*db)->master_key_set = 0; 2935e9cd1aeSAssar Westerlund (*db)->openp = 0; 2945e9cd1aeSAssar Westerlund (*db)->open = DB_open; 2955e9cd1aeSAssar Westerlund (*db)->close = DB_close; 2965e9cd1aeSAssar Westerlund (*db)->fetch = _hdb_fetch; 2975e9cd1aeSAssar Westerlund (*db)->store = _hdb_store; 2985e9cd1aeSAssar Westerlund (*db)->remove = _hdb_remove; 2995e9cd1aeSAssar Westerlund (*db)->firstkey = DB_firstkey; 3005e9cd1aeSAssar Westerlund (*db)->nextkey= DB_nextkey; 3015e9cd1aeSAssar Westerlund (*db)->lock = DB_lock; 3025e9cd1aeSAssar Westerlund (*db)->unlock = DB_unlock; 3035e9cd1aeSAssar Westerlund (*db)->rename = DB_rename; 3045e9cd1aeSAssar Westerlund (*db)->_get = DB__get; 3055e9cd1aeSAssar Westerlund (*db)->_put = DB__put; 3065e9cd1aeSAssar Westerlund (*db)->_del = DB__del; 3075e9cd1aeSAssar Westerlund (*db)->destroy = DB_destroy; 3085e9cd1aeSAssar Westerlund return 0; 3095e9cd1aeSAssar Westerlund } 3105e9cd1aeSAssar Westerlund #endif 311