Re: Patch status
Howard Chu <[email protected]>
| Newsgroups | gmane.comp.security.cyrus.sasl |
|---|---|
| Message-ID | <[email protected]> |
Howard Chu wrote: > Alexey Melnikov wrote: >> On 09/10/2012 23:10, Howard Chu wrote: >>> Speaking of new releases, I'd like to see some feedback/movement on >>> these patches... >>> >>> http://lists.andrew.cmu.edu/pipermail/cyrus-sasl/2012-March/002479.html >> If you add/update makefiles, the process would be much quicker. (And if >> you are not sure, ask). >>> http://lists.andrew.cmu.edu/pipermail/cyrus-sasl/2012-May/002490.html >> This one is in GIT already. > > Ah, I wasn't aware there was a git repo, I was still looking at CVS. > > I'll sync up with git and provide Makefiles/etc for the MDB patch shortly. > Updated patch... -- -- Howard Chu CTO, Symas Corp. http://www.symas.com Director, Highland Sun http://highlandsun.com/hyc/ Chief Architect, OpenLDAP http://www.openldap.org/project/
0001-Add-support-for-OpenLDAP-MDB.patch
(text/x-diff, 16.3 KB)
>From b106449b18200d3b176286575f76cbe5952e4f2a Mon Sep 17 00:00:00 2001 From: Howard Chu <[email protected]> Date: Fri, 12 Oct 2012 11:11:31 -0700 Subject: [PATCH] Add support for OpenLDAP MDB --- config/sasldb.m4 | 21 ++- configure.in | 10 +- doc/options.html | 26 +++ sasldb/Makefile.am | 2 +- sasldb/db_mdb.c | 468 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 519 insertions(+), 8 deletions(-) create mode 100644 sasldb/db_mdb.c diff --git a/config/sasldb.m4 b/config/sasldb.m4 index b28b087..e3c9016 100644 --- a/config/sasldb.m4 +++ b/config/sasldb.m4 @@ -5,7 +5,9 @@ dnl Berkeley DB specific checks first.. dnl Figure out what database type we're using AC_DEFUN([SASL_DB_CHECK], [ cmu_save_LIBS="$LIBS" -AC_ARG_WITH(dblib, [ --with-dblib=DBLIB set the DB library to use [berkeley] ], +AC_ARG_WITH(dblib, + [AC_HELP_STRING([--with-dblib={berkeley|gdbm|mdb|ndbm|none|auto_detect}], + [set the DB library to use [[berkeley]]])], dblib=$withval, dblib=auto_detect) @@ -43,6 +45,11 @@ dnl named. arg. fi esac ;; + mdb) + AC_CHECK_HEADER(mdb.h, [ + AC_CHECK_LIB(mdb, mdb_env_create, SASL_DB_LIB="-lmdb"; enable_keep_db_open=yes, dblib="no")], + dblib="no") + ;; ndbm) dnl We want to attempt to use -lndbm if we can, just in case dnl there's some version of it installed and overriding libc @@ -55,6 +62,12 @@ dnl named. arg. dnl How about berkeley db? CYRUS_BERKELEY_DB_CHK() if test "$dblib" = no; then + dnl How about OpenLDAP's mdb? + AC_CHECK_HEADER(mdb.h, [ + AC_CHECK_LIB(mdb, mdb_env_create, SASL_DB_LIB="-lmdb"; enable_keep_db_open=yes, dblib="no")], + dblib="no") + fi + if test "$dblib" = no; then dnl How about ndbm? AC_CHECK_HEADER(ndbm.h, [ AC_CHECK_LIB(ndbm, dbm_open, @@ -86,7 +99,7 @@ dnl named. arg. ;; *) AC_MSG_WARN([Bad DB library implementation specified;]) - AC_ERROR([Use either \"berkeley\", \"gdbm\", \"ndbm\" or \"none\"]) + AC_ERROR([Use either \"berkeley\", \"gdbm\", \"mdb\", \"ndbm\" or \"none\"]) dblib=no ;; esac @@ -106,6 +119,10 @@ case "$dblib" in SASL_MECHS="$SASL_MECHS libsasldb.la" AC_DEFINE(SASL_GDBM,[],[Use GDBM for SASLdb]) ;; + mdb) + SASL_MECHS="$SASL_MECHS libsasldb.la" + AC_DEFINE(SASL_MDB,[],[Use MDB for SASLdb]) + ;; ndbm) SASL_MECHS="$SASL_MECHS libsasldb.la" AC_DEFINE(SASL_NDBM,[],[Use NDBM for SASLdb]) diff --git a/configure.in b/configure.in index 465a362..5f75064 100644 --- a/configure.in +++ b/configure.in @@ -200,19 +200,19 @@ SASL_DB_CHECK() # Do we not install the SASL DB man pages? AM_CONDITIONAL(NO_SASL_DB_MANS, test "x$SASL_DB_MANS" = "x") -AC_ARG_ENABLE(keep_db_open, [ --enable-keep-db-open keep handle to Berkeley DB open for improved performance [[no]] ], +AC_ARG_ENABLE(keep_db_open, [ --enable-keep-db-open keep handle to DB open for improved performance [[no]] ], keep_db_open=$enableval, keep_db_open=no) -# Disable if Berkeley DB is not used -if test "$dblib" != berkeley; then +# Disable if Berkeley DB and MDB are not used +if test "$dblib" != berkeley -a "$dblib" != mdb; then keep_db_open=no fi if test "$keep_db_open" = yes; then - AC_DEFINE(KEEP_DB_OPEN,[],[Should we keep handle to Berkeley DB open in SASLDB plugin?]) + AC_DEFINE(KEEP_DB_OPEN,[],[Should we keep handle to DB open in SASLDB plugin?]) fi -AC_MSG_CHECKING(if Berkeley DB handle is kept open in SASLDB) +AC_MSG_CHECKING(if DB handle is kept open in SASLDB) AC_MSG_RESULT($keep_db_open) AC_CHECK_LIB(dl, dlopen, SASL_DL_LIB="-ldl", SASL_DL_LIB="") diff --git a/doc/options.html b/doc/options.html index 4f195f7..66db5f6 100644 --- a/doc/options.html +++ b/doc/options.html @@ -148,6 +148,20 @@ cached for a fast reauth. A value of 0 will disable reauth.</TD> <TR> <TD>sasldb_path</TD><TD>sasldb plugin</TD> <TD>Path to sasldb file</TD><TD><tt>/etc/sasldb2</tt> (system dependant)</TD> +</TR> +<TR> +<TD>sasldb_mapsize</TD><TD>sasldb with MDB</TD> +<TD>Size of the memory map used by the DB. This is also the maximum possible +size of the database, so it must be set to a value large enough to contain +all the desired user records.</TD> +<TD>1048576 bytes</TD> +</TR> +<TR> +<TD>sasldb_maxreaders</TD><TD>sasldb with MDB</TD> +<TD>Maximum number of threads (or processes) that may concurrently read the +database.</TD> +<TD>126</TD> +</TR> <TR> <TD>sql_engine</TD><TD>SQL plugin</TD> <TD>Name of SQL engine to use (possible values: 'mysql', 'pgsql', 'sqlite', 'sqlite3').</TD> @@ -342,6 +356,18 @@ sasl-regexp uid=(.*),cn=external,cn=auth </p> +<h2>Notes on sasldb with MDB</h2> + +<p> +</p> + +<p>The OpenLDAP MDB library is an extremely compact, extremely high performance +B+tree database. The code for it is available in the regular OpenLDAP source +distributions and it is distributed under the terms of the OpenLDAP Public License.</p> + +<p>Full documentation, plus papers and presentations are available on +<a href="http://highlandsun.com/hyc/mdb/">the MDB page</a>.</p> + <hr> Back to the <A href=index.html>index</a> diff --git a/sasldb/Makefile.am b/sasldb/Makefile.am index 067477c..e1e3f56 100644 --- a/sasldb/Makefile.am +++ b/sasldb/Makefile.am @@ -46,7 +46,7 @@ sasl_version = 1:25:0 INCLUDES=-I$(top_srcdir)/include -I$(top_builddir)/include @SASL_DB_INC@ -extra_common_sources = db_none.c db_ndbm.c db_gdbm.c db_berkeley.c +extra_common_sources = db_none.c db_mdb.c db_ndbm.c db_gdbm.c db_berkeley.c EXTRA_DIST = NTMakefile diff --git a/sasldb/db_mdb.c b/sasldb/db_mdb.c new file mode 100644 index 0000000..c8e62c0 --- /dev/null +++ b/sasldb/db_mdb.c @@ -0,0 +1,468 @@ +/* db_mdb.c--SASL OpenLDAP MDB interface + * Howard Chu + * $Id$ + */ +/* + * Copyright (C) 2011 Howard Chu, All rights reserved. <[email protected]> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ + +#include <config.h> + +#include <mdb.h> + +#include <sys/stat.h> +#include <stdlib.h> +#include <assert.h> +#include <errno.h> +#include "sasldb.h" + +static int db_ok = 0; +static MDB_env *db_env; +static MDB_dbi db_dbi; + +#define KILO 1024 + +/* + * Open the environment + */ +static int do_open(const sasl_utils_t *utils, + sasl_conn_t *conn, + int rdwr, MDB_txn **mtxn) +{ + const char *path = SASL_DB_PATH; + void *cntxt; + MDB_env *env; + MDB_txn *txn; + sasl_getopt_t *getopt; + size_t mapsize = 0; + int readers = 0; + int ret; + int flags; + + if (!db_env) { + + if (utils->getcallback(conn, SASL_CB_GETOPT, + (sasl_callback_ft *)&getopt, &cntxt) == SASL_OK) { + const char *p; + if (getopt(cntxt, NULL, "sasldb_path", &p, NULL) == SASL_OK + && p != NULL && *p != 0) { + path = p; + } + if (getopt(cntxt, NULL, "sasldb_maxreaders", &p, NULL) == SASL_OK + && p != NULL && *p != 0) { + readers = atoi(p); + } + if (getopt(cntxt, NULL, "sasldb_mapsize", &p, NULL) == SASL_OK + && p != NULL && *p != 0) { + mapsize = atoi(p); + mapsize *= KILO; + } + } + + ret = mdb_env_create(&env); + if (ret) { + utils->log(conn, SASL_LOG_ERR, + "unable to create MDB environment: %s", + mdb_strerror(ret)); + utils->seterror(conn, SASL_NOLOG, "Unable to create MDB environment"); + return SASL_FAIL; + } + + if (readers) { + ret = mdb_env_set_maxreaders(env, readers); + if (ret) { + utils->log(conn, SASL_LOG_ERR, + "unable to set MDB maxreaders: %s", + mdb_strerror(ret)); + utils->seterror(conn, SASL_NOLOG, "Unable to set MDB maxreaders"); + return SASL_FAIL; + } + } + + if (mapsize) { + ret = mdb_env_set_mapsize(env, mapsize); + if (ret) { + utils->log(conn, SASL_LOG_ERR, + "unable to set MDB mapsize: %s", + mdb_strerror(ret)); + utils->seterror(conn, SASL_NOLOG, "Unable to set MDB mapsize"); + return SASL_FAIL; + } + } + + flags = MDB_NOSUBDIR; + if (!rdwr) flags |= MDB_RDONLY; + ret = mdb_env_open(env, path, flags, 0660); + if (ret) { + mdb_env_close(env); + if (!rdwr && ret == ENOENT) { + /* File not found and we are only reading the data. + Treat as SASL_NOUSER. */ + return SASL_NOUSER; + } + utils->log(conn, SASL_LOG_ERR, + "unable to open MDB environment %s: %s", + path, mdb_strerror(ret)); + utils->seterror(conn, SASL_NOLOG, "Unable to open MDB environment"); + return SASL_FAIL; + } + } else { + env = db_env; + } + + ret = mdb_txn_begin(env, NULL, rdwr ? 0 : MDB_RDONLY, &txn); + if (ret) { + mdb_env_close(env); + utils->log(conn, SASL_LOG_ERR, + "unable to open MDB transaction: %s", + mdb_strerror(ret)); + utils->seterror(conn, SASL_NOLOG, "Unable to open MDB transaction"); + return SASL_FAIL; + } + + if (!db_dbi) { + ret = mdb_open(txn, NULL, 0, &db_dbi); + if (ret) { + mdb_txn_abort(txn); + mdb_env_close(env); + utils->log(conn, SASL_LOG_ERR, + "unable to open MDB database: %s", + mdb_strerror(ret)); + utils->seterror(conn, SASL_NOLOG, "Unable to open MDB database"); + return SASL_FAIL; + } + } + + if (!db_env) + db_env = env; + *mtxn = txn; + + return SASL_OK; +} + +/* + * Close the environment + */ +static void do_close() +{ + mdb_env_close(db_env); + db_env = NULL; +} + + +/* + * Retrieve the secret from the database. + * + * Return SASL_NOUSER if the entry doesn't exist, + * SASL_OK on success. + * + */ +int _sasldb_getdata(const sasl_utils_t *utils, + sasl_conn_t *context, + const char *auth_identity, + const char *realm, + const char *propName, + char *out, const size_t max_out, size_t *out_len) +{ + int result = SASL_OK; + char *key; + size_t key_len; + MDB_val dbkey, data; + MDB_txn *txn = NULL; + + if(!utils) return SASL_BADPARAM; + + /* check parameters */ + if (!auth_identity || !realm || !propName || !out || !max_out) { + utils->seterror(context, 0, + "Bad parameter in db_berkeley.c: _sasldb_getdata"); + return SASL_BADPARAM; + } + + if (!db_ok) { + utils->seterror(context, 0, + "Database not checked"); + return SASL_FAIL; + } + + /* allocate a key */ + result = _sasldb_alloc_key(utils, auth_identity, realm, propName, + &key, &key_len); + if (result != SASL_OK) { + utils->seterror(context, 0, + "Could not allocate key in _sasldb_getdata"); + return result; + } + + /* open the db */ + result = do_open(utils, context, 0, &txn); + if (result != SASL_OK) goto cleanup; + + /* create the key to search for */ + dbkey.mv_data = key; + dbkey.mv_size = key_len; + + /* ask MDB for the entry */ + result = mdb_get(txn, db_dbi, &dbkey, &data); + + switch (result) { + case 0: + /* success */ + break; + + case MDB_NOTFOUND: + result = SASL_NOUSER; + utils->seterror(context, SASL_NOLOG, + "user: %s@%s property: %s not found in sasldb", + auth_identity,realm,propName); + goto cleanup; + break; + default: + utils->seterror(context, 0, + "error fetching from sasldb: %s", + mdb_strerror(result)); + result = SASL_FAIL; + goto cleanup; + break; + } + + if(data.mv_size > max_out + 1) + return SASL_BUFOVER; + + if(out_len) *out_len = data.mv_size; + memcpy(out, data.mv_data, data.mv_size); + out[data.mv_size] = '\0'; + + cleanup: + + mdb_txn_abort(txn); + utils->free(key); + + return result; +} + +/* + * Put or delete an entry + * + * + */ + +int _sasldb_putdata(const sasl_utils_t *utils, + sasl_conn_t *context, + const char *authid, + const char *realm, + const char *propName, + const char *data_in, size_t data_len) +{ + int result = SASL_OK; + char *key; + size_t key_len; + MDB_val dbkey; + MDB_txn *txn = NULL; + + if (!utils) return SASL_BADPARAM; + + if (!authid || !realm || !propName) { + utils->seterror(context, 0, + "Bad parameter in db_berkeley.c: _sasldb_putdata"); + return SASL_BADPARAM; + } + + if (!db_ok) { + utils->seterror(context, 0, + "Database not checked"); + return SASL_FAIL; + } + + result = _sasldb_alloc_key(utils, authid, realm, propName, + &key, &key_len); + if (result != SASL_OK) { + utils->seterror(context, 0, + "Could not allocate key in _sasldb_putdata"); + return result; + } + + /* open the db */ + result=do_open(utils, context, 1, &txn); + if (result!=SASL_OK) goto cleanup; + + /* create the db key */ + dbkey.mv_data = key; + dbkey.mv_size = key_len; + + if (data_in) { /* putting secret */ + MDB_val data; + + data.mv_data = (char *)data_in; + if(!data_len) data_len = strlen(data_in); + data.mv_size = data_len; + + result = mdb_put(txn, db_dbi, &dbkey, &data, 0); + + if (result != 0) + { + utils->log(NULL, SASL_LOG_ERR, + "error updating sasldb: %s", mdb_strerror(result)); + utils->seterror(context, SASL_NOLOG, + "Couldn't update db"); + result = SASL_FAIL; + goto cleanup; + } + } else { /* removing secret */ + result=mdb_del(txn, db_dbi, &dbkey, NULL); + + if (result != 0) + { + utils->log(NULL, SASL_LOG_ERR, + "error deleting entry from sasldb: %s", mdb_strerror(result)); + utils->seterror(context, SASL_NOLOG, + "Couldn't update db"); + if (result == MDB_NOTFOUND) + result = SASL_NOUSER; + else + result = SASL_FAIL; + goto cleanup; + } + } + result = mdb_txn_commit(txn); + if (result) { + utils->log(NULL, SASL_LOG_ERR, + "error committing to sasldb: %s", mdb_strerror(result)); + utils->seterror(context, SASL_NOLOG, + "Couldn't update db"); + result = SASL_FAIL; + } + txn = NULL; + + cleanup: + + mdb_txn_abort(txn); + utils->free(key); + + return result; +} + +int _sasl_check_db(const sasl_utils_t *utils, + sasl_conn_t *conn) +{ + const char *path = SASL_DB_PATH; + int ret; + void *cntxt; + sasl_getopt_t *getopt; + sasl_verifyfile_t *vf; + + if (!utils) return SASL_BADPARAM; + + if (utils->getcallback(conn, SASL_CB_GETOPT, + (sasl_callback_ft *)&getopt, &cntxt) == SASL_OK) { + const char *p; + if (getopt(cntxt, NULL, "sasldb_path", &p, NULL) == SASL_OK + && p != NULL && *p != 0) { + path = p; + } + } + + ret = utils->getcallback(conn, SASL_CB_VERIFYFILE, + (sasl_callback_ft *)&vf, &cntxt); + if (ret != SASL_OK) { + utils->seterror(conn, 0, "verifyfile failed"); + return ret; + } + + ret = vf(cntxt, path, SASL_VRFY_PASSWD); + + if (ret == SASL_OK) { + db_ok = 1; + } + + if (ret == SASL_OK || ret == SASL_CONTINUE) { + return SASL_OK; + } else { + return ret; + } +} + +void sasldb_auxprop_free (void *glob_context, + const sasl_utils_t *utils) +{ + do_close(); +} + +sasldb_handle _sasldb_getkeyhandle(const sasl_utils_t *utils, + sasl_conn_t *conn) +{ + int ret; + MDB_txn *txn; + MDB_cursor *mc; + + if(!utils || !conn) return NULL; + + if(!db_ok) { + utils->seterror(conn, 0, "Database not OK in _sasldb_getkeyhandle"); + return NULL; + } + + ret = do_open(utils, conn, 0, &txn); + + if (ret != SASL_OK) { + return NULL; + } + + ret = mdb_cursor_open(txn, db_dbi, &mc); + if (ret) { + utils->seterror(conn, 0, "cursor_open failed in _sasldb_gekeythandle"); + return NULL; + } + + return (sasldb_handle)mc; +} + +int _sasldb_getnextkey(const sasl_utils_t *utils __attribute__((unused)), + sasldb_handle handle, char *out, + const size_t max_out, size_t *out_len) +{ + int result; + MDB_cursor *mc = (MDB_cursor *)handle; + MDB_val key; + + if(!utils || !handle || !out || !max_out) + return SASL_BADPARAM; + + result = mdb_cursor_get(mc, &key, NULL, MDB_NEXT); + + if (result == MDB_NOTFOUND) return SASL_OK; + + if (result != 0) { + return SASL_FAIL; + } + + if (key.mv_size > max_out) { + return SASL_BUFOVER; + } + + memcpy(out, key.mv_data, key.mv_size); + if (out_len) *out_len = key.mv_size; + + return SASL_CONTINUE; +} + + +int _sasldb_releasekeyhandle(const sasl_utils_t *utils, + sasldb_handle handle) +{ + MDB_cursor *mc = (MDB_cursor *)handle; + + if (!utils || !handle) return SASL_BADPARAM; + + mdb_cursor_close(mc); + + return SASL_OK; +} -- 1.7.9.5