]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - crypto/heimdal/lib/hdb/db3.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / crypto / heimdal / lib / hdb / db3.c
1 /*
2  * Copyright (c) 1997 - 2006 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 21610 2007-07-17 07:10:45Z lha $");
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->hdb_db;
52     DBC *dbcp = (DBC*)db->hdb_dbc;
53
54     (*dbcp->c_close)(dbcp);
55     db->hdb_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->hdb_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->hdb_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->hdb_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_ex *entry, int flag)
95 {
96     DBT key, value;
97     DBC *dbcp = db->hdb_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->hdb_lock)(context, db, HDB_RLOCK))
104         return HDB_ERR_DB_INUSE;
105     code = (*dbcp->c_get)(dbcp, &key, &value, flag);
106     (*db->hdb_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     memset(entry, 0, sizeof(*entry));
117     if (hdb_value2entry(context, &data, &entry->entry))
118         return DB_seq(context, db, flags, entry, DB_NEXT);
119     if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
120         code = hdb_unseal_keys (context, db, &entry->entry);
121         if (code)
122             hdb_free_entry (context, entry);
123     }
124     if (entry->entry.principal == NULL) {
125         entry->entry.principal = malloc(sizeof(*entry->entry.principal));
126         if (entry->entry.principal == NULL) {
127             hdb_free_entry (context, entry);
128             krb5_set_error_string(context, "malloc: out of memory");
129             return ENOMEM;
130         } else {
131             hdb_key2principal(context, &key_data, entry->entry.principal);
132         }
133     }
134     return 0;
135 }
136
137
138 static krb5_error_code
139 DB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
140 {
141     return DB_seq(context, db, flags, entry, DB_FIRST);
142 }
143
144
145 static krb5_error_code
146 DB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
147 {
148     return DB_seq(context, db, flags, entry, DB_NEXT);
149 }
150
151 static krb5_error_code
152 DB_rename(krb5_context context, HDB *db, const char *new_name)
153 {
154     int ret;
155     char *old, *new;
156
157     asprintf(&old, "%s.db", db->hdb_name);
158     asprintf(&new, "%s.db", new_name);
159     ret = rename(old, new);
160     free(old);
161     free(new);
162     if(ret)
163         return errno;
164     
165     free(db->hdb_name);
166     db->hdb_name = strdup(new_name);
167     return 0;
168 }
169
170 static krb5_error_code
171 DB__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply)
172 {
173     DB *d = (DB*)db->hdb_db;
174     DBT k, v;
175     int code;
176
177     memset(&k, 0, sizeof(DBT));
178     memset(&v, 0, sizeof(DBT));
179     k.data = key.data;
180     k.size = key.length;
181     k.flags = 0;
182     if ((code = (*db->hdb_lock)(context, db, HDB_RLOCK)))
183         return code;
184     code = (*d->get)(d, NULL, &k, &v, 0);
185     (*db->hdb_unlock)(context, db);
186     if(code == DB_NOTFOUND)
187         return HDB_ERR_NOENTRY;
188     if(code)
189         return code;
190
191     krb5_data_copy(reply, v.data, v.size);
192     return 0;
193 }
194
195 static krb5_error_code
196 DB__put(krb5_context context, HDB *db, int replace, 
197         krb5_data key, krb5_data value)
198 {
199     DB *d = (DB*)db->hdb_db;
200     DBT k, v;
201     int code;
202
203     memset(&k, 0, sizeof(DBT));
204     memset(&v, 0, sizeof(DBT));
205     k.data = key.data;
206     k.size = key.length;
207     k.flags = 0;
208     v.data = value.data;
209     v.size = value.length;
210     v.flags = 0;
211     if ((code = (*db->hdb_lock)(context, db, HDB_WLOCK)))
212         return code;
213     code = (*d->put)(d, NULL, &k, &v, replace ? 0 : DB_NOOVERWRITE);
214     (*db->hdb_unlock)(context, db);
215     if(code == DB_KEYEXIST)
216         return HDB_ERR_EXISTS;
217     if(code)
218         return errno;
219     return 0;
220 }
221
222 static krb5_error_code
223 DB__del(krb5_context context, HDB *db, krb5_data key)
224 {
225     DB *d = (DB*)db->hdb_db;
226     DBT k;
227     krb5_error_code code;
228     memset(&k, 0, sizeof(DBT));
229     k.data = key.data;
230     k.size = key.length;
231     k.flags = 0;
232     code = (*db->hdb_lock)(context, db, HDB_WLOCK);
233     if(code)
234         return code;
235     code = (*d->del)(d, NULL, &k, 0);
236     (*db->hdb_unlock)(context, db);
237     if(code == DB_NOTFOUND)
238         return HDB_ERR_NOENTRY;
239     if(code)
240         return code;
241     return 0;
242 }
243
244 static krb5_error_code
245 DB_open(krb5_context context, HDB *db, int flags, mode_t mode)
246 {
247     DBC *dbc = NULL;
248     char *fn;
249     krb5_error_code ret;
250     DB *d;
251     int myflags = 0;
252
253     if (flags & O_CREAT)
254       myflags |= DB_CREATE;
255
256     if (flags & O_EXCL)
257       myflags |= DB_EXCL;
258
259     if((flags & O_ACCMODE) == O_RDONLY)
260       myflags |= DB_RDONLY;
261
262     if (flags & O_TRUNC)
263       myflags |= DB_TRUNCATE;
264
265     asprintf(&fn, "%s.db", db->hdb_name);
266     if (fn == NULL) {
267         krb5_set_error_string(context, "malloc: out of memory");
268         return ENOMEM;
269     }
270     db_create(&d, NULL, 0);
271     db->hdb_db = d;
272
273 #if (DB_VERSION_MAJOR >= 4) && (DB_VERSION_MINOR >= 1)
274     ret = (*d->open)(db->hdb_db, NULL, fn, NULL, DB_BTREE, myflags, mode);
275 #else
276     ret = (*d->open)(db->hdb_db, fn, NULL, DB_BTREE, myflags, mode);
277 #endif
278
279     if (ret == ENOENT) {
280         /* try to open without .db extension */
281 #if (DB_VERSION_MAJOR >= 4) && (DB_VERSION_MINOR >= 1)
282         ret = (*d->open)(db->hdb_db, NULL, db->hdb_name, NULL, DB_BTREE,
283                          myflags, mode);
284 #else
285         ret = (*d->open)(db->hdb_db, db->hdb_name, NULL, DB_BTREE, 
286                          myflags, mode);
287 #endif
288     }
289
290     if (ret) {
291         free(fn);
292         krb5_set_error_string(context, "opening %s: %s",
293                               db->hdb_name, strerror(ret));
294         return ret;
295     }
296     free(fn);
297
298     ret = (*d->cursor)(d, NULL, &dbc, 0);
299     if (ret) {
300         krb5_set_error_string(context, "d->cursor: %s", strerror(ret));
301         return ret;
302     }
303     db->hdb_dbc = dbc;
304
305     if((flags & O_ACCMODE) == O_RDONLY)
306         ret = hdb_check_db_format(context, db);
307     else
308         ret = hdb_init_db(context, db);
309     if(ret == HDB_ERR_NOENTRY)
310         return 0;
311     if (ret) {
312         DB_close(context, db);
313         krb5_set_error_string(context, "hdb_open: failed %s database %s",
314                               (flags & O_ACCMODE) == O_RDONLY ? 
315                               "checking format of" : "initialize", 
316                               db->hdb_name);
317     }
318
319     return ret;
320 }
321
322 krb5_error_code
323 hdb_db_create(krb5_context context, HDB **db, 
324               const char *filename)
325 {
326     *db = calloc(1, sizeof(**db));
327     if (*db == NULL) {
328         krb5_set_error_string(context, "malloc: out of memory");
329         return ENOMEM;
330     }
331
332     (*db)->hdb_db = NULL;
333     (*db)->hdb_name = strdup(filename);
334     if ((*db)->hdb_name == NULL) {
335         krb5_set_error_string(context, "malloc: out of memory");
336         free(*db);
337         *db = NULL;
338         return ENOMEM;
339     }
340     (*db)->hdb_master_key_set = 0;
341     (*db)->hdb_openp = 0;
342     (*db)->hdb_open  = DB_open;
343     (*db)->hdb_close = DB_close;
344     (*db)->hdb_fetch = _hdb_fetch;
345     (*db)->hdb_store = _hdb_store;
346     (*db)->hdb_remove = _hdb_remove;
347     (*db)->hdb_firstkey = DB_firstkey;
348     (*db)->hdb_nextkey= DB_nextkey;
349     (*db)->hdb_lock = DB_lock;
350     (*db)->hdb_unlock = DB_unlock;
351     (*db)->hdb_rename = DB_rename;
352     (*db)->hdb__get = DB__get;
353     (*db)->hdb__put = DB__put;
354     (*db)->hdb__del = DB__del;
355     (*db)->hdb_destroy = DB_destroy;
356     return 0;
357 }
358 #endif /* HAVE_DB3 */