xref: /freebsd/crypto/heimdal/lib/hdb/ndbm.c (revision 6990ffd8a95caaba6858ad44ff1b3157d1efba8f)
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: ndbm.c,v 1.30 2001/01/30 01:24:00 assar Exp $");
37 
38 #if defined(HAVE_NDBM_H) || defined(HAVE_GDBM_NDBM_H)
39 
40 struct ndbm_db {
41     DBM *db;
42     int lock_fd;
43 };
44 
45 static krb5_error_code
46 NDBM_destroy(krb5_context context, HDB *db)
47 {
48     krb5_error_code ret;
49 
50     ret = hdb_clear_master_key (context, db);
51     free(db->name);
52     free(db);
53     return 0;
54 }
55 
56 static krb5_error_code
57 NDBM_lock(krb5_context context, HDB *db, int operation)
58 {
59     struct ndbm_db *d = db->db;
60     return hdb_lock(d->lock_fd, operation);
61 }
62 
63 static krb5_error_code
64 NDBM_unlock(krb5_context context, HDB *db)
65 {
66     struct ndbm_db *d = db->db;
67     return hdb_unlock(d->lock_fd);
68 }
69 
70 static krb5_error_code
71 NDBM_seq(krb5_context context, HDB *db,
72 	 unsigned flags, hdb_entry *entry, int first)
73 
74 {
75     struct ndbm_db *d = (struct ndbm_db *)db->db;
76     datum key, value;
77     krb5_data key_data, data;
78     krb5_error_code ret = 0;
79 
80     if(first)
81 	key = dbm_firstkey(d->db);
82     else
83 	key = dbm_nextkey(d->db);
84     if(key.dptr == NULL)
85 	return HDB_ERR_NOENTRY;
86     key_data.data = key.dptr;
87     key_data.length = key.dsize;
88     ret = db->lock(context, db, HDB_RLOCK);
89     if(ret) return ret;
90     value = dbm_fetch(d->db, key);
91     db->unlock(context, db);
92     data.data = value.dptr;
93     data.length = value.dsize;
94     if(hdb_value2entry(context, &data, entry))
95 	return NDBM_seq(context, db, flags, entry, 0);
96     if (db->master_key_set && (flags & HDB_F_DECRYPT)) {
97 	ret = hdb_unseal_keys (context, db, entry);
98 	if (ret)
99 	    hdb_free_entry (context, entry);
100     }
101     if (entry->principal == NULL) {
102 	entry->principal = malloc (sizeof(*entry->principal));
103 	if (entry->principal == NULL) {
104 	    ret = ENOMEM;
105 	    hdb_free_entry (context, entry);
106 	} else {
107 	    hdb_key2principal (context, &key_data, entry->principal);
108 	}
109     }
110     return ret;
111 }
112 
113 
114 static krb5_error_code
115 NDBM_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
116 {
117     return NDBM_seq(context, db, flags, entry, 1);
118 }
119 
120 
121 static krb5_error_code
122 NDBM_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
123 {
124     return NDBM_seq(context, db, flags, entry, 0);
125 }
126 
127 static krb5_error_code
128 NDBM_rename(krb5_context context, HDB *db, const char *new_name)
129 {
130     /* XXX this function will break */
131     struct ndbm_db *d = db->db;
132 
133     int ret;
134     char *old_dir, *old_pag, *new_dir, *new_pag;
135     char *new_lock;
136     int lock_fd;
137 
138     /* lock old and new databases */
139     ret = db->lock(context, db, HDB_WLOCK);
140     if(ret) return ret;
141     asprintf(&new_lock, "%s.lock", new_name);
142     lock_fd = open(new_lock, O_RDWR | O_CREAT, 0600);
143     free(new_lock);
144     if(lock_fd < 0) {
145 	ret = errno;
146 	db->unlock(context, db);
147 	return ret;
148     }
149     ret = hdb_lock(lock_fd, HDB_WLOCK);
150     if(ret) {
151 	db->unlock(context, db);
152 	close(lock_fd);
153 	return ret;
154     }
155 
156     asprintf(&old_dir, "%s.dir", db->name);
157     asprintf(&old_pag, "%s.pag", db->name);
158     asprintf(&new_dir, "%s.dir", new_name);
159     asprintf(&new_pag, "%s.pag", new_name);
160 
161     ret = rename(old_dir, new_dir) || rename(old_pag, new_pag);
162     free(old_dir);
163     free(old_pag);
164     free(new_dir);
165     free(new_pag);
166     hdb_unlock(lock_fd);
167     db->unlock(context, db);
168 
169     if(ret) {
170 	close(lock_fd);
171 	return errno;
172     }
173 
174     close(d->lock_fd);
175     d->lock_fd = lock_fd;
176 
177     free(db->name);
178     db->name = strdup(new_name);
179     return 0;
180 }
181 
182 static krb5_error_code
183 NDBM__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply)
184 {
185     struct ndbm_db *d = (struct ndbm_db *)db->db;
186     datum k, v;
187     int code;
188 
189     k.dptr  = key.data;
190     k.dsize = key.length;
191     code = db->lock(context, db, HDB_RLOCK);
192     if(code)
193 	return code;
194     v = dbm_fetch(d->db, k);
195     db->unlock(context, db);
196     if(v.dptr == NULL)
197 	return HDB_ERR_NOENTRY;
198 
199     krb5_data_copy(reply, v.dptr, v.dsize);
200     return 0;
201 }
202 
203 static krb5_error_code
204 NDBM__put(krb5_context context, HDB *db, int replace,
205 	krb5_data key, krb5_data value)
206 {
207     struct ndbm_db *d = (struct ndbm_db *)db->db;
208     datum k, v;
209     int code;
210 
211     k.dptr  = key.data;
212     k.dsize = key.length;
213     v.dptr  = value.data;
214     v.dsize = value.length;
215 
216     code = db->lock(context, db, HDB_WLOCK);
217     if(code)
218 	return code;
219     code = dbm_store(d->db, k, v, replace ? DBM_REPLACE : DBM_INSERT);
220     db->unlock(context, db);
221     if(code == 1)
222 	return HDB_ERR_EXISTS;
223     if (code < 0)
224 	return code;
225     return 0;
226 }
227 
228 static krb5_error_code
229 NDBM__del(krb5_context context, HDB *db, krb5_data key)
230 {
231     struct ndbm_db *d = (struct ndbm_db *)db->db;
232     datum k;
233     int code;
234     krb5_error_code ret;
235 
236     k.dptr = key.data;
237     k.dsize = key.length;
238     ret = db->lock(context, db, HDB_WLOCK);
239     if(ret) return ret;
240     code = dbm_delete(d->db, k);
241     db->unlock(context, db);
242     if(code < 0)
243 	return errno;
244     return 0;
245 }
246 
247 static krb5_error_code
248 NDBM_open(krb5_context context, HDB *db, int flags, mode_t mode)
249 {
250     krb5_error_code ret;
251     struct ndbm_db *d = malloc(sizeof(*d));
252     char *lock_file;
253 
254     if(d == NULL)
255 	return ENOMEM;
256     asprintf(&lock_file, "%s.lock", (char*)db->name);
257     if(lock_file == NULL) {
258 	free(d);
259 	return ENOMEM;
260     }
261     d->db = dbm_open((char*)db->name, flags, mode);
262     if(d->db == NULL){
263 	free(d);
264 	free(lock_file);
265 	return errno;
266     }
267     d->lock_fd = open(lock_file, O_RDWR | O_CREAT, 0600);
268     free(lock_file);
269     if(d->lock_fd < 0){
270 	dbm_close(d->db);
271 	free(d);
272 	return errno;
273     }
274     db->db = d;
275     if((flags & O_ACCMODE) == O_RDONLY)
276 	ret = hdb_check_db_format(context, db);
277     else
278 	ret = hdb_init_db(context, db);
279     if(ret == HDB_ERR_NOENTRY)
280 	return 0;
281     return ret;
282 }
283 
284 static krb5_error_code
285 NDBM_close(krb5_context context, HDB *db)
286 {
287     struct ndbm_db *d = db->db;
288     dbm_close(d->db);
289     close(d->lock_fd);
290     free(d);
291     return 0;
292 }
293 
294 krb5_error_code
295 hdb_ndbm_create(krb5_context context, HDB **db,
296 		const char *filename)
297 {
298     *db = malloc(sizeof(**db));
299     if (*db == NULL)
300 	return ENOMEM;
301 
302     (*db)->db = NULL;
303     (*db)->name = strdup(filename);
304     (*db)->master_key_set = 0;
305     (*db)->openp = 0;
306     (*db)->open = NDBM_open;
307     (*db)->close = NDBM_close;
308     (*db)->fetch = _hdb_fetch;
309     (*db)->store = _hdb_store;
310     (*db)->remove = _hdb_remove;
311     (*db)->firstkey = NDBM_firstkey;
312     (*db)->nextkey= NDBM_nextkey;
313     (*db)->lock = NDBM_lock;
314     (*db)->unlock = NDBM_unlock;
315     (*db)->rename = NDBM_rename;
316     (*db)->_get = NDBM__get;
317     (*db)->_put = NDBM__put;
318     (*db)->_del = NDBM__del;
319     (*db)->destroy = NDBM_destroy;
320     return 0;
321 }
322 
323 #endif
324