db.c revision 90926
1139823Simp/*
244165Sjulian * Copyright (c) 1997 - 2001 Kungliga Tekniska H�gskolan
344165Sjulian * (Royal Institute of Technology, Stockholm, Sweden).
444165Sjulian * All rights reserved.
544165Sjulian *
644165Sjulian * Redistribution and use in source and binary forms, with or without
744165Sjulian * modification, are permitted provided that the following conditions
844165Sjulian * are met:
944165Sjulian *
1044165Sjulian * 1. Redistributions of source code must retain the above copyright
1144165Sjulian *    notice, this list of conditions and the following disclaimer.
1244165Sjulian *
1344165Sjulian * 2. Redistributions in binary form must reproduce the above copyright
1444165Sjulian *    notice, this list of conditions and the following disclaimer in the
1544165Sjulian *    documentation and/or other materials provided with the distribution.
1644165Sjulian *
1744165Sjulian * 3. Neither the name of the Institute nor the names of its contributors
1844165Sjulian *    may be used to endorse or promote products derived from this software
1944165Sjulian *    without specific prior written permission.
2044165Sjulian *
2144165Sjulian * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
2244165Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2344165Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2444165Sjulian * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
2544165Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2644165Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2744165Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2844165Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2944165Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3044165Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3144165Sjulian * SUCH DAMAGE.
3244165Sjulian */
3350477Speter
3444165Sjulian#include "hdb_locl.h"
3544165Sjulian
3644165SjulianRCSID("$Id: db.c,v 1.30 2001/08/09 08:41:48 assar Exp $");
3744165Sjulian
3844165Sjulian#if HAVE_DB1
3944165Sjulian
4044165Sjulian#if defined(HAVE_DB_185_H)
4144165Sjulian#include <db_185.h>
4244165Sjulian#elif defined(HAVE_DB_H)
4344165Sjulian#include <db.h>
4474408Smdodd#endif
4574408Smdodd
4644165Sjulianstatic krb5_error_code
4744165SjulianDB_close(krb5_context context, HDB *db)
4844165Sjulian{
49112271Smdodd    DB *d = (DB*)db->db;
50112271Smdodd    d->close(d);
5144165Sjulian    return 0;
52112271Smdodd}
5344165Sjulian
5444165Sjulianstatic krb5_error_code
5544165SjulianDB_destroy(krb5_context context, HDB *db)
5644165Sjulian{
57184710Sbz    krb5_error_code ret;
58112271Smdodd
5944165Sjulian    ret = hdb_clear_master_key (context, db);
6044165Sjulian    free(db->name);
61186119Sqingli    free(db);
6244165Sjulian    return ret;
63184710Sbz}
64112271Smdodd
65112271Smdoddstatic krb5_error_code
66112271SmdoddDB_lock(krb5_context context, HDB *db, int operation)
6744165Sjulian{
6844165Sjulian    DB *d = (DB*)db->db;
6974408Smdodd    int fd = (*d->fd)(d);
7044165Sjulian    if(fd < 0)
7144165Sjulian	return HDB_ERR_CANT_LOCK_DB;
7244165Sjulian    return hdb_lock(fd, operation);
7344165Sjulian}
7474408Smdodd
7574408Smdoddstatic krb5_error_code
7674408SmdoddDB_unlock(krb5_context context, HDB *db)
7744165Sjulian{
7874408Smdodd    DB *d = (DB*)db->db;
7974408Smdodd    int fd = (*d->fd)(d);
8074408Smdodd    if(fd < 0)
8174408Smdodd	return HDB_ERR_CANT_LOCK_DB;
8274408Smdodd    return hdb_unlock(fd);
83163606Srwatson}
84163606Srwatson
85126907Srwatson
86112277Smdoddstatic krb5_error_code
87112277SmdoddDB_seq(krb5_context context, HDB *db,
88112273Smdodd       unsigned flags, hdb_entry *entry, int flag)
89112294Smdodd{
90112273Smdodd    DB *d = (DB*)db->db;
91112276Smdodd    DBT key, value;
9274408Smdodd    krb5_data key_data, data;
93112297Smdodd    int code;
94112297Smdodd
95112297Smdodd    code = db->lock(context, db, HDB_RLOCK);
9644165Sjulian    if(code == -1)
97152296Sru	return HDB_ERR_DB_INUSE;
9844165Sjulian    code = d->seq(d, &key, &value, flag);
99112296Smdodd    db->unlock(context, db); /* XXX check value */
100111774Smdodd    if(code == -1)
10144165Sjulian	return errno;
102112296Smdodd    if(code == 1)
103112296Smdodd	return HDB_ERR_NOENTRY;
10444165Sjulian
10558313Slile    key_data.data = key.data;
10658313Slile    key_data.length = key.size;
107112297Smdodd    data.data = value.data;
108112297Smdodd    data.length = value.size;
109112297Smdodd    if (hdb_value2entry(context, &data, entry))
110112297Smdodd	return DB_seq(context, db, flags, entry, R_NEXT);
111112297Smdodd    if (db->master_key_set && (flags & HDB_F_DECRYPT)) {
112112297Smdodd	code = hdb_unseal_keys (context, db, entry);
113112297Smdodd	if (code)
114112297Smdodd	    hdb_free_entry (context, entry);
11544165Sjulian    }
11658313Slile    if (code == 0 && entry->principal == NULL) {
11744165Sjulian	entry->principal = malloc(sizeof(*entry->principal));
11844165Sjulian	if (entry->principal == NULL) {
11944165Sjulian	    krb5_set_error_string(context, "malloc: out of memory");
120152315Sru	    code = ENOMEM;
121152315Sru	    hdb_free_entry (context, entry);
122112297Smdodd	} else {
123112272Smdodd	    hdb_key2principal(context, &key_data, entry->principal);
124112272Smdodd	}
125112272Smdodd    }
126152296Sru    return code;
127112297Smdodd}
128112297Smdodd
129112297Smdodd
130112297Smdoddstatic krb5_error_code
131112297SmdoddDB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
13244165Sjulian{
13344165Sjulian    return DB_seq(context, db, flags, entry, R_FIRST);
13474408Smdodd}
13574408Smdodd
13674408Smdodd
13774408Smdoddstatic krb5_error_code
13874408SmdoddDB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
13974408Smdodd{
14074408Smdodd    return DB_seq(context, db, flags, entry, R_NEXT);
14174408Smdodd}
142112274Smdodd
14374408Smdoddstatic krb5_error_code
14474408SmdoddDB_rename(krb5_context context, HDB *db, const char *new_name)
145112274Smdodd{
14674408Smdodd    int ret;
147112274Smdodd    char *old, *new;
148112274Smdodd
14974408Smdodd    asprintf(&old, "%s.db", db->name);
15074408Smdodd    asprintf(&new, "%s.db", new_name);
15144165Sjulian    ret = rename(old, new);
152194581Srdivacky    free(old);
15344165Sjulian    free(new);
154112274Smdodd    if(ret)
155112274Smdodd	return errno;
156112274Smdodd
15744165Sjulian    free(db->name);
158112274Smdodd    db->name = strdup(new_name);
159112274Smdodd    return 0;
160112274Smdodd}
161112274Smdodd
16244165Sjulianstatic krb5_error_code
16344165SjulianDB__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply)
16444165Sjulian{
16544165Sjulian    DB *d = (DB*)db->db;
16644165Sjulian    DBT k, v;
16744165Sjulian    int code;
16844165Sjulian
16944165Sjulian    k.data = key.data;
17084931Sfjoe    k.size = key.length;
17144165Sjulian    code = db->lock(context, db, HDB_RLOCK);
17274408Smdodd    if(code)
17374408Smdodd	return code;
17474408Smdodd    code = d->get(d, &k, &v, 0);
17574408Smdodd    db->unlock(context, db);
17674408Smdodd    if(code < 0)
177120048Smdodd	return errno;
178120048Smdodd    if(code == 1)
17974408Smdodd	return HDB_ERR_NOENTRY;
180120048Smdodd
18174408Smdodd    krb5_data_copy(reply, v.data, v.size);
182120048Smdodd    return 0;
183120048Smdodd}
184152315Sru
185120048Smdoddstatic krb5_error_code
186120048SmdoddDB__put(krb5_context context, HDB *db, int replace,
187152315Sru	krb5_data key, krb5_data value)
188120048Smdodd{
189120048Smdodd    DB *d = (DB*)db->db;
190120048Smdodd    DBT k, v;
191120048Smdodd    int code;
192120048Smdodd
193120048Smdodd    k.data = key.data;
194120048Smdodd    k.size = key.length;
195120048Smdodd    v.data = value.data;
19674408Smdodd    v.size = value.length;
19744165Sjulian    code = db->lock(context, db, HDB_WLOCK);
19844165Sjulian    if(code)
19944165Sjulian	return code;
20044165Sjulian    code = d->put(d, &k, &v, replace ? 0 : R_NOOVERWRITE);
20144165Sjulian    db->unlock(context, db);
20244165Sjulian    if(code < 0)
203120047Smdodd	return errno;
20444165Sjulian    if(code == 1)
20544165Sjulian	return HDB_ERR_EXISTS;
20644165Sjulian    return 0;
207152315Sru}
20844165Sjulian
20944165Sjulianstatic krb5_error_code
21044165SjulianDB__del(krb5_context context, HDB *db, krb5_data key)
21144165Sjulian{
21244165Sjulian    DB *d = (DB*)db->db;
21344165Sjulian    DBT k;
21444165Sjulian    krb5_error_code code;
21544165Sjulian    k.data = key.data;
21658313Slile    k.size = key.length;
21744165Sjulian    code = db->lock(context, db, HDB_WLOCK);
21844165Sjulian    if(code)
21944165Sjulian	return code;
22044165Sjulian    code = d->del(d, &k, 0);
22144165Sjulian    db->unlock(context, db);
222112274Smdodd    if(code == 1)
223112274Smdodd	return HDB_ERR_NOENTRY;
224112274Smdodd    if(code < 0)
22544165Sjulian	return errno;
226112274Smdodd    return 0;
22744165Sjulian}
22844165Sjulian
22944165Sjulianstatic krb5_error_code
23044165SjulianDB_open(krb5_context context, HDB *db, int flags, mode_t mode)
23144165Sjulian{
23244165Sjulian    char *fn;
23344165Sjulian    krb5_error_code ret;
234249925Sglebius
235249925Sglebius    asprintf(&fn, "%s.db", db->name);
23644165Sjulian    if (fn == NULL) {
23774408Smdodd	krb5_set_error_string(context, "malloc: out of memory");
23887914Sjlemon	return ENOMEM;
23987914Sjlemon    }
24074408Smdodd    db->db = dbopen(fn, flags, mode, DB_BTREE, NULL);
24144627Sjulian    free(fn);
24274408Smdodd    /* try to open without .db extension */
243193891Sbz    if(db->db == NULL && errno == ENOENT)
244193891Sbz	db->db = dbopen(db->name, flags, mode, DB_BTREE, NULL);
245186119Sqingli    if(db->db == NULL) {
246193891Sbz	ret = errno;
24744165Sjulian	krb5_set_error_string(context, "dbopen (%s): %s",
248191148Skmacy			      db->name, strerror(ret));
249191148Skmacy	return ret;
250191148Skmacy    }
251112285Smdodd    if((flags & O_ACCMODE) == O_RDONLY)
252172930Srwatson	ret = hdb_check_db_format(context, db);
253112285Smdodd    else
254112285Smdodd	ret = hdb_init_db(context, db);
255112285Smdodd    if(ret == HDB_ERR_NOENTRY) {
256112285Smdodd	krb5_clear_error_string(context);
257112308Smdodd	return 0;
258112308Smdodd    }
259148887Srwatson    return ret;
260148887Srwatson}
26144165Sjulian
26274408Smdoddkrb5_error_code
26374408Smdoddhdb_db_create(krb5_context context, HDB **db,
264128636Sluigi	      const char *filename)
265128636Sluigi{
26644627Sjulian    *db = malloc(sizeof(**db));
267186119Sqingli    if (*db == NULL) {
268102291Sarchie	krb5_set_error_string(context, "malloc: out of memory");
26996184Skbyanc	return ENOMEM;
27044627Sjulian    }
27144627Sjulian
27258313Slile    (*db)->db = NULL;
27358313Slile    (*db)->name = strdup(filename);
274152315Sru    if ((*db)->name == NULL) {
275112278Smdodd	krb5_set_error_string(context, "malloc: out of memory");
27644627Sjulian	free(*db);
27758313Slile	*db = NULL;
27844627Sjulian	return ENOMEM;
27996184Skbyanc    }
28074408Smdodd    (*db)->master_key_set = 0;
28196184Skbyanc    (*db)->openp = 0;
28296184Skbyanc    (*db)->open  = DB_open;
28344627Sjulian    (*db)->close = DB_close;
28444627Sjulian    (*db)->fetch = _hdb_fetch;
28544627Sjulian    (*db)->store = _hdb_store;
28644165Sjulian    (*db)->remove = _hdb_remove;
28744165Sjulian    (*db)->firstkey = DB_firstkey;
28844165Sjulian    (*db)->nextkey= DB_nextkey;
289186119Sqingli    (*db)->lock = DB_lock;
290128636Sluigi    (*db)->unlock = DB_unlock;
291128636Sluigi    (*db)->rename = DB_rename;
29274408Smdodd    (*db)->_get = DB__get;
29374408Smdodd    (*db)->_put = DB__put;
294126951Smdodd    (*db)->_del = DB__del;
295126951Smdodd    (*db)->destroy = DB_destroy;
296126951Smdodd    return 0;
297126951Smdodd}
298126951Smdodd
299126951Smdodd#endif /* HAVE_DB1 */
300126951Smdodd