]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/bconfig.c
trim use of uninitialized data; please review
[openldap] / servers / slapd / bconfig.c
index 1bd6e75ad6dbbb912ae70e2a64770b1387e7bbe9..d050122be294e76f174044fb3474f2d60a8f41bb 100644 (file)
@@ -32,6 +32,7 @@
 #include "slapi/slapi.h"
 #endif
 
+#include <ldif.h>
 #include <lutil.h>
 
 #include "config.h"
@@ -78,7 +79,9 @@ static int replicationInterval;
 
 static char    *passwd_salt;
 static char    *logfileName;
+#ifdef SLAP_AUTH_REWRITE
 static BerVarray authz_rewrites;
+#endif
 
 static struct berval cfdir;
 
@@ -86,12 +89,12 @@ static struct berval cfdir;
 static AttributeDescription *cfAd_backend, *cfAd_database, *cfAd_overlay,
        *cfAd_include;
 
-static ConfigFile cf_prv, *cfn = &cf_prv;
+static ConfigFile *cfn;
 
 static Avlnode *CfOcTree;
 
-static int config_add_internal( CfBackInfo *cfb, Entry *e, SlapReply *rs,
-       int *renumber );
+static int config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca,
+       SlapReply *rs, int *renumber );
 
 static ConfigDriver config_fname;
 static ConfigDriver config_cfdir;
@@ -103,7 +106,6 @@ static ConfigDriver config_sizelimit;
 static ConfigDriver config_timelimit;
 static ConfigDriver config_overlay;
 static ConfigDriver config_suffix; 
-static ConfigDriver config_deref_depth;
 static ConfigDriver config_rootdn;
 static ConfigDriver config_rootpw;
 static ConfigDriver config_restrict;
@@ -147,7 +149,6 @@ enum {
        CFG_DIT,
        CFG_ATTR,
        CFG_ATOPT,
-       CFG_CHECK,
        CFG_REPLOG,
        CFG_ROOTDSE,
        CFG_LOGFILE,
@@ -160,6 +161,8 @@ enum {
        CFG_SASLSECP,
        CFG_SSTR_IF_MAX,
        CFG_SSTR_IF_MIN,
+
+       CFG_LAST
 };
 
 typedef struct {
@@ -224,6 +227,10 @@ static ConfigTable config_back_cf_table[] = {
                        "DESC 'File for slapd command line options' "
                        "EQUALITY caseIgnoreMatch "
                        "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
+       { "attributeoptions", NULL, 0, 0, 0, ARG_MAGIC|CFG_ATOPT,
+               &config_generic, "( OLcfgGlAt:5 NAME 'olcAttributeOptions' "
+                       "EQUALITY caseIgnoreMatch "
+                       "SYNTAX OMsDirectoryString )", NULL, NULL },
        { "attribute",  "attribute", 2, 0, 9,
                ARG_PAREN|ARG_MAGIC|CFG_ATTR|ARG_NO_DELETE|ARG_NO_INSERT,
                &config_generic, "( OLcfgGlAt:4 NAME 'olcAttributeTypes' "
@@ -231,11 +238,7 @@ static ConfigTable config_back_cf_table[] = {
                        "EQUALITY caseIgnoreMatch "
                        "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )",
                                NULL, NULL },
-       { "attributeoptions", NULL, 0, 0, 0, ARG_MAGIC|CFG_ATOPT,
-               &config_generic, "( OLcfgGlAt:5 NAME 'olcAttributeOptions' "
-                       "EQUALITY caseIgnoreMatch "
-                       "SYNTAX OMsDirectoryString )", NULL, NULL },
-       { "authid-rewrite", NULL, 2, 0, 0,
+       { "authid-rewrite", NULL, 2, 0, STRLENOF( "authid-rewrite" ),
 #ifdef SLAP_AUTH_REWRITE
                ARG_MAGIC|CFG_REWRITE|ARG_NO_INSERT, &config_generic,
 #else
@@ -271,7 +274,7 @@ static ConfigTable config_back_cf_table[] = {
                &config_generic, "( OLcfgGlAt:13 NAME 'olcDatabase' "
                        "DESC 'The backend type for a database instance' "
                        "SUP olcBackend SINGLE-VALUE X-ORDERED 'SIBLINGS' )", NULL, NULL },
-       { "defaultSearchBase", "dn", 2, 2, 0, ARG_PRE_BI|ARG_PRE_DB|ARG_DN|ARG_MAGIC,
+       { "defaultSearchBase", "dn", 2, 2, 0, ARG_PRE_BI|ARG_PRE_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC,
                &config_search_base, "( OLcfgGlAt:14 NAME 'olcDefaultSearchBase' "
                        "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
        { "disallows", "features", 2, 0, 8, ARG_PRE_DB|ARG_MAGIC,
@@ -307,7 +310,7 @@ static ConfigTable config_back_cf_table[] = {
        { "index_substr_any_len", "len", 2, 2, 0, ARG_INT|ARG_NONZERO,
                &index_substr_any_len, "( OLcfgGlAt:22 NAME 'olcIndexSubstrAnyLen' "
                        "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
-       { "index_substr_step", "step", 2, 2, 0, ARG_INT|ARG_NONZERO,
+       { "index_substr_any_step", "step", 2, 2, 0, ARG_INT|ARG_NONZERO,
                &index_substr_any_step, "( OLcfgGlAt:23 NAME 'olcIndexSubstrAnyStep' "
                        "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
        { "lastmod", "on|off", 2, 2, 0, ARG_DB|ARG_ON_OFF|ARG_MAGIC|CFG_LASTMOD,
@@ -416,7 +419,7 @@ static ConfigTable config_back_cf_table[] = {
 #endif
                "( OLcfgGlAt:49 NAME 'olcReverseLookup' "
                        "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
-       { "rootdn", "dn", 2, 2, 0, ARG_DB|ARG_DN|ARG_MAGIC,
+       { "rootdn", "dn", 2, 2, 0, ARG_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC,
                &config_rootdn, "( OLcfgDbAt:0.8 NAME 'olcRootDN' "
                        "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
        { "rootDSE", "file", 2, 2, 0, ARG_MAGIC|CFG_ROOTDSE,
@@ -455,10 +458,7 @@ static ConfigTable config_back_cf_table[] = {
                        "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
        { "saslRegexp", NULL, 3, 3, 0, ARG_MAGIC|CFG_AZREGEXP,
                &config_generic, NULL, NULL, NULL },
-       { "schemacheck", "on|off", 2, 2, 0, ARG_ON_OFF|ARG_MAGIC|CFG_CHECK,
-               &config_generic, "( OLcfgGlAt:57 NAME 'olcSchemaCheck' "
-                       "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
-       { "schemadn", "dn", 2, 2, 0, ARG_MAY_DB|ARG_DN|ARG_MAGIC,
+       { "schemadn", "dn", 2, 2, 0, ARG_MAY_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC,
                &config_schema_dn, "( OLcfgGlAt:58 NAME 'olcSchemaDN' "
                        "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
        { "security", "factors", 2, 0, 0, ARG_MAY_DB|ARG_MAGIC,
@@ -481,7 +481,7 @@ static ConfigTable config_back_cf_table[] = {
 #endif
                "( OLcfgGlAt:63 NAME 'olcSrvtab' "
                        "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
-       { "suffix",     "suffix", 2, 2, 0, ARG_DB|ARG_DN|ARG_MAGIC,
+       { "suffix",     "suffix", 2, 2, 0, ARG_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC,
                &config_suffix, "( OLcfgDbAt:0.10 NAME 'olcSuffix' "
                        "SYNTAX OMsDN )", NULL, NULL },
        { "syncrepl", NULL, 0, 0, 0, ARG_DB|ARG_MAGIC,
@@ -559,7 +559,7 @@ static ConfigTable config_back_cf_table[] = {
                        "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
        { "ucdata-path", "path", 2, 2, 0, ARG_IGNORED,
                NULL, NULL, NULL, NULL },
-       { "updatedn", "dn", 2, 2, 0, ARG_DB|ARG_MAGIC,
+       { "updatedn", "dn", 2, 2, 0, ARG_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC,
                &config_updatedn, "( OLcfgDbAt:0.12 NAME 'olcUpdateDN' "
                        "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
        { "updateref", "url", 2, 2, 0, ARG_DB|ARG_MAGIC,
@@ -573,20 +573,25 @@ static ConfigTable config_back_cf_table[] = {
 static ConfigLDAPadd cfAddSchema, cfAddInclude, cfAddDatabase,
        cfAddBackend, cfAddModule, cfAddOverlay;
 
+/* NOTE: be careful when defining array members
+ * that can be conditionally compiled */
 #define CFOC_GLOBAL    cf_ocs[1]
 #define CFOC_SCHEMA    cf_ocs[2]
 #define CFOC_BACKEND   cf_ocs[3]
 #define CFOC_DATABASE  cf_ocs[4]
 #define CFOC_OVERLAY   cf_ocs[5]
 #define CFOC_INCLUDE   cf_ocs[6]
-#define CFOC_MODULE    cf_ocs[7]
+#define CFOC_FRONTEND  cf_ocs[7]
+#ifdef SLAPD_MODULES
+#define CFOC_MODULE    cf_ocs[8]
+#endif /* SLAPD_MODULES */
 
 static ConfigOCs cf_ocs[] = {
-       { "( OLcfgGlOc:1 "
+       { "( OLcfgGlOc:0 "
                "NAME 'olcConfig' "
                "DESC 'OpenLDAP configuration object' "
                "ABSTRACT SUP top )", Cft_Abstract, NULL },
-       { "( OLcfgGlOc:2 "
+       { "( OLcfgGlOc:1 "
                "NAME 'olcGlobal' "
                "DESC 'OpenLDAP Global configuration options' "
                "SUP olcConfig STRUCTURAL "
@@ -602,9 +607,9 @@ static ConfigOCs cf_ocs[] = {
                 "olcPluginLogFile $ olcReadOnly $ olcReferral $ "
                 "olcReplicaPidFile $ olcReplicaArgsFile $ olcReplicationInterval $ "
                 "olcReplogFile $ olcRequires $ olcRestrict $ olcReverseLookup $ "
-                "olcRootDSE $ olcRootPW $ "
+                "olcRootDSE $ "
                 "olcSaslHost $ olcSaslRealm $ olcSaslSecProps $ "
-                "olcSchemaCheck $ olcSecurity $ olcSizeLimit $ "
+                "olcSecurity $ olcSizeLimit $ "
                 "olcSockbufMaxIncoming $ olcSockbufMaxIncomingAuth $ olcSrvtab $ "
                 "olcThreads $ olcTimeLimit $ olcTLSCACertificateFile $ "
                 "olcTLSCACertificatePath $ olcTLSCertificateFile $ "
@@ -612,19 +617,19 @@ static ConfigOCs cf_ocs[] = {
                 "olcTLSRandFile $ olcTLSVerifyClient $ "
                 "olcObjectIdentifier $ olcAttributeTypes $ olcObjectClasses $ "
                 "olcDitContentRules ) )", Cft_Global },
-       { "( OLcfgGlOc:3 "
+       { "( OLcfgGlOc:2 "
                "NAME 'olcSchemaConfig' "
                "DESC 'OpenLDAP schema object' "
                "SUP olcConfig STRUCTURAL "
                "MAY ( cn $ olcObjectIdentifier $ olcAttributeTypes $ "
                 "olcObjectClasses $ olcDitContentRules ) )",
                        Cft_Schema, NULL, cfAddSchema },
-       { "( OLcfgGlOc:4 "
+       { "( OLcfgGlOc:3 "
                "NAME 'olcBackendConfig' "
                "DESC 'OpenLDAP Backend-specific options' "
                "SUP olcConfig STRUCTURAL "
                "MUST olcBackend )", Cft_Backend, NULL, cfAddBackend },
-       { "( OLcfgGlOc:5 "
+       { "( OLcfgGlOc:4 "
                "NAME 'olcDatabaseConfig' "
                "DESC 'OpenLDAP Database-specific options' "
                "SUP olcConfig STRUCTURAL "
@@ -635,25 +640,35 @@ static ConfigOCs cf_ocs[] = {
                 "olcSchemaDN $ olcSecurity $ olcSizeLimit $ olcSyncrepl $ "
                 "olcTimeLimit $ olcUpdateDN $ olcUpdateRef ) )",
                        Cft_Database, NULL, cfAddDatabase },
-       { "( OLcfgGlOc:6 "
+       { "( OLcfgGlOc:5 "
                "NAME 'olcOverlayConfig' "
                "DESC 'OpenLDAP Overlay-specific options' "
                "SUP olcConfig STRUCTURAL "
                "MUST olcOverlay )", Cft_Overlay, NULL, cfAddOverlay },
-       { "( OLcfgGlOc:7 "
+       { "( OLcfgGlOc:6 "
                "NAME 'olcIncludeFile' "
                "DESC 'OpenLDAP configuration include file' "
                "SUP olcConfig STRUCTURAL "
                "MUST olcInclude "
                "MAY ( cn $ olcRootDSE ) )",
                Cft_Include, NULL, cfAddInclude },
+       /* This should be STRUCTURAL like all the other database classes, but
+        * that would mean inheriting all of the olcDatabaseConfig attributes,
+        * which causes them to be merged twice in config_build_entry.
+        */
+       { "( OLcfgGlOc:7 "
+               "NAME 'olcFrontendConfig' "
+               "DESC 'OpenLDAP frontend configuration' "
+               "AUXILIARY "
+               "MAY olcDefaultSearchBase )",
+               Cft_Database, NULL, NULL },
 #ifdef SLAPD_MODULES
        { "( OLcfgGlOc:8 "
                "NAME 'olcModuleList' "
                "DESC 'OpenLDAP dynamic module info' "
                "SUP olcConfig STRUCTURAL "
-               "MUST ( olcModulePath $ olcModuleLoad ) "
-               "MAY cn )", Cft_Module, NULL, cfAddModule },
+               "MAY ( cn $ olcModulePath $ olcModuleLoad ) )",
+               Cft_Module, NULL, cfAddModule },
 #endif
        { NULL, 0, NULL }
 };
@@ -696,7 +711,8 @@ config_generic(ConfigArgs *c) {
                        if ( !c->rvalue_vals ) rc = 1;
                        break;
                case CFG_RO:
-                       c->value_int = (c->be->be_restrictops & SLAP_RESTRICT_OP_WRITES) != 0;
+                       c->value_int = (c->be->be_restrictops & SLAP_RESTRICT_OP_WRITES) ==
+                               SLAP_RESTRICT_OP_WRITES;
                        break;
                case CFG_AZPOLICY:
                        c->value_string = ch_strdup( slap_sasl_getpolicy());
@@ -765,9 +781,6 @@ config_generic(ConfigArgs *c) {
                        }
                        break;
                        
-               case CFG_CHECK:
-                       c->value_int = global_schemacheck;
-                       break;
                case CFG_ACL: {
                        AccessControl *a;
                        char *src, *dst, ibuf[11];
@@ -840,7 +853,8 @@ config_generic(ConfigArgs *c) {
                        break;
                case CFG_MODPATH: {
                        ModPaths *mp = c->private;
-                       value_add_one( &c->rvalue_vals, &mp->mp_path );
+                       if ( !BER_BVISNULL( &mp->mp_path ))
+                               value_add_one( &c->rvalue_vals, &mp->mp_path );
 
                        rc = c->rvalue_vals ? 0 : 1;
                        }
@@ -885,7 +899,6 @@ config_generic(ConfigArgs *c) {
                case CFG_RO:
                case CFG_AZPOLICY:
                case CFG_DEPTH:
-               case CFG_CHECK:
                case CFG_LASTMOD:
                case CFG_SASLSECP:
                case CFG_SSTR_IF_MAX:
@@ -976,11 +989,14 @@ config_generic(ConfigArgs *c) {
                                c->be = LDAP_STAILQ_FIRST(&backendDB);
                        } else if ( !strcasecmp( c->argv[1], "frontend" )) {
                                c->be = frontendDB;
-                       } else if(!(c->be = backend_db_init(c->argv[1]))) {
-                               sprintf( c->msg, "<%s> failed init", c->argv[0] );
-                               Debug(LDAP_DEBUG_ANY, "%s: %s (%s)!\n",
-                                       c->log, c->msg, c->argv[1] );
-                               return(1);
+                       } else {
+                               c->be = backend_db_init(c->argv[1]);
+                               if ( !c->be ) {
+                                       sprintf( c->msg, "<%s> failed init", c->argv[0] );
+                                       Debug(LDAP_DEBUG_ANY, "%s: %s (%s)!\n",
+                                               c->log, c->msg, c->argv[1] );
+                                       return(1);
+                               }
                        }
                        break;
 
@@ -1088,13 +1104,6 @@ config_generic(ConfigArgs *c) {
                                        return(1);
                        break;
 
-               case CFG_CHECK:
-                       global_schemacheck = c->value_int;
-                       if(!global_schemacheck) Debug(LDAP_DEBUG_ANY, "%s: "
-                               "schema checking disabled! your mileage may vary!\n",
-                               c->log, 0, 0);
-                       break;
-
                case CFG_ACL:
                        parse_acl(c->be, c->fname, c->lineno, c->argc, c->argv, c->valx);
                        break;
@@ -1169,21 +1178,35 @@ config_generic(ConfigArgs *c) {
 
 #ifdef SLAPD_MODULES
                case CFG_MODLOAD:
+                       /* If we're just adding a module on an existing modpath,
+                        * make sure we've selected the current path.
+                        */
+                       if ( c->op == LDAP_MOD_ADD && c->private && modcur != c->private ) {
+                               modcur = c->private;
+                               /* This should never fail */
+                               if ( module_path( modcur->mp_path.bv_val )) {
+                                       sprintf( c->msg, "<%s> module path no longer valid",
+                                               c->argv[0] );
+                                       Debug(LDAP_DEBUG_ANY, "%s: %s (%s)\n",
+                                               c->log, c->msg, modcur->mp_path.bv_val );
+                                       return(1);
+                               }
+                       }
                        if(module_load(c->argv[1], c->argc - 2, (c->argc > 2) ? c->argv + 2 : NULL))
                                return(1);
                        /* Record this load on the current path */
                        {
                                struct berval bv;
-                               ModPaths *mp;
-                               char *ptr = c->line + STRLENOF("moduleload");
-                               while (!isspace(*ptr)) ptr++;
-                               while (isspace(*ptr)) ptr++;
+                               char *ptr;
+                               if ( c->op == SLAP_CONFIG_ADD ) {
+                                       ptr = c->line + STRLENOF("moduleload");
+                                       while (!isspace(*ptr)) ptr++;
+                                       while (isspace(*ptr)) ptr++;
+                               } else {
+                                       ptr = c->line;
+                               }
                                ber_str2bv(ptr, 0, 1, &bv);
-                               if ( c->op == SLAP_CONFIG_ADD )
-                                       mp = modcur;
-                               else
-                                       mp = c->private;
-                               ber_bvarray_add( &mp->mp_loads, &bv );
+                               ber_bvarray_add( &modcur->mp_loads, &bv );
                        }
                        break;
 
@@ -1204,8 +1227,7 @@ config_generic(ConfigArgs *c) {
                                mp->mp_loads = NULL;
                                modlast = mp;
                                c->private = mp;
-                               if ( c->op == SLAP_CONFIG_ADD )
-                                       modcur = mp;
+                               modcur = mp;
                        }
                        
                        break;
@@ -1222,9 +1244,27 @@ config_generic(ConfigArgs *c) {
 #ifdef SLAP_AUTH_REWRITE
                case CFG_REWRITE: {
                        struct berval bv;
+                       char *line;
+                       
                        if(slap_sasl_rewrite_config(c->fname, c->lineno, c->argc, c->argv))
                                return(1);
-                       ber_str2bv( c->line, 0, 1, &bv );
+
+                       if ( c->argc > 1 ) {
+                               char    *s;
+
+                               /* quote all args but the first */
+                               line = ldap_charray2str( c->argv, "\" \"" );
+                               ber_str2bv( line, 0, 0, &bv );
+                               s = strchr( bv.bv_val, '"' );
+                               assert( s != NULL );
+                               /* move the trailing quote of argv[0] to the end */
+                               AC_MEMCPY( s, s + 1, bv.bv_len - ( s - bv.bv_val ) );
+                               bv.bv_val[ bv.bv_len - 1 ] = '"';
+
+                       } else {
+                               ber_str2bv( c->argv[ 0 ], 0, 1, &bv );
+                       }
+                       
                        ber_bvarray_add( &authz_rewrites, &bv );
                        }
                        break;
@@ -1272,8 +1312,6 @@ config_cfdir(ConfigArgs *c) {
 
 static int
 config_search_base(ConfigArgs *c) {
-       struct berval dn;
-
        if(c->op == SLAP_CONFIG_EMIT) {
                int rc = 1;
                if (!BER_BVISEMPTY(&default_search_base)) {
@@ -1507,26 +1545,71 @@ config_overlay(ConfigArgs *c) {
                /* log error */
                Debug( SLAPD_DEBUG_CONFIG_ERROR, "%s: (optional) %s overlay \"%s\" configuration failed"
                        SLAPD_CONF_UNKNOWN_IGNORED ".\n",
-                       c->log, c->be == frontendDB ? "global " : "", c->argv[1][1]);
+                       c->log, c->be == frontendDB ? "global " : "", &c->argv[1][1]);
 #ifdef SLAPD_CONF_UNKNOWN_BAILOUT
                return 1;
 #endif /* SLAPD_CONF_UNKNOWN_BAILOUT */
        } else if(overlay_config(c->be, c->argv[1])) {
                return(1);
        }
+       /* Setup context for subsequent config directives.
+        * The newly added overlay is at the head of the list.
+        */
        oi = (slap_overinfo *)c->be->bd_info;
        c->bi = &oi->oi_list->on_bi;
        return(0);
 }
 
 static int
-config_suffix(ConfigArgs *c) {
+config_suffix(ConfigArgs *c)
+{
        Backend *tbe;
        struct berval pdn, ndn;
-       int rc;
+       char    *notallowed = NULL;
+
+       if ( c->be == frontendDB ) {
+               notallowed = "frontend";
+
+       } else if ( SLAP_MONITOR(c->be) ) {
+               notallowed = "monitor";
+
+       } else if ( SLAP_CONFIG(c->be) ) {
+               notallowed = "config";
+       }
+
+       if ( notallowed != NULL ) {
+               char    buf[ SLAP_TEXT_BUFLEN ] = { '\0' };
+
+               switch ( c->op ) {
+               case LDAP_MOD_ADD:
+               case LDAP_MOD_DELETE:
+               case LDAP_MOD_REPLACE:
+               case LDAP_MOD_INCREMENT:
+               case SLAP_CONFIG_ADD:
+                       if ( !BER_BVISNULL( &c->value_dn ) ) {
+                               snprintf( buf, sizeof( buf ), "<%s> ",
+                                               c->value_dn.bv_val );
+                       }
 
-       if (c->be == frontendDB || SLAP_MONITOR(c->be) ||
-               SLAP_CONFIG(c->be)) return 1;
+                       Debug(LDAP_DEBUG_ANY,
+                               "%s: suffix %snot allowed in %s database.\n",
+                               c->log, buf, notallowed );
+                       break;
+
+               case SLAP_CONFIG_EMIT:
+                       /* don't complain when emitting... */
+                       break;
+
+               default:
+                       /* FIXME: don't know what values may be valid;
+                        * please remove assertion, or add legal values
+                        * to either block */
+                       assert( 0 );
+                       break;
+               }
+
+               return 1;
+       }
 
        if (c->op == SLAP_CONFIG_EMIT) {
                if ( c->be->be_suffix == NULL
@@ -1555,6 +1638,7 @@ config_suffix(ConfigArgs *c) {
                }
                return 0;
        }
+
 #ifdef SLAPD_MONITOR_DN
        if(!strcasecmp(c->argv[1], SLAPD_MONITOR_DN)) {
                sprintf( c->msg, "<%s> DN is reserved for monitoring slapd",
@@ -1625,16 +1709,12 @@ config_rootdn(ConfigArgs *c) {
 static int
 config_rootpw(ConfigArgs *c) {
        Backend *tbe;
-       /* config_add_internal sets c->be = frontendDB. While the cn=config
-        * rootpw is technically inside a backend, we expose it in the
-        * global entry, and need to point to it properly here.
-        */
-       if (c->be == frontendDB)
-               c->be = LDAP_STAILQ_FIRST(&backendDB);
 
        if (c->op == SLAP_CONFIG_EMIT) {
                if (!BER_BVISEMPTY(&c->be->be_rootpw)) {
-                       ber_dupbv( &c->value_bv, &c->be->be_rootpw);
+                       /* don't copy, because "rootpw" is marked
+                        * as CFG_BERVAL */
+                       c->value_bv = c->be->be_rootpw;
                        return 0;
                }
                return 1;
@@ -1807,11 +1887,13 @@ config_requires(ConfigArgs *c) {
        return(0);
 }
 
+static slap_verbmasks  *loglevel_ops;
+
 static int
-config_loglevel(ConfigArgs *c) {
-       int i;
-       char *next;
-       slap_verbmasks loglevel_ops[] = {
+loglevel_init( void )
+{
+       slap_verbmasks  lo[] = {
+               { BER_BVC("Any"),       -1 },
                { BER_BVC("Trace"),     LDAP_DEBUG_TRACE },
                { BER_BVC("Packets"),   LDAP_DEBUG_PACKETS },
                { BER_BVC("Args"),      LDAP_DEBUG_ARGS },
@@ -1826,10 +1908,72 @@ config_loglevel(ConfigArgs *c) {
                { BER_BVC("Parse"),     LDAP_DEBUG_PARSE },
                { BER_BVC("Cache"),     LDAP_DEBUG_CACHE },
                { BER_BVC("Index"),     LDAP_DEBUG_INDEX },
-               { BER_BVC("Any"),       -1 },
+               { BER_BVC("Sync"),      LDAP_DEBUG_SYNC },
                { BER_BVNULL,   0 }
        };
 
+       return slap_verbmasks_init( &loglevel_ops, lo );
+}
+
+static void
+loglevel_destroy( void )
+{
+       if ( loglevel_ops ) {
+               (void)slap_verbmasks_destroy( loglevel_ops );
+       }
+       loglevel_ops = NULL;
+}
+
+static slap_mask_t     loglevel_ignore[] = { -1, 0 };
+
+int
+slap_loglevel_register( slap_mask_t m, struct berval *s )
+{
+       int     rc;
+
+       if ( loglevel_ops == NULL ) {
+               loglevel_init();
+       }
+
+       rc = slap_verbmasks_append( &loglevel_ops, m, s, loglevel_ignore );
+
+       if ( rc != 0 ) {
+               Debug( LDAP_DEBUG_ANY, "slap_loglevel_register(%lu, \"%s\") failed\n",
+                       m, s->bv_val, 0 );
+       }
+
+       return rc;
+}
+
+int
+str2loglevel( const char *s, int *l )
+{
+       int     i;
+
+       if ( loglevel_ops == NULL ) {
+               loglevel_init();
+       }
+
+       i = verb_to_mask( s, loglevel_ops );
+
+       if ( BER_BVISNULL( &loglevel_ops[ i ].word) ) {
+               return -1;
+       }
+
+       *l = loglevel_ops[ i ].mask;
+
+       return 0;
+}
+
+static int
+config_loglevel(ConfigArgs *c) {
+       int i;
+       char *next;
+
+       if ( loglevel_ops == NULL ) {
+               loglevel_init();
+       }
+
        if (c->op == SLAP_CONFIG_EMIT) {
                return mask_to_verbs( loglevel_ops, ldap_syslog, &c->rvalue_vals );
        } else if ( c->op == LDAP_MOD_DELETE ) {
@@ -1847,7 +1991,7 @@ config_loglevel(ConfigArgs *c) {
        for( i=1; i < c->argc; i++ ) {
                int     level;
 
-               if ( isdigit( c->argv[i][0] ) ) {
+               if ( isdigit( c->argv[i][0] ) || c->argv[i][0] == '-' ) {
                        level = strtol( c->argv[i], &next, 10 );
                        if ( next == NULL || next[0] != '\0' ) {
                                sprintf( c->msg, "<%s> unable to parse level", c->argv[0] );
@@ -1856,14 +2000,12 @@ config_loglevel(ConfigArgs *c) {
                                return( 1 );
                        }
                } else {
-                       int j = verb_to_mask(c->argv[i], loglevel_ops);
-                       if(BER_BVISNULL(&loglevel_ops[j].word)) {
+                       if ( str2loglevel( c->argv[i], &level ) ) {
                                sprintf( c->msg, "<%s> unknown level", c->argv[0] );
                                Debug( LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
                                        c->log, c->msg, c->argv[i]);
                                return( 1 );
                        }
-                       level = loglevel_ops[j].mask;
                }
                ldap_syslog |= level;
        }
@@ -1991,7 +2133,7 @@ replica_unparse( struct slap_replica_info *ri, int i, struct berval *bv )
 {
        int len;
        char *ptr;
-       struct berval bc = {0};
+       struct berval bc = BER_BVNULL;
        char numbuf[32];
 
        len = sprintf(numbuf, IFMT, i );
@@ -2083,6 +2225,7 @@ config_replica(ConfigArgs *c) {
                                return(1);
                        }
                        if(!ludp->lud_host) {
+                               ldap_free_urldesc(ludp);
                                sprintf( c->msg, "<%s> invalid uri - missing hostname",
                                        c->argv[0] );
                                Debug(LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->msg, 0 );
@@ -2156,8 +2299,6 @@ config_replica(ConfigArgs *c) {
 
 static int
 config_updatedn(ConfigArgs *c) {
-       struct berval dn;
-       int rc;
        if (c->op == SLAP_CONFIG_EMIT) {
                if (!BER_BVISEMPTY(&c->be->be_update_ndn)) {
                        value_add_one(&c->rvalue_vals, &c->be->be_update_ndn);
@@ -2167,7 +2308,7 @@ config_updatedn(ConfigArgs *c) {
                return 1;
        } else if ( c->op == LDAP_MOD_DELETE ) {
                ch_free( c->be->be_update_ndn.bv_val );
-               c->be->be_update_ndn.bv_val = NULL;
+               BER_BVZERO( &c->be->be_update_ndn );
                SLAP_DBFLAGS(c->be) ^= (SLAP_DBFLAG_SHADOW | SLAP_DBFLAG_SLURP_SHADOW);
                return 0;
        }
@@ -2178,17 +2319,13 @@ config_updatedn(ConfigArgs *c) {
                return(1);
        }
 
-       ber_str2bv(c->argv[1], 0, 0, &dn);
-
-       rc = dnNormalize(0, NULL, NULL, &dn, &c->be->be_update_ndn, NULL);
-
-       if(rc != LDAP_SUCCESS) {
-               sprintf( c->msg, "<%s> invalid DN %d (%s)", c->argv[0],
-                       rc, ldap_err2string(rc));
-               Debug(LDAP_DEBUG_ANY, "%s: %s\n",
-                       c->log, c->msg, 0 );
-               return(1);
+       ber_memfree_x( c->value_dn.bv_val, NULL );
+       if ( !BER_BVISNULL( &c->be->be_update_ndn ) ) {
+               ber_memfree_x( c->be->be_update_ndn.bv_val, NULL );
        }
+       c->be->be_update_ndn = c->value_ndn;
+       BER_BVZERO( &c->value_dn );
+       BER_BVZERO( &c->value_ndn );
 
        SLAP_DBFLAGS(c->be) |= (SLAP_DBFLAG_SHADOW | SLAP_DBFLAG_SLURP_SHADOW);
        return(0);
@@ -2237,7 +2374,7 @@ config_updateref(ConfigArgs *c) {
 
 static int
 config_include(ConfigArgs *c) {
-       unsigned long savelineno = c->lineno;
+       int savelineno = c->lineno;
        int rc;
        ConfigFile *cf;
        ConfigFile *cfsave = cfn;
@@ -2385,14 +2522,19 @@ config_find_base( CfEntryInfo *root, struct berval *dn, CfEntryInfo **last )
        return root;
 }
 
+typedef struct setup_cookie {
+       CfBackInfo *cfb;
+       ConfigArgs *ca;
+} setup_cookie;
+
 static int
 config_ldif_resp( Operation *op, SlapReply *rs )
 {
        if ( rs->sr_type == REP_SEARCH ) {
-               CfBackInfo *cfb = op->o_callback->sc_private;
+               setup_cookie *sc = op->o_callback->sc_private;
 
-               cfb->cb_got_ldif = 1;
-               rs->sr_err = config_add_internal( cfb, rs->sr_entry, NULL, NULL );
+               sc->cfb->cb_got_ldif = 1;
+               rs->sr_err = config_add_internal( sc->cfb, rs->sr_entry, sc->ca, NULL, NULL );
        }
        return rs->sr_err;
 }
@@ -2405,6 +2547,7 @@ config_setup_ldif( BackendDB *be, const char *dir, int readit ) {
        ConfigTable *ct;
        char *argv[3];
        int rc = 0;
+       setup_cookie sc;
        slap_callback cb = { NULL, config_ldif_resp, NULL, NULL };
        Connection conn = {0};
        char opbuf[OPERATION_BUFFER_SIZE];
@@ -2481,10 +2624,14 @@ config_setup_ldif( BackendDB *be, const char *dir, int readit ) {
                op->ors_attrsonly = 0;
 
                op->o_callback = &cb;
-               cb.sc_private = cfb;
+               sc.cfb = cfb;
+               sc.ca = &c;
+               cb.sc_private = &sc;
 
                op->o_bd = &cfb->cb_db;
                rc = op->o_bd->be_search( op, &rs );
+
+               slap_sl_mem_destroy( NULL, op->o_tmpmemctx );
        }
 
        cfb->cb_use_ldif = 1;
@@ -2553,12 +2700,17 @@ read_config(const char *fname, const char *dir) {
                        cfdir = SLAPD_DEFAULT_CONFIGDIR;
                }
                /* if fname is defaulted, try reading .d */
-               if ( config_setup_ldif( be, cfdir, !fname ))
+               rc = config_setup_ldif( be, cfdir, !fname );
+
+               /* It's OK if the base object doesn't exist yet */
+               if ( rc && rc != LDAP_NO_SUCH_OBJECT )
                        return 1;
 
                /* If we read the config from back-ldif, nothing to do here */
-               if ( cfb->cb_got_ldif )
-                       return 0;
+               if ( cfb->cb_got_ldif ) {
+                       rc = 0;
+                       goto done;
+               }
        }
 
        if ( fname )
@@ -2569,7 +2721,7 @@ read_config(const char *fname, const char *dir) {
        rc = read_config_file(cfname, 0, NULL, config_back_cf_table);
 
        if ( rc == 0 )
-               ber_str2bv( cfname, 0, 1, &cf_prv.c_file );
+               ber_str2bv( cfname, 0, 1, &cfb->cb_config->c_file );
 
        /* If we got this far and failed, it may be a serious problem. In server
         * mode, we should never come to this. However, it may be alright if we're
@@ -2589,6 +2741,20 @@ read_config(const char *fname, const char *dir) {
                }
                break;
        }
+
+done:
+       if ( rc == 0 && BER_BVISNULL( &frontendDB->be_schemadn ) ) {
+               ber_str2bv( SLAPD_SCHEMA_DN, STRLENOF( SLAPD_SCHEMA_DN ), 1,
+                       &frontendDB->be_schemadn );
+               rc = dnNormalize( 0, NULL, NULL, &frontendDB->be_schemadn, &frontendDB->be_schemandn, NULL );
+               if ( rc != LDAP_SUCCESS ) {
+                       Debug(LDAP_DEBUG_ANY, "read_config: "
+                               "unable to normalize default schema DN \"%s\"\n",
+                               frontendDB->be_schemadn.bv_val, 0, 0 );
+                       /* must not happen */
+                       assert( 0 );
+               }
+       }
        return rc;
 }
 
@@ -2736,8 +2902,9 @@ check_vals( ConfigTable *ct, ConfigArgs *ca, void *ptr, int isAttr )
                        if ( idx ) ca->line = idx+1;
                }
                rc = config_parse_vals( ct, ca, i );
-               if ( rc )
+               if ( rc ) {
                        break;
+               }
        }
        return rc;
 }
@@ -2772,8 +2939,13 @@ check_name_index( CfEntryInfo *parent, ConfigType ce_type, Entry *e,
                        return LDAP_NAMING_VIOLATION;
                gotindex = 1;
                index = atoi(ptr1+1);
-               if ( index < 0 )
-                       return LDAP_NAMING_VIOLATION;
+               if ( index < 0 ) {
+                       /* Special case, we allow -1 for the frontendDB */
+                       if ( index != -1 || ce_type != Cft_Database ||
+                               strncmp( ptr2+1, "frontend,", STRLENOF("frontend,") ))
+
+                               return LDAP_NAMING_VIOLATION;
+               }
        }
 
        /* count related kids */
@@ -2904,10 +3076,7 @@ cfAddInclude( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
        if ( ca->lineno )
                return LDAP_COMPARE_TRUE;
 
-       if ( p->ce_type == Cft_Global )
-               cfn = &cf_prv;
-       else
-               cfn = p->ce_private;
+       cfn = p->ce_private;
        ca->private = cfn;
        return LDAP_SUCCESS;
 }
@@ -2919,7 +3088,7 @@ cfAddSchema( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
 
        /* This entry is hardcoded, don't re-parse it */
        if ( p->ce_type == Cft_Global ) {
-               cfn = &cf_prv;
+               cfn = p->ce_private;
                ca->private = cfn;
                return LDAP_COMPARE_TRUE;
        }
@@ -2970,13 +3139,12 @@ cfAddOverlay( CfEntryInfo *p, Entry *e, struct config_args_s *ca )
 
 /* Parse an LDAP entry into config directives */
 static int
-config_add_internal( CfBackInfo *cfb, Entry *e, SlapReply *rs, int *renum )
+config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca, SlapReply *rs, int *renum )
 {
        CfEntryInfo *ce, *last;
        ConfigOCs **colst;
        Attribute *a, *oc_at;
-       int i, j, nocs, rc = 0;
-       ConfigArgs ca = {0};
+       int i, nocs, rc = 0;
        struct berval pdn;
        ConfigTable *ct;
        char *ptr;
@@ -3000,15 +3168,17 @@ config_add_internal( CfBackInfo *cfb, Entry *e, SlapReply *rs, int *renum )
        oc_at = attr_find( e->e_attrs, slap_schema.si_ad_objectClass );
        if ( !oc_at ) return LDAP_OBJECT_CLASS_VIOLATION;
 
+       memset( ca, 0, sizeof(ConfigArgs));
+
        /* Fake the coordinates based on whether we're part of an
         * LDAP Add or if reading the config dir
         */
        if ( rs ) {
-               ca.fname = "slapd";
-               ca.lineno = 0;
+               ca->fname = "slapd";
+               ca->lineno = 0;
        } else {
-               ca.fname = cfdir.bv_val;
-               ca.lineno = 1;
+               ca->fname = cfdir.bv_val;
+               ca->lineno = 1;
        }
 
        colst = count_ocs( oc_at, &nocs );
@@ -3018,9 +3188,9 @@ config_add_internal( CfBackInfo *cfb, Entry *e, SlapReply *rs, int *renum )
         */
        rc = LDAP_CONSTRAINT_VIOLATION;
        if ( colst[0]->co_type == Cft_Global && !last ) {
-               cfn = &cf_prv;
-               ca.private = cfn;
-               ca.be = frontendDB;     /* just to get past check_vals */
+               cfn = cfb->cb_config;
+               ca->private = cfn;
+               ca->be = frontendDB;    /* just to get past check_vals */
                rc = LDAP_SUCCESS;
        }
 
@@ -3030,7 +3200,7 @@ config_add_internal( CfBackInfo *cfb, Entry *e, SlapReply *rs, int *renum )
        if ( last ) {
                for ( i=0; i<nocs; i++ ) {
                        if ( colst[i]->co_ldadd &&
-                               ( rc = colst[i]->co_ldadd( last, e, &ca ))
+                               ( rc = colst[i]->co_ldadd( last, e, ca ))
                                        != LDAP_CONSTRAINT_VIOLATION ) {
                                break;
                        }
@@ -3066,7 +3236,7 @@ config_add_internal( CfBackInfo *cfb, Entry *e, SlapReply *rs, int *renum )
        if ( rc )
                goto leave;
 
-       init_config_argv( &ca );
+       init_config_argv( ca );
 
        /* Make sure we process attrs in the required order */
        sort_attrs( e, colst, nocs );
@@ -3075,7 +3245,7 @@ config_add_internal( CfBackInfo *cfb, Entry *e, SlapReply *rs, int *renum )
                if ( a == oc_at ) continue;
                ct = config_find_table( colst, nocs, a->a_desc );
                if ( !ct ) continue;    /* user data? */
-               rc = check_vals( ct, &ca, a, 1 );
+               rc = check_vals( ct, ca, a, 1 );
                if ( rc ) goto leave;
        }
 
@@ -3085,13 +3255,13 @@ config_add_internal( CfBackInfo *cfb, Entry *e, SlapReply *rs, int *renum )
                ct = config_find_table( colst, nocs, a->a_desc );
                if ( !ct ) continue;    /* user data? */
                for (i=0; a->a_vals[i].bv_val; i++) {
-                       ca.line = a->a_vals[i].bv_val;
+                       ca->line = a->a_vals[i].bv_val;
                        if ( a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED ) {
-                               ptr = strchr( ca.line, '}' );
-                               if ( ptr ) ca.line = ptr+1;
+                               ptr = strchr( ca->line, '}' );
+                               if ( ptr ) ca->line = ptr+1;
                        }
-                       ca.valx = i;
-                       rc = config_parse_add( ct, &ca );
+                       ca->valx = i;
+                       rc = config_parse_add( ct, ca );
                        if ( rc ) {
                                rc = LDAP_OTHER;
                                goto leave;
@@ -3099,14 +3269,36 @@ config_add_internal( CfBackInfo *cfb, Entry *e, SlapReply *rs, int *renum )
                }
        }
 ok:
+       /* Newly added databases and overlays need to be started up */
+       if ( CONFIG_ONLINE_ADD( ca )) {
+               if ( colst[0]->co_type == Cft_Database ) {
+                       rc = backend_startup_one( ca->be );
+
+               } else if ( colst[0]->co_type == Cft_Overlay ) {
+                       if ( ca->bi->bi_db_open ) {
+                               BackendInfo *bi_orig = ca->be->bd_info;
+                               ca->be->bd_info = ca->bi;
+                               rc = ca->bi->bi_db_open( ca->be );
+                               ca->be->bd_info = bi_orig;
+                       }
+               }
+               if ( rc ) {
+                       sprintf( ca->msg, "<%s> failed startup", ca->argv[0] );
+                       Debug(LDAP_DEBUG_ANY, "%s: %s (%s)!\n",
+                               ca->log, ca->msg, ca->argv[1] );
+                       rc = LDAP_OTHER;
+                       goto leave;
+               }
+       }
+
        ce = ch_calloc( 1, sizeof(CfEntryInfo) );
        ce->ce_parent = last;
        ce->ce_entry = entry_dup( e );
        ce->ce_entry->e_private = ce;
        ce->ce_type = colst[0]->co_type;
-       ce->ce_be = ca.be;
-       ce->ce_bi = ca.bi;
-       ce->ce_private = ca.private;
+       ce->ce_be = ca->be;
+       ce->ce_bi = ca->bi;
+       ce->ce_private = ca->private;
        if ( !last ) {
                cfb->cb_root = ce;
        } else if ( last->ce_kids ) {
@@ -3120,7 +3312,16 @@ ok:
        }
 
 leave:
-       ch_free( ca.argv );
+       if ( rc ) {
+               if ( (colst[0]->co_type == Cft_Database) && ca->be ) {
+                       if ( ca->be != frontendDB )
+                               backend_destroy_one( ca->be, 1 );
+               } else if ( (colst[0]->co_type == Cft_Overlay) && ca->bi ) {
+                       overlay_destroy_one( ca->be, (slap_overinst *)ca->bi );
+               }
+       }
+
+       ch_free( ca->argv );
        if ( colst ) ch_free( colst );
        return rc;
 }
@@ -3132,8 +3333,8 @@ static int
 config_back_add( Operation *op, SlapReply *rs )
 {
        CfBackInfo *cfb;
-       CfEntryInfo *ce, *last;
        int renumber;
+       ConfigArgs ca;
 
        if ( !be_isroot( op ) ) {
                rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
@@ -3151,8 +3352,10 @@ config_back_add( Operation *op, SlapReply *rs )
         * 4) store entry in underlying database
         * 5) perform any necessary renumbering
         */
-       rs->sr_err = config_add_internal( cfb, op->ora_e, rs, &renumber );
-       if ( rs->sr_err == LDAP_SUCCESS && cfb->cb_use_ldif ) {
+       rs->sr_err = config_add_internal( cfb, op->ora_e, &ca, rs, &renumber );
+       if ( rs->sr_err != LDAP_SUCCESS ) {
+               rs->sr_text = ca.msg;
+       } else if ( cfb->cb_use_ldif ) {
                BackendDB *be = op->o_bd;
                slap_callback sc = { NULL, slap_null_cb, NULL, NULL };
                op->o_bd = &cfb->cb_db;
@@ -3175,14 +3378,13 @@ out:
 typedef struct delrec {
        struct delrec *next;
        int nidx;
-       int idx[0];
+       int idx[1];
 } delrec;
 
 static int
 config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs,
        ConfigArgs *ca )
 {
-       CfBackInfo *cfb = (CfBackInfo *)op->o_bd->be_private;
        int rc = LDAP_UNWILLING_TO_PERFORM;
        Modifications *ml;
        Entry *e = ce->ce_entry;
@@ -3216,8 +3418,6 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs,
                        int *idx = NULL;
                        if ( ct && ( ct->arg_type & ARG_NO_DELETE )) {
                                rc = LDAP_OTHER;
-                               snprintf( ca->msg, sizeof(ca->msg),
-                                       "<%s> cannot be deleted" );
                                snprintf(ca->msg, sizeof(ca->msg), "cannot delete %s",
                                        ml->sml_desc->ad_cname.bv_val );
                                goto out;
@@ -3234,7 +3434,7 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs,
                        if ( ct && ml->sml_values ) {
                                delrec *d;
                                for (i=0; ml->sml_values[i].bv_val; i++);
-                               d = ch_malloc( sizeof(delrec) + * sizeof(int));
+                               d = ch_malloc( sizeof(delrec) + (i - 1)* sizeof(int));
                                d->nidx = i;
                                d->next = NULL;
                                if ( dels ) {
@@ -3313,8 +3513,8 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs,
        
        if(rc == LDAP_SUCCESS) {
                /* check that the entry still obeys the schema */
-               rc = entry_schema_check(op->o_bd, e, NULL,
-                                 &rs->sr_text, ca->msg, sizeof(ca->msg) );
+               rc = entry_schema_check(op, e, NULL, 0,
+                       &rs->sr_text, ca->msg, sizeof(ca->msg) );
        }
        if ( rc == LDAP_SUCCESS ) {
                /* Basic syntax checks are OK. Do the actual settings. */
@@ -3537,7 +3737,6 @@ config_back_search( Operation *op, SlapReply *rs )
 {
        CfBackInfo *cfb;
        CfEntryInfo *ce, *last;
-       int rc;
 
        if ( !be_isroot( op ) ) {
                rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
@@ -3772,12 +3971,10 @@ config_back_db_open( BackendDB *be )
        CfBackInfo *cfb = be->be_private;
        struct berval rdn;
        Entry *e, *parent;
-       CfEntryInfo *ce, *ceparent, *ceprev;
-       int i, rc;
+       CfEntryInfo *ce, *ceparent;
+       int i;
        BackendInfo *bi;
-       BackendDB *bptr;
        ConfigArgs c;
-       ConfigTable *ct;
        Connection conn = {0};
        char opbuf[OPERATION_BUFFER_SIZE];
        Operation *op;
@@ -3860,25 +4057,22 @@ config_back_db_open( BackendDB *be )
        }
 
        /* Create database nodes... */
-       i = -1;
-       LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) {
+       frontendDB->be_cf_ocs = &CFOC_FRONTEND;
+       LDAP_STAILQ_NEXT(frontendDB, be_next) = LDAP_STAILQ_FIRST(&backendDB);
+       for ( i = -1, be = frontendDB ; be;
+               i++, be = LDAP_STAILQ_NEXT( be, be_next )) {
                slap_overinfo *oi = NULL;
-               i++;
-               if ( i == 0 ) {
-                       bptr = frontendDB;
-               } else {
-                       bptr = be;
-               }
-               if ( overlay_is_over( bptr )) {
-                       oi = bptr->bd_info->bi_private;
+
+               if ( overlay_is_over( be )) {
+                       oi = be->bd_info->bi_private;
                        bi = oi->oi_orig;
                } else {
-                       bi = bptr->bd_info;
+                       bi = be->bd_info;
                }
                rdn.bv_val = c.log;
                rdn.bv_len = sprintf(rdn.bv_val, "%s=" IFMT "%s", cfAd_database->ad_cname.bv_val,
                        i, bi->bi_type);
-               c.be = bptr;
+               c.be = be;
                c.bi = bi;
                e = config_build_entry( op, &rs, ceparent, &c, &rdn, &CFOC_DATABASE,
                        be->be_cf_ocs );
@@ -3895,7 +4089,7 @@ config_back_db_open( BackendDB *be )
                                rdn.bv_val = c.log;
                                rdn.bv_len = sprintf(rdn.bv_val, "%s=" IFMT "%s",
                                        cfAd_overlay->ad_cname.bv_val, j, on->on_bi.bi_type );
-                               c.be = bptr;
+                               c.be = be;
                                c.bi = &on->on_bi;
                                oe = config_build_entry( op, &rs, ce, &c, &rdn,
                                        &CFOC_OVERLAY, c.bi->bi_cf_ocs );
@@ -3904,25 +4098,93 @@ config_back_db_open( BackendDB *be )
                        }
                }
        }
+       if ( op )
+               slap_sl_mem_destroy( NULL, op->o_tmpmemctx );
+
+       return 0;
+}
+
+static void
+cfb_free_cffile( ConfigFile *cf )
+{
+       ConfigFile *next;
+
+       for (; cf; cf=next) {
+               next = cf->c_sibs;
+               if ( cf->c_kids )
+                       cfb_free_cffile( cf->c_kids );
+               ch_free( cf->c_file.bv_val );
+               ber_bvarray_free( cf->c_dseFiles );
+               ch_free( cf );
+       }
+}
+
+static void
+cfb_free_entries( CfEntryInfo *ce )
+{
+       CfEntryInfo *next;
+
+       for (; ce; ce=next) {
+               next = ce->ce_sibs;
+               if ( ce->ce_kids )
+                       cfb_free_entries( ce->ce_kids );
+               ce->ce_entry->e_private = NULL;
+               entry_free( ce->ce_entry );
+               ch_free( ce );
+       }
+}
+
+static int
+config_back_db_close( BackendDB *be )
+{
+       CfBackInfo *cfb = be->be_private;
+
+       cfb_free_entries( cfb->cb_root );
+       cfb->cb_root = NULL;
+
+       if ( cfb->cb_db.bd_info ) {
+               backend_shutdown( &cfb->cb_db );
+       }
 
        return 0;
 }
 
 static int
-config_back_db_destroy( Backend *be )
+config_back_db_destroy( BackendDB *be )
 {
+       CfBackInfo *cfb = be->be_private;
+
+       cfb_free_cffile( cfb->cb_config );
+
+       ch_free( cfdir.bv_val );
+
+       avl_free( CfOcTree, NULL );
+
+       if ( cfb->cb_db.bd_info ) {
+               cfb->cb_db.be_suffix = NULL;
+               cfb->cb_db.be_nsuffix = NULL;
+               BER_BVZERO( &cfb->cb_db.be_rootdn );
+               BER_BVZERO( &cfb->cb_db.be_rootndn );
+
+               backend_destroy_one( &cfb->cb_db, 0 );
+       }
+
        free( be->be_private );
+
+       loglevel_destroy();
+
        return 0;
 }
 
 static int
-config_back_db_init( Backend *be )
+config_back_db_init( BackendDB *be )
 {
        struct berval dn;
        CfBackInfo *cfb;
 
        cfb = ch_calloc( 1, sizeof(CfBackInfo));
-       cfb->cb_config = &cf_prv;
+       cfb->cb_config = ch_calloc( 1, sizeof(ConfigFile));
+       cfn = cfb->cb_config;
        be->be_private = cfb;
 
        ber_dupbv( &be->be_rootdn, &config_rdn );
@@ -4011,9 +4273,10 @@ config_tool_entry_put( BackendDB *be, Entry *e, struct berval *text )
 {
        CfBackInfo *cfb = be->be_private;
        BackendInfo *bi = cfb->cb_db.bd_info;
+       ConfigArgs ca;
 
        if ( bi && bi->bi_tool_entry_put &&
-               config_add_internal( cfb, e, NULL, NULL ) == 0 )
+               config_add_internal( cfb, e, &ca, NULL, NULL ) == 0 )
                return bi->bi_tool_entry_put( &cfb->cb_db, e, text );
        else
                return NOID;
@@ -4076,7 +4339,7 @@ config_back_initialize( BackendInfo *bi )
        bi->bi_db_init = config_back_db_init;
        bi->bi_db_config = 0;
        bi->bi_db_open = config_back_db_open;
-       bi->bi_db_close = 0;
+       bi->bi_db_close = config_back_db_close;
        bi->bi_db_destroy = config_back_db_destroy;
 
        bi->bi_op_bind = config_back_bind;
@@ -4107,6 +4370,9 @@ config_back_initialize( BackendInfo *bi )
        bi->bi_tool_entry_get = config_tool_entry_get;
        bi->bi_tool_entry_put = config_tool_entry_put;
 
+       /* Make sure we don't exceed the bits reserved for userland */
+       assert( ( ( CFG_LAST - 1 ) & ARGS_USERLAND ) == ( CFG_LAST - 1 ) );
+
        argv[3] = NULL;
        for (i=0; OidMacros[i].name; i++ ) {
                argv[1] = OidMacros[i].name;