This commit was manufactured by cvs2svn to create tag
[heimdal.git] / lib / hdb / ndbm.c
blobf350a2d23e37490e06bcd3f700c6eb842a72d5f4
1 /*
2 * Copyright (c) 1997, 1998, 1999 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Kungliga Tekniska
20 * Högskolan and its contributors.
22 * 4. Neither the name of the Institute nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
39 #include "hdb_locl.h"
41 RCSID("$Id$");
43 #ifdef HAVE_NDBM_H
45 struct ndbm_db {
46 DBM *db;
47 int lock_fd;
50 static krb5_error_code
51 NDBM_destroy(krb5_context context, HDB *db)
53 krb5_error_code ret;
55 ret = hdb_clear_master_key (context, db);
56 free(db->name);
57 free(db);
58 return 0;
61 static krb5_error_code
62 NDBM_lock(krb5_context context, HDB *db, int operation)
64 struct ndbm_db *d = db->db;
65 return hdb_lock(d->lock_fd, operation);
68 static krb5_error_code
69 NDBM_unlock(krb5_context context, HDB *db)
71 struct ndbm_db *d = db->db;
72 return hdb_unlock(d->lock_fd);
75 static krb5_error_code
76 NDBM_seq(krb5_context context, HDB *db,
77 unsigned flags, hdb_entry *entry, int first)
80 struct ndbm_db *d = (struct ndbm_db *)db->db;
81 datum key, value;
82 krb5_data key_data, data;
83 krb5_error_code ret;
85 if(first)
86 key = dbm_firstkey(d->db);
87 else
88 key = dbm_nextkey(d->db);
89 if(key.dptr == NULL)
90 return HDB_ERR_NOENTRY;
91 key_data.data = key.dptr;
92 key_data.length = key.dsize;
93 ret = db->lock(context, db, HDB_RLOCK);
94 if(ret) return ret;
95 value = dbm_fetch(d->db, key);
96 db->unlock(context, db);
97 data.data = value.dptr;
98 data.length = value.dsize;
99 if(hdb_value2entry(context, &data, entry))
100 return NDBM_seq(context, db, flags, entry, 0);
101 if (db->master_key_set && (flags & HDB_F_DECRYPT))
102 hdb_unseal_keys (db, entry);
103 if (entry->principal == NULL) {
104 entry->principal = malloc (sizeof(*entry->principal));
105 hdb_key2principal (context, &key_data, entry->principal);
107 return 0;
111 static krb5_error_code
112 NDBM_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
114 return NDBM_seq(context, db, flags, entry, 1);
118 static krb5_error_code
119 NDBM_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
121 return NDBM_seq(context, db, flags, entry, 0);
124 static krb5_error_code
125 NDBM_rename(krb5_context context, HDB *db, const char *new_name)
127 /* XXX this function will break */
128 struct ndbm_db *d = db->db;
130 int ret;
131 char *old_dir, *old_pag, *new_dir, *new_pag;
132 char *new_lock;
133 int lock_fd;
135 /* lock old and new databases */
136 ret = db->lock(context, db, HDB_WLOCK);
137 if(ret) return ret;
138 asprintf(&new_lock, "%s.lock", new_name);
139 lock_fd = open(new_lock, O_RDWR | O_CREAT, 0600);
140 free(new_lock);
141 if(lock_fd < 0) {
142 ret = errno;
143 db->unlock(context, db);
144 return ret;
146 ret = hdb_lock(lock_fd, HDB_WLOCK);
147 if(ret) {
148 db->unlock(context, db);
149 close(lock_fd);
150 return ret;
153 asprintf(&old_dir, "%s.dir", db->name);
154 asprintf(&old_pag, "%s.pag", db->name);
155 asprintf(&new_dir, "%s.dir", new_name);
156 asprintf(&new_pag, "%s.pag", new_name);
158 ret = rename(old_dir, new_dir) || rename(old_pag, new_pag);
159 free(old_dir);
160 free(old_pag);
161 free(new_dir);
162 free(new_pag);
163 hdb_unlock(lock_fd);
164 db->unlock(context, db);
166 if(ret) {
167 close(lock_fd);
168 return errno;
171 close(d->lock_fd);
172 d->lock_fd = lock_fd;
174 free(db->name);
175 db->name = strdup(new_name);
176 return 0;
179 static krb5_error_code
180 NDBM__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply)
182 struct ndbm_db *d = (struct ndbm_db *)db->db;
183 datum k, v;
184 int code;
186 k.dptr = key.data;
187 k.dsize = key.length;
188 code = db->lock(context, db, HDB_RLOCK);
189 if(code)
190 return code;
191 v = dbm_fetch(d->db, k);
192 db->unlock(context, db);
193 if(v.dptr == NULL)
194 return HDB_ERR_NOENTRY;
196 krb5_data_copy(reply, v.dptr, v.dsize);
197 return 0;
200 static krb5_error_code
201 NDBM__put(krb5_context context, HDB *db, int replace,
202 krb5_data key, krb5_data value)
204 struct ndbm_db *d = (struct ndbm_db *)db->db;
205 datum k, v;
206 int code;
208 k.dptr = key.data;
209 k.dsize = key.length;
210 v.dptr = value.data;
211 v.dsize = value.length;
213 code = db->lock(context, db, HDB_WLOCK);
214 if(code)
215 return code;
216 code = dbm_store(d->db, k, v, replace ? DBM_REPLACE : DBM_INSERT);
217 db->unlock(context, db);
218 if(code == 1)
219 return HDB_ERR_EXISTS;
220 if (code < 0)
221 return code;
222 return 0;
225 static krb5_error_code
226 NDBM__del(krb5_context context, HDB *db, krb5_data key)
228 struct ndbm_db *d = (struct ndbm_db *)db->db;
229 datum k;
230 int code;
231 krb5_error_code ret;
233 k.dptr = key.data;
234 k.dsize = key.length;
235 ret = db->lock(context, db, HDB_WLOCK);
236 if(ret) return ret;
237 code = dbm_delete(d->db, k);
238 db->unlock(context, db);
239 if(code < 0)
240 return errno;
241 return 0;
244 static krb5_error_code
245 NDBM_open(krb5_context context, HDB *db, int flags, mode_t mode)
247 krb5_error_code ret;
248 struct ndbm_db *d = malloc(sizeof(*d));
249 char *lock_file;
251 if(d == NULL)
252 return ENOMEM;
253 asprintf(&lock_file, "%s.lock", (char*)db->name);
254 if(lock_file == NULL) {
255 free(d);
256 return ENOMEM;
258 d->db = dbm_open((char*)db->name, flags, mode);
259 if(d->db == NULL){
260 free(d);
261 free(lock_file);
262 return errno;
264 d->lock_fd = open(lock_file, O_RDWR | O_CREAT, 0600);
265 free(lock_file);
266 if(d->lock_fd < 0){
267 dbm_close(d->db);
268 free(d);
269 return errno;
271 db->db = d;
272 if((flags & O_ACCMODE) == O_RDONLY)
273 ret = hdb_check_db_format(context, db);
274 else
275 ret = hdb_init_db(context, db);
276 if(ret == HDB_ERR_NOENTRY)
277 return 0;
278 return ret;
281 static krb5_error_code
282 NDBM_close(krb5_context context, HDB *db)
284 struct ndbm_db *d = db->db;
285 dbm_close(d->db);
286 close(d->lock_fd);
287 free(d);
288 return 0;
291 krb5_error_code
292 hdb_ndbm_create(krb5_context context, HDB **db,
293 const char *filename)
295 *db = malloc(sizeof(**db));
296 if (*db == NULL)
297 return ENOMEM;
299 (*db)->db = NULL;
300 (*db)->name = strdup(filename);
301 (*db)->master_key_set = 0;
302 (*db)->openp = 0;
303 (*db)->open = NDBM_open;
304 (*db)->close = NDBM_close;
305 (*db)->fetch = _hdb_fetch;
306 (*db)->store = _hdb_store;
307 (*db)->remove = _hdb_remove;
308 (*db)->firstkey = NDBM_firstkey;
309 (*db)->nextkey= NDBM_nextkey;
310 (*db)->lock = NDBM_lock;
311 (*db)->unlock = NDBM_unlock;
312 (*db)->rename = NDBM_rename;
313 (*db)->_get = NDBM__get;
314 (*db)->_put = NDBM__put;
315 (*db)->_del = NDBM__del;
316 (*db)->destroy = NDBM_destroy;
317 return 0;
321 #endif