db.c revision 55682
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
36RCSID("$Id: db.c,v 1.25 1999/12/02 17:05:04 joda Exp $");
37
38#ifdef HAVE_DB_H
39
40static krb5_error_code
41DB_close(krb5_context context, HDB *db)
42{
43    DB *d = (DB*)db->db;
44    d->close(d);
45    return 0;
46}
47
48static krb5_error_code
49DB_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
59static krb5_error_code
60DB_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
69static krb5_error_code
70DB_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
80static krb5_error_code
81DB_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
115static krb5_error_code
116DB_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
122static krb5_error_code
123DB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
124{
125    return DB_seq(context, db, flags, entry, R_NEXT);
126}
127
128static krb5_error_code
129DB_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
147static krb5_error_code
148DB__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
170static krb5_error_code
171DB__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
194static krb5_error_code
195DB__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
214static krb5_error_code
215DB_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
239krb5_error_code
240hdb_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