xref: /freebsd/crypto/heimdal/lib/hdb/db.c (revision 5521ff5a4d1929056e7ffc982fac3341ca54df7c)
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: db.c,v 1.28 2001/01/30 01:24:00 assar Exp $");
37 
38 #if defined(HAVE_DB_H) && DB_VERSION_MAJOR < 3
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 	code = hdb_unseal_keys (context, db, entry);
107 	if (code)
108 	    hdb_free_entry (context, entry);
109     }
110     if (code == 0 && entry->principal == NULL) {
111 	entry->principal = malloc(sizeof(*entry->principal));
112 	if (entry->principal == NULL) {
113 	    code = ENOMEM;
114 	    hdb_free_entry (context, entry);
115 	} else {
116 	    hdb_key2principal(context, &key_data, entry->principal);
117 	}
118     }
119     return code;
120 }
121 
122 
123 static krb5_error_code
124 DB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
125 {
126     return DB_seq(context, db, flags, entry, R_FIRST);
127 }
128 
129 
130 static krb5_error_code
131 DB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
132 {
133     return DB_seq(context, db, flags, entry, R_NEXT);
134 }
135 
136 static krb5_error_code
137 DB_rename(krb5_context context, HDB *db, const char *new_name)
138 {
139     int ret;
140     char *old, *new;
141 
142     asprintf(&old, "%s.db", db->name);
143     asprintf(&new, "%s.db", new_name);
144     ret = rename(old, new);
145     free(old);
146     free(new);
147     if(ret)
148 	return errno;
149 
150     free(db->name);
151     db->name = strdup(new_name);
152     return 0;
153 }
154 
155 static krb5_error_code
156 DB__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply)
157 {
158     DB *d = (DB*)db->db;
159     DBT k, v;
160     int code;
161 
162     k.data = key.data;
163     k.size = key.length;
164     code = db->lock(context, db, HDB_RLOCK);
165     if(code)
166 	return code;
167     code = d->get(d, &k, &v, 0);
168     db->unlock(context, db);
169     if(code < 0)
170 	return errno;
171     if(code == 1)
172 	return HDB_ERR_NOENTRY;
173 
174     krb5_data_copy(reply, v.data, v.size);
175     return 0;
176 }
177 
178 static krb5_error_code
179 DB__put(krb5_context context, HDB *db, int replace,
180 	krb5_data key, krb5_data value)
181 {
182     DB *d = (DB*)db->db;
183     DBT k, v;
184     int code;
185 
186     k.data = key.data;
187     k.size = key.length;
188     v.data = value.data;
189     v.size = value.length;
190     code = db->lock(context, db, HDB_WLOCK);
191     if(code)
192 	return code;
193     code = d->put(d, &k, &v, replace ? 0 : R_NOOVERWRITE);
194     db->unlock(context, db);
195     if(code < 0)
196 	return errno;
197     if(code == 1)
198 	return HDB_ERR_EXISTS;
199     return 0;
200 }
201 
202 static krb5_error_code
203 DB__del(krb5_context context, HDB *db, krb5_data key)
204 {
205     DB *d = (DB*)db->db;
206     DBT k;
207     krb5_error_code code;
208     k.data = key.data;
209     k.size = key.length;
210     code = db->lock(context, db, HDB_WLOCK);
211     if(code)
212 	return code;
213     code = d->del(d, &k, 0);
214     db->unlock(context, db);
215     if(code == 1)
216 	return HDB_ERR_NOENTRY;
217     if(code < 0)
218 	return errno;
219     return 0;
220 }
221 
222 static krb5_error_code
223 DB_open(krb5_context context, HDB *db, int flags, mode_t mode)
224 {
225     char *fn;
226     krb5_error_code ret;
227 
228     asprintf(&fn, "%s.db", db->name);
229     if (fn == NULL)
230 	return ENOMEM;
231     db->db = dbopen(fn, flags, mode, DB_BTREE, NULL);
232     free(fn);
233     /* try to open without .db extension */
234     if(db->db == NULL && errno == ENOENT)
235 	db->db = dbopen(db->name, flags, mode, DB_BTREE, NULL);
236     if(db->db == NULL)
237 	return errno;
238     if((flags & O_ACCMODE) == O_RDONLY)
239 	ret = hdb_check_db_format(context, db);
240     else
241 	ret = hdb_init_db(context, db);
242     if(ret == HDB_ERR_NOENTRY)
243 	return 0;
244     return ret;
245 }
246 
247 krb5_error_code
248 hdb_db_create(krb5_context context, HDB **db,
249 	      const char *filename)
250 {
251     *db = malloc(sizeof(**db));
252     if (*db == NULL)
253 	return ENOMEM;
254 
255     (*db)->db = NULL;
256     (*db)->name = strdup(filename);
257     (*db)->master_key_set = 0;
258     (*db)->openp = 0;
259     (*db)->open  = DB_open;
260     (*db)->close = DB_close;
261     (*db)->fetch = _hdb_fetch;
262     (*db)->store = _hdb_store;
263     (*db)->remove = _hdb_remove;
264     (*db)->firstkey = DB_firstkey;
265     (*db)->nextkey= DB_nextkey;
266     (*db)->lock = DB_lock;
267     (*db)->unlock = DB_unlock;
268     (*db)->rename = DB_rename;
269     (*db)->_get = DB__get;
270     (*db)->_put = DB__put;
271     (*db)->_del = DB__del;
272     (*db)->destroy = DB_destroy;
273     return 0;
274 }
275 
276 #endif
277