xref: /freebsd/crypto/heimdal/lib/hdb/db3.c (revision 5e9cd1ae3e10592ed70e7575551cba1bbab04d84)
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