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