]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/bconfig.c
ITS#7935 fix schema RDN normalization
[openldap] / servers / slapd / bconfig.c
index 882be198c825b9c528af4e32b1abccd69fb73426..c501135236665d02ad5f5a6236763d9a1ef87e08 100644 (file)
@@ -2,7 +2,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 2005-2008 The OpenLDAP Foundation.
+ * Copyright 2005-2014 The OpenLDAP Foundation.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -25,6 +25,7 @@
 #include <ac/ctype.h>
 #include <ac/errno.h>
 #include <sys/stat.h>
+#include <ac/unistd.h>
 
 #include "slap.h"
 
@@ -63,6 +64,7 @@ typedef struct ConfigFile {
        ContentRule *c_cr_head, *c_cr_tail;
        ObjectClass *c_oc_head, *c_oc_tail;
        OidMacro *c_om_head, *c_om_tail;
+       Syntax *c_syn_head, *c_syn_tail;
        BerVarray c_dseFiles;
 } ConfigFile;
 
@@ -82,12 +84,13 @@ static char *logfileName;
 #ifdef SLAP_AUTH_REWRITE
 static BerVarray authz_rewrites;
 #endif
+static AccessControl *defacl_parsed = NULL;
 
 static struct berval cfdir;
 
 /* Private state */
 static AttributeDescription *cfAd_backend, *cfAd_database, *cfAd_overlay,
-       *cfAd_include, *cfAd_attr, *cfAd_oc, *cfAd_om;
+       *cfAd_include, *cfAd_attr, *cfAd_oc, *cfAd_om, *cfAd_syntax;
 
 static ConfigFile *cfn;
 
@@ -97,9 +100,11 @@ static Avlnode *CfOcTree;
 extern AttributeType *at_sys_tail;     /* at.c */
 extern ObjectClass *oc_sys_tail;       /* oc.c */
 extern OidMacro *om_sys_tail;  /* oidm.c */
+extern Syntax *syn_sys_tail;   /* syntax.c */
 static AttributeType *cf_at_tail;
 static ObjectClass *cf_oc_tail;
 static OidMacro *cf_om_tail;
+static Syntax *cf_syn_tail;
 
 static int config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca,
        SlapReply *rs, int *renumber, Operation *op );
@@ -117,6 +122,9 @@ static ConfigDriver config_timelimit;
 static ConfigDriver config_overlay;
 static ConfigDriver config_subordinate; 
 static ConfigDriver config_suffix; 
+#ifdef LDAP_TCP_BUFFER
+static ConfigDriver config_tcp_buffer; 
+#endif /* LDAP_TCP_BUFFER */
 static ConfigDriver config_rootdn;
 static ConfigDriver config_rootpw;
 static ConfigDriver config_restrict;
@@ -128,6 +136,7 @@ static ConfigDriver config_referral;
 static ConfigDriver config_loglevel;
 static ConfigDriver config_updatedn;
 static ConfigDriver config_updateref;
+static ConfigDriver config_extra_attrs;
 static ConfigDriver config_include;
 static ConfigDriver config_obsolete;
 #ifdef HAVE_TLS
@@ -142,6 +151,7 @@ enum {
        CFG_DATABASE,
        CFG_TLS_RAND,
        CFG_TLS_CIPHER,
+       CFG_TLS_PROTOCOL_MIN,
        CFG_TLS_CERT_FILE,
        CFG_TLS_CERT_KEY,
        CFG_TLS_CA_PATH,
@@ -180,6 +190,10 @@ enum {
        CFG_SERVERID,
        CFG_SORTVALS,
        CFG_IX_INTLEN,
+       CFG_SYNTAX,
+       CFG_ACL_ADD,
+       CFG_SYNC_SUBENTRY,
+       CFG_LTHREADS,
 
        CFG_LAST
 };
@@ -226,11 +240,16 @@ static OidRec OidMacros[] = {
  * OLcfg{Bk|Db}{Oc|At}:0               -> common
  * OLcfg{Bk|Db}{Oc|At}:1               -> back-bdb(/back-hdb)
  * OLcfg{Bk|Db}{Oc|At}:2               -> back-ldif
- * OLcfg{Bk|Db}{Oc|At}:3               -> back-ldap
+ * OLcfg{Bk|Db}{Oc|At}:3               -> back-ldap/meta
  * OLcfg{Bk|Db}{Oc|At}:4               -> back-monitor
  * OLcfg{Bk|Db}{Oc|At}:5               -> back-relay
- * OLcfg{Bk|Db}{Oc|At}:6               -> back-sql
+ * OLcfg{Bk|Db}{Oc|At}:6               -> back-sql(/back-ndb)
  * OLcfg{Bk|Db}{Oc|At}:7               -> back-sock
+ * OLcfg{Bk|Db}{Oc|At}:8               -> back-null
+ * OLcfg{Bk|Db}{Oc|At}:9               -> back-passwd
+ * OLcfg{Bk|Db}{Oc|At}:10              -> back-shell
+ * OLcfg{Bk|Db}{Oc|At}:11              -> back-perl
+ * OLcfg{Bk|Db}{Oc|At}:12              -> back-mdb
  */
 
 /*
@@ -254,6 +273,8 @@ static OidRec OidMacros[] = {
  * OLcfgOv{Oc|At}:17                   -> dyngroup
  * OLcfgOv{Oc|At}:18                   -> memberof
  * OLcfgOv{Oc|At}:19                   -> collect
+ * OLcfgOv{Oc|At}:20                   -> retcode
+ * OLcfgOv{Oc|At}:21                   -> sssvlv
  */
 
 /* alphabetical ordering */
@@ -275,6 +296,10 @@ static ConfigTable config_back_cf_table[] = {
                        "DESC 'Access Control List' "
                        "EQUALITY caseIgnoreMatch "
                        "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
+       { "add_content_acl",    NULL, 0, 0, 0, ARG_MAY_DB|ARG_ON_OFF|ARG_MAGIC|CFG_ACL_ADD,
+               &config_generic, "( OLcfgGlAt:86 NAME 'olcAddContentAcl' "
+                       "DESC 'Check ACLs against content of Add ops' "
+                       "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
        { "allows",     "features", 2, 0, 5, ARG_PRE_DB|ARG_MAGIC,
                &config_allows, "( OLcfgGlAt:2 NAME 'olcAllows' "
                        "DESC 'Allowed set of deprecated features' "
@@ -294,6 +319,7 @@ static ConfigTable config_back_cf_table[] = {
                &config_generic, "( OLcfgGlAt:4 NAME 'olcAttributeTypes' "
                        "DESC 'OpenLDAP attributeTypes' "
                        "EQUALITY caseIgnoreMatch "
+                       "SUBSTR caseIgnoreSubstringsMatch "
                        "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )",
                                NULL, NULL },
        { "authid-rewrite", NULL, 2, 0, STRLENOF( "authid-rewrite" ),
@@ -309,7 +335,7 @@ static ConfigTable config_back_cf_table[] = {
                &config_generic, "( OLcfgGlAt:7 NAME 'olcAuthzPolicy' "
                        "EQUALITY caseIgnoreMatch "
                        "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
-       { "authz-regexp", NULL, 3, 3, 0, ARG_MAGIC|CFG_AZREGEXP|ARG_NO_INSERT,
+       { "authz-regexp", "regexp> <DN", 3, 3, 0, ARG_MAGIC|CFG_AZREGEXP|ARG_NO_INSERT,
                &config_generic, "( OLcfgGlAt:8 NAME 'olcAuthzRegexp' "
                        "EQUALITY caseIgnoreMatch "
                        "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
@@ -343,8 +369,13 @@ static ConfigTable config_back_cf_table[] = {
                &config_generic, "( OLcfgGlAt:16 NAME 'olcDitContentRules' "
                        "DESC 'OpenLDAP DIT content rules' "
                        "EQUALITY caseIgnoreMatch "
+                       "SUBSTR caseIgnoreSubstringsMatch "
                        "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )",
                        NULL, NULL },
+       { "extra_attrs", "attrlist", 2, 2, 0, ARG_DB|ARG_MAGIC,
+               &config_extra_attrs, "( OLcfgDbAt:0.20 NAME 'olcExtraAttrs' "
+                       "EQUALITY caseIgnoreMatch "
+                       "SYNTAX OMsDirectoryString )", NULL, NULL },
        { "gentlehup", "on|off", 2, 2, 0,
 #ifdef SIGHUP
                ARG_ON_OFF, &global_gentlehup,
@@ -362,28 +393,44 @@ static ConfigTable config_back_cf_table[] = {
        { "include", "file", 2, 2, 0, ARG_MAGIC,
                &config_include, "( OLcfgGlAt:19 NAME 'olcInclude' "
                        "SUP labeledURI )", NULL, NULL },
-       { "index_substr_if_minlen", "min", 2, 2, 0, ARG_INT|ARG_NONZERO|ARG_MAGIC|CFG_SSTR_IF_MIN,
+       { "index_substr_if_minlen", "min", 2, 2, 0, ARG_UINT|ARG_NONZERO|ARG_MAGIC|CFG_SSTR_IF_MIN,
                &config_generic, "( OLcfgGlAt:20 NAME 'olcIndexSubstrIfMinLen' "
                        "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
-       { "index_substr_if_maxlen", "max", 2, 2, 0, ARG_INT|ARG_NONZERO|ARG_MAGIC|CFG_SSTR_IF_MAX,
+       { "index_substr_if_maxlen", "max", 2, 2, 0, ARG_UINT|ARG_NONZERO|ARG_MAGIC|CFG_SSTR_IF_MAX,
                &config_generic, "( OLcfgGlAt:21 NAME 'olcIndexSubstrIfMaxLen' "
                        "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
-       { "index_substr_any_len", "len", 2, 2, 0, ARG_INT|ARG_NONZERO,
+       { "index_substr_any_len", "len", 2, 2, 0, ARG_UINT|ARG_NONZERO,
                &index_substr_any_len, "( OLcfgGlAt:22 NAME 'olcIndexSubstrAnyLen' "
                        "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
-       { "index_substr_any_step", "step", 2, 2, 0, ARG_INT|ARG_NONZERO,
+       { "index_substr_any_step", "step", 2, 2, 0, ARG_UINT|ARG_NONZERO,
                &index_substr_any_step, "( OLcfgGlAt:23 NAME 'olcIndexSubstrAnyStep' "
                        "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
-       { "index_intlen", "len", 2, 2, 0, ARG_INT|ARG_MAGIC|CFG_IX_INTLEN,
+       { "index_intlen", "len", 2, 2, 0, ARG_UINT|ARG_MAGIC|CFG_IX_INTLEN,
                &config_generic, "( OLcfgGlAt:84 NAME 'olcIndexIntLen' "
                        "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
        { "lastmod", "on|off", 2, 2, 0, ARG_DB|ARG_ON_OFF|ARG_MAGIC|CFG_LASTMOD,
                &config_generic, "( OLcfgDbAt:0.4 NAME 'olcLastMod' "
                        "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
+       { "ldapsyntax", "syntax", 2, 0, 0,
+               ARG_PAREN|ARG_MAGIC|CFG_SYNTAX,
+               &config_generic, "( OLcfgGlAt:85 NAME 'olcLdapSyntaxes' "
+                       "DESC 'OpenLDAP ldapSyntax' "
+                       "EQUALITY caseIgnoreMatch "
+                       "SUBSTR caseIgnoreSubstringsMatch "
+                       "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )",
+                               NULL, NULL },
        { "limits", "limits", 2, 0, 0, ARG_DB|ARG_MAGIC|CFG_LIMITS,
                &config_generic, "( OLcfgDbAt:0.5 NAME 'olcLimits' "
                        "EQUALITY caseIgnoreMatch "
                        "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
+       { "listener-threads", "count", 2, 0, 0,
+#ifdef NO_THREADS
+               ARG_IGNORED, NULL,
+#else
+               ARG_UINT|ARG_MAGIC|CFG_LTHREADS, &config_generic,
+#endif
+               "( OLcfgGlAt:93 NAME 'olcListenerThreads' "
+                       "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
        { "localSSF", "ssf", 2, 2, 0, ARG_INT,
                &local_ssf, "( OLcfgGlAt:26 NAME 'olcLocalSSF' "
                        "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
@@ -425,11 +472,13 @@ static ConfigTable config_back_cf_table[] = {
                &config_generic, "( OLcfgGlAt:32 NAME 'olcObjectClasses' "
                "DESC 'OpenLDAP object classes' "
                "EQUALITY caseIgnoreMatch "
+               "SUBSTR caseIgnoreSubstringsMatch "
                "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )",
                        NULL, NULL },
        { "objectidentifier", "name> <oid",     3, 3, 0, ARG_MAGIC|CFG_OID,
                &config_generic, "( OLcfgGlAt:33 NAME 'olcObjectIdentifier' "
                        "EQUALITY caseIgnoreMatch "
+                       "SUBSTR caseIgnoreSubstringsMatch "
                        "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
        { "overlay", "overlay", 2, 2, 0, ARG_MAGIC,
                &config_overlay, "( OLcfgGlAt:34 NAME 'olcOverlay' "
@@ -437,7 +486,7 @@ static ConfigTable config_back_cf_table[] = {
        { "password-crypt-salt-format", "salt", 2, 2, 0, ARG_STRING|ARG_MAGIC|CFG_SALT,
                &config_generic, "( OLcfgGlAt:35 NAME 'olcPasswordCryptSaltFormat' "
                        "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
-       { "password-hash", "hash", 2, 2, 0, ARG_MAGIC,
+       { "password-hash", "hash", 2, 0, 0, ARG_MAGIC,
                &config_passwd_hash, "( OLcfgGlAt:36 NAME 'olcPasswordHash' "
                        "EQUALITY caseIgnoreMatch "
                        "SYNTAX OMsDirectoryString )", NULL, NULL },
@@ -501,6 +550,7 @@ static ConfigTable config_back_cf_table[] = {
                        "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
        { "rootdn", "dn", 2, 2, 0, ARG_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC,
                &config_rootdn, "( OLcfgDbAt:0.8 NAME 'olcRootDN' "
+                       "EQUALITY distinguishedNameMatch "
                        "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
        { "rootDSE", "file", 2, 2, 0, ARG_MAGIC|CFG_ROOTDSE,
                &config_generic, "( OLcfgGlAt:51 NAME 'olcRootDSE' "
@@ -511,6 +561,14 @@ static ConfigTable config_back_cf_table[] = {
                        "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
        { "sasl-authz-policy", NULL, 2, 2, 0, ARG_MAGIC|CFG_AZPOLICY,
                &config_generic, NULL, NULL, NULL },
+       { "sasl-auxprops", NULL, 2, 0, 0,
+#ifdef HAVE_CYRUS_SASL
+               ARG_STRING|ARG_UNIQUE, &slap_sasl_auxprops,
+#else
+               ARG_IGNORED, NULL,
+#endif
+               "( OLcfgGlAt:89 NAME 'olcSaslAuxprops' "
+                       "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
        { "sasl-host", "host", 2, 2, 0,
 #ifdef HAVE_CYRUS_SASL
                ARG_STRING|ARG_UNIQUE, &sasl_host,
@@ -541,6 +599,7 @@ static ConfigTable config_back_cf_table[] = {
                &config_generic, NULL, NULL, NULL },
        { "schemadn", "dn", 2, 2, 0, ARG_MAY_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC,
                &config_schema_dn, "( OLcfgGlAt:58 NAME 'olcSchemaDN' "
+                       "EQUALITY distinguishedNameMatch "
                        "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
        { "security", "factors", 2, 0, 0, ARG_MAY_DB|ARG_MAGIC,
                &config_security, "( OLcfgGlAt:59 NAME 'olcSecurity' "
@@ -571,10 +630,23 @@ static ConfigTable config_back_cf_table[] = {
                &config_suffix, "( OLcfgDbAt:0.10 NAME 'olcSuffix' "
                        "EQUALITY distinguishedNameMatch "
                        "SYNTAX OMsDN )", NULL, NULL },
+       { "sync_use_subentry", NULL, 0, 0, 0, ARG_ON_OFF|ARG_DB|ARG_MAGIC|CFG_SYNC_SUBENTRY,
+               &config_generic, "( OLcfgDbAt:0.19 NAME 'olcSyncUseSubentry' "
+                       "DESC 'Store sync context in a subentry' "
+                       "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
        { "syncrepl", NULL, 0, 0, 0, ARG_DB|ARG_MAGIC,
                &syncrepl_config, "( OLcfgDbAt:0.11 NAME 'olcSyncrepl' "
                        "EQUALITY caseIgnoreMatch "
                        "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
+       { "tcp-buffer", "[listener=<listener>] [{read|write}=]size", 0, 0, 0,
+#ifndef LDAP_TCP_BUFFER
+               ARG_IGNORED, NULL,
+#else /* LDAP_TCP_BUFFER */
+               ARG_MAGIC, &config_tcp_buffer,
+#endif /* LDAP_TCP_BUFFER */
+                       "( OLcfgGlAt:90 NAME 'olcTCPBuffer' "
+                       "DESC 'Custom TCP buffer size' "
+                       "SYNTAX OMsDirectoryString )", NULL, NULL },
        { "threads", "count", 2, 2, 0,
 #ifdef NO_THREADS
                ARG_IGNORED, NULL,
@@ -586,7 +658,7 @@ static ConfigTable config_back_cf_table[] = {
        { "timelimit", "limit", 2, 0, 0, ARG_MAY_DB|ARG_MAGIC,
                &config_timelimit, "( OLcfgGlAt:67 NAME 'olcTimeLimit' "
                        "SYNTAX OMsDirectoryString )", NULL, NULL },
-       { "TLSCACertificateFile", NULL, 0, 0, 0,
+       { "TLSCACertificateFile", NULL, 2, 2, 0,
 #ifdef HAVE_TLS
                CFG_TLS_CA_FILE|ARG_STRING|ARG_MAGIC, &config_tls_option,
 #else
@@ -594,7 +666,7 @@ static ConfigTable config_back_cf_table[] = {
 #endif
                "( OLcfgGlAt:68 NAME 'olcTLSCACertificateFile' "
                        "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
-       { "TLSCACertificatePath", NULL, 0, 0, 0,
+       { "TLSCACertificatePath", NULL, 2, 2, 0,
 #ifdef HAVE_TLS
                CFG_TLS_CA_PATH|ARG_STRING|ARG_MAGIC, &config_tls_option,
 #else
@@ -602,7 +674,7 @@ static ConfigTable config_back_cf_table[] = {
 #endif
                "( OLcfgGlAt:69 NAME 'olcTLSCACertificatePath' "
                        "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
-       { "TLSCertificateFile", NULL, 0, 0, 0,
+       { "TLSCertificateFile", NULL, 2, 2, 0,
 #ifdef HAVE_TLS
                CFG_TLS_CERT_FILE|ARG_STRING|ARG_MAGIC, &config_tls_option,
 #else
@@ -610,7 +682,7 @@ static ConfigTable config_back_cf_table[] = {
 #endif
                "( OLcfgGlAt:70 NAME 'olcTLSCertificateFile' "
                        "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
-       { "TLSCertificateKeyFile", NULL, 0, 0, 0,
+       { "TLSCertificateKeyFile", NULL, 2, 2, 0,
 #ifdef HAVE_TLS
                CFG_TLS_CERT_KEY|ARG_STRING|ARG_MAGIC, &config_tls_option,
 #else
@@ -618,7 +690,7 @@ static ConfigTable config_back_cf_table[] = {
 #endif
                "( OLcfgGlAt:71 NAME 'olcTLSCertificateKeyFile' "
                        "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
-       { "TLSCipherSuite",     NULL, 0, 0, 0,
+       { "TLSCipherSuite",     NULL, 2, 2, 0,
 #ifdef HAVE_TLS
                CFG_TLS_CIPHER|ARG_STRING|ARG_MAGIC, &config_tls_option,
 #else
@@ -626,7 +698,7 @@ static ConfigTable config_back_cf_table[] = {
 #endif
                "( OLcfgGlAt:72 NAME 'olcTLSCipherSuite' "
                        "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
-       { "TLSCRLCheck", NULL, 0, 0, 0,
+       { "TLSCRLCheck", NULL, 2, 2, 0,
 #if defined(HAVE_TLS) && defined(HAVE_OPENSSL_CRL)
                CFG_TLS_CRLCHECK|ARG_STRING|ARG_MAGIC, &config_tls_config,
 #else
@@ -634,7 +706,7 @@ static ConfigTable config_back_cf_table[] = {
 #endif
                "( OLcfgGlAt:73 NAME 'olcTLSCRLCheck' "
                        "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
-       { "TLSCRLFile", NULL, 0, 0, 0,
+       { "TLSCRLFile", NULL, 2, 2, 0,
 #if defined(HAVE_GNUTLS)
                CFG_TLS_CRL_FILE|ARG_STRING|ARG_MAGIC, &config_tls_option,
 #else
@@ -642,7 +714,7 @@ static ConfigTable config_back_cf_table[] = {
 #endif
                "( OLcfgGlAt:82 NAME 'olcTLSCRLFile' "
                        "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
-       { "TLSRandFile", NULL, 0, 0, 0,
+       { "TLSRandFile", NULL, 2, 2, 0,
 #ifdef HAVE_TLS
                CFG_TLS_RAND|ARG_STRING|ARG_MAGIC, &config_tls_option,
 #else
@@ -650,7 +722,7 @@ static ConfigTable config_back_cf_table[] = {
 #endif
                "( OLcfgGlAt:74 NAME 'olcTLSRandFile' "
                        "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
-       { "TLSVerifyClient", NULL, 0, 0, 0,
+       { "TLSVerifyClient", NULL, 2, 2, 0,
 #ifdef HAVE_TLS
                CFG_TLS_VERIFY|ARG_STRING|ARG_MAGIC, &config_tls_config,
 #else
@@ -658,7 +730,7 @@ static ConfigTable config_back_cf_table[] = {
 #endif
                "( OLcfgGlAt:75 NAME 'olcTLSVerifyClient' "
                        "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
-       { "TLSDHParamFile", NULL, 0, 0, 0,
+       { "TLSDHParamFile", NULL, 2, 2, 0,
 #ifdef HAVE_TLS
                CFG_TLS_DH_FILE|ARG_STRING|ARG_MAGIC, &config_tls_option,
 #else
@@ -666,6 +738,14 @@ static ConfigTable config_back_cf_table[] = {
 #endif
                "( OLcfgGlAt:77 NAME 'olcTLSDHParamFile' "
                        "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
+       { "TLSProtocolMin",     NULL, 2, 2, 0,
+#ifdef HAVE_TLS
+               CFG_TLS_PROTOCOL_MIN|ARG_STRING|ARG_MAGIC, &config_tls_config,
+#else
+               ARG_IGNORED, NULL,
+#endif
+               "( OLcfgGlAt:87 NAME 'olcTLSProtocolMin' "
+                       "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
        { "tool-threads", "count", 2, 2, 0, ARG_INT|ARG_MAGIC|CFG_TTHREADS,
                &config_generic, "( OLcfgGlAt:80 NAME 'olcToolThreads' "
                        "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
@@ -678,10 +758,22 @@ static ConfigTable config_back_cf_table[] = {
                &config_updateref, "( OLcfgDbAt:0.13 NAME 'olcUpdateRef' "
                        "EQUALITY caseIgnoreMatch "
                        "SUP labeledURI )", NULL, NULL },
+       { "writetimeout", "timeout", 2, 2, 0, ARG_INT,
+               &global_writetimeout, "( OLcfgGlAt:88 NAME 'olcWriteTimeout' "
+                       "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
        { NULL, NULL, 0, 0, 0, ARG_IGNORED,
                NULL, NULL, NULL, NULL }
 };
 
+/* Need to no-op this keyword for dynamic config */
+ConfigTable olcDatabaseDummy[] = {
+       { "", "", 0, 0, 0, ARG_IGNORED,
+               NULL, "( OLcfgGlAt:13 NAME 'olcDatabase' "
+                       "DESC 'The backend type for a database instance' "
+                       "SUP olcBackend SINGLE-VALUE X-ORDERED 'SIBLINGS' )", NULL, NULL },
+       { NULL, NULL, 0, 0, 0, ARG_IGNORED }
+};
+
 /* Routines to check if a child can be added to this type */
 static ConfigLDAPadd cfAddSchema, cfAddInclude, cfAddDatabase,
        cfAddBackend, cfAddModule, cfAddOverlay;
@@ -715,27 +807,28 @@ static ConfigOCs cf_ocs[] = {
                 "olcDisallows $ olcGentleHUP $ olcIdleTimeout $ "
                 "olcIndexSubstrIfMaxLen $ olcIndexSubstrIfMinLen $ "
                 "olcIndexSubstrAnyLen $ olcIndexSubstrAnyStep $ olcIndexIntLen $ "
-                "olcLocalSSF $ olcLogLevel $ "
+                "olcListenerThreads $ olcLocalSSF $ olcLogFile $ olcLogLevel $ "
                 "olcPasswordCryptSaltFormat $ olcPasswordHash $ olcPidFile $ "
                 "olcPluginLogFile $ olcReadOnly $ olcReferral $ "
                 "olcReplogFile $ olcRequires $ olcRestrict $ olcReverseLookup $ "
                 "olcRootDSE $ "
-                "olcSaslHost $ olcSaslRealm $ olcSaslSecProps $ "
+                "olcSaslAuxprops $ olcSaslHost $ olcSaslRealm $ olcSaslSecProps $ "
                 "olcSecurity $ olcServerID $ olcSizeLimit $ "
                 "olcSockbufMaxIncoming $ olcSockbufMaxIncomingAuth $ "
+                "olcTCPBuffer $ "
                 "olcThreads $ olcTimeLimit $ olcTLSCACertificateFile $ "
                 "olcTLSCACertificatePath $ olcTLSCertificateFile $ "
                 "olcTLSCertificateKeyFile $ olcTLSCipherSuite $ olcTLSCRLCheck $ "
                 "olcTLSRandFile $ olcTLSVerifyClient $ olcTLSDHParamFile $ "
-                "olcTLSCRLFile $ olcToolThreads $ "
+                "olcTLSCRLFile $ olcTLSProtocolMin $ olcToolThreads $ olcWriteTimeout $ "
                 "olcObjectIdentifier $ olcAttributeTypes $ olcObjectClasses $ "
-                "olcDitContentRules ) )", Cft_Global },
+                "olcDitContentRules $ olcLdapSyntaxes ) )", Cft_Global },
        { "( OLcfgGlOc:2 "
                "NAME 'olcSchemaConfig' "
                "DESC 'OpenLDAP schema object' "
                "SUP olcConfig STRUCTURAL "
-               "MAY ( cn $ olcObjectIdentifier $ olcAttributeTypes $ "
-                "olcObjectClasses $ olcDitContentRules ) )",
+               "MAY ( cn $ olcObjectIdentifier $ olcLdapSyntaxes $ "
+                "olcAttributeTypes $ olcObjectClasses $ olcDitContentRules ) )",
                        Cft_Schema, NULL, cfAddSchema },
        { "( OLcfgGlOc:3 "
                "NAME 'olcBackendConfig' "
@@ -748,13 +841,13 @@ static ConfigOCs cf_ocs[] = {
                "SUP olcConfig STRUCTURAL "
                "MUST olcDatabase "
                "MAY ( olcHidden $ olcSuffix $ olcSubordinate $ olcAccess $ "
-                "olcLastMod $ olcLimits $ "
+                "olcAddContentAcl $ olcLastMod $ olcLimits $ "
                 "olcMaxDerefDepth $ olcPlugin $ olcReadOnly $ olcReplica $ "
                 "olcReplicaArgsFile $ olcReplicaPidFile $ olcReplicationInterval $ "
                 "olcReplogFile $ olcRequires $ olcRestrict $ olcRootDN $ olcRootPW $ "
-                "olcSchemaDN $ olcSecurity $ olcSizeLimit $ olcSyncrepl $ "
+                "olcSchemaDN $ olcSecurity $ olcSizeLimit $ olcSyncUseSubentry $ olcSyncrepl $ "
                 "olcTimeLimit $ olcUpdateDN $ olcUpdateRef $ olcMirrorMode $ "
-                "olcMonitoring ) )",
+                "olcMonitoring $ olcExtraAttrs ) )",
                        Cft_Database, NULL, cfAddDatabase },
        { "( OLcfgGlOc:5 "
                "NAME 'olcOverlayConfig' "
@@ -797,6 +890,7 @@ typedef struct ServerID {
 } ServerID;
 
 static ServerID *sid_list;
+static ServerID *sid_set;
 
 typedef struct voidList {
        struct voidList *vl_next;
@@ -826,6 +920,9 @@ config_generic(ConfigArgs *c) {
                case CFG_TTHREADS:
                        c->value_int = slap_tool_thread_max;
                        break;
+               case CFG_LTHREADS:
+                       c->value_uint = slapd_daemon_threads;
+                       break;
                case CFG_SALT:
                        if ( passwd_salt )
                                c->value_string = ch_strdup( passwd_salt );
@@ -856,8 +953,7 @@ 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) ==
-                               SLAP_RESTRICT_OP_WRITES;
+                       c->value_int = (c->be->be_restrictops & SLAP_RESTRICT_READONLY);
                        break;
                case CFG_AZPOLICY:
                        c->value_string = ch_strdup( slap_sasl_getpolicy());
@@ -924,6 +1020,17 @@ config_generic(ConfigArgs *c) {
                                rc = 1;
                        }
                        break;
+               case CFG_SYNTAX: {
+                       ConfigFile *cf = c->ca_private;
+                       if ( !cf )
+                               syn_unparse( &c->rvalue_vals, NULL, NULL, 1 );
+                       else if ( cf->c_syn_head )
+                               syn_unparse( &c->rvalue_vals, cf->c_syn_head,
+                                       cf->c_syn_tail, 0 );
+                       if ( !c->rvalue_vals )
+                               rc = 1;
+                       }
+                       break;
                case CFG_DIT: {
                        ConfigFile *cf = c->ca_private;
                        if ( !cf )
@@ -940,12 +1047,7 @@ config_generic(ConfigArgs *c) {
                        AccessControl *a;
                        char *src, *dst, ibuf[11];
                        struct berval bv, abv;
-                       AccessControl *end;
-                       if ( c->be == frontendDB )
-                               end = NULL;
-                       else
-                               end = frontendDB->be_acl;
-                       for (i=0, a=c->be->be_acl; a && a != end; i++,a=a->acl_next) {
+                       for (i=0, a=c->be->be_acl; a; i++,a=a->acl_next) {
                                abv.bv_len = snprintf( ibuf, sizeof( ibuf ), SLAP_X_ORDERED_FMT, i );
                                if ( abv.bv_len >= sizeof( ibuf ) ) {
                                        ber_bvarray_free_x( c->rvalue_vals, NULL );
@@ -972,6 +1074,9 @@ config_generic(ConfigArgs *c) {
                        rc = (!i);
                        break;
                }
+               case CFG_ACL_ADD:
+                       c->value_int = (SLAP_DBACL_ADD(c->be) != 0);
+                       break;
                case CFG_ROOTDSE: {
                        ConfigFile *cf = c->ca_private;
                        if ( cf->c_dseFiles ) {
@@ -991,7 +1096,7 @@ config_generic(ConfigArgs *c) {
                                        if ( !BER_BVISEMPTY( &si->si_url )) {
                                                bv.bv_len = si->si_url.bv_len + 6;
                                                bv.bv_val = ch_malloc( bv.bv_len );
-                                               sprintf( bv.bv_val, "%d %s", si->si_num,
+                                               bv.bv_len = sprintf( bv.bv_val, "%d %s", si->si_num,
                                                        si->si_url.bv_val );
                                                ber_bvarray_add( &c->rvalue_vals, &bv );
                                        } else {
@@ -1014,9 +1119,12 @@ config_generic(ConfigArgs *c) {
                case CFG_LASTMOD:
                        c->value_int = (SLAP_NOLASTMOD(c->be) == 0);
                        break;
+               case CFG_SYNC_SUBENTRY:
+                       c->value_int = (SLAP_SYNC_SUBENTRY(c->be) != 0);
+                       break;
                case CFG_MIRRORMODE:
                        if ( SLAP_SHADOW(c->be))
-                               c->value_int = (SLAP_SINGLE_SHADOW(c->be) == 0);
+                               c->value_int = (SLAP_MULTIMASTER(c->be) != 0);
                        else
                                rc = 1;
                        break;
@@ -1024,10 +1132,10 @@ config_generic(ConfigArgs *c) {
                        c->value_int = (SLAP_DBMONITORING(c->be) != 0);
                        break;
                case CFG_SSTR_IF_MAX:
-                       c->value_int = index_substr_if_maxlen;
+                       c->value_uint = index_substr_if_maxlen;
                        break;
                case CFG_SSTR_IF_MIN:
-                       c->value_int = index_substr_if_minlen;
+                       c->value_uint = index_substr_if_minlen;
                        break;
                case CFG_IX_INTLEN:
                        c->value_int = index_intlen;
@@ -1116,15 +1224,17 @@ config_generic(ConfigArgs *c) {
                case CFG_CONCUR:
                case CFG_THREADS:
                case CFG_TTHREADS:
+               case CFG_LTHREADS:
                case CFG_RO:
                case CFG_AZPOLICY:
                case CFG_DEPTH:
                case CFG_LASTMOD:
-               case CFG_MIRRORMODE:
                case CFG_MONITORING:
                case CFG_SASLSECP:
                case CFG_SSTR_IF_MAX:
                case CFG_SSTR_IF_MIN:
+               case CFG_ACL_ADD:
+               case CFG_SYNC_SUBENTRY:
                        break;
 
                /* no-ops, requires slapd restart */
@@ -1135,6 +1245,12 @@ config_generic(ConfigArgs *c) {
                        snprintf(c->log, sizeof( c->log ), "change requires slapd restart");
                        break;
 
+               case CFG_MIRRORMODE:
+                       SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_MULTI_SHADOW;
+                       if(SLAP_SHADOW(c->be))
+                               SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_SINGLE_SHADOW;
+                       break;
+
                case CFG_SALT:
                        ch_free( passwd_salt );
                        passwd_salt = NULL;
@@ -1156,6 +1272,8 @@ config_generic(ConfigArgs *c) {
                                si; si = *sip, i++ ) {
                                if ( c->valx == -1 || i == c->valx ) {
                                        *sip = si->si_next;
+                                       if ( sid_set == si )
+                                               sid_set = NULL;
                                        ch_free( si );
                                        if ( c->valx >= 0 )
                                                break;
@@ -1177,13 +1295,8 @@ config_generic(ConfigArgs *c) {
 
                case CFG_ACL:
                        if ( c->valx < 0 ) {
-                               AccessControl *end;
-                               if ( c->be == frontendDB )
-                                       end = NULL;
-                               else
-                                       end = frontendDB->be_acl;
-                               acl_destroy( c->be->be_acl, end );
-                               c->be->be_acl = end;
+                               acl_destroy( c->be->be_acl );
+                               c->be->be_acl = NULL;
 
                        } else {
                                AccessControl **prev, *a;
@@ -1197,6 +1310,12 @@ config_generic(ConfigArgs *c) {
                                *prev = a->acl_next;
                                acl_free( a );
                        }
+                       if ( SLAP_CONFIG( c->be ) && !c->be->be_acl ) {
+                               Debug( LDAP_DEBUG_CONFIG, "config_generic (CFG_ACL): "
+                                               "Last explicit ACL for back-config removed. "
+                                               "Using hardcoded default\n", 0, 0, 0 );
+                               c->be->be_acl = defacl_parsed;
+                       }
                        break;
 
                case CFG_OC: {
@@ -1274,6 +1393,44 @@ config_generic(ConfigArgs *c) {
                                }
                        }
                        break;
+
+               case CFG_SYNTAX: {
+                       CfEntryInfo *ce;
+                       /* Can be NULL when undoing a failed add */
+                       if ( c->ca_entry ) {
+                               ce = c->ca_entry->e_private;
+                               /* can't modify the hardcoded schema */
+                               if ( ce->ce_parent->ce_type == Cft_Global )
+                                       return 1;
+                               }
+                       }
+                       cfn = c->ca_private;
+                       if ( c->valx < 0 ) {
+                               Syntax *syn;
+
+                               for( syn = cfn->c_syn_head; syn; syn_next( &syn )) {
+                                       syn_delete( syn );
+                                       if ( syn == cfn->c_syn_tail )
+                                               break;
+                               }
+                               cfn->c_syn_head = cfn->c_syn_tail = NULL;
+                       } else {
+                               Syntax *syn, *prev = NULL;
+
+                               for ( i = 0, syn = cfn->c_syn_head; i < c->valx; i++) {
+                                       prev = syn;
+                                       syn_next( &syn );
+                               }
+                               syn_delete( syn );
+                               if ( cfn->c_syn_tail == syn ) {
+                                       cfn->c_syn_tail = prev;
+                               }
+                               if ( cfn->c_syn_head == syn ) {
+                                       syn_next( &syn );
+                                       cfn->c_syn_head = syn;
+                               }
+                       }
+                       break;
                case CFG_SORTVALS:
                        if ( c->valx < 0 ) {
                                ADlist *sv;
@@ -1298,6 +1455,36 @@ config_generic(ConfigArgs *c) {
 
                case CFG_LIMITS:
                        /* FIXME: there is no limits_free function */
+                       if ( c->valx < 0 ) {
+                               limits_destroy( c->be->be_limits );
+                               c->be->be_limits = NULL;
+
+                       } else {
+                               int cnt, num = -1;
+
+                               if ( c->be->be_limits ) {
+                                       for ( num = 0; c->be->be_limits[ num ]; num++ )
+                                               /* just count */ ;
+                               }
+
+                               if ( c->valx >= num ) {
+                                       return 1;
+                               }
+
+                               if ( num == 1 ) {
+                                       limits_destroy( c->be->be_limits );
+                                       c->be->be_limits = NULL;
+
+                               } else {
+                                       limits_free_one( c->be->be_limits[ c->valx ] );
+
+                                       for ( cnt = c->valx; cnt < num; cnt++ ) {
+                                               c->be->be_limits[ cnt ] = c->be->be_limits[ cnt + 1 ];
+                                       }
+                               }
+                       }
+                       break;
+
                case CFG_ATOPT:
                        /* FIXME: there is no ad_option_free function */
                case CFG_ROOTDSE:
@@ -1373,6 +1560,19 @@ config_generic(ConfigArgs *c) {
                        slap_tool_thread_max = c->value_int;    /* save for reference */
                        break;
 
+               case CFG_LTHREADS:
+                       { int mask = 0;
+                       /* use a power of two */
+                       while (c->value_uint > 1) {
+                               c->value_uint >>= 1;
+                               mask <<= 1;
+                               mask |= 1;
+                       }
+                       slapd_daemon_mask = mask;
+                       slapd_daemon_threads = mask+1;
+                       }
+                       break;
+
                case CFG_SALT:
                        if ( passwd_salt ) ch_free( passwd_salt );
                        passwd_salt = c->value_string;
@@ -1386,9 +1586,9 @@ config_generic(ConfigArgs *c) {
 
                case CFG_RO:
                        if(c->value_int)
-                               c->be->be_restrictops |= SLAP_RESTRICT_OP_WRITES;
+                               c->be->be_restrictops |= SLAP_RESTRICT_READONLY;
                        else
-                               c->be->be_restrictops &= ~SLAP_RESTRICT_OP_WRITES;
+                               c->be->be_restrictops &= ~SLAP_RESTRICT_READONLY;
                        break;
 
                case CFG_AZPOLICY:
@@ -1450,7 +1650,8 @@ config_generic(ConfigArgs *c) {
                                        int i;
                                        for (i=0, oc = cfn->c_oc_head; i<c->valx; i++) {
                                                prev = oc;
-                                               oc_next( &oc );
+                                               if ( !oc_next( &oc ))
+                                                       break;
                                        }
                                } else
                                /* If adding the first, and head exists, find its prev */
@@ -1463,7 +1664,7 @@ config_generic(ConfigArgs *c) {
                                /* else prev is NULL, append to end of global list */
                        }
                        if(parse_oc(c, &oc, prev)) return(1);
-                       if (!cfn->c_oc_head) cfn->c_oc_head = oc;
+                       if (!cfn->c_oc_head || !c->valx) cfn->c_oc_head = oc;
                        if (cfn->c_oc_tail == prev) cfn->c_oc_tail = oc;
                        }
                        break;
@@ -1482,7 +1683,8 @@ config_generic(ConfigArgs *c) {
                                        int i;
                                        for (i=0, at = cfn->c_at_head; i<c->valx; i++) {
                                                prev = at;
-                                               at_next( &at );
+                                               if ( !at_next( &at ))
+                                                       break;
                                        }
                                } else
                                /* If adding the first, and head exists, find its prev */
@@ -1495,11 +1697,44 @@ config_generic(ConfigArgs *c) {
                                /* else prev is NULL, append to end of global list */
                        }
                        if(parse_at(c, &at, prev)) return(1);
-                       if (!cfn->c_at_head) cfn->c_at_head = at;
+                       if (!cfn->c_at_head || !c->valx) cfn->c_at_head = at;
                        if (cfn->c_at_tail == prev) cfn->c_at_tail = at;
                        }
                        break;
 
+               case CFG_SYNTAX: {
+                       Syntax *syn, *prev;
+
+                       if ( c->op == LDAP_MOD_ADD && c->ca_private && cfn != c->ca_private )
+                               cfn = c->ca_private;
+                       if ( c->valx < 0 ) {
+                               prev = cfn->c_syn_tail;
+                       } else {
+                               prev = NULL;
+                               /* If adding anything after the first, prev is easy */
+                               if ( c->valx ) {
+                                       int i;
+                                       for ( i = 0, syn = cfn->c_syn_head; i < c->valx; i++ ) {
+                                               prev = syn;
+                                               if ( !syn_next( &syn ))
+                                                       break;
+                                       }
+                               } else
+                               /* If adding the first, and head exists, find its prev */
+                                       if (cfn->c_syn_head) {
+                                       for ( syn_start( &syn ); syn != cfn->c_syn_head; ) {
+                                               prev = syn;
+                                               syn_next( &syn );
+                                       }
+                               }
+                               /* else prev is NULL, append to end of global list */
+                       }
+                       if ( parse_syn( c, &syn, prev ) ) return(1);
+                       if ( !cfn->c_syn_head || !c->valx ) cfn->c_syn_head = syn;
+                       if ( cfn->c_syn_tail == prev ) cfn->c_syn_tail = syn;
+                       }
+                       break;
+
                case CFG_DIT: {
                        ContentRule *cr;
 
@@ -1576,20 +1811,32 @@ sortval_reject:
                        break;
 
                case CFG_ACL:
+                       if ( SLAP_CONFIG( c->be ) && c->be->be_acl == defacl_parsed) {
+                               c->be->be_acl = NULL;
+                       }
                        /* Don't append to the global ACL if we're on a specific DB */
                        i = c->valx;
-                       if ( c->be != frontendDB && frontendDB->be_acl && c->valx == -1 ) {
+                       if ( c->valx == -1 ) {
                                AccessControl *a;
                                i = 0;
-                               for ( a=c->be->be_acl; a && a != frontendDB->be_acl;
-                                       a = a->acl_next )
+                               for ( a=c->be->be_acl; a; a = a->acl_next )
                                        i++;
                        }
                        if ( parse_acl(c->be, c->fname, c->lineno, c->argc, c->argv, i ) ) {
+                               if ( SLAP_CONFIG( c->be ) && !c->be->be_acl) {
+                                       c->be->be_acl = defacl_parsed;
+                               }
                                return 1;
                        }
                        break;
 
+               case CFG_ACL_ADD:
+                       if(c->value_int)
+                               SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_ACL_ADD;
+                       else
+                               SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_ACL_ADD;
+                       break;
+
                case CFG_ROOTDSE:
                        if(root_dse_read_file(c->argv[1])) {
                                snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> could not read file", c->argv[0] );
@@ -1611,7 +1858,8 @@ sortval_reject:
                                ServerID *si, **sip;
                                LDAPURLDesc *lud;
                                int num;
-                               if ( lutil_atoi( &num, c->argv[1] ) ||
+                               if (( lutil_atoi( &num, c->argv[1] ) && 
+                                       lutil_atoix( &num, c->argv[1], 16 )) ||
                                        num < 0 || num > SLAP_SYNC_SID_MAX )
                                {
                                        snprintf( c->cr_msg, sizeof( c->cr_msg ),
@@ -1656,8 +1904,9 @@ sortval_reject:
                                        BER_BVZERO( &si->si_url );
                                        slap_serverID = num;
                                        Debug( LDAP_DEBUG_CONFIG,
-                                               "%s: SID=%d\n",
+                                               "%s: SID=0x%03x\n",
                                                c->log, slap_serverID, 0 );
+                                       sid_set = si;
                                }
                                si->si_next = NULL;
                                si->si_num = num;
@@ -1665,56 +1914,22 @@ sortval_reject:
                                *sip = si;
 
                                if (( slapMode & SLAP_SERVER_MODE ) && c->argc > 2 ) {
-                                       /* If hostname is empty, or is localhost, or matches
-                                        * our hostname, this serverID refers to this host.
-                                        * Compare it against listeners and ports.
-                                        */
-                                       if ( !lud->lud_host || !lud->lud_host[0] ||
-                                               !strncasecmp("localhost", lud->lud_host,
-                                                       STRLENOF("localhost")) ||
-                                               !strcasecmp( global_host, lud->lud_host )) {
-                                               Listener **l = slapd_get_listeners();
-                                               int i;
-
-                                               for ( i=0; l[i]; i++ ) {
-                                                       LDAPURLDesc *lu2;
-                                                       int isMe = 0;
-                                                       ldap_url_parse( l[i]->sl_url.bv_val, &lu2 );
-                                                       do {
-                                                               if ( strcasecmp( lud->lud_scheme,
-                                                                       lu2->lud_scheme ))
-                                                                       break;
-                                                               if ( lud->lud_port != lu2->lud_port )
-                                                                       break;
-                                                               /* Listener on ANY address */
-                                                               if ( !lu2->lud_host || !lu2->lud_host[0] ) {
-                                                                       isMe = 1;
-                                                                       break;
-                                                               }
-                                                               /* URL on ANY address */
-                                                               if ( !lud->lud_host || !lud->lud_host[0] ) {
-                                                                       isMe = 1;
-                                                                       break;
-                                                               }
-                                                               /* Listener has specific host, must
-                                                                * match it
-                                                                */
-                                                               if ( !strcasecmp( lud->lud_host,
-                                                                       lu2->lud_host )) {
-                                                                       isMe = 1;
-                                                                       break;
-                                                               }
-                                                       } while(0);
-                                                       ldap_free_urldesc( lu2 );
-                                                       if ( isMe ) {
-                                                               slap_serverID = si->si_num;
-                                                               Debug( LDAP_DEBUG_CONFIG,
-                                                                       "%s: SID=%d (listener=%s)\n",
-                                                                       c->log, slap_serverID,
-                                                                       l[i]->sl_url.bv_val );
-                                                               break;
-                                                       }
+                                       Listener *l = config_check_my_url( c->argv[2], lud );
+                                       if ( l ) {
+                                               if ( sid_set ) {
+                                                       ldap_free_urldesc( lud );
+                                                       snprintf( c->cr_msg, sizeof( c->cr_msg ),
+                                                               "<%s> multiple server ID URLs matched, only one is allowed", c->argv[0] );
+                                                       Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
+                                                               c->log, c->cr_msg, c->argv[1] );
+                                                       return 1;
                                                }
+                                               slap_serverID = si->si_num;
+                                               Debug( LDAP_DEBUG_CONFIG,
+                                                       "%s: SID=0x%03x (listener=%s)\n",
+                                                       c->log, slap_serverID,
+                                                       l->sl_url.bv_val );
+                                               sid_set = si;
                                        }
                                }
                                if ( c->argc > 2 )
@@ -1743,17 +1958,20 @@ sortval_reject:
                        break;
 
                case CFG_MIRRORMODE:
-                       if(!SLAP_SHADOW(c->be)) {
+                       if(c->value_int && !SLAP_SHADOW(c->be)) {
                                snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> database is not a shadow",
                                        c->argv[0] );
                                Debug(LDAP_DEBUG_ANY, "%s: %s\n",
                                        c->log, c->cr_msg, 0 );
                                return(1);
                        }
-                       if(c->value_int)
+                       if(c->value_int) {
                                SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_SINGLE_SHADOW;
-                       else
+                               SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_MULTI_SHADOW;
+                       } else {
                                SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_SINGLE_SHADOW;
+                               SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_MULTI_SHADOW;
+                       }
                        break;
 
                case CFG_MONITORING:
@@ -1770,24 +1988,31 @@ sortval_reject:
                                SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_HIDDEN;
                        break;
 
+               case CFG_SYNC_SUBENTRY:
+                       if (c->value_int)
+                               SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_SYNC_SUBENTRY;
+                       else
+                               SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_SYNC_SUBENTRY;
+                       break;
+
                case CFG_SSTR_IF_MAX:
-                       if (c->value_int < index_substr_if_minlen) {
+                       if (c->value_uint < index_substr_if_minlen) {
                                snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid value", c->argv[0] );
                                Debug(LDAP_DEBUG_ANY, "%s: %s (%d)\n",
                                        c->log, c->cr_msg, c->value_int );
                                return(1);
                        }
-                       index_substr_if_maxlen = c->value_int;
+                       index_substr_if_maxlen = c->value_uint;
                        break;
 
                case CFG_SSTR_IF_MIN:
-                       if (c->value_int > index_substr_if_maxlen) {
+                       if (c->value_uint > index_substr_if_maxlen) {
                                snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid value", c->argv[0] );
                                Debug(LDAP_DEBUG_ANY, "%s: %s (%d)\n",
                                        c->log, c->cr_msg, c->value_int );
                                return(1);
                        }
-                       index_substr_if_minlen = c->value_int;
+                       index_substr_if_minlen = c->value_uint;
                        break;
 
 #ifdef SLAPD_MODULES
@@ -1863,29 +2088,40 @@ sortval_reject:
                case CFG_REWRITE: {
                        struct berval bv;
                        char *line;
-                       
+                       int rc = 0;
+
+                       if ( c->op == LDAP_MOD_ADD ) {
+                               c->argv++;
+                               c->argc--;
+                       }
                        if(slap_sasl_rewrite_config(c->fname, c->lineno, c->argc, c->argv))
-                               return(1);
+                               rc = 1;
+                       if ( rc == 0 ) {
 
-                       if ( c->argc > 1 ) {
-                               char    *s;
+                               if ( c->argc > 1 ) {
+                                       char    *s;
 
-                               /* quote all args but the first */
-                               line = ldap_charray2str( c->argv, "\" \"" );
-                               ber_str2bv( line, 0, 0, &bv );
-                               s = ber_bvchr( &bv, '"' );
-                               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 ] = '"';
+                                       /* quote all args but the first */
+                                       line = ldap_charray2str( c->argv, "\" \"" );
+                                       ber_str2bv( line, 0, 0, &bv );
+                                       s = ber_bvchr( &bv, '"' );
+                                       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 );
+                               } else {
+                                       ber_str2bv( c->argv[ 0 ], 0, 1, &bv );
+                               }
+
+                               ber_bvarray_add( &authz_rewrites, &bv );
                        }
-                       
-                       ber_bvarray_add( &authz_rewrites, &bv );
+                       if ( c->op == LDAP_MOD_ADD ) {
+                               c->argv--;
+                               c->argc++;
+                       }
+                       return rc;
                        }
-                       break;
 #endif
 
 
@@ -2050,14 +2286,23 @@ config_sizelimit(ConfigArgs *c) {
                        rc = 1;
                return rc;
        } else if ( c->op == LDAP_MOD_DELETE ) {
-               /* Reset to defaults */
-               lim->lms_s_soft = SLAPD_DEFAULT_SIZELIMIT;
-               lim->lms_s_hard = 0;
-               lim->lms_s_unchecked = -1;
-               lim->lms_s_pr = 0;
-               lim->lms_s_pr_hide = 0;
-               lim->lms_s_pr_total = 0;
-               return 0;
+               /* Reset to defaults or values from frontend */
+               if ( c->be == frontendDB ) {
+                       lim->lms_s_soft = SLAPD_DEFAULT_SIZELIMIT;
+                       lim->lms_s_hard = 0;
+                       lim->lms_s_unchecked = -1;
+                       lim->lms_s_pr = 0;
+                       lim->lms_s_pr_hide = 0;
+                       lim->lms_s_pr_total = 0;
+               } else {
+                       lim->lms_s_soft = frontendDB->be_def_limit.lms_s_soft;
+                       lim->lms_s_hard = frontendDB->be_def_limit.lms_s_hard;
+                       lim->lms_s_unchecked = frontendDB->be_def_limit.lms_s_unchecked;
+                       lim->lms_s_pr = frontendDB->be_def_limit.lms_s_pr;
+                       lim->lms_s_pr_hide = frontendDB->be_def_limit.lms_s_pr_hide;
+                       lim->lms_s_pr_total = frontendDB->be_def_limit.lms_s_pr_total;
+               }
+               goto ok;
        }
        for(i = 1; i < c->argc; i++) {
                if(!strncasecmp(c->argv[i], "size", 4)) {
@@ -2082,6 +2327,35 @@ config_sizelimit(ConfigArgs *c) {
                        lim->lms_s_hard = 0;
                }
        }
+
+ok:
+       if ( ( c->be == frontendDB ) && ( c->ca_entry ) ) {
+               /* This is a modification to the global limits apply it to
+                * the other databases as needed */
+               AttributeDescription *ad=NULL;
+               const char *text = NULL;
+               CfEntryInfo *ce = c->ca_entry->e_private;
+
+               slap_str2ad(c->argv[0], &ad, &text);
+               /* if we got here... */
+               assert( ad != NULL );
+
+               if ( ce->ce_type == Cft_Global ){
+                       ce = ce->ce_kids;
+               }
+               for (; ce; ce=ce->ce_sibs) {
+                       Entry *dbe = ce->ce_entry;
+                       if ( (ce->ce_type == Cft_Database) && (ce->ce_be != frontendDB)
+                                       && (!attr_find(dbe->e_attrs, ad)) ) {
+                               ce->ce_be->be_def_limit.lms_s_soft = lim->lms_s_soft;
+                               ce->ce_be->be_def_limit.lms_s_hard = lim->lms_s_hard;
+                               ce->ce_be->be_def_limit.lms_s_unchecked =lim->lms_s_unchecked;
+                               ce->ce_be->be_def_limit.lms_s_pr =lim->lms_s_pr;
+                               ce->ce_be->be_def_limit.lms_s_pr_hide =lim->lms_s_pr_hide;
+                               ce->ce_be->be_def_limit.lms_s_pr_total =lim->lms_s_pr_total;
+                       }
+               }
+       }
        return(0);
 }
 
@@ -2101,10 +2375,15 @@ config_timelimit(ConfigArgs *c) {
                        rc = 1;
                return rc;
        } else if ( c->op == LDAP_MOD_DELETE ) {
-               /* Reset to defaults */
-               lim->lms_t_soft = SLAPD_DEFAULT_TIMELIMIT;
-               lim->lms_t_hard = 0;
-               return 0;
+               /* Reset to defaults or values from frontend */
+               if ( c->be == frontendDB ) {
+                       lim->lms_t_soft = SLAPD_DEFAULT_TIMELIMIT;
+                       lim->lms_t_hard = 0;
+               } else {
+                       lim->lms_t_soft = frontendDB->be_def_limit.lms_t_soft;
+                       lim->lms_t_hard = frontendDB->be_def_limit.lms_t_hard;
+               }
+               goto ok;
        }
        for(i = 1; i < c->argc; i++) {
                if(!strncasecmp(c->argv[i], "time", 4)) {
@@ -2129,6 +2408,31 @@ config_timelimit(ConfigArgs *c) {
                        lim->lms_t_hard = 0;
                }
        }
+
+ok:
+       if ( ( c->be == frontendDB ) && ( c->ca_entry ) ) {
+               /* This is a modification to the global limits apply it to
+                * the other databases as needed */
+               AttributeDescription *ad=NULL;
+               const char *text = NULL;
+               CfEntryInfo *ce = c->ca_entry->e_private;
+
+               slap_str2ad(c->argv[0], &ad, &text);
+               /* if we got here... */
+               assert( ad != NULL );
+
+               if ( ce->ce_type == Cft_Global ){
+                       ce = ce->ce_kids;
+               }
+               for (; ce; ce=ce->ce_sibs) {
+                       Entry *dbe = ce->ce_entry;
+                       if ( (ce->ce_type == Cft_Database) && (ce->ce_be != frontendDB)
+                                       && (!attr_find(dbe->e_attrs, ad)) ) {
+                               ce->ce_be->be_def_limit.lms_t_soft = lim->lms_t_soft;
+                               ce->ce_be->be_def_limit.lms_t_hard = lim->lms_t_hard;
+                       }
+               }
+       }
        return(0);
 }
 
@@ -2156,7 +2460,7 @@ static int
 config_subordinate(ConfigArgs *c)
 {
        int rc = 1;
-       int advertise;
+       int advertise = 0;
 
        switch( c->op ) {
        case SLAP_CONFIG_EMIT:
@@ -2181,13 +2485,369 @@ config_subordinate(ConfigArgs *c)
                break;
        case LDAP_MOD_ADD:
        case SLAP_CONFIG_ADD:
-               advertise = ( c->argc == 2 && !strcasecmp( c->argv[1], "advertise" ));
+               if ( c->be->be_nsuffix == NULL ) {
+                       /* log error */
+                       snprintf( c->cr_msg, sizeof( c->cr_msg),
+                               "subordinate configuration needs a suffix" );
+                       Debug( LDAP_DEBUG_ANY,
+                               "%s: %s.\n",
+                               c->log, c->cr_msg, 0 );
+                       rc = 1;
+                       break;
+               }
+
+               if ( c->argc == 2 ) {
+                       if ( strcasecmp( c->argv[1], "advertise" ) == 0 ) {
+                               advertise = 1;
+
+                       } else if ( strcasecmp( c->argv[1], "TRUE" ) != 0 ) {
+                               /* log error */
+                               snprintf( c->cr_msg, sizeof( c->cr_msg),
+                                       "subordinate must be \"TRUE\" or \"advertise\"" );
+                               Debug( LDAP_DEBUG_ANY,
+                                       "%s: suffix \"%s\": %s.\n",
+                                       c->log, c->be->be_suffix[0].bv_val, c->cr_msg );
+                               rc = 1;
+                               break;
+                       }
+               }
+
                rc = glue_sub_add( c->be, advertise, CONFIG_ONLINE_ADD( c ));
                break;
        }
+
+       return rc;
+}
+
+/*
+ * [listener=<listener>] [{read|write}=]<size>
+ */
+
+#ifdef LDAP_TCP_BUFFER
+static BerVarray tcp_buffer;
+int tcp_buffer_num;
+
+#define SLAP_TCP_RMEM (0x1U)
+#define SLAP_TCP_WMEM (0x2U)
+
+static int
+tcp_buffer_parse( struct berval *val, int argc, char **argv,
+               int *size, int *rw, Listener **l )
+{
+       int i, rc = LDAP_SUCCESS;
+       LDAPURLDesc *lud = NULL;
+       char *ptr;
+
+       if ( val != NULL && argv == NULL ) {
+               char *s = val->bv_val;
+
+               argv = ldap_str2charray( s, " \t" );
+               if ( argv == NULL ) {
+                       return LDAP_OTHER;
+               }
+       }
+
+       i = 0;
+       if ( strncasecmp( argv[ i ], "listener=", STRLENOF( "listener=" ) )
+               == 0 )
+       {
+               char *url = argv[ i ] + STRLENOF( "listener=" );
+               
+               if ( ldap_url_parse( url, &lud ) ) {
+                       rc = LDAP_INVALID_SYNTAX;
+                       goto done;
+               }
+
+               *l = config_check_my_url( url, lud );
+               if ( *l == NULL ) {
+                       rc = LDAP_NO_SUCH_ATTRIBUTE;
+                       goto done;
+               }
+
+               i++;
+       }
+
+       ptr = argv[ i ];
+       if ( strncasecmp( ptr, "read=", STRLENOF( "read=" ) ) == 0 ) {
+               *rw |= SLAP_TCP_RMEM;
+               ptr += STRLENOF( "read=" );
+
+       } else if ( strncasecmp( ptr, "write=", STRLENOF( "write=" ) ) == 0 ) {
+               *rw |= SLAP_TCP_WMEM;
+               ptr += STRLENOF( "write=" );
+
+       } else {
+               *rw |= ( SLAP_TCP_RMEM | SLAP_TCP_WMEM );
+       }
+
+       /* accept any base */
+       if ( lutil_atoix( size, ptr, 0 ) ) {
+               rc = LDAP_INVALID_SYNTAX;
+               goto done;
+       }
+
+done:;
+       if ( val != NULL && argv != NULL ) {
+               ldap_charray_free( argv );
+       }
+
+       if ( lud != NULL ) {
+               ldap_free_urldesc( lud );
+       }
+
+       return rc;
+}
+
+static int
+tcp_buffer_delete_one( struct berval *val )
+{
+       int rc = 0;
+       int size = -1, rw = 0;
+       Listener *l = NULL;
+
+       rc = tcp_buffer_parse( val, 0, NULL, &size, &rw, &l );
+       if ( rc != 0 ) {
+               return rc;
+       }
+
+       if ( l != NULL ) {
+               int i;
+               Listener **ll = slapd_get_listeners();
+
+               for ( i = 0; ll[ i ] != NULL; i++ ) {
+                       if ( ll[ i ] == l ) break;
+               }
+
+               if ( ll[ i ] == NULL ) {
+                       return LDAP_NO_SUCH_ATTRIBUTE;
+               }
+
+               if ( rw & SLAP_TCP_RMEM ) l->sl_tcp_rmem = -1;
+               if ( rw & SLAP_TCP_WMEM ) l->sl_tcp_wmem = -1;
+
+               for ( i++ ; ll[ i ] != NULL && bvmatch( &l->sl_url, &ll[ i ]->sl_url ); i++ ) {
+                       if ( rw & SLAP_TCP_RMEM ) ll[ i ]->sl_tcp_rmem = -1;
+                       if ( rw & SLAP_TCP_WMEM ) ll[ i ]->sl_tcp_wmem = -1;
+               }
+
+       } else {
+               /* NOTE: this affects listeners without a specific setting,
+                * does not reset all listeners.  If a listener without
+                * specific settings was assigned a buffer because of
+                * a global setting, it will not be reset.  In any case,
+                * buffer changes will only take place at restart. */
+               if ( rw & SLAP_TCP_RMEM ) slapd_tcp_rmem = -1;
+               if ( rw & SLAP_TCP_WMEM ) slapd_tcp_wmem = -1;
+       }
+
+       return rc;
+}
+
+static int
+tcp_buffer_delete( BerVarray vals )
+{
+       int i;
+
+       for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
+               tcp_buffer_delete_one( &vals[ i ] );
+       }
+
+       return 0;
+}
+
+static int
+tcp_buffer_unparse( int size, int rw, Listener *l, struct berval *val )
+{
+       char buf[sizeof("2147483648")], *ptr;
+
+       /* unparse for later use */
+       val->bv_len = snprintf( buf, sizeof( buf ), "%d", size );
+       if ( l != NULL ) {
+               val->bv_len += STRLENOF( "listener=" " " ) + l->sl_url.bv_len;
+       }
+
+       if ( rw != ( SLAP_TCP_RMEM | SLAP_TCP_WMEM ) ) {
+               if ( rw & SLAP_TCP_RMEM ) {
+                       val->bv_len += STRLENOF( "read=" );
+               } else if ( rw & SLAP_TCP_WMEM ) {
+                       val->bv_len += STRLENOF( "write=" );
+               }
+       }
+
+       val->bv_val = SLAP_MALLOC( val->bv_len + 1 );
+
+       ptr = val->bv_val;
+
+       if ( l != NULL ) {
+               ptr = lutil_strcopy( ptr, "listener=" );
+               ptr = lutil_strncopy( ptr, l->sl_url.bv_val, l->sl_url.bv_len );
+               *ptr++ = ' ';
+       }
+
+       if ( rw != ( SLAP_TCP_RMEM | SLAP_TCP_WMEM ) ) {
+               if ( rw & SLAP_TCP_RMEM ) {
+                       ptr = lutil_strcopy( ptr, "read=" );
+               } else if ( rw & SLAP_TCP_WMEM ) {
+                       ptr = lutil_strcopy( ptr, "write=" );
+               }
+       }
+
+       ptr = lutil_strcopy( ptr, buf );
+       *ptr = '\0';
+
+       assert( val->bv_val + val->bv_len == ptr );
+
+       return LDAP_SUCCESS;
+}
+
+static int
+tcp_buffer_add_one( int argc, char **argv )
+{
+       int rc = 0;
+       int size = -1, rw = 0;
+       Listener *l = NULL;
+
+       struct berval val;
+
+       /* parse */
+       rc = tcp_buffer_parse( NULL, argc, argv, &size, &rw, &l );
+       if ( rc != 0 ) {
+               return rc;
+       }
+
+       /* unparse for later use */
+       rc = tcp_buffer_unparse( size, rw, l, &val );
+       if ( rc != LDAP_SUCCESS ) {
+               return rc;
+       }
+
+       /* use parsed values */
+       if ( l != NULL ) {
+               int i;
+               Listener **ll = slapd_get_listeners();
+
+               for ( i = 0; ll[ i ] != NULL; i++ ) {
+                       if ( ll[ i ] == l ) break;
+               }
+
+               if ( ll[ i ] == NULL ) {
+                       return LDAP_NO_SUCH_ATTRIBUTE;
+               }
+
+               /* buffer only applies to TCP listeners;
+                * we do not do any check here, and delegate them
+                * to setsockopt(2) */
+               if ( rw & SLAP_TCP_RMEM ) l->sl_tcp_rmem = size;
+               if ( rw & SLAP_TCP_WMEM ) l->sl_tcp_wmem = size;
+
+               for ( i++ ; ll[ i ] != NULL && bvmatch( &l->sl_url, &ll[ i ]->sl_url ); i++ ) {
+                       if ( rw & SLAP_TCP_RMEM ) ll[ i ]->sl_tcp_rmem = size;
+                       if ( rw & SLAP_TCP_WMEM ) ll[ i ]->sl_tcp_wmem = size;
+               }
+
+       } else {
+               /* NOTE: this affects listeners without a specific setting,
+                * does not set all listeners */
+               if ( rw & SLAP_TCP_RMEM ) slapd_tcp_rmem = size;
+               if ( rw & SLAP_TCP_WMEM ) slapd_tcp_wmem = size;
+       }
+
+       tcp_buffer = SLAP_REALLOC( tcp_buffer, sizeof( struct berval ) * ( tcp_buffer_num + 2 ) );
+       /* append */
+       tcp_buffer[ tcp_buffer_num ] = val;
+
+       tcp_buffer_num++;
+       BER_BVZERO( &tcp_buffer[ tcp_buffer_num ] );
+
        return rc;
 }
 
+static int
+config_tcp_buffer( ConfigArgs *c )
+{
+       if ( c->op == SLAP_CONFIG_EMIT ) {
+               if ( tcp_buffer == NULL || BER_BVISNULL( &tcp_buffer[ 0 ] ) ) {
+                       return 1;
+               }
+               value_add( &c->rvalue_vals, tcp_buffer );
+               value_add( &c->rvalue_nvals, tcp_buffer );
+               
+       } else if ( c->op == LDAP_MOD_DELETE ) {
+               if ( !c->line  ) {
+                       tcp_buffer_delete( tcp_buffer );
+                       ber_bvarray_free( tcp_buffer );
+                       tcp_buffer = NULL;
+                       tcp_buffer_num = 0;
+
+               } else {
+                       int rc = 0;
+                       int size = -1, rw = 0;
+                       Listener *l = NULL;
+
+                       struct berval val = BER_BVNULL;
+
+                       int i;
+
+                       if ( tcp_buffer_num == 0 ) {
+                               return 1;
+                       }
+
+                       /* parse */
+                       rc = tcp_buffer_parse( NULL, c->argc - 1, &c->argv[ 1 ], &size, &rw, &l );
+                       if ( rc != 0 ) {
+                               return 1;
+                       }
+
+                       /* unparse for later use */
+                       rc = tcp_buffer_unparse( size, rw, l, &val );
+                       if ( rc != LDAP_SUCCESS ) {
+                               return 1;
+                       }
+
+                       for ( i = 0; !BER_BVISNULL( &tcp_buffer[ i ] ); i++ ) {
+                               if ( bvmatch( &tcp_buffer[ i ], &val ) ) {
+                                       break;
+                               }
+                       }
+
+                       if ( BER_BVISNULL( &tcp_buffer[ i ] ) ) {
+                               /* not found */
+                               rc = 1;
+                               goto done;
+                       }
+
+                       tcp_buffer_delete_one( &tcp_buffer[ i ] );
+                       ber_memfree( tcp_buffer[ i ].bv_val );
+                       for ( ; i < tcp_buffer_num; i++ ) {
+                               tcp_buffer[ i ] = tcp_buffer[ i + 1 ];
+                       }
+                       tcp_buffer_num--;
+
+done:;
+                       if ( !BER_BVISNULL( &val ) ) {
+                               SLAP_FREE( val.bv_val );
+                       }
+       
+               }
+
+       } else {
+               int rc;
+
+               rc = tcp_buffer_add_one( c->argc - 1, &c->argv[ 1 ] );
+               if ( rc ) {
+                       snprintf( c->cr_msg, sizeof( c->cr_msg ),
+                               "<%s> unable to add value #%d",
+                               c->argv[0], tcp_buffer_num );
+                       Debug( LDAP_DEBUG_ANY, "%s: %s\n",
+                               c->log, c->cr_msg, 0 );
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+#endif /* LDAP_TCP_BUFFER */
+
 static int
 config_suffix(ConfigArgs *c)
 {
@@ -2278,7 +2938,8 @@ config_suffix(ConfigArgs *c)
        }
 #endif
 
-       if (SLAP_DB_ONE_SUFFIX( c->be ) && c->be->be_suffix ) {
+       if (SLAP_DB_ONE_SUFFIX( c->be ) && c->be->be_suffix &&
+               !BER_BVISNULL( &c->be->be_suffix[0] )) {
                snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> Only one suffix is allowed on this %s backend",
                        c->argv[0], c->be->bd_info->bi_type );
                Debug(LDAP_DEBUG_ANY, "%s: %s\n",
@@ -2422,8 +3083,8 @@ config_restrict(ConfigArgs *c) {
                if ( !c->line ) {
                        c->be->be_restrictops = 0;
                } else {
-                       restrictops = verb_to_mask( c->line, restrictable_ops );
-                       c->be->be_restrictops ^= restrictops;
+                       i = verb_to_mask( c->line, restrictable_ops );
+                       c->be->be_restrictops &= ~restrictable_ops[i].mask;
                }
                return 0;
        }
@@ -2458,8 +3119,8 @@ config_allows(ConfigArgs *c) {
                if ( !c->line ) {
                        global_allows = 0;
                } else {
-                       allows = verb_to_mask( c->line, allowable_ops );
-                       global_allows ^= allows;
+                       i = verb_to_mask( c->line, allowable_ops );
+                       global_allows &= ~allowable_ops[i].mask;
                }
                return 0;
        }
@@ -2483,6 +3144,8 @@ config_disallows(ConfigArgs *c) {
                { BER_BVC("bind_simple"),       SLAP_DISALLOW_BIND_SIMPLE },
                { BER_BVC("tls_2_anon"),                SLAP_DISALLOW_TLS_2_ANON },
                { BER_BVC("tls_authc"),         SLAP_DISALLOW_TLS_AUTHC },
+               { BER_BVC("proxy_authz_non_critical"),  SLAP_DISALLOW_PROXY_AUTHZ_N_CRIT },
+               { BER_BVC("dontusecopy_non_critical"),  SLAP_DISALLOW_DONTUSECOPY_N_CRIT },
                { BER_BVNULL, 0 }
        };
        if (c->op == SLAP_CONFIG_EMIT) {
@@ -2491,8 +3154,8 @@ config_disallows(ConfigArgs *c) {
                if ( !c->line ) {
                        global_disallows = 0;
                } else {
-                       disallows = verb_to_mask( c->line, disallowable_ops );
-                       global_disallows ^= disallows;
+                       i = verb_to_mask( c->line, disallowable_ops );
+                       global_disallows &= ~disallowable_ops[i].mask;
                }
                return 0;
        }
@@ -2527,8 +3190,8 @@ config_requires(ConfigArgs *c) {
                if ( !c->line ) {
                        c->be->be_requires = 0;
                } else {
-                       requires = verb_to_mask( c->line, requires_ops );
-                       c->be->be_requires ^= requires;
+                       i = verb_to_mask( c->line, requires_ops );
+                       c->be->be_requires &= ~requires_ops[i].mask;
                }
                return 0;
        }
@@ -2545,14 +3208,66 @@ config_requires(ConfigArgs *c) {
                        Debug(LDAP_DEBUG_ANY, "%s: %s\n",
                                c->log, c->cr_msg, 0);
                } else {
-                       snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown feature #%d", c->argv[0], i - 1 );
-                       Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
-                               c->log, c->cr_msg, c->argv[i]);
+                       snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown feature #%d", c->argv[0], i - 1 );
+                       Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
+                               c->log, c->cr_msg, c->argv[i]);
+               }
+               return(1);
+       }
+       c->be->be_requires = requires;
+       return(0);
+}
+
+static int
+config_extra_attrs(ConfigArgs *c)
+{
+       assert( c->be != NULL );
+
+       if ( c->op == SLAP_CONFIG_EMIT ) {
+               int i;
+
+               if ( c->be->be_extra_anlist == NULL ) {
+                       return 1;
+               }
+
+               for ( i = 0; !BER_BVISNULL( &c->be->be_extra_anlist[i].an_name ); i++ ) {
+                       value_add_one( &c->rvalue_vals, &c->be->be_extra_anlist[i].an_name );
+               }
+
+       } else if ( c->op == LDAP_MOD_DELETE ) {
+               if ( c->be->be_extra_anlist == NULL ) {
+                       return 1;
+               }
+
+               if ( c->valx < 0 ) {
+                       anlist_free( c->be->be_extra_anlist, 1, NULL );
+                       c->be->be_extra_anlist = NULL;
+
+               } else {
+                       int i;
+
+                       for ( i = 0; i < c->valx && !BER_BVISNULL( &c->be->be_extra_anlist[i + 1].an_name ); i++ )
+                               ;
+
+                       if ( BER_BVISNULL( &c->be->be_extra_anlist[i].an_name ) ) {
+                               return 1;
+                       }
+
+                       ch_free( c->be->be_extra_anlist[i].an_name.bv_val );
+
+                       for ( ; !BER_BVISNULL( &c->be->be_extra_anlist[i].an_name ); i++ ) {
+                               c->be->be_extra_anlist[i] = c->be->be_extra_anlist[i + 1];
+                       }
+               }
+
+       } else {
+               c->be->be_extra_anlist = str2anlist( c->be->be_extra_anlist, c->argv[1], " ,\t" );
+               if ( c->be->be_extra_anlist == NULL ) {
+                       return 1;
                }
-               return(1);
        }
-       c->be->be_requires = requires;
-       return(0);
+
+       return 0;
 }
 
 static slap_verbmasks  *loglevel_ops;
@@ -2561,7 +3276,7 @@ static int
 loglevel_init( void )
 {
        slap_verbmasks  lo[] = {
-               { BER_BVC("Any"),       -1 },
+               { BER_BVC("Any"),       (slap_mask_t) LDAP_DEBUG_ANY },
                { BER_BVC("Trace"),     LDAP_DEBUG_TRACE },
                { BER_BVC("Packets"),   LDAP_DEBUG_PACKETS },
                { BER_BVC("Args"),      LDAP_DEBUG_ARGS },
@@ -2699,6 +3414,11 @@ loglevel2bvarray( int l, BerVarray *bva )
                loglevel_init();
        }
 
+       if ( l == 0 ) {
+               struct berval bv = BER_BVC("0");
+               return value_add_one( bva, &bv );
+       }
+
        return mask_to_verbs( loglevel_ops, l, bva );
 }
 
@@ -2713,9 +3433,11 @@ loglevel_print( FILE *out )
 
        fprintf( out, "Installed log subsystems:\n\n" );
        for ( i = 0; !BER_BVISNULL( &loglevel_ops[ i ].word ); i++ ) {
-               fprintf( out, "\t%-30s (%lu)\n",
-                       loglevel_ops[ i ].word.bv_val,
-                       loglevel_ops[ i ].mask );
+               unsigned mask = loglevel_ops[ i ].mask & 0xffffffffUL;
+               fprintf( out,
+                       (mask == ((slap_mask_t) -1 & 0xffffffffUL)
+                        ? "\t%-30s (-1, 0xffffffff)\n" : "\t%-30s (%u, 0x%x)\n"),
+                       loglevel_ops[ i ].word.bv_val, mask, mask );
        }
 
        fprintf( out, "\nNOTE: custom log subsystems may be later installed "
@@ -2744,8 +3466,8 @@ config_loglevel(ConfigArgs *c) {
                if ( !c->line ) {
                        config_syslog = 0;
                } else {
-                       int level = verb_to_mask( c->line, loglevel_ops );
-                       config_syslog ^= level;
+                       i = verb_to_mask( c->line, loglevel_ops );
+                       config_syslog &= ~loglevel_ops[i].mask;
                }
                if ( slapMode & SLAP_SERVER_MODE ) {
                        ldap_syslog = config_syslog;
@@ -2757,7 +3479,7 @@ config_loglevel(ConfigArgs *c) {
                int     level;
 
                if ( isdigit((unsigned char)c->argv[i][0]) || c->argv[i][0] == '-' ) {
-                       if( lutil_atoi( &level, c->argv[i] ) != 0 ) {
+                       if( lutil_atoix( &level, c->argv[i], 0 ) != 0 ) {
                                snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse level", c->argv[0] );
                                Debug( LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
                                        c->log, c->cr_msg, c->argv[i]);
@@ -2942,7 +3664,7 @@ config_updatedn(ConfigArgs *c) {
 }
 
 int
-config_shadow( ConfigArgs *c, int flag )
+config_shadow( ConfigArgs *c, slap_mask_t flag )
 {
        char    *notallowed = NULL;
 
@@ -2958,7 +3680,19 @@ config_shadow( ConfigArgs *c, int flag )
                return 1;
        }
 
-       SLAP_DBFLAGS(c->be) |= (SLAP_DBFLAG_SHADOW | SLAP_DBFLAG_SINGLE_SHADOW | flag);
+       if ( SLAP_SHADOW(c->be) ) {
+               /* if already shadow, only check consistency */
+               if ( ( SLAP_DBFLAGS(c->be) & flag ) != flag ) {
+                       Debug( LDAP_DEBUG_ANY, "%s: inconsistent shadow flag 0x%lx.\n",
+                               c->log, flag, 0 );
+                       return 1;
+               }
+
+       } else {
+               SLAP_DBFLAGS(c->be) |= (SLAP_DBFLAG_SHADOW | flag);
+               if ( !SLAP_MULTIMASTER( c->be ))
+                       SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_SINGLE_SHADOW;
+       }
 
        return 0;
 }
@@ -3051,6 +3785,33 @@ config_include(ConfigArgs *c) {
 }
 
 #ifdef HAVE_TLS
+static int
+config_tls_cleanup(ConfigArgs *c) {
+       int rc = 0;
+
+       if ( slap_tls_ld ) {
+               int opt = 1;
+
+               ldap_pvt_tls_ctx_free( slap_tls_ctx );
+               slap_tls_ctx = NULL;
+
+               /* Force new ctx to be created */
+               rc = ldap_pvt_tls_set_option( slap_tls_ld, LDAP_OPT_X_TLS_NEWCTX, &opt );
+               if( rc == 0 ) {
+                       /* The ctx's refcount is bumped up here */
+                       ldap_pvt_tls_get_option( slap_tls_ld, LDAP_OPT_X_TLS_CTX, &slap_tls_ctx );
+                       /* This is a no-op if it's already loaded */
+                       load_extop( &slap_EXOP_START_TLS, 0, starttls_extop );
+               } else {
+                       if ( rc == LDAP_NOT_SUPPORTED )
+                               rc = LDAP_UNWILLING_TO_PERFORM;
+                       else
+                               rc = LDAP_OTHER;
+               }
+       }
+       return rc;
+}
+
 static int
 config_tls_option(ConfigArgs *c) {
        int flag;
@@ -3074,9 +3835,11 @@ config_tls_option(ConfigArgs *c) {
        if (c->op == SLAP_CONFIG_EMIT) {
                return ldap_pvt_tls_get_option( ld, flag, &c->value_string );
        } else if ( c->op == LDAP_MOD_DELETE ) {
+               c->cleanup = config_tls_cleanup;
                return ldap_pvt_tls_set_option( ld, flag, NULL );
        }
        ch_free(c->value_string);
+       c->cleanup = config_tls_cleanup;
        return(ldap_pvt_tls_set_option(ld, flag, c->argv[1]));
 }
 
@@ -3087,6 +3850,7 @@ config_tls_config(ConfigArgs *c) {
        switch(c->type) {
        case CFG_TLS_CRLCHECK:  flag = LDAP_OPT_X_TLS_CRLCHECK; break;
        case CFG_TLS_VERIFY:    flag = LDAP_OPT_X_TLS_REQUIRE_CERT; break;
+       case CFG_TLS_PROTOCOL_MIN: flag = LDAP_OPT_X_TLS_PROTOCOL_MIN; break;
        default:
                Debug(LDAP_DEBUG_ANY, "%s: "
                                "unknown tls_option <0x%x>\n",
@@ -3097,10 +3861,12 @@ config_tls_config(ConfigArgs *c) {
                return slap_tls_get_config( slap_tls_ld, flag, &c->value_string );
        } else if ( c->op == LDAP_MOD_DELETE ) {
                int i = 0;
+               c->cleanup = config_tls_cleanup;
                return ldap_pvt_tls_set_option( slap_tls_ld, flag, &i );
        }
        ch_free( c->value_string );
-       if ( isdigit( (unsigned char)c->argv[1][0] ) ) {
+       c->cleanup = config_tls_cleanup;
+       if ( isdigit( (unsigned char)c->argv[1][0] ) && c->type != CFG_TLS_PROTOCOL_MIN ) {
                if ( lutil_atoi( &i, c->argv[1] ) != 0 ) {
                        Debug(LDAP_DEBUG_ANY, "%s: "
                                "unable to parse %s \"%s\"\n",
@@ -3158,7 +3924,7 @@ typedef struct setup_cookie {
        ConfigArgs *ca;
        Entry *frontend;
        Entry *config;
-       int     got_frontend;
+       int got_frontend;
        int got_config;
 } setup_cookie;
 
@@ -3167,15 +3933,18 @@ config_ldif_resp( Operation *op, SlapReply *rs )
 {
        if ( rs->sr_type == REP_SEARCH ) {
                setup_cookie *sc = op->o_callback->sc_private;
+               struct berval pdn;
 
                sc->cfb->cb_got_ldif = 1;
                /* Does the frontend exist? */
                if ( !sc->got_frontend ) {
                        if ( !strncmp( rs->sr_entry->e_nname.bv_val,
-                               "olcDatabase", STRLENOF( "olcDatabase" ))) {
+                               "olcDatabase", STRLENOF( "olcDatabase" )))
+                       {
                                if ( strncmp( rs->sr_entry->e_nname.bv_val +
                                        STRLENOF( "olcDatabase" ), "={-1}frontend",
-                                       STRLENOF( "={-1}frontend" ))) {
+                                       STRLENOF( "={-1}frontend" )))
+                               {
                                        struct berval rdn;
                                        int i = op->o_noop;
                                        sc->ca->be = frontendDB;
@@ -3198,13 +3967,19 @@ config_ldif_resp( Operation *op, SlapReply *rs )
                                }
                        }
                }
+
+               dnParent( &rs->sr_entry->e_nname, &pdn );
+
                /* Does the configDB exist? */
                if ( sc->got_frontend && !sc->got_config &&
                        !strncmp( rs->sr_entry->e_nname.bv_val,
-                       "olcDatabase", STRLENOF( "olcDatabase" ))) {
+                       "olcDatabase", STRLENOF( "olcDatabase" )) &&
+                       dn_match( &config_rdn, &pdn ) )
+               {
                        if ( strncmp( rs->sr_entry->e_nname.bv_val +
                                STRLENOF( "olcDatabase" ), "={0}config",
-                               STRLENOF( "={0}config" ))) {
+                               STRLENOF( "={0}config" )))
+                       {
                                struct berval rdn;
                                int i = op->o_noop;
                                sc->ca->be = LDAP_STAILQ_FIRST( &backendDB );
@@ -3346,10 +4121,12 @@ config_setup_ldif( BackendDB *be, const char *dir, int readit ) {
 
                op->o_tag = LDAP_REQ_ADD;
                if ( rc == LDAP_SUCCESS && sc.frontend ) {
+                       rs_reinit( &rs, REP_RESULT );
                        op->ora_e = sc.frontend;
                        rc = op->o_bd->be_add( op, &rs );
                }
                if ( rc == LDAP_SUCCESS && sc.config ) {
+                       rs_reinit( &rs, REP_RESULT );
                        op->ora_e = sc.config;
                        rc = op->o_bd->be_add( op, &rs );
                }
@@ -3476,6 +4253,13 @@ done:
                        assert( 0 );
                }
        }
+       if ( rc == 0 && ( slapMode & SLAP_SERVER_MODE ) && sid_list ) {
+               if ( !BER_BVISEMPTY( &sid_list->si_url ) && !sid_set ) {
+                       Debug(LDAP_DEBUG_ANY, "read_config: no serverID / URL match found. "
+                               "Check slapd -h arguments.\n", 0,0,0 );
+                       rc = LDAP_OTHER;
+               }
+       }
        return rc;
 }
 
@@ -3505,6 +4289,9 @@ config_send( Operation *op, SlapReply *rs, CfEntryInfo *ce, int depth )
                rs->sr_entry = ce->ce_entry;
                rs->sr_flags = 0;
                rc = send_search_entry( op, rs );
+               if ( rc != LDAP_SUCCESS ) {
+                       return rc;
+               }
        }
        if ( op->ors_scope == LDAP_SCOPE_SUBTREE ) {
                if ( ce->ce_kids ) {
@@ -3667,14 +4454,15 @@ config_rename_kids( CfEntryInfo *ce )
        struct berval rdn, nrdn;
 
        for (ce2 = ce->ce_kids; ce2; ce2 = ce2->ce_sibs) {
+               struct berval newdn, newndn;
                dnRdn ( &ce2->ce_entry->e_name, &rdn );
                dnRdn ( &ce2->ce_entry->e_nname, &nrdn );
+               build_new_dn( &newdn, &ce->ce_entry->e_name, &rdn, NULL );
+               build_new_dn( &newndn, &ce->ce_entry->e_nname, &nrdn, NULL );
                free( ce2->ce_entry->e_name.bv_val );
                free( ce2->ce_entry->e_nname.bv_val );
-               build_new_dn( &ce2->ce_entry->e_name, &ce->ce_entry->e_name,
-                       &rdn, NULL );
-               build_new_dn( &ce2->ce_entry->e_nname, &ce->ce_entry->e_nname,
-                       &nrdn, NULL );
+               ce2->ce_entry->e_name = newdn;
+               ce2->ce_entry->e_nname = newndn;
                config_rename_kids( ce2 );
        }
 }
@@ -3835,10 +4623,10 @@ check_name_index( CfEntryInfo *parent, ConfigType ce_type, Entry *e,
                        isconfig = 1;
        }
        ptr1 = ber_bvchr( &e->e_name, '{' );
-       if ( ptr1 && ptr1 - e->e_name.bv_val < rdn.bv_len ) {
+       if ( ptr1 && ptr1 < &e->e_name.bv_val[ rdn.bv_len ] ) {
                char    *next;
                ptr2 = strchr( ptr1, '}' );
-               if (!ptr2 || ptr2 - e->e_name.bv_val > rdn.bv_len)
+               if ( !ptr2 || ptr2 > &e->e_name.bv_val[ rdn.bv_len ] )
                        return LDAP_NAMING_VIOLATION;
                if ( ptr2-ptr1 == 1)
                        return LDAP_NAMING_VIOLATION;
@@ -3857,9 +4645,34 @@ check_name_index( CfEntryInfo *parent, ConfigType ce_type, Entry *e,
                }
        }
 
-       /* count related kids */
-       for (nsibs=0, ce=parent->ce_kids; ce; ce=ce->ce_sibs) {
-               if ( ce->ce_type == ce_type ) nsibs++;
+       /* count related kids.
+        * For entries of type Cft_Misc, only count siblings with same RDN type
+        */
+       if ( ce_type == Cft_Misc ) {
+               rdn.bv_val = e->e_nname.bv_val;
+               ptr1 = strchr( rdn.bv_val, '=' );
+               assert( ptr1 != NULL );
+
+               rdn.bv_len = ptr1 - rdn.bv_val;
+
+               for (nsibs=0, ce=parent->ce_kids; ce; ce=ce->ce_sibs) {
+                       struct berval rdn2;
+                       if ( ce->ce_type != ce_type )
+                               continue;
+
+                       dnRdn( &ce->ce_entry->e_nname, &rdn2 );
+
+                       ptr1 = strchr( rdn2.bv_val, '=' );
+                       assert( ptr1 != NULL );
+
+                       rdn2.bv_len = ptr1 - rdn2.bv_val;
+                       if ( bvmatch( &rdn, &rdn2 ))
+                               nsibs++;
+               }
+       } else {
+               for (nsibs=0, ce=parent->ce_kids; ce; ce=ce->ce_sibs) {
+                       if ( ce->ce_type == ce_type ) nsibs++;
+               }
        }
 
        /* account for -1 frontend */
@@ -3879,7 +4692,7 @@ check_name_index( CfEntryInfo *parent, ConfigType ce_type, Entry *e,
                if ( isconfig && index == -1 ) {
                        index = 0;
                }
-               if ( !isfrontend && index == -1 ) {
+               if (( !isfrontend && index == -1 ) || ( index > nsibs ) ){
                        index = nsibs;
                }
 
@@ -3893,12 +4706,19 @@ check_name_index( CfEntryInfo *parent, ConfigType ce_type, Entry *e,
        return rc;
 }
 
+/* Insert all superior classes of the given class */
 static int
 count_oc( ObjectClass *oc, ConfigOCs ***copp, int *nocs )
 {
        ConfigOCs       co, *cop;
        ObjectClass     **sups;
 
+       for ( sups = oc->soc_sups; sups && *sups; sups++ ) {
+               if ( count_oc( *sups, copp, nocs ) ) {
+                       return -1;
+               }
+       }
+
        co.co_name = &oc->soc_cname;
        cop = avl_find( CfOcTree, &co, CfOc_cmp );
        if ( cop ) {
@@ -3922,27 +4742,23 @@ count_oc( ObjectClass *oc, ConfigOCs ***copp, int *nocs )
                }
        }
 
-       for ( sups = oc->soc_sups; sups && *sups; sups++ ) {
-               if ( count_oc( *sups, copp, nocs ) ) {
-                       return -1;
-               }
-       }
-
        return 0;
 }
 
+/* Find all superior classes of the given objectclasses,
+ * return list in order of most-subordinate first.
+ *
+ * Special / auxiliary / Cft_Misc classes always take precedence.
+ */
 static ConfigOCs **
 count_ocs( Attribute *oc_at, int *nocs )
 {
-       int             i;
+       int             i, j, misc = -1;
        ConfigOCs       **colst = NULL;
 
        *nocs = 0;
 
-       for ( i = 0; !BER_BVISNULL( &oc_at->a_nvals[i] ); i++ )
-               /* count attrs */ ;
-
-       for ( ; i--; ) {
+       for ( i = oc_at->a_numvals; i--; ) {
                ObjectClass     *oc = oc_bvfind( &oc_at->a_nvals[i] );
 
                assert( oc != NULL );
@@ -3952,6 +4768,25 @@ count_ocs( Attribute *oc_at, int *nocs )
                }
        }
 
+       /* invert order */
+       i = 0;
+       j = *nocs - 1;
+       while ( i < j ) {
+               ConfigOCs *tmp = colst[i];
+               colst[i] = colst[j];
+               colst[j] = tmp;
+               if (tmp->co_type == Cft_Misc)
+                       misc = j;
+               i++; j--;
+       }
+       /* Move misc class to front of list */
+       if (misc > 0) {
+               ConfigOCs *tmp = colst[misc];
+               for (i=misc; i>0; i--)
+                       colst[i] = colst[i-1];
+               colst[0] = tmp;
+       }
+
        return colst;
 }
 
@@ -3990,6 +4825,11 @@ cfAddDatabase( CfEntryInfo *p, Entry *e, struct config_args_s *ca )
        if ( p->ce_type != Cft_Global ) {
                return LDAP_CONSTRAINT_VIOLATION;
        }
+       /* config must be {0}, nothing else allowed */
+       if ( !strncmp( e->e_nname.bv_val, "olcDatabase={0}", STRLENOF("olcDatabase={0}")) &&
+               strncmp( e->e_nname.bv_val + STRLENOF("olcDatabase={0}"), "config,", STRLENOF("config,") )) {
+               return LDAP_CONSTRAINT_VIOLATION;
+       }
        ca->be = frontendDB;    /* just to get past check_vals */
        return LDAP_SUCCESS;
 }
@@ -4033,6 +4873,7 @@ schema_destroy_one( ConfigArgs *ca, ConfigOCs **colst, int nocs,
 
        ca->valx = -1;
        ca->line = NULL;
+       ca->argc = 1;
        if ( cfn->c_cr_head ) {
                struct berval bv = BER_BVC("olcDitContentRules");
                ad = NULL;
@@ -4054,6 +4895,13 @@ schema_destroy_one( ConfigArgs *ca, ConfigOCs **colst, int nocs,
                ct = config_find_table( colst, nocs, ad, ca );
                config_del_vals( ct, ca );
        }
+       if ( cfn->c_syn_head ) {
+               struct berval bv = BER_BVC("olcLdapSyntaxes");
+               ad = NULL;
+               slap_bv2ad( &bv, &ad, &text );
+               ct = config_find_table( colst, nocs, ad, ca );
+               config_del_vals( ct, ca );
+       }
        if ( cfn->c_om_head ) {
                struct berval bv = BER_BVC("olcObjectIdentifier");
                ad = NULL;
@@ -4125,6 +4973,9 @@ config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca, SlapReply *rs,
                        Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: "
                                "DN=\"%s\" already exists\n",
                                log_prefix, e->e_name.bv_val, 0 );
+                       /* global schema ignores all writes */
+                       if ( ce->ce_type == Cft_Schema && ce->ce_parent->ce_type == Cft_Global )
+                               return LDAP_COMPARE_TRUE;
                        return LDAP_ALREADY_EXISTS;
                }
        }
@@ -4323,6 +5174,7 @@ config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca, SlapReply *rs,
                if ( !ct ) continue;    /* user data? */
                for (i=0; a->a_vals[i].bv_val; i++) {
                        char *iptr = NULL;
+                       ca->valx = -1;
                        ca->line = a->a_vals[i].bv_val;
                        if ( a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED ) {
                                ptr = strchr( ca->line, '}' );
@@ -4334,8 +5186,6 @@ config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca, SlapReply *rs,
                        if ( a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED_SIB ) {
                                if ( iptr ) {
                                        ca->valx = strtol( iptr+1, NULL, 0 );
-                               } else {
-                                       ca->valx = -1;
                                }
                        } else {
                                ca->valx = i;
@@ -4350,10 +5200,10 @@ config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca, SlapReply *rs,
 ok:
        /* Newly added databases and overlays need to be started up */
        if ( CONFIG_ONLINE_ADD( ca )) {
-               if ( colst[0]->co_type == Cft_Database ) {
+               if ( coptr->co_type == Cft_Database ) {
                        rc = backend_startup_one( ca->be, &ca->reply );
 
-               } else if ( colst[0]->co_type == Cft_Overlay ) {
+               } else if ( coptr->co_type == Cft_Overlay ) {
                        if ( ca->bi->bi_db_open ) {
                                BackendInfo *bi_orig = ca->be->bd_info;
                                ca->be->bd_info = ca->bi;
@@ -4379,7 +5229,7 @@ ok:
        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_type = coptr->co_type;
        ce->ce_be = ca->be;
        ce->ce_bi = ca->bi;
        ce->ce_private = ca->ca_private;
@@ -4424,12 +5274,12 @@ ok:
 
 done:
        if ( rc ) {
-               if ( (colst[0]->co_type == Cft_Database) && ca->be ) {
+               if ( (coptr->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 ) {
+               } else if ( (coptr->co_type == Cft_Overlay) && ca->bi ) {
                        overlay_destroy_one( ca->be, (slap_overinst *)ca->bi );
-               } else if ( colst[0]->co_type == Cft_Schema ) {
+               } else if ( coptr->co_type == Cft_Schema ) {
                        schema_destroy_one( ca, colst, nocs, last );
                }
        }
@@ -4526,13 +5376,22 @@ config_back_add( Operation *op, SlapReply *rs )
                goto out;
        }
 
+       /*
+        * Check for attribute ACL
+        */
+       if ( !acl_check_modlist( op, op->ora_e, op->orm_modlist )) {
+               rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
+               rs->sr_text = "no write access to attribute";
+               goto out;
+       }
+
        cfb = (CfBackInfo *)op->o_bd->be_private;
 
        /* add opattrs for syncprov */
        {
                char textbuf[SLAP_TEXT_BUFLEN];
                size_t textlen = sizeof textbuf;
-               rs->sr_err = entry_schema_check(op, op->ora_e, NULL, 0, 1,
+               rs->sr_err = entry_schema_check(op, op->ora_e, NULL, 0, 1, NULL,
                        &rs->sr_text, textbuf, sizeof( textbuf ) );
                if ( rs->sr_err != LDAP_SUCCESS )
                        goto out;
@@ -4545,6 +5404,10 @@ config_back_add( Operation *op, SlapReply *rs )
                }
        }
 
+       if ( op->o_abandon ) {
+               rs->sr_err = SLAPD_ABANDON;
+               goto out;
+       }
        ldap_pvt_thread_pool_pause( &connection_pool );
 
        /* Strategy:
@@ -4598,7 +5461,15 @@ out2:;
        ldap_pvt_thread_pool_resume( &connection_pool );
 
 out:;
-       send_ldap_result( op, rs );
+       {       int repl = op->o_dont_replicate;
+               if ( rs->sr_err == LDAP_COMPARE_TRUE ) {
+                       rs->sr_text = NULL; /* Set after config_add_internal */
+                       rs->sr_err = LDAP_SUCCESS;
+                       op->o_dont_replicate = 1;
+               }
+               send_ldap_result( op, rs );
+               op->o_dont_replicate = repl;
+       }
        slap_graduate_commit_csn( op );
        return rs->sr_err;
 }
@@ -4615,6 +5486,7 @@ config_modify_add( ConfigTable *ct, ConfigArgs *ca, AttributeDescription *ad,
 {
        int rc;
 
+       ca->valx = -1;
        if (ad->ad_type->sat_flags & SLAP_AT_ORDERED &&
                ca->line[0] == '{' )
        {
@@ -4653,6 +5525,11 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs,
        oc_at = attr_find( e->e_attrs, slap_schema.si_ad_objectClass );
        if ( !oc_at ) return LDAP_OBJECT_CLASS_VIOLATION;
 
+       for (ml = op->orm_modlist; ml; ml=ml->sml_next) {
+               if (ml->sml_desc == slap_schema.si_ad_objectClass)
+                       return rc;
+       }
+
        colst = count_ocs( oc_at, &nocs );
 
        /* make sure add/del flags are clear; should always be true */
@@ -4675,7 +5552,9 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs,
                ct = config_find_table( colst, nocs, ml->sml_desc, ca );
                switch (ml->sml_op) {
                case LDAP_MOD_DELETE:
-               case LDAP_MOD_REPLACE: {
+               case LDAP_MOD_REPLACE:
+               case SLAP_MOD_SOFTDEL:
+               {
                        BerVarray vals = NULL, nvals = NULL;
                        int *idx = NULL;
                        if ( ct && ( ct->arg_type & ARG_NO_DELETE )) {
@@ -4714,11 +5593,24 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs,
                                ml->sml_values = vals;
                                ml->sml_nvalues = nvals;
                        }
+                       if ( rc == LDAP_NO_SUCH_ATTRIBUTE && ml->sml_op == SLAP_MOD_SOFTDEL )
+                       {
+                               rc = LDAP_SUCCESS;
+                       }
+                       /* FIXME: check rc before fallthru? */
                        if ( !vals )
                                break;
-                       }
+               }
                        /* FALLTHRU: LDAP_MOD_REPLACE && vals */
 
+               case SLAP_MOD_ADD_IF_NOT_PRESENT:
+                       if ( ml->sml_op == SLAP_MOD_ADD_IF_NOT_PRESENT
+                               && attr_find( e->e_attrs, ml->sml_desc ) )
+                       {
+                               rc = LDAP_SUCCESS;
+                               break;
+                       }
+
                case LDAP_MOD_ADD:
                case SLAP_MOD_SOFTADD: {
                        int mop = ml->sml_op;
@@ -4778,7 +5670,7 @@ 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, e, NULL, 0, 0,
+               rc = entry_schema_check(op, e, NULL, 0, 0, NULL,
                        &rs->sr_text, ca->cr_msg, sizeof(ca->cr_msg) );
        }
        if ( rc ) goto out_noop;
@@ -4828,6 +5720,7 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs,
                                        }
                                        ca->line = bv.bv_val;
                                        ca->valx = d->idx[i];
+                                       config_parse_vals(ct, ca, d->idx[i] );
                                        rc = config_del_vals( ct, ca );
                                        if ( rc != LDAP_SUCCESS ) break;
                                        if ( s )
@@ -4839,6 +5732,7 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs,
                        } else {
                                ca->valx = -1;
                                ca->line = NULL;
+                               ca->argc = 1;
                                rc = config_del_vals( ct, ca );
                                if ( rc ) rc = LDAP_OTHER;
                                if ( s )
@@ -4859,6 +5753,8 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs,
                        /* FALLTHRU: LDAP_MOD_REPLACE && vals */
 
                case LDAP_MOD_ADD:
+                       if ( !a )
+                               break;
                        for (i=0; ml->sml_values[i].bv_val; i++) {
                                ca->line = ml->sml_values[i].bv_val;
                                ca->valx = -1;
@@ -4885,6 +5781,7 @@ out:
                                        a->a_flags &= ~(SLAP_ATTR_IXDEL|SLAP_ATTR_IXADD);
                                        ca->valx = -1;
                                        ca->line = NULL;
+                                       ca->argc = 1;
                                        config_del_vals( ct, ca );
                                }
                                for ( i=0; !BER_BVISNULL( &s->a_vals[i] ); i++ ) {
@@ -4899,6 +5796,7 @@ out:
                                ct = config_find_table( colst, nocs, a->a_desc, ca );
                                ca->valx = -1;
                                ca->line = NULL;
+                               ca->argc = 1;
                                config_del_vals( ct, ca );
                                s = attr_find( save_attrs, a->a_desc );
                                if ( s ) {
@@ -4914,11 +5812,15 @@ out:
                ca->reply = msg;
        }
 
-       if ( ca->cleanup )
-               ca->cleanup( ca );
+       if ( ca->cleanup ) {
+               i = ca->cleanup( ca );
+               if (rc == LDAP_SUCCESS)
+                       rc = i;
+       }
 out_noop:
        if ( rc == LDAP_SUCCESS ) {
                attrs_free( save_attrs );
+               rs->sr_text = NULL;
        } else {
                attrs_free( e->e_attrs );
                e->e_attrs = save_attrs;
@@ -4965,7 +5867,10 @@ config_back_modify( Operation *op, SlapReply *rs )
        rdn = ce->ce_entry->e_nname;
        ptr = strchr( rdn.bv_val, '=' );
        rdn.bv_len = ptr - rdn.bv_val;
-       slap_bv2ad( &rdn, &rad, &rs->sr_text );
+       rs->sr_err = slap_bv2ad( &rdn, &rad, &rs->sr_text );
+       if ( rs->sr_err != LDAP_SUCCESS ) {
+               goto out;
+       }
 
        /* Some basic validation... */
        for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
@@ -4984,8 +5889,13 @@ config_back_modify( Operation *op, SlapReply *rs )
 
        slap_mods_opattrs( op, &op->orm_modlist, 1 );
 
-       if ( do_pause )
+       if ( do_pause ) {
+               if ( op->o_abandon ) {
+                       rs->sr_err = SLAPD_ABANDON;
+                       goto out;
+               }
                ldap_pvt_thread_pool_pause( &connection_pool );
+       }
 
        /* Strategy:
         * 1) perform the Modify on the cached Entry.
@@ -5149,6 +6059,10 @@ config_back_modrdn( Operation *op, SlapReply *rs )
                goto out;
        }
 
+       if ( op->o_abandon ) {
+               rs->sr_err = SLAPD_ABANDON;
+               goto out;
+       }
        ldap_pvt_thread_pool_pause( &connection_pool );
 
        if ( ce->ce_type == Cft_Schema ) {
@@ -5225,7 +6139,145 @@ out:
 static int
 config_back_delete( Operation *op, SlapReply *rs )
 {
-       send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, NULL );
+#ifdef SLAP_CONFIG_DELETE
+       CfBackInfo *cfb;
+       CfEntryInfo *ce, *last, *ce2;
+
+       cfb = (CfBackInfo *)op->o_bd->be_private;
+
+       ce = config_find_base( cfb->cb_root, &op->o_req_ndn, &last );
+       if ( !ce ) {
+               if ( last )
+                       rs->sr_matched = last->ce_entry->e_name.bv_val;
+               rs->sr_err = LDAP_NO_SUCH_OBJECT;
+       } else if ( ce->ce_kids ) {
+               rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
+       } else if ( op->o_abandon ) {
+               rs->sr_err = SLAPD_ABANDON;
+       } else if ( ce->ce_type == Cft_Overlay ||
+                       ce->ce_type == Cft_Database ||
+                       ce->ce_type == Cft_Misc ){
+               char *iptr;
+               int count, ixold;
+
+               ldap_pvt_thread_pool_pause( &connection_pool );
+
+               if ( ce->ce_type == Cft_Overlay ){
+                       overlay_remove( ce->ce_be, (slap_overinst *)ce->ce_bi, op );
+               } else if ( ce->ce_type == Cft_Misc ) {
+                       /*
+                        * only Cft_Misc objects that have a co_lddel handler set in
+                        * the ConfigOCs struct can be deleted. This code also
+                        * assumes that the entry can be only have one objectclass
+                        * with co_type == Cft_Misc
+                        */
+                       ConfigOCs co, *coptr;
+                       Attribute *oc_at;
+                       int i;
+
+                       oc_at = attr_find( ce->ce_entry->e_attrs,
+                                       slap_schema.si_ad_objectClass );
+                       if ( !oc_at ) {
+                               rs->sr_err = LDAP_OTHER;
+                               rs->sr_text = "objectclass not found";
+                               ldap_pvt_thread_pool_resume( &connection_pool );
+                               goto out;
+                       }
+                       for ( i=0; !BER_BVISNULL(&oc_at->a_nvals[i]); i++ ) {
+                               co.co_name = &oc_at->a_nvals[i];
+                               coptr = avl_find( CfOcTree, &co, CfOc_cmp );
+                               if ( coptr == NULL || coptr->co_type != Cft_Misc ) {
+                                       continue;
+                               }
+                               if ( ! coptr->co_lddel || coptr->co_lddel( ce, op ) ){
+                                       rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
+                                       if ( ! coptr->co_lddel ) {
+                                               rs->sr_text = "No delete handler found";
+                                       } else {
+                                               rs->sr_err = LDAP_OTHER;
+                                               /* FIXME: We should return a helpful error message
+                                                * here */
+                                       }
+                                       ldap_pvt_thread_pool_resume( &connection_pool );
+                                       goto out;
+                               }
+                               break;
+                       }
+               } else if (ce->ce_type == Cft_Database ) {
+                       if ( ce->ce_be == frontendDB || ce->ce_be == op->o_bd ){
+                               rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
+                               rs->sr_text = "Cannot delete config or frontend database";
+                               ldap_pvt_thread_pool_resume( &connection_pool );
+                               goto out;
+                       }
+                       if ( ce->ce_be->bd_info->bi_db_close ) {
+                               ce->ce_be->bd_info->bi_db_close( ce->ce_be, NULL );
+                       }
+                       backend_destroy_one( ce->ce_be, 1);
+               }
+
+               /* remove CfEntryInfo from the siblings list */
+               if ( ce->ce_parent->ce_kids == ce ) {
+                       ce->ce_parent->ce_kids = ce->ce_sibs;
+               } else {
+                       for ( ce2 = ce->ce_parent->ce_kids ; ce2; ce2 = ce2->ce_sibs ) {
+                               if ( ce2->ce_sibs == ce ) {
+                                       ce2->ce_sibs = ce->ce_sibs;
+                                       break;
+                               }
+                       }
+               }
+
+               /* remove from underlying database */
+               if ( cfb->cb_use_ldif ) {
+                       BackendDB *be = op->o_bd;
+                       slap_callback sc = { NULL, slap_null_cb, NULL, NULL }, *scp;
+                       struct berval dn, ndn, req_dn, req_ndn;
+
+                       op->o_bd = &cfb->cb_db;
+
+                       dn = op->o_dn;
+                       ndn = op->o_ndn;
+                       req_dn = op->o_req_dn;
+                       req_ndn = op->o_req_ndn;
+
+                       op->o_dn = op->o_bd->be_rootdn;
+                       op->o_ndn = op->o_bd->be_rootndn;
+                       op->o_req_dn = ce->ce_entry->e_name;
+                       op->o_req_ndn = ce->ce_entry->e_nname;
+
+                       scp = op->o_callback;
+                       op->o_callback = &sc;
+                       op->o_bd->be_delete( op, rs );
+                       op->o_bd = be;
+                       op->o_callback = scp;
+                       op->o_dn = dn;
+                       op->o_ndn = ndn;
+                       op->o_req_dn = req_dn;
+                       op->o_req_ndn = req_ndn;
+               }
+
+               /* renumber siblings */
+               iptr = ber_bvchr( &op->o_req_ndn, '{' ) + 1;
+               ixold = strtol( iptr, NULL, 0 );
+               for (ce2 = ce->ce_sibs, count=0; ce2; ce2=ce2->ce_sibs) {
+                       config_renumber_one( op, rs, ce2->ce_parent, ce2->ce_entry,
+                               count+ixold, 0, cfb->cb_use_ldif );
+                       count++;
+               }
+
+               ce->ce_entry->e_private=NULL;
+               entry_free(ce->ce_entry);
+               ch_free(ce);
+               ldap_pvt_thread_pool_resume( &connection_pool );
+       } else {
+               rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
+       }
+out:
+#else
+       rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
+#endif /* SLAP_CONFIG_DELETE */
+       send_ldap_result( op, rs );
        return rs->sr_err;
 }
 
@@ -5258,20 +6310,22 @@ config_back_search( Operation *op, SlapReply *rs )
        switch ( op->ors_scope ) {
        case LDAP_SCOPE_BASE:
        case LDAP_SCOPE_SUBTREE:
-               config_send( op, rs, ce, 0 );
+               rs->sr_err = config_send( op, rs, ce, 0 );
                break;
                
        case LDAP_SCOPE_ONELEVEL:
                for (ce = ce->ce_kids; ce; ce=ce->ce_sibs) {
-                       config_send( op, rs, ce, 1 );
+                       rs->sr_err = config_send( op, rs, ce, 1 );
+                       if ( rs->sr_err ) {
+                               break;
+                       }
                }
                break;
        }
-               
-       rs->sr_err = LDAP_SUCCESS;
+
 out:
        send_ldap_result( op, rs );
-       return 0;
+       return rs->sr_err;
 }
 
 /* no-op, we never free entries */
@@ -5317,7 +6371,7 @@ int config_back_entry_get(
        return rc;
 }
 
-static void
+static int
 config_build_attrs( Entry *e, AttributeType **at, AttributeDescription *ad,
        ConfigTable *ct, ConfigArgs *c )
 {
@@ -5334,36 +6388,61 @@ config_build_attrs( Entry *e, AttributeType **at, AttributeDescription *ad,
                                 * returns success with no values */
                                if (rc == LDAP_SUCCESS && c->rvalue_vals != NULL ) {
                                        if ( c->rvalue_nvals )
-                                               attr_merge(e, ct[i].ad, c->rvalue_vals,
+                                               rc = attr_merge(e, ct[i].ad, c->rvalue_vals,
                                                        c->rvalue_nvals);
-                                       else
-                                               attr_merge_normalize(e, ct[i].ad,
+                                       else {
+                                               slap_syntax_validate_func *validate =
+                                                       ct[i].ad->ad_type->sat_syntax->ssyn_validate;
+                                               if ( validate ) {
+                                                       int j;
+                                                       for ( j=0; c->rvalue_vals[j].bv_val; j++ ) {
+                                                               rc = ordered_value_validate( ct[i].ad,
+                                                                       &c->rvalue_vals[j], LDAP_MOD_ADD );
+                                                               if ( rc ) {
+                                                                       Debug( LDAP_DEBUG_ANY,
+                                                                               "config_build_attrs: error %d on %s value #%d\n",
+                                                                               rc, ct[i].ad->ad_cname.bv_val, j );
+                                                                       return rc;
+                                                               }
+                                                       }
+                                               }
+                                                       
+                                               rc = attr_merge_normalize(e, ct[i].ad,
                                                        c->rvalue_vals, NULL);
+                                       }
                                        ber_bvarray_free( c->rvalue_nvals );
                                        ber_bvarray_free( c->rvalue_vals );
+                                       if ( rc ) {
+                                               Debug( LDAP_DEBUG_ANY,
+                                                       "config_build_attrs: error %d on %s\n",
+                                                       rc, ct[i].ad->ad_cname.bv_val, 0 );
+                                               return rc;
+                                       }
                                }
                                break;
                        }
                }
        }
+       return 0;
 }
 
+/* currently (2010) does not access rs except possibly writing rs->sr_err */
+
 Entry *
 config_build_entry( Operation *op, SlapReply *rs, CfEntryInfo *parent,
        ConfigArgs *c, struct berval *rdn, ConfigOCs *main, ConfigOCs *extra )
 {
        Entry *e = entry_alloc();
        CfEntryInfo *ce = ch_calloc( 1, sizeof(CfEntryInfo) );
-       struct berval val;
-       struct berval ad_name;
        AttributeDescription *ad = NULL;
        int rc;
        char *ptr;
-       const char *text;
+       const char *text = "";
        Attribute *oc_at;
        struct berval pdn;
        ObjectClass *oc;
        CfEntryInfo *ceprev = NULL;
+       LDAPRDN srdn = NULL;
 
        Debug( LDAP_DEBUG_TRACE, "config_build_entry: \"%s\"\n", rdn->bv_val, 0, 0);
        e->e_private = ce;
@@ -5372,7 +6451,7 @@ config_build_entry( Operation *op, SlapReply *rs, CfEntryInfo *parent,
        ce->ce_parent = parent;
        if ( parent ) {
                pdn = parent->ce_entry->e_nname;
-               if ( parent->ce_kids )
+               if ( parent->ce_kids && parent->ce_kids->ce_type <= ce->ce_type )
                        for ( ceprev = parent->ce_kids; ceprev->ce_sibs &&
                                ceprev->ce_type <= ce->ce_type;
                                ceprev = ceprev->ce_sibs );
@@ -5392,48 +6471,67 @@ config_build_entry( Operation *op, SlapReply *rs, CfEntryInfo *parent,
        if ( extra )
                attr_merge_normalize_one(e, slap_schema.si_ad_objectClass,
                        extra->co_name, NULL );
-       ptr = strchr(rdn->bv_val, '=');
-       ad_name.bv_val = rdn->bv_val;
-       ad_name.bv_len = ptr - rdn->bv_val;
-       rc = slap_bv2ad( &ad_name, &ad, &text );
+       if ( ldap_bv2rdn_x( rdn, &srdn, &ptr, LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx ))
+               goto fail;
+
+       rc = slap_bv2ad( &srdn[0]->la_attr, &ad, &text );
        if ( rc ) {
-               return NULL;
+               ldap_rdnfree_x( srdn, op->o_tmpmemctx );
+               goto fail;
        }
-       val.bv_val = ptr+1;
-       val.bv_len = rdn->bv_len - (val.bv_val - rdn->bv_val);
-       attr_merge_normalize_one(e, ad, &val, NULL );
+       attr_merge_normalize_one(e, ad, &srdn[0]->la_value, NULL );
+       ldap_rdnfree_x( srdn, op->o_tmpmemctx );
+       srdn = NULL;
 
        oc = main->co_oc;
        c->table = main->co_type;
-       if ( oc->soc_required )
-               config_build_attrs( e, oc->soc_required, ad, main->co_table, c );
+       if ( oc->soc_required ) {
+               rc = config_build_attrs( e, oc->soc_required, ad, main->co_table, c );
+               if ( rc ) goto fail;
+       }
 
-       if ( oc->soc_allowed )
-               config_build_attrs( e, oc->soc_allowed, ad, main->co_table, c );
+       if ( oc->soc_allowed ) {
+               rc = config_build_attrs( e, oc->soc_allowed, ad, main->co_table, c );
+               if ( rc ) goto fail;
+       }
 
        if ( extra ) {
                oc = extra->co_oc;
                c->table = extra->co_type;
-               if ( oc->soc_required )
-                       config_build_attrs( e, oc->soc_required, ad, extra->co_table, c );
+               if ( oc->soc_required ) {
+                       rc = config_build_attrs( e, oc->soc_required, ad, extra->co_table, c );
+                       if ( rc ) goto fail;
+               }
 
-               if ( oc->soc_allowed )
-                       config_build_attrs( e, oc->soc_allowed, ad, extra->co_table, c );
+               if ( oc->soc_allowed ) {
+                       rc = config_build_attrs( e, oc->soc_allowed, ad, extra->co_table, c );
+                       if ( rc ) goto fail;
+               }
        }
 
        oc_at = attr_find( e->e_attrs, slap_schema.si_ad_objectClass );
        rc = structural_class(oc_at->a_vals, &oc, NULL, &text, c->cr_msg,
                sizeof(c->cr_msg), op ? op->o_tmpmemctx : NULL );
+       if ( rc != LDAP_SUCCESS ) {
+fail:
+               Debug( LDAP_DEBUG_ANY,
+                       "config_build_entry: build \"%s\" failed: \"%s\"\n",
+                       rdn->bv_val, text, 0);
+               return NULL;
+       }
        attr_merge_normalize_one(e, slap_schema.si_ad_structuralObjectClass, &oc->soc_cname, NULL );
        if ( op ) {
                op->ora_e = e;
                op->ora_modlist = NULL;
                slap_add_opattrs( op, NULL, NULL, 0, 0 );
                if ( !op->o_noop ) {
-                       op->o_bd->be_add( op, rs );
-                       if ( ( rs->sr_err != LDAP_SUCCESS ) 
-                                       && (rs->sr_err != LDAP_ALREADY_EXISTS) ) {
-                               return NULL;
+                       SlapReply rs2 = {REP_RESULT};
+                       op->o_bd->be_add( op, &rs2 );
+                       rs->sr_err = rs2.sr_err;
+                       rs_assert_done( &rs2 );
+                       if ( ( rs2.sr_err != LDAP_SUCCESS ) 
+                                       && (rs2.sr_err != LDAP_ALREADY_EXISTS) ) {
+                               goto fail;
                        }
                }
        }
@@ -5455,11 +6553,11 @@ config_build_schema_inc( ConfigArgs *c, CfEntryInfo *ceparent,
        Entry *e;
        ConfigFile *cf = c->ca_private;
        char *ptr;
-       struct berval bv;
+       struct berval bv, rdn;
 
        for (; cf; cf=cf->c_sibs, c->depth++) {
                if ( !cf->c_at_head && !cf->c_cr_head && !cf->c_oc_head &&
-                       !cf->c_om_head ) continue;
+                       !cf->c_om_head && !cf->c_syn_head && !cf->c_kids ) continue;
                c->value_dn.bv_val = c->log;
                LUTIL_SLASHPATH( cf->c_file.bv_val );
                bv.bv_val = strrchr(cf->c_file.bv_val, LDAP_DIRSEP[0]);
@@ -5472,7 +6570,7 @@ config_build_schema_inc( ConfigArgs *c, CfEntryInfo *ceparent,
                ptr = strchr( bv.bv_val, '.' );
                if ( ptr )
                        bv.bv_len = ptr - bv.bv_val;
-               c->value_dn.bv_len = snprintf(c->value_dn.bv_val, sizeof( c->log ), "cn=" SLAP_X_ORDERED_FMT, c->depth);
+               c->value_dn.bv_len = snprintf(c->value_dn.bv_val, sizeof( c->log ), "cn=\"" SLAP_X_ORDERED_FMT, c->depth);
                if ( c->value_dn.bv_len >= sizeof( c->log ) ) {
                        /* FIXME: how can indicate error? */
                        return -1;
@@ -5480,11 +6578,20 @@ config_build_schema_inc( ConfigArgs *c, CfEntryInfo *ceparent,
                strncpy( c->value_dn.bv_val + c->value_dn.bv_len, bv.bv_val,
                        bv.bv_len );
                c->value_dn.bv_len += bv.bv_len;
+               c->value_dn.bv_val[c->value_dn.bv_len] ='"';
+               c->value_dn.bv_len++;
                c->value_dn.bv_val[c->value_dn.bv_len] ='\0';
+               if ( rdnNormalize( 0, NULL, NULL, &c->value_dn, &rdn, NULL )) {
+                       Debug( LDAP_DEBUG_ANY,
+                               "config_build_schema_inc: invalid schema name \"%s\"\n",
+                               bv.bv_val, 0, 0 );
+                       return -1;
+               }
 
                c->ca_private = cf;
-               e = config_build_entry( op, rs, ceparent, c, &c->value_dn,
+               e = config_build_entry( op, rs, ceparent, c, &rdn,
                        &CFOC_SCHEMA, NULL );
+               ch_free( rdn.bv_val );
                if ( !e ) {
                        return -1;
                } else if ( e && cf->c_kids ) {
@@ -5588,6 +6695,21 @@ config_check_schema(Operation *op, CfBackInfo *cfb)
                        ber_bvarray_free( bv );
                        cf_oc_tail = oc_sys_tail;
                }
+               if ( cf_syn_tail != syn_sys_tail ) {
+                       a = attr_find( e->e_attrs, cfAd_syntax );
+                       if ( a ) {
+                               if ( a->a_nvals != a->a_vals )
+                                       ber_bvarray_free( a->a_nvals );
+                               ber_bvarray_free( a->a_vals );
+                               a->a_vals = NULL;
+                               a->a_nvals = NULL;
+                               a->a_numvals = 0;
+                       }
+                       syn_unparse( &bv, NULL, NULL, 1 );
+                       attr_merge_normalize( e, cfAd_syntax, bv, NULL );
+                       ber_bvarray_free( bv );
+                       cf_syn_tail = syn_sys_tail;
+               }
        } else {
                SlapReply rs = {REP_RESULT};
                c.ca_private = NULL;
@@ -5601,6 +6723,7 @@ config_check_schema(Operation *op, CfBackInfo *cfb)
                cf_at_tail = at_sys_tail;
                cf_oc_tail = oc_sys_tail;
                cf_om_tail = om_sys_tail;
+               cf_syn_tail = syn_sys_tail;
        }
        return 0;
 }
@@ -5625,14 +6748,23 @@ config_back_db_open( BackendDB *be, ConfigReply *cr )
        slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
        SlapReply rs = {REP_RESULT};
        void *thrctx = NULL;
+       AccessControl *save_access;
 
        Debug( LDAP_DEBUG_TRACE, "config_back_db_open\n", 0, 0, 0);
 
        /* If we have no explicitly configured ACLs, don't just use
         * the global ACLs. Explicitly deny access to everything.
         */
-       if ( frontendDB->be_acl && be->be_acl == frontendDB->be_acl ) {
-               parse_acl(be, "config_back_db_open", 0, 6, (char **)defacl, 0 );
+       save_access = be->bd_self->be_acl;
+       be->bd_self->be_acl = NULL;
+       parse_acl(be->bd_self, "config_back_db_open", 0, 6, (char **)defacl, 0 );
+       defacl_parsed = be->bd_self->be_acl;
+       if ( save_access ) {
+               be->bd_self->be_acl = save_access;
+       } else {
+               Debug( LDAP_DEBUG_CONFIG, "config_back_db_open: "
+                               "No explicit ACL for back-config configured. "
+                               "Using hardcoded default\n", 0, 0, 0 );
        }
 
        thrctx = ldap_pvt_thread_pool_context();
@@ -5692,12 +6824,15 @@ config_back_db_open( BackendDB *be, ConfigReply *cr )
        cf_at_tail = at_sys_tail;
        cf_oc_tail = oc_sys_tail;
        cf_om_tail = om_sys_tail;
+       cf_syn_tail = syn_sys_tail;
 
        /* Create schema nodes for included schema... */
        if ( cfb->cb_config->c_kids ) {
+               int rc;
                c.depth = 0;
                c.ca_private = cfb->cb_config->c_kids;
-               if (config_build_schema_inc( &c, ce, op, &rs )) {
+               rc = config_build_schema_inc( &c, ce, op, &rs );
+               if ( rc ) {
                        return -1;
                }
        }
@@ -5772,8 +6907,10 @@ config_back_db_open( BackendDB *be, ConfigReply *cr )
                        return -1;
                }
                ce = e->e_private;
-               if ( be->be_cf_ocs && be->be_cf_ocs->co_cfadd )
+               if ( be->be_cf_ocs && be->be_cf_ocs->co_cfadd ) {
+                       rs_reinit( &rs, REP_RESULT );
                        be->be_cf_ocs->co_cfadd( op, &rs, e, &c );
+               }
                /* Iterate through overlays */
                if ( oi ) {
                        slap_overinst *on;
@@ -5812,8 +6949,10 @@ config_back_db_open( BackendDB *be, ConfigReply *cr )
                                if ( !oe ) {
                                        return -1;
                                }
-                               if ( c.bi->bi_cf_ocs && c.bi->bi_cf_ocs->co_cfadd )
+                               if ( c.bi->bi_cf_ocs && c.bi->bi_cf_ocs->co_cfadd ) {
+                                       rs_reinit( &rs, REP_RESULT );
                                        c.bi->bi_cf_ocs->co_cfadd( op, &rs, oe, &c );
+                               }
                        }
                }
        }
@@ -5870,6 +7009,11 @@ config_back_db_close( BackendDB *be, ConfigReply *cr )
                backend_shutdown( &cfb->cb_db );
        }
 
+       if ( defacl_parsed && be->be_acl != defacl_parsed ) {
+               acl_free( defacl_parsed );
+               defacl_parsed = NULL;
+       }
+
        return 0;
 }
 
@@ -5919,6 +7063,9 @@ config_back_db_init( BackendDB *be, ConfigReply* cr )
        /* Hide from namingContexts */
        SLAP_BFLAGS(be) |= SLAP_BFLAG_CONFIG;
 
+       /* Check ACLs on content of Adds by default */
+       SLAP_DBFLAGS(be) |= SLAP_DBFLAG_ACL_ADD;
+
        return 0;
 }
 
@@ -5960,10 +7107,30 @@ config_tool_entry_first( BackendDB *be )
        CfBackInfo *cfb = be->be_private;
        BackendInfo *bi = cfb->cb_db.bd_info;
 
-       if ( bi && bi->bi_tool_entry_first )
+       if ( bi && bi->bi_tool_entry_first ) {
                return bi->bi_tool_entry_first( &cfb->cb_db );
-       else
-               return NOID;
+       }
+       if ( bi && bi->bi_tool_entry_first_x ) {
+               return bi->bi_tool_entry_first_x( &cfb->cb_db,
+                       NULL, LDAP_SCOPE_DEFAULT, NULL );
+       }
+       return NOID;
+}
+
+static ID
+config_tool_entry_first_x(
+       BackendDB *be,
+       struct berval *base,
+       int scope,
+       Filter *f )
+{
+       CfBackInfo *cfb = be->be_private;
+       BackendInfo *bi = cfb->cb_db.bd_info;
+
+       if ( bi && bi->bi_tool_entry_first_x ) {
+               return bi->bi_tool_entry_first_x( &cfb->cb_db, base, scope, f );
+       }
+       return NOID;
 }
 
 static ID
@@ -6006,6 +7173,7 @@ config_tool_entry_put( BackendDB *be, Entry *e, struct berval *text )
        Operation *op = NULL;
        void *thrctx;
        int isFrontend = 0;
+       int isFrontendChild = 0;
 
        /* Create entry for frontend database if it does not exist already */
        if ( !entry_put_got_frontend ) {
@@ -6054,13 +7222,55 @@ config_tool_entry_put( BackendDB *be, Entry *e, struct berval *text )
                                        return NOID;
                                }
                        } else {
+                               if ( !strncmp( e->e_nname.bv_val + 
+                                       STRLENOF( "olcDatabase" ), "=frontend",
+                                       STRLENOF( "=frontend" ) ) )
+                               {
+                                       struct berval rdn, pdn, ndn;
+                                       dnParent( &e->e_nname, &pdn );
+                                       rdn.bv_val = ca.log;
+                                       rdn.bv_len = snprintf(rdn.bv_val, sizeof( ca.log ),
+                                               "%s=" SLAP_X_ORDERED_FMT "%s",
+                                               cfAd_database->ad_cname.bv_val, -1,
+                                               frontendDB->bd_info->bi_type );
+                                       build_new_dn( &ndn, &pdn, &rdn, NULL );
+                                       ber_memfree( e->e_name.bv_val );
+                                       e->e_name = ndn;
+                                       ber_bvreplace( &e->e_nname, &e->e_name );
+                               }
                                entry_put_got_frontend++;
                                isFrontend = 1;
                        }
                }
        }
+
+       /* Child entries of the frontend database, e.g. slapo-chain's back-ldap
+        * instances, may appear before the config database entry in the ldif, skip
+        * auto-creation of olcDatabase={0}config in such a case */
+       if ( !entry_put_got_config &&
+                       !strncmp( e->e_nname.bv_val, "olcDatabase", STRLENOF( "olcDatabase" ))) {
+               struct berval pdn;
+               dnParent( &e->e_nname, &pdn );
+               while ( pdn.bv_len ) {
+                       if ( !strncmp( pdn.bv_val, "olcDatabase",
+                                       STRLENOF( "olcDatabase" ))) {
+                               if ( !strncmp( pdn.bv_val +
+                                               STRLENOF( "olcDatabase" ), "={-1}frontend",
+                                               STRLENOF( "={-1}frontend" )) ||
+                                               !strncmp( pdn.bv_val +
+                                               STRLENOF( "olcDatabase" ), "=frontend",
+                                               STRLENOF( "=frontend" ))) {
+
+                                       isFrontendChild = 1;
+                                       break;
+                               }
+                       }
+                       dnParent( &pdn, &pdn );
+               }
+       }
+
        /* Create entry for config database if it does not exist already */
-       if ( !entry_put_got_config && !isFrontend ) {
+       if ( !entry_put_got_config && !isFrontend && !isFrontendChild ) {
                if ( !strncmp( e->e_nname.bv_val, "olcDatabase",
                                STRLENOF( "olcDatabase" ))) {
                        if ( strncmp( e->e_nname.bv_val +
@@ -6125,6 +7335,7 @@ static struct {
        { "backend", &cfAd_backend },
        { "database", &cfAd_database },
        { "include", &cfAd_include },
+       { "ldapsyntax", &cfAd_syntax },
        { "objectclass", &cfAd_oc },
        { "objectidentifier", &cfAd_om },
        { "overlay", &cfAd_overlay },
@@ -6209,6 +7420,7 @@ config_back_initialize( BackendInfo *bi )
        bi->bi_tool_entry_open = config_tool_entry_open;
        bi->bi_tool_entry_close = config_tool_entry_close;
        bi->bi_tool_entry_first = config_tool_entry_first;
+       bi->bi_tool_entry_first_x = config_tool_entry_first_x;
        bi->bi_tool_entry_next = config_tool_entry_next;
        bi->bi_tool_entry_get = config_tool_entry_get;
        bi->bi_tool_entry_put = config_tool_entry_put;
@@ -6231,6 +7443,9 @@ config_back_initialize( BackendInfo *bi )
        i = config_register_schema( ct, cf_ocs );
        if ( i ) return i;
 
+       i = slap_str2ad( "olcDatabase", &olcDatabaseDummy[0].ad, &text );
+       if ( i ) return i;
+
        /* setup olcRootPW to be base64-encoded when written in LDIF form;
         * basically, we don't care if it fails */
        i = slap_str2ad( "olcRootPW", &ad, &text );
@@ -6255,4 +7470,3 @@ config_back_initialize( BackendInfo *bi )
 
        return 0;
 }
-