xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/hdb/db.c (revision 241bea01a19bbb306af27777a870b86d41cb3fda)
1 /*	$NetBSD: db.c,v 1.3 2019/12/15 22:50:49 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 
46 typedef struct {
47     HDB hdb;            /* generic members */
48     int lock_fd;        /* DB-specific */
49     int do_sync;        /* DB-specific */
50 } DB1_HDB;
51 
52 static krb5_error_code
DB_close(krb5_context context,HDB * db)53 DB_close(krb5_context context, HDB *db)
54 {
55     DB1_HDB *db1 = (DB1_HDB *)db;
56     DB *d = (DB*)db->hdb_db;
57 
58     heim_assert(d != 0, "Closing already closed HDB");
59 
60     (*d->close)(d);
61     db->hdb_db = 0;
62 
63     if (db1->lock_fd >= 0) {
64 	close(db1->lock_fd);
65 	db1->lock_fd = -1;
66     }
67 
68     return 0;
69 }
70 
71 static krb5_error_code
DB_destroy(krb5_context context,HDB * db)72 DB_destroy(krb5_context context, HDB *db)
73 {
74     krb5_error_code ret;
75 
76     ret = hdb_clear_master_key (context, db);
77     free(db->hdb_name);
78     free(db);
79     return ret;
80 }
81 
82 static krb5_error_code
DB_set_sync(krb5_context context,HDB * db,int on)83 DB_set_sync(krb5_context context, HDB *db, int on)
84 {
85     DB1_HDB *db1 = (DB1_HDB *)db;
86     DB *d = (DB*)db->hdb_db;
87     krb5_error_code ret = 0;
88 
89     db1->do_sync = on;
90     if (on) {
91         ret = (*d->sync)(d, 0);
92         if (ret == -1) {
93             ret = errno;
94             krb5_set_error_message(context, ret, "Database %s put sync error: %s",
95                                    db->hdb_name, strerror(ret));
96         }
97     }
98     return ret;
99 }
100 
101 static krb5_error_code
DB_lock(krb5_context context,HDB * db,int operation)102 DB_lock(krb5_context context, HDB *db, int operation)
103 {
104 
105     return 0;
106 }
107 
108 static krb5_error_code
DB_unlock(krb5_context context,HDB * db)109 DB_unlock(krb5_context context, HDB *db)
110 {
111 
112     return 0;
113 }
114 
115 
116 static krb5_error_code
DB_seq(krb5_context context,HDB * db,unsigned flags,hdb_entry_ex * entry,int flag)117 DB_seq(krb5_context context, HDB *db,
118        unsigned flags, hdb_entry_ex *entry, int flag)
119 {
120     DB *d = (DB*)db->hdb_db;
121     DBT key, value;
122     krb5_data key_data, data;
123     int code;
124 
125     code = (*d->seq)(d, &key, &value, flag);
126     if(code == -1) {
127 	code = errno;
128 	krb5_set_error_message(context, code, "Database %s seq error: %s",
129 			       db->hdb_name, strerror(code));
130 	return code;
131     }
132     if(code == 1) {
133 	krb5_clear_error_message(context);
134 	return HDB_ERR_NOENTRY;
135     }
136 
137     key_data.data = key.data;
138     key_data.length = key.size;
139     data.data = value.data;
140     data.length = value.size;
141     memset(entry, 0, sizeof(*entry));
142     if (hdb_value2entry(context, &data, &entry->entry))
143 	return DB_seq(context, db, flags, entry, R_NEXT);
144     if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
145 	code = hdb_unseal_keys (context, db, &entry->entry);
146 	if (code)
147 	    hdb_free_entry (context, entry);
148     }
149     if (code == 0 && entry->entry.principal == NULL) {
150 	entry->entry.principal = malloc(sizeof(*entry->entry.principal));
151 	if (entry->entry.principal == NULL) {
152 	    code = ENOMEM;
153 	    krb5_set_error_message(context, code, "malloc: out of memory");
154 	    hdb_free_entry (context, entry);
155 	} else {
156 	    hdb_key2principal(context, &key_data, entry->entry.principal);
157 	}
158     }
159     return code;
160 }
161 
162 
163 static krb5_error_code
DB_firstkey(krb5_context context,HDB * db,unsigned flags,hdb_entry_ex * entry)164 DB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
165 {
166     return DB_seq(context, db, flags, entry, R_FIRST);
167 }
168 
169 
170 static krb5_error_code
DB_nextkey(krb5_context context,HDB * db,unsigned flags,hdb_entry_ex * entry)171 DB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
172 {
173     return DB_seq(context, db, flags, entry, R_NEXT);
174 }
175 
176 static krb5_error_code
DB_rename(krb5_context context,HDB * db,const char * new_name)177 DB_rename(krb5_context context, HDB *db, const char *new_name)
178 {
179     int ret;
180     char *old, *new;
181 
182     if (strncmp(new_name, "db:", sizeof("db:") - 1) == 0)
183         new_name += sizeof("db:") - 1;
184     else if (strncmp(new_name, "db1:", sizeof("db1:") - 1) == 0)
185         new_name += sizeof("db1:") - 1;
186     asprintf(&old, "%s.db", db->hdb_name);
187     asprintf(&new, "%s.db", new_name);
188     ret = rename(old, new);
189     free(old);
190     free(new);
191     if(ret)
192 	return errno;
193 
194     free(db->hdb_name);
195     db->hdb_name = strdup(new_name);
196     return 0;
197 }
198 
199 static krb5_error_code
DB__get(krb5_context context,HDB * db,krb5_data key,krb5_data * reply)200 DB__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply)
201 {
202     DB *d = (DB*)db->hdb_db;
203     DBT k, v;
204     int code;
205 
206     k.data = key.data;
207     k.size = key.length;
208     code = (*d->get)(d, &k, &v, 0);
209     if(code < 0) {
210 	code = errno;
211 	krb5_set_error_message(context, code, "Database %s get error: %s",
212 			       db->hdb_name, strerror(code));
213 	return code;
214     }
215     if(code == 1) {
216 	krb5_clear_error_message(context);
217 	return HDB_ERR_NOENTRY;
218     }
219 
220     krb5_data_copy(reply, v.data, v.size);
221     return 0;
222 }
223 
224 static krb5_error_code
DB__put(krb5_context context,HDB * db,int replace,krb5_data key,krb5_data value)225 DB__put(krb5_context context, HDB *db, int replace,
226 	krb5_data key, krb5_data value)
227 {
228     DB1_HDB *db1 = (DB1_HDB *)db;
229     DB *d = (DB*)db->hdb_db;
230     DBT k, v;
231     int code;
232 
233     k.data = key.data;
234     k.size = key.length;
235     v.data = value.data;
236     v.size = value.length;
237     krb5_clear_error_message(context);
238     code = (*d->put)(d, &k, &v, replace ? 0 : R_NOOVERWRITE);
239     if(code < 0) {
240 	code = errno;
241 	krb5_set_error_message(context, code, "Database %s put error: %s",
242 			       db->hdb_name, strerror(code));
243 	return code;
244     }
245     if(code == 1) {
246 	return HDB_ERR_EXISTS;
247     }
248 
249     return db->hdb_set_sync(context, db, db1->do_sync);
250 }
251 
252 static krb5_error_code
DB__del(krb5_context context,HDB * db,krb5_data key)253 DB__del(krb5_context context, HDB *db, krb5_data key)
254 {
255     DB1_HDB *db1 = (DB1_HDB *)db;
256     DB *d = (DB*)db->hdb_db;
257     DBT k;
258     krb5_error_code code;
259     k.data = key.data;
260     k.size = key.length;
261     krb5_clear_error_message(context);
262     code = (*d->del)(d, &k, 0);
263     if (code == 1)
264         return HDB_ERR_NOENTRY;
265     if (code < 0) {
266 	code = errno;
267 	krb5_set_error_message(context, code, "Database %s del error: %s",
268 			       db->hdb_name, strerror(code));
269 	return code;
270     }
271     return db->hdb_set_sync(context, db, db1->do_sync);
272 }
273 
274 static DB *
_open_db(char * fn,int flags,int mode,int * fd)275 _open_db(char *fn, int flags, int mode, int *fd)
276 {
277 #ifndef O_EXLOCK
278     int op;
279     int ret;
280 
281     *fd = open(fn, flags, mode);
282     if (*fd == -1)
283 	return NULL;
284 
285     if ((flags & O_ACCMODE) == O_RDONLY)
286 	op = LOCK_SH;
287     else
288 	op = LOCK_EX;
289 
290     ret = flock(*fd, op);
291     if (ret == -1) {
292 	int saved_errno;
293 
294 	saved_errno = errno;
295 	close(*fd);
296 	errno = saved_errno;
297 	return NULL;
298     }
299 #else
300     if ((flags & O_ACCMODE) == O_RDONLY)
301 	flags |= O_SHLOCK;
302     else
303 	flags |= O_EXLOCK;
304 #endif
305 
306     return dbopen(fn, flags, mode, DB_BTREE, NULL);
307 }
308 
309 static krb5_error_code
DB_open(krb5_context context,HDB * db,int flags,mode_t mode)310 DB_open(krb5_context context, HDB *db, int flags, mode_t mode)
311 {
312     DB1_HDB *db1 = (DB1_HDB *)db;
313     char *fn;
314     krb5_error_code ret;
315 
316     asprintf(&fn, "%s.db", db->hdb_name);
317     if (fn == NULL) {
318 	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
319 	return ENOMEM;
320     }
321     db->hdb_db = _open_db(fn, flags, mode, &db1->lock_fd);
322     free(fn);
323     /* try to open without .db extension */
324     if(db->hdb_db == NULL && errno == ENOENT)
325 	db->hdb_db = _open_db(db->hdb_name, flags, mode, &db1->lock_fd);
326     if(db->hdb_db == NULL) {
327 	krb5_set_error_message(context, errno, "dbopen (%s): %s",
328 			      db->hdb_name, strerror(errno));
329 	return errno;
330     }
331     if((flags & O_ACCMODE) == O_RDONLY)
332 	ret = hdb_check_db_format(context, db);
333     else
334 	ret = hdb_init_db(context, db);
335     if(ret == HDB_ERR_NOENTRY) {
336 	krb5_clear_error_message(context);
337 	return 0;
338     }
339     if (ret) {
340 	DB_close(context, db);
341 	krb5_set_error_message(context, ret, "hdb_open: failed %s database %s",
342 			      (flags & O_ACCMODE) == O_RDONLY ?
343 			      "checking format of" : "initialize",
344 			      db->hdb_name);
345     }
346     return ret;
347 }
348 
349 krb5_error_code
hdb_db1_create(krb5_context context,HDB ** db,const char * filename)350 hdb_db1_create(krb5_context context, HDB **db,
351 	       const char *filename)
352 {
353     DB1_HDB **db1 = (DB1_HDB **)db;
354     *db = calloc(1, sizeof(**db1));	/* Allocate space for the larger db1 */
355     if (*db == NULL) {
356 	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
357 	return ENOMEM;
358     }
359 
360     (*db)->hdb_db = NULL;
361     (*db)->hdb_name = strdup(filename);
362     if ((*db)->hdb_name == NULL) {
363 	free(*db);
364 	*db = NULL;
365 	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
366 	return ENOMEM;
367     }
368     (*db)->hdb_master_key_set = 0;
369     (*db)->hdb_openp = 0;
370     (*db)->hdb_capability_flags = HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL;
371     (*db)->hdb_open = DB_open;
372     (*db)->hdb_close = DB_close;
373     (*db)->hdb_fetch_kvno = _hdb_fetch_kvno;
374     (*db)->hdb_store = _hdb_store;
375     (*db)->hdb_remove = _hdb_remove;
376     (*db)->hdb_firstkey = DB_firstkey;
377     (*db)->hdb_nextkey= DB_nextkey;
378     (*db)->hdb_lock = DB_lock;
379     (*db)->hdb_unlock = DB_unlock;
380     (*db)->hdb_rename = DB_rename;
381     (*db)->hdb__get = DB__get;
382     (*db)->hdb__put = DB__put;
383     (*db)->hdb__del = DB__del;
384     (*db)->hdb_destroy = DB_destroy;
385     (*db)->hdb_set_sync = DB_set_sync;
386 
387     (*db1)->lock_fd = -1;
388     (*db1)->do_sync = 1;
389     return 0;
390 }
391 
392 #endif /* defined(HAVE_DB1) */
393