1 /* db_berkeley.c--SASL berkeley db interface
4 * $Id: db_berkeley.c,v 1.8 2006/04/03 10:58:19 mel Exp $
7 * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
21 * 3. The name "Carnegie Mellon University" must not be used to
22 * endorse or promote products derived from this software without
23 * prior written permission. For permission or any other legal
24 * details, please contact
25 * Office of Technology Transfer
26 * Carnegie Mellon University
28 * Pittsburgh, PA 15213-3890
29 * (412) 268-4387, fax: (412) 268-7395
30 * tech-transfer@andrew.cmu.edu
32 * 4. Redistributions of any form whatsoever must retain the following
34 * "This product includes software developed by Computing Services
35 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
37 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
38 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
39 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
40 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
41 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
42 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
43 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
56 #if defined(KEEP_DB_OPEN)
57 static DB * g_db = NULL;
63 static int berkeleydb_open(const sasl_utils_t *utils,
67 const char *path = SASL_DB_PATH;
71 sasl_getopt_t *getopt;
73 #if defined(KEEP_DB_OPEN)
80 if (utils->getcallback(conn, SASL_CB_GETOPT,
81 &getopt, &cntxt) == SASL_OK) {
83 if (getopt(cntxt, NULL, "sasldb_path", &p, NULL) == SASL_OK
84 && p != NULL && *p != 0) {
89 if (rdwr) flags = DB_CREATE;
90 else flags = DB_RDONLY;
91 #if defined(KEEP_DB_OPEN)
92 #if defined(DB_THREAD)
97 #if DB_VERSION_MAJOR < 3
98 ret = db_open(path, DB_HASH, flags, 0660, NULL, NULL, mbdb);
99 #else /* DB_VERSION_MAJOR < 3 */
100 ret = db_create(mbdb, NULL, 0);
101 if (ret == 0 && *mbdb != NULL)
103 #if DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1
104 ret = (*mbdb)->open(*mbdb, NULL, path, NULL, DB_HASH, flags, 0660);
106 ret = (*mbdb)->open(*mbdb, path, NULL, DB_HASH, flags, 0660);
110 (void) (*mbdb)->close(*mbdb, 0);
114 #endif /* DB_VERSION_MAJOR < 3 */
117 utils->log(conn, SASL_LOG_ERR,
118 "unable to open Berkeley db %s: %s",
119 path, db_strerror(ret));
120 utils->seterror(conn, SASL_NOLOG, "Unable to open DB");
124 #if defined(KEEP_DB_OPEN)
125 /* Save the DB handle for later use */
134 static void berkeleydb_close(const sasl_utils_t *utils, DB *mbdb)
138 #if defined(KEEP_DB_OPEN)
139 /* Prevent other threads from reusing the same handle */
144 ret = mbdb->close(mbdb, 0);
147 utils->log(NULL, SASL_LOG_ERR,
148 "error closing sasldb: %s",
155 * Retrieve the secret from the database.
157 * Return SASL_NOUSER if the entry doesn't exist,
158 * SASL_OK on success.
161 int _sasldb_getdata(const sasl_utils_t *utils,
162 sasl_conn_t *context,
163 const char *auth_identity,
165 const char *propName,
166 char *out, const size_t max_out, size_t *out_len)
168 int result = SASL_OK;
174 if(!utils) return SASL_BADPARAM;
176 /* check parameters */
177 if (!auth_identity || !realm || !propName || !out || !max_out) {
178 utils->seterror(context, 0,
179 "Bad parameter in db_berkeley.c: _sasldb_getdata");
180 return SASL_BADPARAM;
184 utils->seterror(context, 0,
185 "Database not checked");
190 result = _sasldb_alloc_key(utils, auth_identity, realm, propName,
192 if (result != SASL_OK) {
193 utils->seterror(context, 0,
194 "Could not allocate key in _sasldb_getdata");
199 memset(&dbkey, 0, sizeof(dbkey));
200 memset(&data, 0, sizeof(data));
203 result = berkeleydb_open(utils, context, 0, &mbdb);
204 if (result != SASL_OK) goto cleanup;
206 /* create the key to search for */
208 dbkey.size = (u_int32_t) key_len;
209 dbkey.flags = DB_DBT_USERMEM;
210 data.flags = DB_DBT_MALLOC;
212 /* ask berkeley db for the entry */
213 result = mbdb->get(mbdb, NULL, &dbkey, &data, 0);
221 result = SASL_NOUSER;
222 utils->seterror(context, SASL_NOLOG,
223 "user: %s@%s property: %s not found in sasldb",
224 auth_identity,realm,propName);
228 utils->seterror(context, 0,
229 "error fetching from sasldb: %s",
230 db_strerror(result));
236 if(data.size > max_out + 1)
239 if(out_len) *out_len = data.size;
240 memcpy(out, data.data, data.size);
241 out[data.size] = '\0';
245 #if !defined(KEEP_DB_OPEN)
246 if (mbdb != NULL) berkeleydb_close(utils, mbdb);
250 utils->free(data.data);
256 * Put or delete an entry
261 int _sasldb_putdata(const sasl_utils_t *utils,
262 sasl_conn_t *context,
265 const char *propName,
266 const char *data_in, size_t data_len)
268 int result = SASL_OK;
274 if (!utils) return SASL_BADPARAM;
276 if (!authid || !realm || !propName) {
277 utils->seterror(context, 0,
278 "Bad parameter in db_berkeley.c: _sasldb_putdata");
279 return SASL_BADPARAM;
283 utils->seterror(context, 0,
284 "Database not checked");
288 result = _sasldb_alloc_key(utils, authid, realm, propName,
290 if (result != SASL_OK) {
291 utils->seterror(context, 0,
292 "Could not allocate key in _sasldb_putdata");
297 result=berkeleydb_open(utils, context, 1, &mbdb);
298 if (result!=SASL_OK) goto cleanup;
300 /* create the db key */
301 memset(&dbkey, 0, sizeof(dbkey));
303 dbkey.size = (u_int32_t) key_len;
305 if (data_in) { /* putting secret */
308 memset(&data, 0, sizeof(data));
310 data.data = (char *)data_in;
311 if(!data_len) data_len = strlen(data_in);
312 data.size = (u_int32_t) data_len;
314 result = mbdb->put(mbdb, NULL, &dbkey, &data, 0);
318 utils->log(NULL, SASL_LOG_ERR,
319 "error updating sasldb: %s", db_strerror(result));
320 utils->seterror(context, SASL_NOLOG,
321 "Couldn't update db");
325 } else { /* removing secret */
326 result=mbdb->del(mbdb, NULL, &dbkey, 0);
330 utils->log(NULL, SASL_LOG_ERR,
331 "error deleting entry from sasldb: %s", db_strerror(result));
332 utils->seterror(context, SASL_NOLOG,
333 "Couldn't update db");
334 if (result == DB_NOTFOUND)
335 result = SASL_NOUSER;
344 #if !defined(KEEP_DB_OPEN)
345 if (mbdb != NULL) berkeleydb_close(utils, mbdb);
353 int _sasl_check_db(const sasl_utils_t *utils,
356 const char *path = SASL_DB_PATH;
359 sasl_getopt_t *getopt;
360 sasl_verifyfile_t *vf;
362 if (!utils) return SASL_BADPARAM;
364 if (utils->getcallback(conn, SASL_CB_GETOPT,
365 &getopt, &cntxt) == SASL_OK) {
367 if (getopt(cntxt, NULL, "sasldb_path", &p, NULL) == SASL_OK
368 && p != NULL && *p != 0) {
373 ret = utils->getcallback(conn, SASL_CB_VERIFYFILE,
375 if (ret != SASL_OK) {
376 utils->seterror(conn, 0, "verifyfile failed");
380 ret = vf(cntxt, path, SASL_VRFY_PASSWD);
382 if (ret == SASL_OK) {
386 if (ret == SASL_OK || ret == SASL_CONTINUE) {
393 #if defined(KEEP_DB_OPEN)
394 void sasldb_auxprop_free (void *glob_context,
395 const sasl_utils_t *utils)
397 if (g_db != NULL) berkeleydb_close(utils, g_db);
401 typedef struct berkeleydb_handle
407 sasldb_handle _sasldb_getkeyhandle(const sasl_utils_t *utils,
412 berkleyhandle_t *handle;
414 if(!utils || !conn) return NULL;
417 utils->seterror(conn, 0, "Database not OK in _sasldb_getkeyhandle");
421 ret = berkeleydb_open(utils, conn, 0, &mbdb);
423 if (ret != SASL_OK) {
427 handle = utils->malloc(sizeof(berkleyhandle_t));
429 #if !defined(KEEP_DB_OPEN)
430 (void)mbdb->close(mbdb, 0);
432 utils->seterror(conn, 0, "Memory error in _sasldb_gethandle");
437 handle->cursor = NULL;
439 return (sasldb_handle)handle;
442 int _sasldb_getnextkey(const sasl_utils_t *utils __attribute__((unused)),
443 sasldb_handle handle, char *out,
444 const size_t max_out, size_t *out_len)
448 berkleyhandle_t *dbh = (berkleyhandle_t *)handle;
451 if(!utils || !handle || !out || !max_out)
452 return SASL_BADPARAM;
456 memset(&key,0, sizeof(key));
457 memset(&data,0,sizeof(data));
461 #if DB_VERSION_MAJOR < 3
462 #if DB_VERSION_MINOR < 6
463 result = mbdb->cursor(mbdb, NULL,&dbh->cursor);
465 result = mbdb->cursor(mbdb, NULL,&dbh->cursor, 0);
466 #endif /* DB_VERSION_MINOR < 7 */
467 #else /* DB_VERSION_MAJOR < 3 */
468 result = mbdb->cursor(mbdb, NULL,&dbh->cursor, 0);
469 #endif /* DB_VERSION_MAJOR < 3 */
476 result = dbh->cursor->c_get(dbh->cursor, &key, &data,
479 result = dbh->cursor->c_get(dbh->cursor, &key, &data,
483 if (result == DB_NOTFOUND) return SASL_OK;
489 if (key.size > max_out) {
493 memcpy(out, key.data, key.size);
494 if (out_len) *out_len = key.size;
496 return SASL_CONTINUE;
500 int _sasldb_releasekeyhandle(const sasl_utils_t *utils,
501 sasldb_handle handle)
503 berkleyhandle_t *dbh = (berkleyhandle_t *)handle;
506 if (!utils || !dbh) return SASL_BADPARAM;
509 dbh->cursor->c_close(dbh->cursor);
512 #if !defined(KEEP_DB_OPEN)
513 /* This is almost the same berkeleydb_close(), except that
514 berkeleydb_close logs a message on error and does not return
517 ret = dbh->mbdb->close(dbh->mbdb, 0);