xref: /freebsd/crypto/heimdal/lib/hdb/ndbm.c (revision daf1cffce2e07931f27c6c6998652e90df6ba87e)
1 /*
2  * Copyright (c) 1997, 1998, 1999 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.26 1999/12/02 17:05:05 joda Exp $");
37 
38 #ifdef HAVE_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;
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 	hdb_unseal_keys (db, entry);
98     if (entry->principal == NULL) {
99 	entry->principal = malloc (sizeof(*entry->principal));
100 	hdb_key2principal (context, &key_data, entry->principal);
101     }
102     return 0;
103 }
104 
105 
106 static krb5_error_code
107 NDBM_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
108 {
109     return NDBM_seq(context, db, flags, entry, 1);
110 }
111 
112 
113 static krb5_error_code
114 NDBM_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
115 {
116     return NDBM_seq(context, db, flags, entry, 0);
117 }
118 
119 static krb5_error_code
120 NDBM_rename(krb5_context context, HDB *db, const char *new_name)
121 {
122     /* XXX this function will break */
123     struct ndbm_db *d = db->db;
124 
125     int ret;
126     char *old_dir, *old_pag, *new_dir, *new_pag;
127     char *new_lock;
128     int lock_fd;
129 
130     /* lock old and new databases */
131     ret = db->lock(context, db, HDB_WLOCK);
132     if(ret) return ret;
133     asprintf(&new_lock, "%s.lock", new_name);
134     lock_fd = open(new_lock, O_RDWR | O_CREAT, 0600);
135     free(new_lock);
136     if(lock_fd < 0) {
137 	ret = errno;
138 	db->unlock(context, db);
139 	return ret;
140     }
141     ret = hdb_lock(lock_fd, HDB_WLOCK);
142     if(ret) {
143 	db->unlock(context, db);
144 	close(lock_fd);
145 	return ret;
146     }
147 
148     asprintf(&old_dir, "%s.dir", db->name);
149     asprintf(&old_pag, "%s.pag", db->name);
150     asprintf(&new_dir, "%s.dir", new_name);
151     asprintf(&new_pag, "%s.pag", new_name);
152 
153     ret = rename(old_dir, new_dir) || rename(old_pag, new_pag);
154     free(old_dir);
155     free(old_pag);
156     free(new_dir);
157     free(new_pag);
158     hdb_unlock(lock_fd);
159     db->unlock(context, db);
160 
161     if(ret) {
162 	close(lock_fd);
163 	return errno;
164     }
165 
166     close(d->lock_fd);
167     d->lock_fd = lock_fd;
168 
169     free(db->name);
170     db->name = strdup(new_name);
171     return 0;
172 }
173 
174 static krb5_error_code
175 NDBM__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply)
176 {
177     struct ndbm_db *d = (struct ndbm_db *)db->db;
178     datum k, v;
179     int code;
180 
181     k.dptr  = key.data;
182     k.dsize = key.length;
183     code = db->lock(context, db, HDB_RLOCK);
184     if(code)
185 	return code;
186     v = dbm_fetch(d->db, k);
187     db->unlock(context, db);
188     if(v.dptr == NULL)
189 	return HDB_ERR_NOENTRY;
190 
191     krb5_data_copy(reply, v.dptr, v.dsize);
192     return 0;
193 }
194 
195 static krb5_error_code
196 NDBM__put(krb5_context context, HDB *db, int replace,
197 	krb5_data key, krb5_data value)
198 {
199     struct ndbm_db *d = (struct ndbm_db *)db->db;
200     datum k, v;
201     int code;
202 
203     k.dptr  = key.data;
204     k.dsize = key.length;
205     v.dptr  = value.data;
206     v.dsize = value.length;
207 
208     code = db->lock(context, db, HDB_WLOCK);
209     if(code)
210 	return code;
211     code = dbm_store(d->db, k, v, replace ? DBM_REPLACE : DBM_INSERT);
212     db->unlock(context, db);
213     if(code == 1)
214 	return HDB_ERR_EXISTS;
215     if (code < 0)
216 	return code;
217     return 0;
218 }
219 
220 static krb5_error_code
221 NDBM__del(krb5_context context, HDB *db, krb5_data key)
222 {
223     struct ndbm_db *d = (struct ndbm_db *)db->db;
224     datum k;
225     int code;
226     krb5_error_code ret;
227 
228     k.dptr = key.data;
229     k.dsize = key.length;
230     ret = db->lock(context, db, HDB_WLOCK);
231     if(ret) return ret;
232     code = dbm_delete(d->db, k);
233     db->unlock(context, db);
234     if(code < 0)
235 	return errno;
236     return 0;
237 }
238 
239 static krb5_error_code
240 NDBM_open(krb5_context context, HDB *db, int flags, mode_t mode)
241 {
242     krb5_error_code ret;
243     struct ndbm_db *d = malloc(sizeof(*d));
244     char *lock_file;
245 
246     if(d == NULL)
247 	return ENOMEM;
248     asprintf(&lock_file, "%s.lock", (char*)db->name);
249     if(lock_file == NULL) {
250 	free(d);
251 	return ENOMEM;
252     }
253     d->db = dbm_open((char*)db->name, flags, mode);
254     if(d->db == NULL){
255 	free(d);
256 	free(lock_file);
257 	return errno;
258     }
259     d->lock_fd = open(lock_file, O_RDWR | O_CREAT, 0600);
260     free(lock_file);
261     if(d->lock_fd < 0){
262 	dbm_close(d->db);
263 	free(d);
264 	return errno;
265     }
266     db->db = d;
267     if((flags & O_ACCMODE) == O_RDONLY)
268 	ret = hdb_check_db_format(context, db);
269     else
270 	ret = hdb_init_db(context, db);
271     if(ret == HDB_ERR_NOENTRY)
272 	return 0;
273     return ret;
274 }
275 
276 static krb5_error_code
277 NDBM_close(krb5_context context, HDB *db)
278 {
279     struct ndbm_db *d = db->db;
280     dbm_close(d->db);
281     close(d->lock_fd);
282     free(d);
283     return 0;
284 }
285 
286 krb5_error_code
287 hdb_ndbm_create(krb5_context context, HDB **db,
288 		const char *filename)
289 {
290     *db = malloc(sizeof(**db));
291     if (*db == NULL)
292 	return ENOMEM;
293 
294     (*db)->db = NULL;
295     (*db)->name = strdup(filename);
296     (*db)->master_key_set = 0;
297     (*db)->openp = 0;
298     (*db)->open = NDBM_open;
299     (*db)->close = NDBM_close;
300     (*db)->fetch = _hdb_fetch;
301     (*db)->store = _hdb_store;
302     (*db)->remove = _hdb_remove;
303     (*db)->firstkey = NDBM_firstkey;
304     (*db)->nextkey= NDBM_nextkey;
305     (*db)->lock = NDBM_lock;
306     (*db)->unlock = NDBM_unlock;
307     (*db)->rename = NDBM_rename;
308     (*db)->_get = NDBM__get;
309     (*db)->_put = NDBM__put;
310     (*db)->_del = NDBM__del;
311     (*db)->destroy = NDBM_destroy;
312     return 0;
313 }
314 
315 
316 #endif
317