Merge from vendor branch BIND:
[dragonfly.git] / crypto / heimdal-0.6.3 / lib / hdb / db3.c
1 /*
2  * Copyright (c) 1997 - 2001 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
36 RCSID("$Id: db3.c,v 1.8.6.1 2003/08/29 16:59:39 lha Exp $");
37
38 #if HAVE_DB3
39
40 #ifdef HAVE_DB4_DB_H
41 #include <db4/db.h>
42 #elif defined(HAVE_DB3_DB_H)
43 #include <db3/db.h>
44 #else
45 #include <db.h>
46 #endif
47
48 static krb5_error_code
49 DB_close(krb5_context context, HDB *db)
50 {
51     DB *d = (DB*)db->db;
52     DBC *dbcp = (DBC*)db->dbc;
53
54     dbcp->c_close(dbcp);
55     db->dbc = 0;
56     d->close(d, 0);
57     return 0;
58 }
59
60 static krb5_error_code
61 DB_destroy(krb5_context context, HDB *db)
62 {
63     krb5_error_code ret;
64
65     ret = hdb_clear_master_key (context, db);
66     free(db->name);
67     free(db);
68     return ret;
69 }
70
71 static krb5_error_code
72 DB_lock(krb5_context context, HDB *db, int operation)
73 {
74     DB *d = (DB*)db->db;
75     int fd;
76     if ((*d->fd)(d, &fd))
77         return HDB_ERR_CANT_LOCK_DB;
78     return hdb_lock(fd, operation);
79 }
80
81 static krb5_error_code
82 DB_unlock(krb5_context context, HDB *db)
83 {
84     DB *d = (DB*)db->db;
85     int fd;
86     if ((*d->fd)(d, &fd))
87         return HDB_ERR_CANT_LOCK_DB;
88     return hdb_unlock(fd);
89 }
90
91
92 static krb5_error_code
93 DB_seq(krb5_context context, HDB *db,
94        unsigned flags, hdb_entry *entry, int flag)
95 {
96     DBT key, value;
97     DBC *dbcp = db->dbc;
98     krb5_data key_data, data;
99     int code;
100
101     memset(&key, 0, sizeof(DBT));
102     memset(&value, 0, sizeof(DBT));
103     if (db->lock(context, db, HDB_RLOCK))
104         return HDB_ERR_DB_INUSE;
105     code = dbcp->c_get(dbcp, &key, &value, flag);
106     db->unlock(context, db); /* XXX check value */
107     if (code == DB_NOTFOUND)
108         return HDB_ERR_NOENTRY;
109     if (code)
110         return code;
111
112     key_data.data = key.data;
113     key_data.length = key.size;
114     data.data = value.data;
115     data.length = value.size;
116     if (hdb_value2entry(context, &data, entry))
117         return DB_seq(context, db, flags, entry, DB_NEXT);
118     if (db->master_key_set && (flags & HDB_F_DECRYPT)) {
119         code = hdb_unseal_keys (context, db, entry);
120         if (code)
121             hdb_free_entry (context, entry);
122     }
123     if (entry->principal == NULL) {
124         entry->principal = malloc(sizeof(*entry->principal));
125         if (entry->principal == NULL) {
126             hdb_free_entry (context, entry);
127             krb5_set_error_string(context, "malloc: out of memory");
128             return ENOMEM;
129         } else {
130             hdb_key2principal(context, &key_data, entry->principal);
131         }
132     }
133     return 0;
134 }
135
136
137 static krb5_error_code
138 DB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
139 {
140     return DB_seq(context, db, flags, entry, DB_FIRST);
141 }
142
143
144 static krb5_error_code
145 DB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
146 {
147     return DB_seq(context, db, flags, entry, DB_NEXT);
148 }
149
150 static krb5_error_code
151 DB_rename(krb5_context context, HDB *db, const char *new_name)
152 {
153     int ret;
154     char *old, *new;
155
156     asprintf(&old, "%s.db", db->name);
157     asprintf(&new, "%s.db", new_name);
158     ret = rename(old, new);
159     free(old);
160     free(new);
161     if(ret)
162         return errno;
163     
164     free(db->name);
165     db->name = strdup(new_name);
166     return 0;
167 }
168
169 static krb5_error_code
170 DB__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply)
171 {
172     DB *d = (DB*)db->db;
173     DBT k, v;
174     int code;
175
176     memset(&k, 0, sizeof(DBT));
177     memset(&v, 0, sizeof(DBT));
178     k.data = key.data;
179     k.size = key.length;
180     k.flags = 0;
181     if ((code = db->lock(context, db, HDB_RLOCK)))
182         return code;
183     code = d->get(d, NULL, &k, &v, 0);
184     db->unlock(context, db);
185     if(code == DB_NOTFOUND)
186         return HDB_ERR_NOENTRY;
187     if(code)
188         return code;
189
190     krb5_data_copy(reply, v.data, v.size);
191     return 0;
192 }
193
194 static krb5_error_code
195 DB__put(krb5_context context, HDB *db, int replace, 
196         krb5_data key, krb5_data value)
197 {
198     DB *d = (DB*)db->db;
199     DBT k, v;
200     int code;
201
202     memset(&k, 0, sizeof(DBT));
203     memset(&v, 0, sizeof(DBT));
204     k.data = key.data;
205     k.size = key.length;
206     k.flags = 0;
207     v.data = value.data;
208     v.size = value.length;
209     v.flags = 0;
210     if ((code = db->lock(context, db, HDB_WLOCK)))
211         return code;
212     code = d->put(d, NULL, &k, &v, replace ? 0 : DB_NOOVERWRITE);
213     db->unlock(context, db);
214     if(code == DB_KEYEXIST)
215         return HDB_ERR_EXISTS;
216     if(code)
217         return errno;
218     return 0;
219 }
220
221 static krb5_error_code
222 DB__del(krb5_context context, HDB *db, krb5_data key)
223 {
224     DB *d = (DB*)db->db;
225     DBT k;
226     krb5_error_code code;
227     memset(&k, 0, sizeof(DBT));
228     k.data = key.data;
229     k.size = key.length;
230     k.flags = 0;
231     code = db->lock(context, db, HDB_WLOCK);
232     if(code)
233         return code;
234     code = d->del(d, NULL, &k, 0);
235     db->unlock(context, db);
236     if(code == DB_NOTFOUND)
237         return HDB_ERR_NOENTRY;
238     if(code)
239         return code;
240     return 0;
241 }
242
243 static krb5_error_code
244 DB_open(krb5_context context, HDB *db, int flags, mode_t mode)
245 {
246     char *fn;
247     krb5_error_code ret;
248     DB *d;
249     int myflags = 0;
250
251     if (flags & O_CREAT)
252       myflags |= DB_CREATE;
253
254     if (flags & O_EXCL)
255       myflags |= DB_EXCL;
256
257     if (flags & O_RDONLY)
258       myflags |= DB_RDONLY;
259
260     if (flags & O_TRUNC)
261       myflags |= DB_TRUNCATE;
262
263     asprintf(&fn, "%s.db", db->name);
264     if (fn == NULL) {
265         krb5_set_error_string(context, "malloc: out of memory");
266         return ENOMEM;
267     }
268     db_create(&d, NULL, 0);
269     db->db = d;
270 #if (DB_VERSION_MAJOR > 3) && (DB_VERSION_MINOR > 0)
271     if ((ret = d->open(db->db, NULL, fn, NULL, DB_BTREE, myflags, mode))) {
272 #else
273     if ((ret = d->open(db->db, fn, NULL, DB_BTREE, myflags, mode))) {
274 #endif
275       if(ret == ENOENT)
276         /* try to open without .db extension */
277 #if (DB_VERSION_MAJOR > 3) && (DB_VERSION_MINOR > 0)
278         if (d->open(db->db, NULL, db->name, NULL, DB_BTREE, myflags, mode)) {
279 #else
280         if (d->open(db->db, db->name, NULL, DB_BTREE, myflags, mode)) {
281 #endif
282           free(fn);
283           krb5_set_error_string(context, "opening %s: %s",
284                                 db->name, strerror(ret));
285           return ret;
286         }
287     }
288     free(fn);
289
290     ret = d->cursor(d, NULL, (DBC **)&db->dbc, 0);
291     if (ret) {
292         krb5_set_error_string(context, "d->cursor: %s", strerror(ret));
293         return ret;
294     }
295
296     if((flags & O_ACCMODE) == O_RDONLY)
297         ret = hdb_check_db_format(context, db);
298     else
299         ret = hdb_init_db(context, db);
300     if(ret == HDB_ERR_NOENTRY)
301         return 0;
302     return ret;
303 }
304
305 krb5_error_code
306 hdb_db_create(krb5_context context, HDB **db, 
307               const char *filename)
308 {
309     *db = malloc(sizeof(**db));
310     if (*db == NULL) {
311         krb5_set_error_string(context, "malloc: out of memory");
312         return ENOMEM;
313     }
314
315     (*db)->db = NULL;
316     (*db)->name = strdup(filename);
317     if ((*db)->name == NULL) {
318         krb5_set_error_string(context, "malloc: out of memory");
319         free(*db);
320         *db = NULL;
321         return ENOMEM;
322     }
323     (*db)->master_key_set = 0;
324     (*db)->openp = 0;
325     (*db)->open  = DB_open;
326     (*db)->close = DB_close;
327     (*db)->fetch = _hdb_fetch;
328     (*db)->store = _hdb_store;
329     (*db)->remove = _hdb_remove;
330     (*db)->firstkey = DB_firstkey;
331     (*db)->nextkey= DB_nextkey;
332     (*db)->lock = DB_lock;
333     (*db)->unlock = DB_unlock;
334     (*db)->rename = DB_rename;
335     (*db)->_get = DB__get;
336     (*db)->_put = DB__put;
337     (*db)->_del = DB__del;
338     (*db)->destroy = DB_destroy;
339     return 0;
340 }
341 #endif /* HAVE_DB3 */