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