1/* $NetBSD: db.c,v 1.2 2017/01/28 21:31:48 christos Exp $ */
2
3/*
4 * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include "hdb_locl.h"
37
38#if defined(HAVE_DB1)
39
40#if defined(HAVE_DB_185_H)
41#include <db_185.h>
42#elif defined(HAVE_DB_H)
43#include <db.h>
44#endif
45
46typedef struct {
47 HDB hdb; /* generic members */
48 int lock_fd; /* DB-specific */
49} DB1_HDB;
50
51static krb5_error_code
52DB_close(krb5_context context, HDB *db)
53{
54 DB1_HDB *db1 = (DB1_HDB *)db;
55 DB *d = (DB*)db->hdb_db;
56
57 heim_assert(d != 0, "Closing already closed HDB");
58
59 (*d->close)(d);
60 db->hdb_db = 0;
61
62 if (db1->lock_fd >= 0) {
63 close(db1->lock_fd);
64 db1->lock_fd = -1;
65 }
66
67 return 0;
68}
69
70static krb5_error_code
71DB_destroy(krb5_context context, HDB *db)
72{
73 krb5_error_code ret;
74
75 ret = hdb_clear_master_key (context, db);
76 free(db->hdb_name);
77 free(db);
78 return ret;
79}
80
81static krb5_error_code
82DB_lock(krb5_context context, HDB *db, int operation)
83{
84
85 return 0;
86}
87
88static krb5_error_code
89DB_unlock(krb5_context context, HDB *db)
90{
91
92 return 0;
93}
94
95
96static krb5_error_code
97DB_seq(krb5_context context, HDB *db,
98 unsigned flags, hdb_entry_ex *entry, int flag)
99{
100 DB *d = (DB*)db->hdb_db;
101 DBT key, value;
102 krb5_data key_data, data;
103 int code;
104
105 code = (*d->seq)(d, &key, &value, flag);
106 if(code == -1) {
107 code = errno;
108 krb5_set_error_message(context, code, "Database %s seq error: %s",
109 db->hdb_name, strerror(code));
110 return code;
111 }
112 if(code == 1) {
113 krb5_clear_error_message(context);
114 return HDB_ERR_NOENTRY;
115 }
116
117 key_data.data = key.data;
118 key_data.length = key.size;
119 data.data = value.data;
120 data.length = value.size;
121 memset(entry, 0, sizeof(*entry));
122 if (hdb_value2entry(context, &data, &entry->entry))
123 return DB_seq(context, db, flags, entry, R_NEXT);
124 if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
125 code = hdb_unseal_keys (context, db, &entry->entry);
126 if (code)
127 hdb_free_entry (context, entry);
128 }
129 if (code == 0 && entry->entry.principal == NULL) {
130 entry->entry.principal = malloc(sizeof(*entry->entry.principal));
131 if (entry->entry.principal == NULL) {
132 code = ENOMEM;
133 krb5_set_error_message(context, code, "malloc: out of memory");
134 hdb_free_entry (context, entry);
135 } else {
136 hdb_key2principal(context, &key_data, entry->entry.principal);
137 }
138 }
139 return code;
140}
141
142
143static krb5_error_code
144DB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
145{
146 return DB_seq(context, db, flags, entry, R_FIRST);
147}
148
149
150static krb5_error_code
151DB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
152{
153 return DB_seq(context, db, flags, entry, R_NEXT);
154}
155
156static krb5_error_code
157DB_rename(krb5_context context, HDB *db, const char *new_name)
158{
159 int ret;
160 char *old, *new;
161
162 if (strncmp(new_name, "db:", sizeof("db:") - 1) == 0)
163 new_name += sizeof("db:") - 1;
164 else if (strncmp(new_name, "db1:", sizeof("db1:") - 1) == 0)
165 new_name += sizeof("db1:") - 1;
166 asprintf(&old, "%s.db", db->hdb_name);
167 asprintf(&new, "%s.db", new_name);
168 ret = rename(old, new);
169 free(old);
170 free(new);
171 if(ret)
172 return errno;
173
174 free(db->hdb_name);
175 db->hdb_name = strdup(new_name);
176 return 0;
177}
178
179static krb5_error_code
180DB__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply)
181{
182 DB *d = (DB*)db->hdb_db;
183 DBT k, v;
184 int code;
185
186 k.data = key.data;
187 k.size = key.length;
188 code = (*d->get)(d, &k, &v, 0);
189 if(code < 0) {
190 code = errno;
191 krb5_set_error_message(context, code, "Database %s get error: %s",
192 db->hdb_name, strerror(code));
193 return code;
194 }
195 if(code == 1) {
196 krb5_clear_error_message(context);
197 return HDB_ERR_NOENTRY;
198 }
199
200 krb5_data_copy(reply, v.data, v.size);
201 return 0;
202}
203
204static krb5_error_code
205DB__put(krb5_context context, HDB *db, int replace,
206 krb5_data key, krb5_data value)
207{
208 DB *d = (DB*)db->hdb_db;
209 DBT k, v;
210 int code;
211
212 k.data = key.data;
213 k.size = key.length;
214 v.data = value.data;
215 v.size = value.length;
216 krb5_clear_error_message(context);
217 code = (*d->put)(d, &k, &v, replace ? 0 : R_NOOVERWRITE);
218 if(code < 0) {
219 code = errno;
220 krb5_set_error_message(context, code, "Database %s put error: %s",
221 db->hdb_name, strerror(code));
222 return code;
223 }
224 if(code == 1) {
225 return HDB_ERR_EXISTS;
226 }
227 code = (*d->sync)(d, 0);
228 if (code == -1) {
229 code = errno;
230 krb5_set_error_message(context, code, "Database %s put sync error: %s",
231 db->hdb_name, strerror(code));
232 return code;
233 }
234 return 0;
235}
236
237static krb5_error_code
238DB__del(krb5_context context, HDB *db, krb5_data key)
239{
240 DB *d = (DB*)db->hdb_db;
241 DBT k;
242 krb5_error_code code;
243 k.data = key.data;
244 k.size = key.length;
245 krb5_clear_error_message(context);
246 code = (*d->del)(d, &k, 0);
247 if (code == 1)
248 return HDB_ERR_NOENTRY;
249 if (code < 0) {
250 code = errno;
251 krb5_set_error_message(context, code, "Database %s del error: %s",
252 db->hdb_name, strerror(code));
253 return code;
254 }
255 code = (*d->sync)(d, 0);
256 if (code == -1) {
257 code = errno;
258 krb5_set_error_message(context, code, "Database %s del sync error: %s",
259 db->hdb_name, strerror(code));
260 return code;
261 }
262 return 0;
263}
264
265static DB *
266_open_db(char *fn, int flags, int mode, int *fd)
267{
268#ifndef O_EXLOCK
269 int op;
270 int ret;
271
272 *fd = open(fn, flags, mode);
273 if (*fd == -1)
274 return NULL;
275
276 if ((flags & O_ACCMODE) == O_RDONLY)
277 op = LOCK_SH;
278 else
279 op = LOCK_EX;
280
281 ret = flock(*fd, op);
282 if (ret == -1) {
283 int saved_errno;
284
285 saved_errno = errno;
286 close(*fd);
287 errno = saved_errno;
288 return NULL;
289 }
290#else
291 if ((flags & O_ACCMODE) == O_RDONLY)
292 flags |= O_SHLOCK;
293 else
294 flags |= O_EXLOCK;
295#endif
296
297 return dbopen(fn, flags, mode, DB_BTREE, NULL);
298}
299
300static krb5_error_code
301DB_open(krb5_context context, HDB *db, int flags, mode_t mode)
302{
303 DB1_HDB *db1 = (DB1_HDB *)db;
304 char *fn;
305 krb5_error_code ret;
306
307 asprintf(&fn, "%s.db", db->hdb_name);
308 if (fn == NULL) {
309 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
310 return ENOMEM;
311 }
312 db->hdb_db = _open_db(fn, flags, mode, &db1->lock_fd);
313 free(fn);
314 /* try to open without .db extension */
315 if(db->hdb_db == NULL && errno == ENOENT)
316 db->hdb_db = _open_db(db->hdb_name, flags, mode, &db1->lock_fd);
317 if(db->hdb_db == NULL) {
318 krb5_set_error_message(context, errno, "dbopen (%s): %s",
319 db->hdb_name, strerror(errno));
320 return errno;
321 }
322 if((flags & O_ACCMODE) == O_RDONLY)
323 ret = hdb_check_db_format(context, db);
324 else
325 ret = hdb_init_db(context, db);
326 if(ret == HDB_ERR_NOENTRY) {
327 krb5_clear_error_message(context);
328 return 0;
329 }
330 if (ret) {
331 DB_close(context, db);
332 krb5_set_error_message(context, ret, "hdb_open: failed %s database %s",
333 (flags & O_ACCMODE) == O_RDONLY ?
334 "checking format of" : "initialize",
335 db->hdb_name);
336 }
337 return ret;
338}
339
340krb5_error_code
341hdb_db1_create(krb5_context context, HDB **db,
342 const char *filename)
343{
344 DB1_HDB **db1 = (DB1_HDB **)db;
345 *db = calloc(1, sizeof(**db1)); /* Allocate space for the larger db1 */
346 if (*db == NULL) {
347 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
348 return ENOMEM;
349 }
350
351 (*db)->hdb_db = NULL;
352 (*db)->hdb_name = strdup(filename);
353 if ((*db)->hdb_name == NULL) {
354 free(*db);
355 *db = NULL;
356 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
357 return ENOMEM;
358 }
359 (*db)->hdb_master_key_set = 0;
360 (*db)->hdb_openp = 0;
361 (*db)->hdb_capability_flags = HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL;
362 (*db)->hdb_open = DB_open;
363 (*db)->hdb_close = DB_close;
364 (*db)->hdb_fetch_kvno = _hdb_fetch_kvno;
365 (*db)->hdb_store = _hdb_store;
366 (*db)->hdb_remove = _hdb_remove;
367 (*db)->hdb_firstkey = DB_firstkey;
368 (*db)->hdb_nextkey= DB_nextkey;
369 (*db)->hdb_lock = DB_lock;
370 (*db)->hdb_unlock = DB_unlock;
371 (*db)->hdb_rename = DB_rename;
372 (*db)->hdb__get = DB__get;
373 (*db)->hdb__put = DB__put;
374 (*db)->hdb__del = DB__del;
375 (*db)->hdb_destroy = DB_destroy;
376
377 (*db1)->lock_fd = -1;
378 return 0;
379}
380
381#endif /* defined(HAVE_DB1) */
382