Re: Patch status

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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/
>From b106449b18200d3b176286575f76cbe5952e4f2a Mon Sep 17 00:00:00 2001
From: Howard Chu <hyc@xxxxxxxxx>
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. <hyc@xxxxxxxxx>
+ *
+ * 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


[Index of Archives]     [Info Cyrus]     [Squirrel Mail]     [Linux Media]     [Yosemite News]     [gtk]     [KDE]     [Gimp on Windows]     [Steve's Art]

  Powered by Linux