1b528cefcSMark Murray /*
2*ae771770SStanislav Sedov * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
3b528cefcSMark Murray * (Royal Institute of Technology, Stockholm, Sweden).
4b528cefcSMark Murray * All rights reserved.
5b528cefcSMark Murray *
6b528cefcSMark Murray * Redistribution and use in source and binary forms, with or without
7b528cefcSMark Murray * modification, are permitted provided that the following conditions
8b528cefcSMark Murray * are met:
9b528cefcSMark Murray *
10b528cefcSMark Murray * 1. Redistributions of source code must retain the above copyright
11b528cefcSMark Murray * notice, this list of conditions and the following disclaimer.
12b528cefcSMark Murray *
13b528cefcSMark Murray * 2. Redistributions in binary form must reproduce the above copyright
14b528cefcSMark Murray * notice, this list of conditions and the following disclaimer in the
15b528cefcSMark Murray * documentation and/or other materials provided with the distribution.
16b528cefcSMark Murray *
17b528cefcSMark Murray * 3. Neither the name of the Institute nor the names of its contributors
18b528cefcSMark Murray * may be used to endorse or promote products derived from this software
19b528cefcSMark Murray * without specific prior written permission.
20b528cefcSMark Murray *
21b528cefcSMark Murray * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22b528cefcSMark Murray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23b528cefcSMark Murray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24b528cefcSMark Murray * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25b528cefcSMark Murray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26b528cefcSMark Murray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27b528cefcSMark Murray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28b528cefcSMark Murray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29b528cefcSMark Murray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30b528cefcSMark Murray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31b528cefcSMark Murray * SUCH DAMAGE.
32b528cefcSMark Murray */
33b528cefcSMark Murray
34b528cefcSMark Murray #include "hdb_locl.h"
35b528cefcSMark Murray
364137ff4cSJacques Vidrine #if HAVE_DB1
374137ff4cSJacques Vidrine
384137ff4cSJacques Vidrine #if defined(HAVE_DB_185_H)
394137ff4cSJacques Vidrine #include <db_185.h>
404137ff4cSJacques Vidrine #elif defined(HAVE_DB_H)
414137ff4cSJacques Vidrine #include <db.h>
424137ff4cSJacques Vidrine #endif
43b528cefcSMark Murray
44b528cefcSMark Murray static krb5_error_code
DB_close(krb5_context context,HDB * db)45b528cefcSMark Murray DB_close(krb5_context context, HDB *db)
46b528cefcSMark Murray {
47c19800e8SDoug Rabson DB *d = (DB*)db->hdb_db;
48c19800e8SDoug Rabson (*d->close)(d);
49b528cefcSMark Murray return 0;
50b528cefcSMark Murray }
51b528cefcSMark Murray
52b528cefcSMark Murray static krb5_error_code
DB_destroy(krb5_context context,HDB * db)53b528cefcSMark Murray DB_destroy(krb5_context context, HDB *db)
54b528cefcSMark Murray {
55b528cefcSMark Murray krb5_error_code ret;
56b528cefcSMark Murray
57b528cefcSMark Murray ret = hdb_clear_master_key (context, db);
58c19800e8SDoug Rabson free(db->hdb_name);
59b528cefcSMark Murray free(db);
60b528cefcSMark Murray return ret;
61b528cefcSMark Murray }
62b528cefcSMark Murray
63b528cefcSMark Murray static krb5_error_code
DB_lock(krb5_context context,HDB * db,int operation)64b528cefcSMark Murray DB_lock(krb5_context context, HDB *db, int operation)
65b528cefcSMark Murray {
66c19800e8SDoug Rabson DB *d = (DB*)db->hdb_db;
67b528cefcSMark Murray int fd = (*d->fd)(d);
68c19800e8SDoug Rabson if(fd < 0) {
69*ae771770SStanislav Sedov krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB,
70c19800e8SDoug Rabson "Can't lock database: %s", db->hdb_name);
71b528cefcSMark Murray return HDB_ERR_CANT_LOCK_DB;
72c19800e8SDoug Rabson }
73b528cefcSMark Murray return hdb_lock(fd, operation);
74b528cefcSMark Murray }
75b528cefcSMark Murray
76b528cefcSMark Murray static krb5_error_code
DB_unlock(krb5_context context,HDB * db)77b528cefcSMark Murray DB_unlock(krb5_context context, HDB *db)
78b528cefcSMark Murray {
79c19800e8SDoug Rabson DB *d = (DB*)db->hdb_db;
80b528cefcSMark Murray int fd = (*d->fd)(d);
81c19800e8SDoug Rabson if(fd < 0) {
82*ae771770SStanislav Sedov krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB,
83c19800e8SDoug Rabson "Can't unlock database: %s", db->hdb_name);
84b528cefcSMark Murray return HDB_ERR_CANT_LOCK_DB;
85c19800e8SDoug Rabson }
86b528cefcSMark Murray return hdb_unlock(fd);
87b528cefcSMark Murray }
88b528cefcSMark Murray
89b528cefcSMark Murray
90b528cefcSMark Murray static krb5_error_code
DB_seq(krb5_context context,HDB * db,unsigned flags,hdb_entry_ex * entry,int flag)91b528cefcSMark Murray DB_seq(krb5_context context, HDB *db,
92c19800e8SDoug Rabson unsigned flags, hdb_entry_ex *entry, int flag)
93b528cefcSMark Murray {
94c19800e8SDoug Rabson DB *d = (DB*)db->hdb_db;
95b528cefcSMark Murray DBT key, value;
96b528cefcSMark Murray krb5_data key_data, data;
97b528cefcSMark Murray int code;
98b528cefcSMark Murray
99c19800e8SDoug Rabson code = db->hdb_lock(context, db, HDB_RLOCK);
100c19800e8SDoug Rabson if(code == -1) {
101*ae771770SStanislav Sedov krb5_set_error_message(context, HDB_ERR_DB_INUSE, "Database %s in use", db->hdb_name);
102b528cefcSMark Murray return HDB_ERR_DB_INUSE;
103c19800e8SDoug Rabson }
104c19800e8SDoug Rabson code = (*d->seq)(d, &key, &value, flag);
105c19800e8SDoug Rabson db->hdb_unlock(context, db); /* XXX check value */
106c19800e8SDoug Rabson if(code == -1) {
107c19800e8SDoug Rabson code = errno;
108*ae771770SStanislav Sedov krb5_set_error_message(context, code, "Database %s seq error: %s",
109c19800e8SDoug Rabson db->hdb_name, strerror(code));
110c19800e8SDoug Rabson return code;
111c19800e8SDoug Rabson }
112c19800e8SDoug Rabson if(code == 1) {
113*ae771770SStanislav Sedov krb5_clear_error_message(context);
114b528cefcSMark Murray return HDB_ERR_NOENTRY;
115c19800e8SDoug Rabson }
116b528cefcSMark Murray
117b528cefcSMark Murray key_data.data = key.data;
118b528cefcSMark Murray key_data.length = key.size;
119b528cefcSMark Murray data.data = value.data;
120b528cefcSMark Murray data.length = value.size;
121c19800e8SDoug Rabson memset(entry, 0, sizeof(*entry));
122c19800e8SDoug Rabson if (hdb_value2entry(context, &data, &entry->entry))
123b528cefcSMark Murray return DB_seq(context, db, flags, entry, R_NEXT);
124c19800e8SDoug Rabson if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
125c19800e8SDoug Rabson code = hdb_unseal_keys (context, db, &entry->entry);
1265e9cd1aeSAssar Westerlund if (code)
1275e9cd1aeSAssar Westerlund hdb_free_entry (context, entry);
1285e9cd1aeSAssar Westerlund }
129c19800e8SDoug Rabson if (code == 0 && entry->entry.principal == NULL) {
130c19800e8SDoug Rabson entry->entry.principal = malloc(sizeof(*entry->entry.principal));
131c19800e8SDoug Rabson if (entry->entry.principal == NULL) {
1325e9cd1aeSAssar Westerlund code = ENOMEM;
133*ae771770SStanislav Sedov krb5_set_error_message(context, code, "malloc: out of memory");
1345e9cd1aeSAssar Westerlund hdb_free_entry (context, entry);
1355e9cd1aeSAssar Westerlund } else {
136c19800e8SDoug Rabson hdb_key2principal(context, &key_data, entry->entry.principal);
137b528cefcSMark Murray }
1385e9cd1aeSAssar Westerlund }
1395e9cd1aeSAssar Westerlund return code;
140b528cefcSMark Murray }
141b528cefcSMark Murray
142b528cefcSMark Murray
143b528cefcSMark Murray static krb5_error_code
DB_firstkey(krb5_context context,HDB * db,unsigned flags,hdb_entry_ex * entry)144c19800e8SDoug Rabson DB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
145b528cefcSMark Murray {
146b528cefcSMark Murray return DB_seq(context, db, flags, entry, R_FIRST);
147b528cefcSMark Murray }
148b528cefcSMark Murray
149b528cefcSMark Murray
150b528cefcSMark Murray static krb5_error_code
DB_nextkey(krb5_context context,HDB * db,unsigned flags,hdb_entry_ex * entry)151c19800e8SDoug Rabson DB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
152b528cefcSMark Murray {
153b528cefcSMark Murray return DB_seq(context, db, flags, entry, R_NEXT);
154b528cefcSMark Murray }
155b528cefcSMark Murray
156b528cefcSMark Murray static krb5_error_code
DB_rename(krb5_context context,HDB * db,const char * new_name)157b528cefcSMark Murray DB_rename(krb5_context context, HDB *db, const char *new_name)
158b528cefcSMark Murray {
159b528cefcSMark Murray int ret;
160b528cefcSMark Murray char *old, *new;
161b528cefcSMark Murray
162c19800e8SDoug Rabson asprintf(&old, "%s.db", db->hdb_name);
163b528cefcSMark Murray asprintf(&new, "%s.db", new_name);
164b528cefcSMark Murray ret = rename(old, new);
165b528cefcSMark Murray free(old);
166b528cefcSMark Murray free(new);
167b528cefcSMark Murray if(ret)
168b528cefcSMark Murray return errno;
169b528cefcSMark Murray
170c19800e8SDoug Rabson free(db->hdb_name);
171c19800e8SDoug Rabson db->hdb_name = strdup(new_name);
172b528cefcSMark Murray return 0;
173b528cefcSMark Murray }
174b528cefcSMark Murray
175b528cefcSMark Murray static krb5_error_code
DB__get(krb5_context context,HDB * db,krb5_data key,krb5_data * reply)176b528cefcSMark Murray DB__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply)
177b528cefcSMark Murray {
178c19800e8SDoug Rabson DB *d = (DB*)db->hdb_db;
179b528cefcSMark Murray DBT k, v;
180b528cefcSMark Murray int code;
181b528cefcSMark Murray
182b528cefcSMark Murray k.data = key.data;
183b528cefcSMark Murray k.size = key.length;
184c19800e8SDoug Rabson code = db->hdb_lock(context, db, HDB_RLOCK);
185b528cefcSMark Murray if(code)
186b528cefcSMark Murray return code;
187c19800e8SDoug Rabson code = (*d->get)(d, &k, &v, 0);
188c19800e8SDoug Rabson db->hdb_unlock(context, db);
189c19800e8SDoug Rabson if(code < 0) {
190c19800e8SDoug Rabson code = errno;
191*ae771770SStanislav Sedov krb5_set_error_message(context, code, "Database %s get error: %s",
192c19800e8SDoug Rabson db->hdb_name, strerror(code));
193c19800e8SDoug Rabson return code;
194c19800e8SDoug Rabson }
195c19800e8SDoug Rabson if(code == 1) {
196*ae771770SStanislav Sedov krb5_clear_error_message(context);
197b528cefcSMark Murray return HDB_ERR_NOENTRY;
198c19800e8SDoug Rabson }
199b528cefcSMark Murray
200b528cefcSMark Murray krb5_data_copy(reply, v.data, v.size);
201b528cefcSMark Murray return 0;
202b528cefcSMark Murray }
203b528cefcSMark Murray
204b528cefcSMark Murray static krb5_error_code
DB__put(krb5_context context,HDB * db,int replace,krb5_data key,krb5_data value)205b528cefcSMark Murray DB__put(krb5_context context, HDB *db, int replace,
206b528cefcSMark Murray krb5_data key, krb5_data value)
207b528cefcSMark Murray {
208c19800e8SDoug Rabson DB *d = (DB*)db->hdb_db;
209b528cefcSMark Murray DBT k, v;
210b528cefcSMark Murray int code;
211b528cefcSMark Murray
212b528cefcSMark Murray k.data = key.data;
213b528cefcSMark Murray k.size = key.length;
214b528cefcSMark Murray v.data = value.data;
215b528cefcSMark Murray v.size = value.length;
216c19800e8SDoug Rabson code = db->hdb_lock(context, db, HDB_WLOCK);
217b528cefcSMark Murray if(code)
218b528cefcSMark Murray return code;
219c19800e8SDoug Rabson code = (*d->put)(d, &k, &v, replace ? 0 : R_NOOVERWRITE);
220c19800e8SDoug Rabson db->hdb_unlock(context, db);
221c19800e8SDoug Rabson if(code < 0) {
222c19800e8SDoug Rabson code = errno;
223*ae771770SStanislav Sedov krb5_set_error_message(context, code, "Database %s put error: %s",
224c19800e8SDoug Rabson db->hdb_name, strerror(code));
225c19800e8SDoug Rabson return code;
226c19800e8SDoug Rabson }
227c19800e8SDoug Rabson if(code == 1) {
228*ae771770SStanislav Sedov krb5_clear_error_message(context);
229b528cefcSMark Murray return HDB_ERR_EXISTS;
230c19800e8SDoug Rabson }
231b528cefcSMark Murray return 0;
232b528cefcSMark Murray }
233b528cefcSMark Murray
234b528cefcSMark Murray static krb5_error_code
DB__del(krb5_context context,HDB * db,krb5_data key)235b528cefcSMark Murray DB__del(krb5_context context, HDB *db, krb5_data key)
236b528cefcSMark Murray {
237c19800e8SDoug Rabson DB *d = (DB*)db->hdb_db;
238b528cefcSMark Murray DBT k;
239b528cefcSMark Murray krb5_error_code code;
240b528cefcSMark Murray k.data = key.data;
241b528cefcSMark Murray k.size = key.length;
242c19800e8SDoug Rabson code = db->hdb_lock(context, db, HDB_WLOCK);
243b528cefcSMark Murray if(code)
244b528cefcSMark Murray return code;
245c19800e8SDoug Rabson code = (*d->del)(d, &k, 0);
246c19800e8SDoug Rabson db->hdb_unlock(context, db);
247c19800e8SDoug Rabson if(code == 1) {
248c19800e8SDoug Rabson code = errno;
249*ae771770SStanislav Sedov krb5_set_error_message(context, code, "Database %s put error: %s",
250c19800e8SDoug Rabson db->hdb_name, strerror(code));
251c19800e8SDoug Rabson return code;
252c19800e8SDoug Rabson }
253b528cefcSMark Murray if(code < 0)
254b528cefcSMark Murray return errno;
255b528cefcSMark Murray return 0;
256b528cefcSMark Murray }
257b528cefcSMark Murray
258b528cefcSMark Murray static krb5_error_code
DB_open(krb5_context context,HDB * db,int flags,mode_t mode)259b528cefcSMark Murray DB_open(krb5_context context, HDB *db, int flags, mode_t mode)
260b528cefcSMark Murray {
261b528cefcSMark Murray char *fn;
262b528cefcSMark Murray krb5_error_code ret;
263b528cefcSMark Murray
264c19800e8SDoug Rabson asprintf(&fn, "%s.db", db->hdb_name);
2654137ff4cSJacques Vidrine if (fn == NULL) {
266*ae771770SStanislav Sedov krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
267b528cefcSMark Murray return ENOMEM;
2684137ff4cSJacques Vidrine }
269c19800e8SDoug Rabson db->hdb_db = dbopen(fn, flags, mode, DB_BTREE, NULL);
270b528cefcSMark Murray free(fn);
271b528cefcSMark Murray /* try to open without .db extension */
272c19800e8SDoug Rabson if(db->hdb_db == NULL && errno == ENOENT)
273c19800e8SDoug Rabson db->hdb_db = dbopen(db->hdb_name, flags, mode, DB_BTREE, NULL);
274c19800e8SDoug Rabson if(db->hdb_db == NULL) {
2754137ff4cSJacques Vidrine ret = errno;
276*ae771770SStanislav Sedov krb5_set_error_message(context, ret, "dbopen (%s): %s",
277c19800e8SDoug Rabson db->hdb_name, strerror(ret));
2784137ff4cSJacques Vidrine return ret;
2794137ff4cSJacques Vidrine }
280b528cefcSMark Murray if((flags & O_ACCMODE) == O_RDONLY)
281b528cefcSMark Murray ret = hdb_check_db_format(context, db);
282b528cefcSMark Murray else
283b528cefcSMark Murray ret = hdb_init_db(context, db);
2844137ff4cSJacques Vidrine if(ret == HDB_ERR_NOENTRY) {
285*ae771770SStanislav Sedov krb5_clear_error_message(context);
286b528cefcSMark Murray return 0;
2874137ff4cSJacques Vidrine }
288c19800e8SDoug Rabson if (ret) {
289c19800e8SDoug Rabson DB_close(context, db);
290*ae771770SStanislav Sedov krb5_set_error_message(context, ret, "hdb_open: failed %s database %s",
291c19800e8SDoug Rabson (flags & O_ACCMODE) == O_RDONLY ?
292c19800e8SDoug Rabson "checking format of" : "initialize",
293c19800e8SDoug Rabson db->hdb_name);
294c19800e8SDoug Rabson }
295b528cefcSMark Murray return ret;
296b528cefcSMark Murray }
297b528cefcSMark Murray
298b528cefcSMark Murray krb5_error_code
hdb_db_create(krb5_context context,HDB ** db,const char * filename)299b528cefcSMark Murray hdb_db_create(krb5_context context, HDB **db,
300b528cefcSMark Murray const char *filename)
301b528cefcSMark Murray {
302c19800e8SDoug Rabson *db = calloc(1, sizeof(**db));
3034137ff4cSJacques Vidrine if (*db == NULL) {
304*ae771770SStanislav Sedov krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
305b528cefcSMark Murray return ENOMEM;
3064137ff4cSJacques Vidrine }
307b528cefcSMark Murray
308c19800e8SDoug Rabson (*db)->hdb_db = NULL;
309c19800e8SDoug Rabson (*db)->hdb_name = strdup(filename);
310c19800e8SDoug Rabson if ((*db)->hdb_name == NULL) {
3114137ff4cSJacques Vidrine free(*db);
3124137ff4cSJacques Vidrine *db = NULL;
313*ae771770SStanislav Sedov krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
3144137ff4cSJacques Vidrine return ENOMEM;
3154137ff4cSJacques Vidrine }
316c19800e8SDoug Rabson (*db)->hdb_master_key_set = 0;
317c19800e8SDoug Rabson (*db)->hdb_openp = 0;
318*ae771770SStanislav Sedov (*db)->hdb_capability_flags = HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL;
319c19800e8SDoug Rabson (*db)->hdb_open = DB_open;
320c19800e8SDoug Rabson (*db)->hdb_close = DB_close;
321*ae771770SStanislav Sedov (*db)->hdb_fetch_kvno = _hdb_fetch_kvno;
322c19800e8SDoug Rabson (*db)->hdb_store = _hdb_store;
323c19800e8SDoug Rabson (*db)->hdb_remove = _hdb_remove;
324c19800e8SDoug Rabson (*db)->hdb_firstkey = DB_firstkey;
325c19800e8SDoug Rabson (*db)->hdb_nextkey= DB_nextkey;
326c19800e8SDoug Rabson (*db)->hdb_lock = DB_lock;
327c19800e8SDoug Rabson (*db)->hdb_unlock = DB_unlock;
328c19800e8SDoug Rabson (*db)->hdb_rename = DB_rename;
329c19800e8SDoug Rabson (*db)->hdb__get = DB__get;
330c19800e8SDoug Rabson (*db)->hdb__put = DB__put;
331c19800e8SDoug Rabson (*db)->hdb__del = DB__del;
332c19800e8SDoug Rabson (*db)->hdb_destroy = DB_destroy;
333b528cefcSMark Murray return 0;
334b528cefcSMark Murray }
335b528cefcSMark Murray
3364137ff4cSJacques Vidrine #endif /* HAVE_DB1 */
337