lib/gssapi/krb5: implement GSS_C_CHANNEL_BOUND_FLAG for gss_init_sec_context()
[heimdal.git] / lib / hdb / ndbm.c
blob52c52c890dc0f5e7501195b930a440defa6fad7d
1 /*
2 * Copyright (c) 1997 - 2001 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. 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.
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.
34 #include "hdb_locl.h"
36 #if HAVE_NDBM
38 #if defined(HAVE_GDBM_NDBM_H)
39 #include <gdbm/ndbm.h>
40 #define WRITE_SUPPORT 1
41 #elif defined(HAVE_NDBM_H)
42 #include <ndbm.h>
43 #elif defined(HAVE_DBM_H)
44 #define WRITE_SUPPORT 1
45 #include <dbm.h>
46 #endif
48 struct ndbm_db {
49 DBM *db;
50 int lock_fd;
53 static krb5_error_code
54 NDBM_destroy(krb5_context context, HDB *db)
56 hdb_clear_master_key(context, db);
57 krb5_config_free_strings(db->virtual_hostbased_princ_svcs);
58 free(db->hdb_name);
59 free(db);
60 return 0;
63 static krb5_error_code
64 NDBM_lock(krb5_context context, HDB *db, int operation)
66 struct ndbm_db *d = db->hdb_db;
67 return hdb_lock(d->lock_fd, operation);
70 static krb5_error_code
71 NDBM_unlock(krb5_context context, HDB *db)
73 struct ndbm_db *d = db->hdb_db;
74 return hdb_unlock(d->lock_fd);
77 static krb5_error_code
78 NDBM_seq(krb5_context context, HDB *db,
79 unsigned flags, hdb_entry *entry, int first)
82 struct ndbm_db *d = (struct ndbm_db *)db->hdb_db;
83 datum key, value;
84 krb5_data key_data, data;
85 krb5_error_code ret = 0;
87 if(first)
88 key = dbm_firstkey(d->db);
89 else
90 key = dbm_nextkey(d->db);
91 if(key.dptr == NULL)
92 return HDB_ERR_NOENTRY;
93 key_data.data = key.dptr;
94 key_data.length = key.dsize;
95 ret = db->hdb_lock(context, db, HDB_RLOCK);
96 if(ret) return ret;
97 value = dbm_fetch(d->db, key);
98 db->hdb_unlock(context, db);
99 data.data = value.dptr;
100 data.length = value.dsize;
101 memset(entry, 0, sizeof(*entry));
102 if(hdb_value2entry(context, &data, entry))
103 return NDBM_seq(context, db, flags, entry, 0);
104 if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
105 ret = hdb_unseal_keys (context, db, entry);
106 if (ret)
107 hdb_free_entry (context, db, entry);
109 if (ret == 0 && entry->principal == NULL) {
110 entry->principal = malloc (sizeof(*entry->principal));
111 if (entry->principal == NULL) {
112 hdb_free_entry (context, db, entry);
113 ret = ENOMEM;
114 krb5_set_error_message(context, ret, "malloc: out of memory");
115 } else {
116 hdb_key2principal (context, &key_data, entry->principal);
119 return ret;
123 static krb5_error_code
124 NDBM_firstkey(krb5_context context, HDB *db,unsigned flags,hdb_entry *entry)
126 return NDBM_seq(context, db, flags, entry, 1);
130 static krb5_error_code
131 NDBM_nextkey(krb5_context context, HDB *db, unsigned flags,hdb_entry *entry)
133 return NDBM_seq(context, db, flags, entry, 0);
136 static krb5_error_code
137 open_lock_file(krb5_context context, const char *db_name, int *fd)
139 char *lock_file;
140 int ret = 0;
142 /* lock old and new databases */
143 if (asprintf(&lock_file, "%s.lock", db_name) == -1) {
144 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
145 return ENOMEM;
148 *fd = open(lock_file, O_RDWR | O_CREAT, 0600);
149 if(*fd < 0) {
150 ret = errno;
151 krb5_set_error_message(context, ret, "open(%s): %s", lock_file,
152 strerror(ret));
154 free(lock_file);
155 return ret;
159 static krb5_error_code
160 NDBM_rename(krb5_context context, HDB *db, const char *new_name)
162 int ret;
163 char *old_dir = NULL, *old_pag = NULL;
164 char *new_dir = NULL, *new_pag = NULL;
165 int old_lock_fd, new_lock_fd;
167 /* lock old and new databases */
168 ret = open_lock_file(context, db->hdb_name, &old_lock_fd);
169 if (ret)
170 return ret;
172 ret = hdb_lock(old_lock_fd, HDB_WLOCK);
173 if(ret) {
174 close(old_lock_fd);
175 return ret;
178 ret = open_lock_file(context, new_name, &new_lock_fd);
179 if (ret) {
180 hdb_unlock(old_lock_fd);
181 close(old_lock_fd);
182 return ret;
185 ret = hdb_lock(new_lock_fd, HDB_WLOCK);
186 if(ret) {
187 hdb_unlock(old_lock_fd);
188 close(old_lock_fd);
189 close(new_lock_fd);
190 return ret;
193 if (asprintf(&old_dir, "%s.dir", db->hdb_name) == -1) {
194 old_dir = NULL;
195 ret = ENOMEM;
196 goto out;
198 if (asprintf(&old_pag, "%s.pag", db->hdb_name) == -1) {
199 old_pag = NULL;
200 ret = ENOMEM;
201 goto out;
203 if (asprintf(&new_dir, "%s.dir", new_name) == -1) {
204 new_dir = NULL;
205 ret = ENOMEM;
206 goto out;
208 if (asprintf(&new_pag, "%s.pag", new_name) == -1) {
209 new_pag = NULL;
210 ret = ENOMEM;
211 goto out;
214 ret = rename(old_dir, new_dir) || rename(old_pag, new_pag);
215 if (ret) {
216 ret = errno;
217 if (ret == 0)
218 ret = EPERM;
219 krb5_set_error_message(context, ret, "rename: %s", strerror(ret));
222 out:
223 free(old_dir);
224 free(old_pag);
225 free(new_dir);
226 free(new_pag);
228 hdb_unlock(new_lock_fd);
229 hdb_unlock(old_lock_fd);
230 close(new_lock_fd);
231 close(old_lock_fd);
233 if(ret)
234 return ret;
236 free(db->hdb_name);
237 db->hdb_name = strdup(new_name);
238 return 0;
241 static krb5_error_code
242 NDBM__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply)
244 struct ndbm_db *d = (struct ndbm_db *)db->hdb_db;
245 datum k, v;
246 int code;
248 k.dptr = key.data;
249 k.dsize = key.length;
250 code = db->hdb_lock(context, db, HDB_RLOCK);
251 if(code)
252 return code;
253 v = dbm_fetch(d->db, k);
254 db->hdb_unlock(context, db);
255 if(v.dptr == NULL)
256 return HDB_ERR_NOENTRY;
258 krb5_data_copy(reply, v.dptr, v.dsize);
259 return 0;
262 static krb5_error_code
263 NDBM__put(krb5_context context, HDB *db, int replace,
264 krb5_data key, krb5_data value)
266 #ifdef WRITE_SUPPORT
267 struct ndbm_db *d = (struct ndbm_db *)db->hdb_db;
268 datum k, v;
269 int code;
271 k.dptr = key.data;
272 k.dsize = key.length;
273 v.dptr = value.data;
274 v.dsize = value.length;
276 code = db->hdb_lock(context, db, HDB_WLOCK);
277 if(code)
278 return code;
279 code = dbm_store(d->db, k, v, replace ? DBM_REPLACE : DBM_INSERT);
280 db->hdb_unlock(context, db);
281 if(code == 1)
282 return HDB_ERR_EXISTS;
283 if (code < 0)
284 return code;
285 return 0;
286 #else
287 return HDB_ERR_NO_WRITE_SUPPORT;
288 #endif
291 static krb5_error_code
292 NDBM__del(krb5_context context, HDB *db, krb5_data key)
294 struct ndbm_db *d = (struct ndbm_db *)db->hdb_db;
295 datum k;
296 int code;
297 krb5_error_code ret;
299 k.dptr = key.data;
300 k.dsize = key.length;
301 ret = db->hdb_lock(context, db, HDB_WLOCK);
302 if(ret) return ret;
303 code = dbm_delete(d->db, k);
304 db->hdb_unlock(context, db);
305 if(code < 0)
306 return errno;
307 return 0;
311 static krb5_error_code
312 NDBM_close(krb5_context context, HDB *db)
314 struct ndbm_db *d = db->hdb_db;
315 dbm_close(d->db);
316 close(d->lock_fd);
317 free(d);
318 return 0;
321 static krb5_error_code
322 NDBM_open(krb5_context context, HDB *db, int flags, mode_t mode)
324 krb5_error_code ret;
325 struct ndbm_db *d = malloc(sizeof(*d));
327 if(d == NULL) {
328 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
329 return ENOMEM;
332 d->db = dbm_open((char*)db->hdb_name, flags, mode);
333 if(d->db == NULL){
334 ret = errno;
335 free(d);
336 krb5_set_error_message(context, ret, "dbm_open(%s): %s", db->hdb_name,
337 strerror(ret));
338 return ret;
341 ret = open_lock_file(context, db->hdb_name, &d->lock_fd);
342 if (ret) {
343 ret = errno;
344 dbm_close(d->db);
345 free(d);
346 krb5_set_error_message(context, ret, "open(lock file): %s",
347 strerror(ret));
348 return ret;
351 db->hdb_db = d;
352 if((flags & O_ACCMODE) == O_RDONLY)
353 ret = hdb_check_db_format(context, db);
354 else
355 ret = hdb_init_db(context, db);
356 if(ret == HDB_ERR_NOENTRY)
357 return 0;
358 if (ret) {
359 NDBM_close(context, db);
360 krb5_set_error_message(context, ret, "hdb_open: failed %s database %s",
361 (flags & O_ACCMODE) == O_RDONLY ?
362 "checking format of" : "initialize",
363 db->hdb_name);
365 return ret;
368 krb5_error_code
369 hdb_ndbm_create(krb5_context context, HDB **db,
370 const char *filename)
372 *db = calloc(1, sizeof(**db));
373 if (*db == NULL) {
374 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
375 return ENOMEM;
378 (*db)->hdb_db = NULL;
379 (*db)->hdb_name = strdup(filename);
380 if ((*db)->hdb_name == NULL) {
381 free(*db);
382 *db = NULL;
383 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
384 return ENOMEM;
386 (*db)->hdb_master_key_set = 0;
387 (*db)->hdb_openp = 0;
388 (*db)->hdb_capability_flags = HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL;
389 (*db)->hdb_open = NDBM_open;
390 (*db)->hdb_close = NDBM_close;
391 (*db)->hdb_fetch_kvno = _hdb_fetch_kvno;
392 (*db)->hdb_store = _hdb_store;
393 (*db)->hdb_remove = _hdb_remove;
394 (*db)->hdb_firstkey = NDBM_firstkey;
395 (*db)->hdb_nextkey= NDBM_nextkey;
396 (*db)->hdb_lock = NDBM_lock;
397 (*db)->hdb_unlock = NDBM_unlock;
398 (*db)->hdb_rename = NDBM_rename;
399 (*db)->hdb__get = NDBM__get;
400 (*db)->hdb__put = NDBM__put;
401 (*db)->hdb__del = NDBM__del;
402 (*db)->hdb_destroy = NDBM_destroy;
403 return 0;
406 #endif /* HAVE_NDBM */