X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fbconfig.c;h=d050122be294e76f174044fb3474f2d60a8f41bb;hb=f38e72b26c4a245dc0aa43c0f6310f20ae3fd9cc;hp=0fe2f2b08e39f0280370cbf40617bf3f0a8a4d25;hpb=931d7f4a952d456b79717e317a83d27072d9f73d;p=openldap diff --git a/servers/slapd/bconfig.c b/servers/slapd/bconfig.c index 0fe2f2b08e..d050122be2 100644 --- a/servers/slapd/bconfig.c +++ b/servers/slapd/bconfig.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "slap.h" @@ -31,6 +32,7 @@ #include "slapi/slapi.h" #endif +#include #include #include "config.h" @@ -61,28 +63,12 @@ typedef struct ConfigFile { BerVarray c_dseFiles; } ConfigFile; -typedef struct CfOcInfo { - struct berval *co_name; - ConfigTable *co_table; - ConfigType co_type; - ObjectClass *co_oc; -} CfOcInfo; - -typedef struct CfEntryInfo { - struct CfEntryInfo *ce_parent; - struct CfEntryInfo *ce_sibs; - struct CfEntryInfo *ce_kids; - Entry *ce_entry; - ConfigType ce_type; - BackendInfo *ce_bi; - BackendDB *ce_be; -} CfEntryInfo; - typedef struct { ConfigFile *cb_config; CfEntryInfo *cb_root; BackendDB cb_db; /* underlying database */ int cb_got_ldif; + int cb_use_ldif; } CfBackInfo; /* These do nothing in slapd, they're kept only to make them @@ -93,7 +79,9 @@ static int replicationInterval; static char *passwd_salt; static char *logfileName; +#ifdef SLAP_AUTH_REWRITE static BerVarray authz_rewrites; +#endif static struct berval cfdir; @@ -101,18 +89,12 @@ static struct berval cfdir; static AttributeDescription *cfAd_backend, *cfAd_database, *cfAd_overlay, *cfAd_include; -static ObjectClass *cfOc_schema, *cfOc_global, *cfOc_backend, *cfOc_database, - *cfOc_include, *cfOc_overlay, *cfOc_module; - -static ConfigFile cf_prv, *cfn = &cf_prv; +static ConfigFile *cfn; static Avlnode *CfOcTree; -static int add_syncrepl LDAP_P(( Backend *, char **, int )); -static int parse_syncrepl_line LDAP_P(( char **, int, syncinfo_t *)); -static void syncrepl_unparse LDAP_P (( syncinfo_t *, struct berval *)); -static int config_add_internal( CfBackInfo *cfb, Entry *e, SlapReply *rs, - int *renumber ); +static int config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca, + SlapReply *rs, int *renumber ); static ConfigDriver config_fname; static ConfigDriver config_cfdir; @@ -122,10 +104,8 @@ static ConfigDriver config_passwd_hash; static ConfigDriver config_schema_dn; static ConfigDriver config_sizelimit; static ConfigDriver config_timelimit; -static ConfigDriver config_limits; static ConfigDriver config_overlay; static ConfigDriver config_suffix; -static ConfigDriver config_deref_depth; static ConfigDriver config_rootdn; static ConfigDriver config_rootpw; static ConfigDriver config_restrict; @@ -135,7 +115,6 @@ static ConfigDriver config_requires; static ConfigDriver config_security; static ConfigDriver config_referral; static ConfigDriver config_loglevel; -static ConfigDriver config_syncrepl; static ConfigDriver config_replica; static ConfigDriver config_updatedn; static ConfigDriver config_updateref; @@ -144,6 +123,7 @@ static ConfigDriver config_include; static ConfigDriver config_tls_option; static ConfigDriver config_tls_config; #endif +extern ConfigDriver syncrepl_config; enum { CFG_ACL = 1, @@ -157,8 +137,6 @@ enum { CFG_TLS_CA_FILE, CFG_TLS_VERIFY, CFG_TLS_CRLCHECK, - CFG_SIZE, - CFG_TIME, CFG_CONCUR, CFG_THREADS, CFG_SALT, @@ -171,8 +149,6 @@ enum { CFG_DIT, CFG_ATTR, CFG_ATOPT, - CFG_CHECK, - CFG_AUDITLOG, CFG_REPLOG, CFG_ROOTDSE, CFG_LOGFILE, @@ -185,6 +161,8 @@ enum { CFG_SASLSECP, CFG_SSTR_IF_MAX, CFG_SSTR_IF_MIN, + + CFG_LAST }; typedef struct { @@ -195,9 +173,17 @@ static OidRec OidMacros[] = { /* OpenLDAProot:666.11.1 */ { "OLcfg", "1.3.6.1.4.1.4203.666.11.1" }, { "OLcfgAt", "OLcfg:3" }, + { "OLcfgGlAt", "OLcfgAt:0" }, + { "OLcfgBkAt", "OLcfgAt:1" }, + { "OLcfgDbAt", "OLcfgAt:2" }, + { "OLcfgOvAt", "OLcfgAt:3" }, { "OLcfgOc", "OLcfg:4" }, + { "OLcfgGlOc", "OLcfgOc:0" }, + { "OLcfgBkOc", "OLcfgOc:1" }, + { "OLcfgDbOc", "OLcfgOc:2" }, + { "OLcfgOvOc", "OLcfgOc:3" }, { "OMsyn", "1.3.6.1.4.1.1466.115.121.1" }, - { "OMsInteger", "OMsyn:2" }, + { "OMsInteger", "OMsyn:27" }, { "OMsBoolean", "OMsyn:7" }, { "OMsDN", "OMsyn:12" }, { "OMsDirectoryString", "OMsyn:15" }, @@ -205,90 +191,98 @@ static OidRec OidMacros[] = { { NULL, NULL } }; +/* + * OLcfg{Bk|Db}{Oc|At}:0 -> common + * OLcfg{Bk|Db}{Oc|At}:1 -> bdb + * OLcfg{Bk|Db}{Oc|At}:2 -> ldif + * OLcfg{Bk|Db}{Oc|At}:3 -> ldap? + */ + /* alphabetical ordering */ -ConfigTable config_back_cf_table[] = { +static ConfigTable config_back_cf_table[] = { /* This attr is read-only */ { "", "", 0, 0, 0, ARG_MAGIC, - &config_fname, "( OLcfgAt:78 NAME 'olcConfigFile' " + &config_fname, "( OLcfgGlAt:78 NAME 'olcConfigFile' " "DESC 'File for slapd configuration directives' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, { "", "", 0, 0, 0, ARG_MAGIC, - &config_cfdir, "( OLcfgAt:79 NAME 'olcConfigDir' " + &config_cfdir, "( OLcfgGlAt:79 NAME 'olcConfigDir' " "DESC 'Directory for slapd configuration backend' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, { "access", NULL, 0, 0, 0, ARG_MAY_DB|ARG_MAGIC|CFG_ACL, - &config_generic, "( OLcfgAt:1 NAME 'olcAccess' " + &config_generic, "( OLcfgGlAt:1 NAME 'olcAccess' " "DESC 'Access Control List' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL }, { "allows", "features", 2, 0, 5, ARG_PRE_DB|ARG_MAGIC, - &config_allows, "( OLcfgAt:2 NAME 'olcAllows' " + &config_allows, "( OLcfgGlAt:2 NAME 'olcAllows' " "DESC 'Allowed set of deprecated features' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString )", NULL, NULL }, { "argsfile", "file", 2, 2, 0, ARG_STRING, - &slapd_args_file, "( OLcfgAt:3 NAME 'olcArgsFile' " + &slapd_args_file, "( OLcfgGlAt:3 NAME 'olcArgsFile' " "DESC 'File for slapd command line options' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, - { "attribute", "attribute", 2, 0, 9, ARG_PAREN|ARG_MAGIC|CFG_ATTR, - &config_generic, "( OLcfgAt:4 NAME 'olcAttributeTypes' " + { "attributeoptions", NULL, 0, 0, 0, ARG_MAGIC|CFG_ATOPT, + &config_generic, "( OLcfgGlAt:5 NAME 'olcAttributeOptions' " + "EQUALITY caseIgnoreMatch " + "SYNTAX OMsDirectoryString )", NULL, NULL }, + { "attribute", "attribute", 2, 0, 9, + ARG_PAREN|ARG_MAGIC|CFG_ATTR|ARG_NO_DELETE|ARG_NO_INSERT, + &config_generic, "( OLcfgGlAt:4 NAME 'olcAttributeTypes' " "DESC 'OpenLDAP attributeTypes' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL }, - { "attributeoptions", NULL, 0, 0, 0, ARG_MAGIC|CFG_ATOPT, - &config_generic, "( OLcfgAt:5 NAME 'olcAttributeOptions' " - "EQUALITY caseIgnoreMatch " - "SYNTAX OMsDirectoryString )", NULL, NULL }, - { "authid-rewrite", NULL, 2, 0, 0, + { "authid-rewrite", NULL, 2, 0, STRLENOF( "authid-rewrite" ), #ifdef SLAP_AUTH_REWRITE - ARG_MAGIC|CFG_REWRITE, &config_generic, + ARG_MAGIC|CFG_REWRITE|ARG_NO_INSERT, &config_generic, #else ARG_IGNORED, NULL, #endif - "( OLcfgAt:6 NAME 'olcAuthIDRewrite' " + "( OLcfgGlAt:6 NAME 'olcAuthIDRewrite' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL }, { "authz-policy", "policy", 2, 2, 0, ARG_STRING|ARG_MAGIC|CFG_AZPOLICY, - &config_generic, "( OLcfgAt:7 NAME 'olcAuthzPolicy' " + &config_generic, "( OLcfgGlAt:7 NAME 'olcAuthzPolicy' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, - { "authz-regexp", NULL, 3, 3, 0, ARG_MAGIC|CFG_AZREGEXP, - &config_generic, "( OLcfgAt:8 NAME 'olcAuthzRegexp' " + { "authz-regexp", NULL, 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 }, { "backend", "type", 2, 2, 0, ARG_PRE_DB|ARG_MAGIC|CFG_BACKEND, - &config_generic, "( OLcfgAt:9 NAME 'olcBackend' " + &config_generic, "( OLcfgGlAt:9 NAME 'olcBackend' " "DESC 'A type of backend' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString SINGLE-VALUE X-ORDERED 'SIBLINGS' )", NULL, NULL }, { "concurrency", "level", 2, 2, 0, ARG_INT|ARG_MAGIC|CFG_CONCUR, - &config_generic, "( OLcfgAt:10 NAME 'olcConcurrency' " + &config_generic, "( OLcfgGlAt:10 NAME 'olcConcurrency' " "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, { "conn_max_pending", "max", 2, 2, 0, ARG_INT, - &slap_conn_max_pending, "( OLcfgAt:11 NAME 'olcConnMaxPending' " + &slap_conn_max_pending, "( OLcfgGlAt:11 NAME 'olcConnMaxPending' " "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, { "conn_max_pending_auth", "max", 2, 2, 0, ARG_INT, - &slap_conn_max_pending_auth, "( OLcfgAt:12 NAME 'olcConnMaxPendingAuth' " + &slap_conn_max_pending_auth, "( OLcfgGlAt:12 NAME 'olcConnMaxPendingAuth' " "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, { "database", "type", 2, 2, 0, ARG_MAGIC|CFG_DATABASE, - &config_generic, "( OLcfgAt:13 NAME 'olcDatabase' " + &config_generic, "( OLcfgGlAt:13 NAME 'olcDatabase' " "DESC 'The backend type for a database instance' " "SUP olcBackend SINGLE-VALUE X-ORDERED 'SIBLINGS' )", NULL, NULL }, - { "defaultSearchBase", "dn", 2, 2, 0, ARG_PRE_BI|ARG_PRE_DB|ARG_DN|ARG_MAGIC, - &config_search_base, "( OLcfgAt:14 NAME 'olcDefaultSearchBase' " + { "defaultSearchBase", "dn", 2, 2, 0, ARG_PRE_BI|ARG_PRE_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC, + &config_search_base, "( OLcfgGlAt:14 NAME 'olcDefaultSearchBase' " "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL }, { "disallows", "features", 2, 0, 8, ARG_PRE_DB|ARG_MAGIC, - &config_disallows, "( OLcfgAt:15 NAME 'olcDisallows' " + &config_disallows, "( OLcfgGlAt:15 NAME 'olcDisallows' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString )", NULL, NULL }, - { "ditcontentrule", NULL, 0, 0, 0, ARG_MAGIC|CFG_DIT, - &config_generic, "( OLcfgAt:16 NAME 'olcDitContentRules' " + { "ditcontentrule", NULL, 0, 0, 0, ARG_MAGIC|CFG_DIT|ARG_NO_DELETE|ARG_NO_INSERT, + &config_generic, "( OLcfgGlAt:16 NAME 'olcDitContentRules' " "DESC 'OpenLDAP DIT content rules' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", @@ -299,44 +293,43 @@ ConfigTable config_back_cf_table[] = { #else ARG_IGNORED, NULL, #endif - "( OLcfgAt:17 NAME 'olcGentleHUP' " + "( OLcfgGlAt:17 NAME 'olcGentleHUP' " "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, { "idletimeout", "timeout", 2, 2, 0, ARG_INT, - &global_idletimeout, "( OLcfgAt:18 NAME 'olcIdleTimeout' " + &global_idletimeout, "( OLcfgGlAt:18 NAME 'olcIdleTimeout' " "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, -/* XXX -- special case? */ { "include", "file", 2, 2, 0, ARG_MAGIC, - &config_include, "( OLcfgAt:19 NAME 'olcInclude' " + &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, - &config_generic, "( OLcfgAt:20 NAME 'olcIndexSubstrIfMinLen' " + &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, - &config_generic, "( OLcfgAt:21 NAME 'olcIndexSubstrIfMaxLen' " + &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, "( OLcfgAt:22 NAME 'olcIndexSubstrAnyLen' " + &index_substr_any_len, "( OLcfgGlAt:22 NAME 'olcIndexSubstrAnyLen' " "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, - { "index_substr_step", "step", 2, 2, 0, ARG_INT|ARG_NONZERO, - &index_substr_any_step, "( OLcfgAt:23 NAME 'olcIndexSubstrAnyStep' " + { "index_substr_any_step", "step", 2, 2, 0, ARG_INT|ARG_NONZERO, + &index_substr_any_step, "( OLcfgGlAt:23 NAME 'olcIndexSubstrAnyStep' " "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, { "lastmod", "on|off", 2, 2, 0, ARG_DB|ARG_ON_OFF|ARG_MAGIC|CFG_LASTMOD, - &config_generic, "( OLcfgAt:24 NAME 'olcLastMod' " + &config_generic, "( OLcfgDbAt:0.4 NAME 'olcLastMod' " "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, { "limits", "limits", 2, 0, 0, ARG_DB|ARG_MAGIC|CFG_LIMITS, - &config_generic, "( OLcfgAt:25 NAME 'olcLimits' " - "SYNTAX OMsDirectoryString )", NULL, NULL }, + &config_generic, "( OLcfgDbAt:0.5 NAME 'olcLimits' " + "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL }, { "localSSF", "ssf", 2, 2, 0, ARG_INT, - &local_ssf, "( OLcfgAt:26 NAME 'olcLocalSSF' " + &local_ssf, "( OLcfgGlAt:26 NAME 'olcLocalSSF' " "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, { "logfile", "file", 2, 2, 0, ARG_STRING|ARG_MAGIC|CFG_LOGFILE, - &config_generic, "( OLcfgAt:27 NAME 'olcLogFile' " + &config_generic, "( OLcfgGlAt:27 NAME 'olcLogFile' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, { "loglevel", "level", 2, 0, 0, ARG_MAGIC, - &config_loglevel, "( OLcfgAt:28 NAME 'olcLogLevel' " + &config_loglevel, "( OLcfgGlAt:28 NAME 'olcLogLevel' " "SYNTAX OMsDirectoryString )", NULL, NULL }, { "maxDerefDepth", "depth", 2, 2, 0, ARG_DB|ARG_INT|ARG_MAGIC|CFG_DEPTH, - &config_generic, "( OLcfgAt:29 NAME 'olcMaxDerefDepth' " + &config_generic, "( OLcfgDbAt:0.6 NAME 'olcMaxDerefDepth' " "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, { "moduleload", "file", 2, 0, 0, #ifdef SLAPD_MODULES @@ -344,36 +337,36 @@ ConfigTable config_back_cf_table[] = { #else ARG_IGNORED, NULL, #endif - "( OLcfgAt:30 NAME 'olcModuleLoad' " + "( OLcfgGlAt:30 NAME 'olcModuleLoad' " "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL }, { "modulepath", "path", 2, 2, 0, #ifdef SLAPD_MODULES - ARG_MAGIC|CFG_MODPATH, &config_generic, + ARG_MAGIC|CFG_MODPATH|ARG_NO_DELETE|ARG_NO_INSERT, &config_generic, #else ARG_IGNORED, NULL, #endif - "( OLcfgAt:31 NAME 'olcModulePath' " - "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL }, - { "objectclass", "objectclass", 2, 0, 0, ARG_PAREN|ARG_MAGIC|CFG_OC, - &config_generic, "( OLcfgAt:32 NAME 'olcObjectClasses' " + "( OLcfgGlAt:31 NAME 'olcModulePath' " + "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, + { "objectclass", "objectclass", 2, 0, 0, ARG_PAREN|ARG_MAGIC|CFG_OC|ARG_NO_DELETE|ARG_NO_INSERT, + &config_generic, "( OLcfgGlAt:32 NAME 'olcObjectClasses' " "DESC 'OpenLDAP object classes' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL }, { "objectidentifier", NULL, 0, 0, 0, ARG_MAGIC|CFG_OID, - &config_generic, "( OLcfgAt:33 NAME 'olcObjectIdentifier' " + &config_generic, "( OLcfgGlAt:33 NAME 'olcObjectIdentifier' " "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL }, { "overlay", "overlay", 2, 2, 0, ARG_MAGIC, - &config_overlay, "( OLcfgAt:34 NAME 'olcOverlay' " + &config_overlay, "( OLcfgGlAt:34 NAME 'olcOverlay' " "SUP olcDatabase SINGLE-VALUE X-ORDERED 'SIBLINGS' )", NULL, NULL }, { "password-crypt-salt-format", "salt", 2, 2, 0, ARG_STRING|ARG_MAGIC|CFG_SALT, - &config_generic, "( OLcfgAt:35 NAME 'olcPasswordCryptSaltFormat' " + &config_generic, "( OLcfgGlAt:35 NAME 'olcPasswordCryptSaltFormat' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, { "password-hash", "hash", 2, 2, 0, ARG_MAGIC, - &config_passwd_hash, "( OLcfgAt:36 NAME 'olcPasswordHash' " + &config_passwd_hash, "( OLcfgGlAt:36 NAME 'olcPasswordHash' " "SYNTAX OMsDirectoryString )", NULL, NULL }, { "pidfile", "file", 2, 2, 0, ARG_STRING, - &slapd_pid_file, "( OLcfgAt:37 NAME 'olcPidFile' " + &slapd_pid_file, "( OLcfgGlAt:37 NAME 'olcPidFile' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, { "plugin", NULL, 0, 0, 0, #ifdef LDAP_SLAPI @@ -381,7 +374,7 @@ ConfigTable config_back_cf_table[] = { #else ARG_IGNORED, NULL, #endif - "( OLcfgAt:38 NAME 'olcPlugin' " + "( OLcfgGlAt:38 NAME 'olcPlugin' " "SYNTAX OMsDirectoryString )", NULL, NULL }, { "pluginlog", "filename", 2, 2, 0, #ifdef LDAP_SLAPI @@ -389,34 +382,34 @@ ConfigTable config_back_cf_table[] = { #else ARG_IGNORED, NULL, #endif - "( OLcfgAt:39 NAME 'olcPluginLogFile' " + "( OLcfgGlAt:39 NAME 'olcPluginLogFile' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, { "readonly", "on|off", 2, 2, 0, ARG_MAY_DB|ARG_ON_OFF|ARG_MAGIC|CFG_RO, - &config_generic, "( OLcfgAt:40 NAME 'olcReadOnly' " + &config_generic, "( OLcfgGlAt:40 NAME 'olcReadOnly' " "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, { "referral", "url", 2, 2, 0, ARG_MAGIC, - &config_referral, "( OLcfgAt:41 NAME 'olcReferral' " + &config_referral, "( OLcfgGlAt:41 NAME 'olcReferral' " "SUP labeledURI SINGLE-VALUE )", NULL, NULL }, { "replica", "host or uri", 2, 0, 0, ARG_DB|ARG_MAGIC, - &config_replica, "( OLcfgAt:42 NAME 'olcReplica' " + &config_replica, "( OLcfgDbAt:0.7 NAME 'olcReplica' " "SUP labeledURI )", NULL, NULL }, { "replica-argsfile", NULL, 0, 0, 0, ARG_STRING, - &replica_argsFile, "( OLcfgAt:43 NAME 'olcReplicaArgsFile' " + &replica_argsFile, "( OLcfgGlAt:43 NAME 'olcReplicaArgsFile' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, { "replica-pidfile", NULL, 0, 0, 0, ARG_STRING, - &replica_pidFile, "( OLcfgAt:44 NAME 'olcReplicaPidFile' " + &replica_pidFile, "( OLcfgGlAt:44 NAME 'olcReplicaPidFile' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, { "replicationInterval", NULL, 0, 0, 0, ARG_INT, - &replicationInterval, "( OLcfgAt:45 NAME 'olcReplicationInterval' " + &replicationInterval, "( OLcfgGlAt:45 NAME 'olcReplicationInterval' " "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, { "replogfile", "filename", 2, 2, 0, ARG_MAY_DB|ARG_MAGIC|ARG_STRING|CFG_REPLOG, - &config_generic, "( OLcfgAt:46 NAME 'olcReplogFile' " + &config_generic, "( OLcfgGlAt:46 NAME 'olcReplogFile' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, { "require", "features", 2, 0, 7, ARG_MAY_DB|ARG_MAGIC, - &config_requires, "( OLcfgAt:47 NAME 'olcRequires' " + &config_requires, "( OLcfgGlAt:47 NAME 'olcRequires' " "SYNTAX OMsDirectoryString )", NULL, NULL }, { "restrict", "op_list", 2, 0, 0, ARG_MAY_DB|ARG_MAGIC, - &config_restrict, "( OLcfgAt:48 NAME 'olcRestrict' " + &config_restrict, "( OLcfgGlAt:48 NAME 'olcRestrict' " "SYNTAX OMsDirectoryString )", NULL, NULL }, { "reverse-lookup", "on|off", 2, 2, 0, #ifdef SLAPD_RLOOKUPS @@ -424,16 +417,16 @@ ConfigTable config_back_cf_table[] = { #else ARG_IGNORED, NULL, #endif - "( OLcfgAt:49 NAME 'olcReverseLookup' " + "( OLcfgGlAt:49 NAME 'olcReverseLookup' " "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, - { "rootdn", "dn", 2, 2, 0, ARG_DB|ARG_DN|ARG_MAGIC, - &config_rootdn, "( OLcfgAt:50 NAME 'olcRootDN' " + { "rootdn", "dn", 2, 2, 0, ARG_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC, + &config_rootdn, "( OLcfgDbAt:0.8 NAME 'olcRootDN' " "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL }, { "rootDSE", "file", 2, 2, 0, ARG_MAGIC|CFG_ROOTDSE, - &config_generic, "( OLcfgAt:51 NAME 'olcRootDSE' " + &config_generic, "( OLcfgGlAt:51 NAME 'olcRootDSE' " "SYNTAX OMsDirectoryString )", NULL, NULL }, { "rootpw", "password", 2, 2, 0, ARG_BERVAL|ARG_DB|ARG_MAGIC, - &config_rootpw, "( OLcfgAt:52 NAME 'olcRootPW' " + &config_rootpw, "( OLcfgDbAt:0.9 NAME 'olcRootPW' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, { "sasl-authz-policy", NULL, 2, 2, 0, ARG_MAGIC|CFG_AZPOLICY, &config_generic, NULL, NULL, NULL }, @@ -443,7 +436,7 @@ ConfigTable config_back_cf_table[] = { #else ARG_IGNORED, NULL, #endif - "( OLcfgAt:53 NAME 'olcSaslHost' " + "( OLcfgGlAt:53 NAME 'olcSaslHost' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, { "sasl-realm", "realm", 2, 2, 0, #ifdef HAVE_CYRUS_SASL @@ -451,7 +444,7 @@ ConfigTable config_back_cf_table[] = { #else ARG_IGNORED, NULL, #endif - "( OLcfgAt:54 NAME 'olcSaslRealm' " + "( OLcfgGlAt:54 NAME 'olcSaslRealm' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, { "sasl-regexp", NULL, 3, 3, 0, ARG_MAGIC|CFG_AZREGEXP, &config_generic, NULL, NULL, NULL }, @@ -461,27 +454,24 @@ ConfigTable config_back_cf_table[] = { #else ARG_IGNORED, NULL, #endif - "( OLcfgAt:56 NAME 'olcSaslSecProps' " + "( OLcfgGlAt:56 NAME 'olcSaslSecProps' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, { "saslRegexp", NULL, 3, 3, 0, ARG_MAGIC|CFG_AZREGEXP, &config_generic, NULL, NULL, NULL }, - { "schemacheck", "on|off", 2, 2, 0, ARG_ON_OFF|ARG_MAGIC|CFG_CHECK, - &config_generic, "( OLcfgAt:57 NAME 'olcSchemaCheck' " - "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, - { "schemadn", "dn", 2, 2, 0, ARG_MAY_DB|ARG_DN|ARG_MAGIC, - &config_schema_dn, "( OLcfgAt:58 NAME 'olcSchemaDN' " + { "schemadn", "dn", 2, 2, 0, ARG_MAY_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC, + &config_schema_dn, "( OLcfgGlAt:58 NAME 'olcSchemaDN' " "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL }, { "security", "factors", 2, 0, 0, ARG_MAY_DB|ARG_MAGIC, - &config_security, "( OLcfgAt:59 NAME 'olcSecurity' " + &config_security, "( OLcfgGlAt:59 NAME 'olcSecurity' " "SYNTAX OMsDirectoryString )", NULL, NULL }, - { "sizelimit", "limit", 2, 0, 0, ARG_MAY_DB|ARG_MAGIC|CFG_SIZE, - &config_sizelimit, "( OLcfgAt:60 NAME 'olcSizeLimit' " - "SYNTAX OMsInteger )", NULL, NULL }, + { "sizelimit", "limit", 2, 0, 0, ARG_MAY_DB|ARG_MAGIC, + &config_sizelimit, "( OLcfgGlAt:60 NAME 'olcSizeLimit' " + "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, { "sockbuf_max_incoming", "max", 2, 2, 0, ARG_BER_LEN_T, - &sockbuf_max_incoming, "( OLcfgAt:61 NAME 'olcSockbufMaxIncoming' " + &sockbuf_max_incoming, "( OLcfgGlAt:61 NAME 'olcSockbufMaxIncoming' " "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, { "sockbuf_max_incoming_auth", "max", 2, 2, 0, ARG_BER_LEN_T, - &sockbuf_max_incoming_auth, "( OLcfgAt:62 NAME 'olcSockbufMaxIncomingAuth' " + &sockbuf_max_incoming_auth, "( OLcfgGlAt:62 NAME 'olcSockbufMaxIncomingAuth' " "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, { "srvtab", "file", 2, 2, 0, #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND @@ -489,27 +479,27 @@ ConfigTable config_back_cf_table[] = { #else ARG_IGNORED, NULL, #endif - "( OLcfgAt:63 NAME 'olcSrvtab' " + "( OLcfgGlAt:63 NAME 'olcSrvtab' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, - { "suffix", "suffix", 2, 2, 0, ARG_DB|ARG_DN|ARG_MAGIC, - &config_suffix, "( OLcfgAt:64 NAME 'olcSuffix' " + { "suffix", "suffix", 2, 2, 0, ARG_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC, + &config_suffix, "( OLcfgDbAt:0.10 NAME 'olcSuffix' " "SYNTAX OMsDN )", NULL, NULL }, { "syncrepl", NULL, 0, 0, 0, ARG_DB|ARG_MAGIC, - &config_syncrepl, "( OLcfgAt:65 NAME 'olcSyncrepl' " + &syncrepl_config, "( OLcfgDbAt:0.11 NAME 'olcSyncrepl' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, { "threads", "count", 2, 2, 0, ARG_INT|ARG_MAGIC|CFG_THREADS, - &config_generic, "( OLcfgAt:66 NAME 'olcThreads' " + &config_generic, "( OLcfgGlAt:66 NAME 'olcThreads' " "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, - { "timelimit", "limit", 2, 0, 0, ARG_MAY_DB|ARG_MAGIC|CFG_TIME, - &config_timelimit, "( OLcfgAt:67 NAME 'olcTimeLimit' " - "SYNTAX OMsInteger )", NULL, NULL }, + { "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, #ifdef HAVE_TLS CFG_TLS_CA_FILE|ARG_STRING|ARG_MAGIC, &config_tls_option, #else ARG_IGNORED, NULL, #endif - "( OLcfgAt:68 NAME 'olcTLSCACertificateFile' " + "( OLcfgGlAt:68 NAME 'olcTLSCACertificateFile' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, { "TLSCACertificatePath", NULL, 0, 0, 0, #ifdef HAVE_TLS @@ -517,7 +507,7 @@ ConfigTable config_back_cf_table[] = { #else ARG_IGNORED, NULL, #endif - "( OLcfgAt:69 NAME 'olcTLSCACertificatePath' " + "( OLcfgGlAt:69 NAME 'olcTLSCACertificatePath' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, { "TLSCertificateFile", NULL, 0, 0, 0, #ifdef HAVE_TLS @@ -525,7 +515,7 @@ ConfigTable config_back_cf_table[] = { #else ARG_IGNORED, NULL, #endif - "( OLcfgAt:70 NAME 'olcTLSCertificateFile' " + "( OLcfgGlAt:70 NAME 'olcTLSCertificateFile' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, { "TLSCertificateKeyFile", NULL, 0, 0, 0, #ifdef HAVE_TLS @@ -533,7 +523,7 @@ ConfigTable config_back_cf_table[] = { #else ARG_IGNORED, NULL, #endif - "( OLcfgAt:71 NAME 'olcTLSCertificateKeyFile' " + "( OLcfgGlAt:71 NAME 'olcTLSCertificateKeyFile' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, { "TLSCipherSuite", NULL, 0, 0, 0, #ifdef HAVE_TLS @@ -541,7 +531,7 @@ ConfigTable config_back_cf_table[] = { #else ARG_IGNORED, NULL, #endif - "( OLcfgAt:72 NAME 'olcTLSCipherSuite' " + "( OLcfgGlAt:72 NAME 'olcTLSCipherSuite' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, { "TLSCRLCheck", NULL, 0, 0, 0, #if defined(HAVE_TLS) && defined(HAVE_OPENSSL_CRL) @@ -549,7 +539,7 @@ ConfigTable config_back_cf_table[] = { #else ARG_IGNORED, NULL, #endif - "( OLcfgAt:73 NAME 'olcTLSCRLCheck' " + "( OLcfgGlAt:73 NAME 'olcTLSCRLCheck' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, { "TLSRandFile", NULL, 0, 0, 0, #ifdef HAVE_TLS @@ -557,7 +547,7 @@ ConfigTable config_back_cf_table[] = { #else ARG_IGNORED, NULL, #endif - "( OLcfgAt:74 NAME 'olcTLSRandFile' " + "( OLcfgGlAt:74 NAME 'olcTLSRandFile' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, { "TLSVerifyClient", NULL, 0, 0, 0, #ifdef HAVE_TLS @@ -565,26 +555,43 @@ ConfigTable config_back_cf_table[] = { #else ARG_IGNORED, NULL, #endif - "( OLcfgAt:75 NAME 'olcTLSVerifyClient' " + "( OLcfgGlAt:75 NAME 'olcTLSVerifyClient' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, { "ucdata-path", "path", 2, 2, 0, ARG_IGNORED, NULL, NULL, NULL, NULL }, - { "updatedn", "dn", 2, 2, 0, ARG_DB|ARG_MAGIC, - &config_updatedn, "( OLcfgAt:76 NAME 'olcUpdateDN' " + { "updatedn", "dn", 2, 2, 0, ARG_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC, + &config_updatedn, "( OLcfgDbAt:0.12 NAME 'olcUpdateDN' " "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL }, { "updateref", "url", 2, 2, 0, ARG_DB|ARG_MAGIC, - &config_updateref, "( OLcfgAt:77 NAME 'olcUpdateRef' " + &config_updateref, "( OLcfgDbAt:0.13 NAME 'olcUpdateRef' " "SUP labeledURI )", NULL, NULL }, { NULL, NULL, 0, 0, 0, ARG_IGNORED, NULL, NULL, NULL, NULL } }; +/* Routines to check if a child can be added to this type */ +static ConfigLDAPadd cfAddSchema, cfAddInclude, cfAddDatabase, + cfAddBackend, cfAddModule, cfAddOverlay; + +/* NOTE: be careful when defining array members + * that can be conditionally compiled */ +#define CFOC_GLOBAL cf_ocs[1] +#define CFOC_SCHEMA cf_ocs[2] +#define CFOC_BACKEND cf_ocs[3] +#define CFOC_DATABASE cf_ocs[4] +#define CFOC_OVERLAY cf_ocs[5] +#define CFOC_INCLUDE cf_ocs[6] +#define CFOC_FRONTEND cf_ocs[7] +#ifdef SLAPD_MODULES +#define CFOC_MODULE cf_ocs[8] +#endif /* SLAPD_MODULES */ + static ConfigOCs cf_ocs[] = { - { "( OLcfgOc:1 " + { "( OLcfgGlOc:0 " "NAME 'olcConfig' " "DESC 'OpenLDAP configuration object' " "ABSTRACT SUP top )", Cft_Abstract, NULL }, - { "( OLcfgOc:2 " + { "( OLcfgGlOc:1 " "NAME 'olcGlobal' " "DESC 'OpenLDAP Global configuration options' " "SUP olcConfig STRUCTURAL " @@ -595,34 +602,34 @@ static ConfigOCs cf_ocs[] = { "olcDisallows $ olcGentleHUP $ olcIdleTimeout $ " "olcIndexSubstrIfMaxLen $ olcIndexSubstrIfMinLen $ " "olcIndexSubstrAnyLen $ olcIndexSubstrAnyStep $ olcLocalSSF $ " - "olcLogLevel $ olcModulePath $ " + "olcLogLevel $ " "olcPasswordCryptSaltFormat $ olcPasswordHash $ olcPidFile $ " "olcPluginLogFile $ olcReadOnly $ olcReferral $ " "olcReplicaPidFile $ olcReplicaArgsFile $ olcReplicationInterval $ " "olcReplogFile $ olcRequires $ olcRestrict $ olcReverseLookup $ " - "olcRootDSE $ olcRootPW $ " + "olcRootDSE $ " "olcSaslHost $ olcSaslRealm $ olcSaslSecProps $ " - "olcSchemaCheck $ olcSecurity $ olcSizeLimit $ " + "olcSecurity $ olcSizeLimit $ " "olcSockbufMaxIncoming $ olcSockbufMaxIncomingAuth $ olcSrvtab $ " "olcThreads $ olcTimeLimit $ olcTLSCACertificateFile $ " "olcTLSCACertificatePath $ olcTLSCertificateFile $ " "olcTLSCertificateKeyFile $ olcTLSCipherSuite $ olcTLSCRLCheck $ " "olcTLSRandFile $ olcTLSVerifyClient $ " "olcObjectIdentifier $ olcAttributeTypes $ olcObjectClasses $ " - "olcDitContentRules ) )", Cft_Global, &cfOc_global }, - { "( OLcfgOc:3 " + "olcDitContentRules ) )", Cft_Global }, + { "( OLcfgGlOc:2 " "NAME 'olcSchemaConfig' " "DESC 'OpenLDAP schema object' " "SUP olcConfig STRUCTURAL " "MAY ( cn $ olcObjectIdentifier $ olcAttributeTypes $ " "olcObjectClasses $ olcDitContentRules ) )", - Cft_Schema, &cfOc_schema }, - { "( OLcfgOc:4 " + Cft_Schema, NULL, cfAddSchema }, + { "( OLcfgGlOc:3 " "NAME 'olcBackendConfig' " "DESC 'OpenLDAP Backend-specific options' " "SUP olcConfig STRUCTURAL " - "MUST olcBackend )", Cft_Backend, &cfOc_backend }, - { "( OLcfgOc:5 " + "MUST olcBackend )", Cft_Backend, NULL, cfAddBackend }, + { "( OLcfgGlOc:4 " "NAME 'olcDatabaseConfig' " "DESC 'OpenLDAP Database-specific options' " "SUP olcConfig STRUCTURAL " @@ -632,26 +639,36 @@ static ConfigOCs cf_ocs[] = { "olcReplogFile $ olcRequires $ olcRestrict $ olcRootDN $ olcRootPW $ " "olcSchemaDN $ olcSecurity $ olcSizeLimit $ olcSyncrepl $ " "olcTimeLimit $ olcUpdateDN $ olcUpdateRef ) )", - Cft_Database, &cfOc_database }, - { "( OLcfgOc:6 " + Cft_Database, NULL, cfAddDatabase }, + { "( OLcfgGlOc:5 " "NAME 'olcOverlayConfig' " "DESC 'OpenLDAP Overlay-specific options' " "SUP olcConfig STRUCTURAL " - "MUST olcOverlay )", Cft_Overlay, &cfOc_overlay }, - { "( OLcfgOc:7 " + "MUST olcOverlay )", Cft_Overlay, NULL, cfAddOverlay }, + { "( OLcfgGlOc:6 " "NAME 'olcIncludeFile' " "DESC 'OpenLDAP configuration include file' " "SUP olcConfig STRUCTURAL " "MUST olcInclude " "MAY ( cn $ olcRootDSE ) )", - Cft_Include, &cfOc_include }, + Cft_Include, NULL, cfAddInclude }, + /* This should be STRUCTURAL like all the other database classes, but + * that would mean inheriting all of the olcDatabaseConfig attributes, + * which causes them to be merged twice in config_build_entry. + */ + { "( OLcfgGlOc:7 " + "NAME 'olcFrontendConfig' " + "DESC 'OpenLDAP frontend configuration' " + "AUXILIARY " + "MAY olcDefaultSearchBase )", + Cft_Database, NULL, NULL }, #ifdef SLAPD_MODULES - { "( OLcfgOc:8 " + { "( OLcfgGlOc:8 " "NAME 'olcModuleList' " "DESC 'OpenLDAP dynamic module info' " "SUP olcConfig STRUCTURAL " - "MUST olcModuleLoad " - "MAY cn )", Cft_Module, &cfOc_module }, + "MAY ( cn $ olcModulePath $ olcModuleLoad ) )", + Cft_Module, NULL, cfAddModule }, #endif { NULL, 0, NULL } }; @@ -694,7 +711,8 @@ config_generic(ConfigArgs *c) { if ( !c->rvalue_vals ) rc = 1; break; case CFG_RO: - c->value_int = (c->be->be_restrictops & SLAP_RESTRICT_OP_WRITES) != 0; + c->value_int = (c->be->be_restrictops & SLAP_RESTRICT_OP_WRITES) == + SLAP_RESTRICT_OP_WRITES; break; case CFG_AZPOLICY: c->value_string = ch_strdup( slap_sasl_getpolicy()); @@ -763,9 +781,6 @@ config_generic(ConfigArgs *c) { } break; - case CFG_CHECK: - c->value_int = global_schemacheck; - break; case CFG_ACL: { AccessControl *a; char *src, *dst, ibuf[11]; @@ -837,16 +852,10 @@ config_generic(ConfigArgs *c) { } break; case CFG_MODPATH: { - ModPaths *mp; - for (i=0, mp=&modpaths; mp; mp=mp->mp_next, i++) { - struct berval bv; - if ( BER_BVISNULL( &mp->mp_path ) && !mp->mp_loads ) - continue; - bv.bv_val = c->log; - bv.bv_len = sprintf( bv.bv_val, IFMT "%s", i, - mp->mp_path.bv_val ); - value_add_one( &c->rvalue_vals, &bv ); - } + ModPaths *mp = c->private; + if ( !BER_BVISNULL( &mp->mp_path )) + value_add_one( &c->rvalue_vals, &mp->mp_path ); + rc = c->rvalue_vals ? 0 : 1; } break; @@ -881,27 +890,93 @@ config_generic(ConfigArgs *c) { rc = 1; } return rc; - } - - p = strchr(c->line,'(' /*')'*/); - if ( c->op == LDAP_MOD_DELETE ) { + } else if ( c->op == LDAP_MOD_DELETE ) { int rc = 0; switch(c->type) { - case CFG_BACKEND: - case CFG_DATABASE: - rc = 1; - break; + /* single-valued attrs, no-ops */ case CFG_CONCUR: - ldap_pvt_thread_set_concurrency(c->value_int); + case CFG_THREADS: + case CFG_RO: + case CFG_AZPOLICY: + case CFG_DEPTH: + case CFG_LASTMOD: + case CFG_SASLSECP: + case CFG_SSTR_IF_MAX: + case CFG_SSTR_IF_MIN: + break; + + /* no-ops, requires slapd restart */ + case CFG_PLUGIN: + case CFG_MODLOAD: + case CFG_AZREGEXP: + case CFG_REWRITE: + sprintf(c->log, "change requires slapd restart"); + break; + + case CFG_SALT: + ch_free( passwd_salt ); + passwd_salt = NULL; + break; + + case CFG_REPLOG: + ch_free( c->be->be_replogfile ); + c->be->be_replogfile = NULL; + break; + + case CFG_LOGFILE: + ch_free( logfileName ); + logfileName = NULL; + break; + + 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 ); + } else { + AccessControl **prev, *a; + int i; + for (i=0, prev = &c->be->be_acl; i < c->valx; + i++ ) { + a = *prev; + prev = &a->acl_next; + } + a = *prev; + *prev = a->acl_next; + acl_free( a ); + } break; + case CFG_LIMITS: + /* FIXME: there is no limits_free function */ + case CFG_ATOPT: + /* FIXME: there is no ad_option_free function */ + case CFG_ROOTDSE: + /* FIXME: there is no way to remove attributes added by + a DSE file */ + case CFG_OID: + case CFG_OC: + case CFG_DIT: + case CFG_ATTR: + case CFG_MODPATH: + default: + rc = 1; + break; } + return rc; } + + p = strchr(c->line,'(' /*')'*/); + switch(c->type) { case CFG_BACKEND: if(!(c->bi = backend_info(c->argv[1]))) { - Debug(LDAP_DEBUG_ANY, "%s: " - "backend %s failed init!\n", c->log, c->argv[1], 0); + sprintf( c->msg, "<%s> failed init", c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s (%s)!\n", + c->log, c->msg, c->argv[1] ); return(1); } break; @@ -914,10 +989,14 @@ config_generic(ConfigArgs *c) { c->be = LDAP_STAILQ_FIRST(&backendDB); } else if ( !strcasecmp( c->argv[1], "frontend" )) { c->be = frontendDB; - } else if(!(c->be = backend_db_init(c->argv[1]))) { - Debug(LDAP_DEBUG_ANY, "%s: " - "database %s failed init!\n", c->log, c->argv[1], 0); - return(1); + } else { + c->be = backend_db_init(c->argv[1]); + if ( !c->be ) { + sprintf( c->msg, "<%s> failed init", c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s (%s)!\n", + c->log, c->msg, c->argv[1] ); + return(1); + } } break; @@ -951,9 +1030,9 @@ config_generic(ConfigArgs *c) { case CFG_AZPOLICY: ch_free(c->value_string); if (slap_sasl_setpolicy( c->argv[1] )) { - Debug(LDAP_DEBUG_ANY, "%s: unable to parse value \"%s\" in" - " \"authz-policy \"\n", - c->log, c->argv[1], 0 ); + sprintf( c->msg, "<%s> unable to parse value", c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", + c->log, c->msg, c->argv[1] ); return(1); } break; @@ -968,8 +1047,9 @@ config_generic(ConfigArgs *c) { { char *txt = slap_sasl_secprops( c->argv[1] ); if ( txt ) { - Debug(LDAP_DEBUG_ANY, "%s: sasl-secprops: %s\n", - c->log, txt, 0 ); + snprintf( c->msg, sizeof(c->msg), "<%s> %s", + c->argv[0], txt ); + Debug(LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->msg, 0 ); return(1); } break; @@ -1024,15 +1104,8 @@ config_generic(ConfigArgs *c) { return(1); break; - case CFG_CHECK: - global_schemacheck = c->value_int; - if(!global_schemacheck) Debug(LDAP_DEBUG_ANY, "%s: " - "schema checking disabled! your mileage may vary!\n", - c->log, 0, 0); - break; - case CFG_ACL: - parse_acl(c->be, c->fname, c->lineno, c->argc, c->argv); + parse_acl(c->be, c->fname, c->lineno, c->argc, c->argv, c->valx); break; case CFG_REPLOG: @@ -1049,9 +1122,9 @@ config_generic(ConfigArgs *c) { case CFG_ROOTDSE: if(read_root_dse_file(c->argv[1])) { - Debug(LDAP_DEBUG_ANY, "%s: " - "could not read \"rootDSE \" line\n", - c->log, 0, 0); + sprintf( c->msg, "<%s> could not read file", c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s %s\n", + c->log, c->msg, c->argv[1] ); return(1); } { @@ -1071,9 +1144,10 @@ config_generic(ConfigArgs *c) { case CFG_LASTMOD: if(SLAP_NOLASTMODCMD(c->be)) { - Debug(LDAP_DEBUG_ANY, "%s: " - "lastmod not available for %s databases\n", - c->log, c->be->bd_info->bi_type, 0); + sprintf( c->msg, "<%s> not available for %s database", + c->argv[0], c->be->bd_info->bi_type ); + Debug(LDAP_DEBUG_ANY, "%s: %s\n", + c->log, c->msg, 0 ); return(1); } if(c->value_int) @@ -1084,9 +1158,9 @@ config_generic(ConfigArgs *c) { case CFG_SSTR_IF_MAX: if (c->value_int < index_substr_if_minlen) { - Debug(LDAP_DEBUG_ANY, "%s: " - "invalid max value (%d)\n", - c->log, c->value_int, 0 ); + sprintf( c->msg, "<%s> invalid value", c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s (%d)\n", + c->log, c->msg, c->value_int ); return(1); } index_substr_if_maxlen = c->value_int; @@ -1094,9 +1168,9 @@ config_generic(ConfigArgs *c) { case CFG_SSTR_IF_MIN: if (c->value_int > index_substr_if_maxlen) { - Debug(LDAP_DEBUG_ANY, "%s: " - "invalid min value (%d)\n", - c->log, c->value_int, 0 ); + sprintf( c->msg, "<%s> invalid value", c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s (%d)\n", + c->log, c->msg, c->value_int ); return(1); } index_substr_if_minlen = c->value_int; @@ -1104,14 +1178,33 @@ config_generic(ConfigArgs *c) { #ifdef SLAPD_MODULES case CFG_MODLOAD: + /* If we're just adding a module on an existing modpath, + * make sure we've selected the current path. + */ + if ( c->op == LDAP_MOD_ADD && c->private && modcur != c->private ) { + modcur = c->private; + /* This should never fail */ + if ( module_path( modcur->mp_path.bv_val )) { + sprintf( c->msg, "<%s> module path no longer valid", + c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s (%s)\n", + c->log, c->msg, modcur->mp_path.bv_val ); + return(1); + } + } if(module_load(c->argv[1], c->argc - 2, (c->argc > 2) ? c->argv + 2 : NULL)) return(1); /* Record this load on the current path */ { struct berval bv; - char *ptr = c->line + STRLENOF("moduleload"); - while (!isspace(*ptr)) ptr++; - while (isspace(*ptr)) ptr++; + char *ptr; + if ( c->op == SLAP_CONFIG_ADD ) { + ptr = c->line + STRLENOF("moduleload"); + while (!isspace(*ptr)) ptr++; + while (isspace(*ptr)) ptr++; + } else { + ptr = c->line; + } ber_str2bv(ptr, 0, 1, &bv); ber_bvarray_add( &modcur->mp_loads, &bv ); } @@ -1133,8 +1226,8 @@ config_generic(ConfigArgs *c) { mp->mp_next = NULL; mp->mp_loads = NULL; modlast = mp; - if ( c->op == SLAP_CONFIG_ADD ) - modcur = mp; + c->private = mp; + modcur = mp; } break; @@ -1151,9 +1244,27 @@ config_generic(ConfigArgs *c) { #ifdef SLAP_AUTH_REWRITE case CFG_REWRITE: { struct berval bv; + char *line; + if(slap_sasl_rewrite_config(c->fname, c->lineno, c->argc, c->argv)) return(1); - ber_str2bv( c->line, 0, 1, &bv ); + + if ( c->argc > 1 ) { + char *s; + + /* quote all args but the first */ + line = ldap_charray2str( c->argv, "\" \"" ); + ber_str2bv( line, 0, 0, &bv ); + s = strchr( bv.bv_val, '"' ); + assert( s != NULL ); + /* move the trailing quote of argv[0] to the end */ + AC_MEMCPY( s, s + 1, bv.bv_len - ( s - bv.bv_val ) ); + bv.bv_val[ bv.bv_len - 1 ] = '"'; + + } else { + ber_str2bv( c->argv[ 0 ], 0, 1, &bv ); + } + ber_bvarray_add( &authz_rewrites, &bv ); } break; @@ -1161,8 +1272,13 @@ config_generic(ConfigArgs *c) { default: - Debug(LDAP_DEBUG_ANY, "%s: unknown CFG_TYPE %d" - "(ignored)\n", c->log, c->type, 0); + Debug( SLAPD_DEBUG_CONFIG_ERROR, + "%s: unknown CFG_TYPE %d" + SLAPD_CONF_UNKNOWN_IGNORED ".\n", + c->log, c->type, 0 ); +#ifdef SLAPD_CONF_UNKNOWN_BAILOUT + return 1; +#endif /* SLAPD_CONF_UNKNOWN_BAILOUT */ } return(0); @@ -1185,16 +1301,17 @@ config_fname(ConfigArgs *c) { static int config_cfdir(ConfigArgs *c) { if(c->op == SLAP_CONFIG_EMIT) { - value_add_one( &c->rvalue_vals, &cfdir ); - return 0; + if ( !BER_BVISEMPTY( &cfdir )) { + value_add_one( &c->rvalue_vals, &cfdir ); + return 0; + } + return 1; } return(0); } static int config_search_base(ConfigArgs *c) { - struct berval dn; - if(c->op == SLAP_CONFIG_EMIT) { int rc = 1; if (!BER_BVISEMPTY(&default_search_base)) { @@ -1203,6 +1320,12 @@ config_search_base(ConfigArgs *c) { rc = 0; } return rc; + } else if( c->op == LDAP_MOD_DELETE ) { + ch_free( default_search_base.bv_val ); + ch_free( default_search_nbase.bv_val ); + BER_BVZERO( &default_search_base ); + BER_BVZERO( &default_search_nbase ); + return 0; } if(c->bi || c->be != frontendDB) { @@ -1213,10 +1336,6 @@ config_search_base(ConfigArgs *c) { } if(default_search_nbase.bv_len) { - Debug(LDAP_DEBUG_ANY, "%s: " - "default search base \"%s\" already defined " - "(discarding old)\n", - c->log, default_search_base.bv_val, 0); free(default_search_base.bv_val); free(default_search_nbase.bv_val); } @@ -1236,6 +1355,17 @@ config_passwd_hash(ConfigArgs *c) { value_add_one(&c->rvalue_vals, &bv); } return i ? 0 : 1; + } else if ( c->op == LDAP_MOD_DELETE ) { + if ( c->valx < 0 ) { + ldap_charray_free( default_passwd_hash ); + default_passwd_hash = NULL; + } else { + i = c->valx; + ch_free( default_passwd_hash[i] ); + for (; default_passwd_hash[i]; i++ ) + default_passwd_hash[i] = default_passwd_hash[i+1]; + } + return 0; } if(default_passwd_hash) { Debug(LDAP_DEBUG_ANY, "%s: " @@ -1245,15 +1375,16 @@ config_passwd_hash(ConfigArgs *c) { } for(i = 1; i < c->argc; i++) { if(!lutil_passwd_scheme(c->argv[i])) { - Debug(LDAP_DEBUG_ANY, "%s: " - "password scheme \"%s\" not available\n", - c->log, c->argv[i], 0); + sprintf( c->msg, "<%s> schema not available", c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s (%s)\n", + c->log, c->msg, c->argv[i]); } else { ldap_charray_add(&default_passwd_hash, c->argv[i]); } if(!default_passwd_hash) { - Debug(LDAP_DEBUG_ANY, "%s: no valid hashes found\n", - c->log, 0, 0 ); + sprintf( c->msg, "<%s> no valid hashes found", c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s\n", + c->log, c->msg, 0 ); return(1); } } @@ -1270,7 +1401,15 @@ config_schema_dn(ConfigArgs *c) { rc = 0; } return rc; + } else if ( c->op == LDAP_MOD_DELETE ) { + ch_free( c->be->be_schemadn.bv_val ); + ch_free( c->be->be_schemandn.bv_val ); + BER_BVZERO( &c->be->be_schemadn ); + BER_BVZERO( &c->be->be_schemandn ); + return 0; } + ch_free( c->be->be_schemadn.bv_val ); + ch_free( c->be->be_schemandn.bv_val ); c->be->be_schemadn = c->value_dn; c->be->be_schemandn = c->value_ndn; return(0); @@ -1292,14 +1431,23 @@ config_sizelimit(ConfigArgs *c) { else 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; } for(i = 1; i < c->argc; i++) { if(!strncasecmp(c->argv[i], "size", 4)) { rc = limits_parse_one(c->argv[i], lim); if ( rc ) { - Debug(LDAP_DEBUG_ANY, "%s: " - "unable to parse value \"%s\" in \"sizelimit \" line\n", - c->log, c->argv[i], 0); + sprintf( c->msg, "<%s> unable to parse value", c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", + c->log, c->msg, c->argv[i]); return(1); } } else { @@ -1308,14 +1456,18 @@ config_sizelimit(ConfigArgs *c) { } else { lim->lms_s_soft = strtol(c->argv[i], &next, 0); if(next == c->argv[i]) { - Debug(LDAP_DEBUG_ANY, "%s: " - "unable to parse limit \"%s\" in \"sizelimit \" line\n", - c->log, c->argv[i], 0); + sprintf( c->msg, "<%s> unable to parse limit", c->argv[0]); + Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", + c->log, c->msg, c->argv[i]); return(1); } else if(next[0] != '\0') { - Debug(LDAP_DEBUG_ANY, "%s: " - "trailing chars \"%s\" in \"sizelimit \" line (ignored)\n", + Debug( SLAPD_DEBUG_CONFIG_ERROR, "%s: " + "trailing chars \"%s\" in \"sizelimit \" line" + SLAPD_CONF_UNKNOWN_IGNORED ".\n", c->log, next, 0); +#ifdef SLAPD_CONF_UNKNOWN_BAILOUT + return 1; +#endif /* SLAPD_CONF_UNKNOWN_BAILOUT */ } } lim->lms_s_hard = 0; @@ -1340,14 +1492,19 @@ config_timelimit(ConfigArgs *c) { else 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; } for(i = 1; i < c->argc; i++) { if(!strncasecmp(c->argv[i], "time", 4)) { rc = limits_parse_one(c->argv[i], lim); if ( rc ) { - Debug(LDAP_DEBUG_ANY, "%s: " - "unable to parse value \"%s\" in \"timelimit \" line\n", - c->log, c->argv[i], 0); + sprintf( c->msg, "<%s> unable to parse value", c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", + c->log, c->msg, c->argv[i]); return(1); } } else { @@ -1356,14 +1513,18 @@ config_timelimit(ConfigArgs *c) { } else { lim->lms_t_soft = strtol(c->argv[i], &next, 0); if(next == c->argv[i]) { - Debug(LDAP_DEBUG_ANY, "%s: " - "unable to parse limit \"%s\" in \"timelimit \" line\n", - c->log, c->argv[i], 0); + sprintf( c->msg, "<%s> unable to parse limit", c->argv[0]); + Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", + c->log, c->msg, c->argv[i]); return(1); } else if(next[0] != '\0') { - Debug(LDAP_DEBUG_ANY, "%s: " - "trailing chars \"%s\" in \"timelimit \" line (ignored)\n", + Debug( SLAPD_DEBUG_CONFIG_ERROR, "%s: " + "trailing chars \"%s\" in \"timelimit \" line" + SLAPD_CONF_UNKNOWN_IGNORED ".\n", c->log, next, 0); +#ifdef SLAPD_CONF_UNKNOWN_BAILOUT + return 1; +#endif /* SLAPD_CONF_UNKNOWN_BAILOUT */ } } lim->lms_t_hard = 0; @@ -1374,42 +1535,116 @@ config_timelimit(ConfigArgs *c) { static int config_overlay(ConfigArgs *c) { + slap_overinfo *oi; if (c->op == SLAP_CONFIG_EMIT) { return 1; + } else if ( c->op == LDAP_MOD_DELETE ) { + assert(0); } if(c->argv[1][0] == '-' && overlay_config(c->be, &c->argv[1][1])) { /* log error */ - Debug(LDAP_DEBUG_ANY, "%s: (optional) %s overlay \"%s\" configuration failed (ignored)\n", - c->log, c->be == frontendDB ? "global " : "", c->argv[1][1]); + Debug( SLAPD_DEBUG_CONFIG_ERROR, "%s: (optional) %s overlay \"%s\" configuration failed" + SLAPD_CONF_UNKNOWN_IGNORED ".\n", + c->log, c->be == frontendDB ? "global " : "", &c->argv[1][1]); +#ifdef SLAPD_CONF_UNKNOWN_BAILOUT + return 1; +#endif /* SLAPD_CONF_UNKNOWN_BAILOUT */ } else if(overlay_config(c->be, c->argv[1])) { return(1); } + /* Setup context for subsequent config directives. + * The newly added overlay is at the head of the list. + */ + oi = (slap_overinfo *)c->be->bd_info; + c->bi = &oi->oi_list->on_bi; return(0); } static int -config_suffix(ConfigArgs *c) { +config_suffix(ConfigArgs *c) +{ Backend *tbe; struct berval pdn, ndn; - int rc; + char *notallowed = NULL; + + if ( c->be == frontendDB ) { + notallowed = "frontend"; + + } else if ( SLAP_MONITOR(c->be) ) { + notallowed = "monitor"; - if (c->be == frontendDB || SLAP_MONITOR(c->be) || - SLAP_CONFIG(c->be)) return 1; + } else if ( SLAP_CONFIG(c->be) ) { + notallowed = "config"; + } + + if ( notallowed != NULL ) { + char buf[ SLAP_TEXT_BUFLEN ] = { '\0' }; + + switch ( c->op ) { + case LDAP_MOD_ADD: + case LDAP_MOD_DELETE: + case LDAP_MOD_REPLACE: + case LDAP_MOD_INCREMENT: + case SLAP_CONFIG_ADD: + if ( !BER_BVISNULL( &c->value_dn ) ) { + snprintf( buf, sizeof( buf ), "<%s> ", + c->value_dn.bv_val ); + } + + Debug(LDAP_DEBUG_ANY, + "%s: suffix %snot allowed in %s database.\n", + c->log, buf, notallowed ); + break; + + case SLAP_CONFIG_EMIT: + /* don't complain when emitting... */ + break; + + default: + /* FIXME: don't know what values may be valid; + * please remove assertion, or add legal values + * to either block */ + assert( 0 ); + break; + } + + return 1; + } if (c->op == SLAP_CONFIG_EMIT) { - if (!BER_BVISNULL( &c->be->be_suffix[0] )) { + if ( c->be->be_suffix == NULL + || BER_BVISNULL( &c->be->be_suffix[0] ) ) + { + return 1; + } else { value_add( &c->rvalue_vals, c->be->be_suffix ); value_add( &c->rvalue_nvals, c->be->be_nsuffix ); return 0; + } + } else if ( c->op == LDAP_MOD_DELETE ) { + if ( c->valx < 0 ) { + ber_bvarray_free( c->be->be_suffix ); + ber_bvarray_free( c->be->be_nsuffix ); + c->be->be_suffix = NULL; + c->be->be_nsuffix = NULL; } else { - return 1; + int i = c->valx; + ch_free( c->be->be_suffix[i].bv_val ); + ch_free( c->be->be_nsuffix[i].bv_val ); + for (; c->be->be_suffix[i].bv_val; i++) { + c->be->be_suffix[i] = c->be->be_suffix[i+1]; + c->be->be_nsuffix[i] = c->be->be_nsuffix[i+1]; + } } + return 0; } + #ifdef SLAPD_MONITOR_DN if(!strcasecmp(c->argv[1], SLAPD_MONITOR_DN)) { - Debug(LDAP_DEBUG_ANY, "%s: " - "\"%s\" is reserved for monitoring slapd\n", - c->log, SLAPD_MONITOR_DN, 0); + sprintf( c->msg, "<%s> DN is reserved for monitoring slapd", + c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s (%s)\n", + c->log, c->msg, SLAPD_MONITOR_DN); return(1); } #endif @@ -1418,13 +1653,20 @@ config_suffix(ConfigArgs *c) { ndn = c->value_ndn; tbe = select_backend(&ndn, 0, 0); if(tbe == c->be) { - Debug(LDAP_DEBUG_ANY, "%s: suffix already served by this backend! (ignored)\n", + Debug( SLAPD_DEBUG_CONFIG_ERROR, + "%s: suffix already served by this backend!" + SLAPD_CONF_UNKNOWN_IGNORED ".\n", c->log, 0, 0); +#ifdef SLAPD_CONF_UNKNOWN_BAILOUT + return 1; +#endif /* SLAPD_CONF_UNKNOWN_BAILOUT */ free(pdn.bv_val); free(ndn.bv_val); } else if(tbe) { - Debug(LDAP_DEBUG_ANY, "%s: suffix already served by a preceding backend \"%s\"\n", - c->log, tbe->be_suffix[0].bv_val, 0); + sprintf( c->msg, "<%s> suffix already served by a preceding backend", + c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", + c->log, c->msg, tbe->be_suffix[0].bv_val); free(pdn.bv_val); free(ndn.bv_val); return(1); @@ -1448,6 +1690,16 @@ config_rootdn(ConfigArgs *c) { } else { return 1; } + } else if ( c->op == LDAP_MOD_DELETE ) { + ch_free( c->be->be_rootdn.bv_val ); + ch_free( c->be->be_rootndn.bv_val ); + BER_BVZERO( &c->be->be_rootdn ); + BER_BVZERO( &c->be->be_rootndn ); + return 0; + } + if ( !BER_BVISNULL( &c->be->be_rootdn )) { + ch_free( c->be->be_rootdn.bv_val ); + ch_free( c->be->be_rootndn.bv_val ); } c->be->be_rootdn = c->value_dn; c->be->be_rootndn = c->value_ndn; @@ -1457,21 +1709,31 @@ config_rootdn(ConfigArgs *c) { static int config_rootpw(ConfigArgs *c) { Backend *tbe; + if (c->op == SLAP_CONFIG_EMIT) { if (!BER_BVISEMPTY(&c->be->be_rootpw)) { - ber_dupbv( &c->value_bv, &c->be->be_rootpw); + /* don't copy, because "rootpw" is marked + * as CFG_BERVAL */ + c->value_bv = c->be->be_rootpw; return 0; } return 1; + } else if ( c->op == LDAP_MOD_DELETE ) { + ch_free( c->be->be_rootpw.bv_val ); + BER_BVZERO( &c->be->be_rootpw ); + return 0; } tbe = select_backend(&c->be->be_rootndn, 0, 0); if(tbe != c->be) { - Debug(LDAP_DEBUG_ANY, "%s: " - "rootpw can only be set when rootdn is under suffix\n", - c->log, 0, 0); + sprintf( c->msg, "<%s> can only be set when rootdn is under suffix", + c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s\n", + c->log, c->msg, 0); return(1); } + if ( !BER_BVISNULL( &c->be->be_rootpw )) + ch_free( c->be->be_rootpw.bv_val ); c->be->be_rootpw = c->value_bv; return(0); } @@ -1502,12 +1764,20 @@ config_restrict(ConfigArgs *c) { if (c->op == SLAP_CONFIG_EMIT) { return mask_to_verbs( restrictable_ops, c->be->be_restrictops, &c->rvalue_vals ); + } else if ( c->op == LDAP_MOD_DELETE ) { + if ( !c->line ) { + c->be->be_restrictops = 0; + } else { + restrictops = verb_to_mask( c->line, restrictable_ops ); + c->be->be_restrictops ^= restrictops; + } + return 0; } i = verbs_to_mask( c->argc, c->argv, restrictable_ops, &restrictops ); if ( i ) { - Debug(LDAP_DEBUG_ANY, "%s: " - "unknown operation %s in \"restrict \" line\n", - c->log, c->argv[i], 0); + sprintf( c->msg, "<%s> unknown operation", c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s %s\n", + c->log, c->msg, c->argv[i]); return(1); } if ( restrictops & SLAP_RESTRICT_OP_EXTENDED ) @@ -1529,12 +1799,20 @@ config_allows(ConfigArgs *c) { }; if (c->op == SLAP_CONFIG_EMIT) { return mask_to_verbs( allowable_ops, global_allows, &c->rvalue_vals ); + } else if ( c->op == LDAP_MOD_DELETE ) { + if ( !c->line ) { + global_allows = 0; + } else { + allows = verb_to_mask( c->line, allowable_ops ); + global_allows ^= allows; + } + return 0; } i = verbs_to_mask(c->argc, c->argv, allowable_ops, &allows); if ( i ) { - Debug(LDAP_DEBUG_ANY, "%s: " - "unknown feature %s in \"allow \" line\n", - c->log, c->argv[i], 0); + sprintf( c->msg, "<%s> unknown feature", c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s %s\n", + c->log, c->msg, c->argv[i]); return(1); } global_allows |= allows; @@ -1555,12 +1833,20 @@ config_disallows(ConfigArgs *c) { }; if (c->op == SLAP_CONFIG_EMIT) { return mask_to_verbs( disallowable_ops, global_disallows, &c->rvalue_vals ); + } else if ( c->op == LDAP_MOD_DELETE ) { + if ( !c->line ) { + global_disallows = 0; + } else { + disallows = verb_to_mask( c->line, disallowable_ops ); + global_disallows ^= disallows; + } + return 0; } i = verbs_to_mask(c->argc, c->argv, disallowable_ops, &disallows); if ( i ) { - Debug(LDAP_DEBUG_ANY, "%s: " - "unknown feature %s in \"disallow \" line\n", - c->log, c->argv[i], 0); + sprintf( c->msg, "<%s> unknown feature", c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s %s\n", + c->log, c->msg, c->argv[i]); return(1); } global_disallows |= disallows; @@ -1581,23 +1867,33 @@ config_requires(ConfigArgs *c) { }; if (c->op == SLAP_CONFIG_EMIT) { return mask_to_verbs( requires_ops, c->be->be_requires, &c->rvalue_vals ); + } else if ( c->op == LDAP_MOD_DELETE ) { + if ( !c->line ) { + c->be->be_requires = 0; + } else { + requires = verb_to_mask( c->line, requires_ops ); + c->be->be_requires ^= requires; + } + return 0; } i = verbs_to_mask(c->argc, c->argv, requires_ops, &requires); if ( i ) { - Debug(LDAP_DEBUG_ANY, "%s: " - "unknown feature %s in \"require \" line\n", - c->log, c->argv[i], 0); + sprintf( c->msg, "<%s> unknown feature", c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s %s\n", + c->log, c->msg, c->argv[i]); return(1); } c->be->be_requires = requires; return(0); } +static slap_verbmasks *loglevel_ops; + static int -config_loglevel(ConfigArgs *c) { - int i; - char *next; - slap_verbmasks loglevel_ops[] = { +loglevel_init( void ) +{ + slap_verbmasks lo[] = { + { BER_BVC("Any"), -1 }, { BER_BVC("Trace"), LDAP_DEBUG_TRACE }, { BER_BVC("Packets"), LDAP_DEBUG_PACKETS }, { BER_BVC("Args"), LDAP_DEBUG_ARGS }, @@ -1612,12 +1908,82 @@ config_loglevel(ConfigArgs *c) { { BER_BVC("Parse"), LDAP_DEBUG_PARSE }, { BER_BVC("Cache"), LDAP_DEBUG_CACHE }, { BER_BVC("Index"), LDAP_DEBUG_INDEX }, - { BER_BVC("Any"), -1 }, + { BER_BVC("Sync"), LDAP_DEBUG_SYNC }, { BER_BVNULL, 0 } }; + return slap_verbmasks_init( &loglevel_ops, lo ); +} + +static void +loglevel_destroy( void ) +{ + if ( loglevel_ops ) { + (void)slap_verbmasks_destroy( loglevel_ops ); + } + loglevel_ops = NULL; +} + +static slap_mask_t loglevel_ignore[] = { -1, 0 }; + +int +slap_loglevel_register( slap_mask_t m, struct berval *s ) +{ + int rc; + + if ( loglevel_ops == NULL ) { + loglevel_init(); + } + + rc = slap_verbmasks_append( &loglevel_ops, m, s, loglevel_ignore ); + + if ( rc != 0 ) { + Debug( LDAP_DEBUG_ANY, "slap_loglevel_register(%lu, \"%s\") failed\n", + m, s->bv_val, 0 ); + } + + return rc; +} + +int +str2loglevel( const char *s, int *l ) +{ + int i; + + if ( loglevel_ops == NULL ) { + loglevel_init(); + } + + i = verb_to_mask( s, loglevel_ops ); + + if ( BER_BVISNULL( &loglevel_ops[ i ].word) ) { + return -1; + } + + *l = loglevel_ops[ i ].mask; + + return 0; +} + +static int +config_loglevel(ConfigArgs *c) { + int i; + char *next; + + if ( loglevel_ops == NULL ) { + loglevel_init(); + } + if (c->op == SLAP_CONFIG_EMIT) { return mask_to_verbs( loglevel_ops, ldap_syslog, &c->rvalue_vals ); + } else if ( c->op == LDAP_MOD_DELETE ) { + if ( !c->line ) { + ldap_syslog = 0; + } else { + int level = verb_to_mask( c->line, loglevel_ops ); + ldap_syslog ^= level; + } + return 0; } ldap_syslog = 0; @@ -1625,57 +1991,30 @@ config_loglevel(ConfigArgs *c) { for( i=1; i < c->argc; i++ ) { int level; - if ( isdigit( c->argv[i][0] ) ) { + if ( isdigit( c->argv[i][0] ) || c->argv[i][0] == '-' ) { level = strtol( c->argv[i], &next, 10 ); if ( next == NULL || next[0] != '\0' ) { - Debug( LDAP_DEBUG_ANY, - "%s: unable to parse level \"%s\" " - "in \"loglevel [...]\" line.\n", - c->log, c->argv[i], 0); + sprintf( c->msg, "<%s> unable to parse level", c->argv[0] ); + Debug( LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", + c->log, c->msg, c->argv[i]); return( 1 ); } } else { - int j = verb_to_mask(c->argv[i], loglevel_ops); - if(BER_BVISNULL(&loglevel_ops[j].word)) { - Debug( LDAP_DEBUG_ANY, - "%s: unknown level \"%s\" " - "in \"loglevel [...]\" line.\n", - c->log, c->argv[i], 0); + if ( str2loglevel( c->argv[i], &level ) ) { + sprintf( c->msg, "<%s> unknown level", c->argv[0] ); + Debug( LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", + c->log, c->msg, c->argv[i]); return( 1 ); } - level = loglevel_ops[j].mask; } ldap_syslog |= level; } return(0); } -static int -config_syncrepl(ConfigArgs *c) { - if (c->op == SLAP_CONFIG_EMIT) { - if ( c->be->be_syncinfo ) { - struct berval bv; - syncrepl_unparse( c->be->be_syncinfo, &bv ); - ber_bvarray_add( &c->rvalue_vals, &bv ); - return 0; - } - return 1; - } - if(SLAP_SHADOW(c->be)) { - Debug(LDAP_DEBUG_ANY, "%s: " - "syncrepl: database already shadowed.\n", - c->log, 0, 0); - return(1); - } else if(add_syncrepl(c->be, c->argv, c->argc)) { - return(1); - } - SLAP_DBFLAGS(c->be) |= (SLAP_DBFLAG_SHADOW | SLAP_DBFLAG_SYNC_SHADOW); - return(0); -} - static int config_referral(ConfigArgs *c) { - struct berval vals[2]; + struct berval val; if (c->op == SLAP_CONFIG_EMIT) { if ( default_referral ) { value_add( &c->rvalue_vals, default_referral ); @@ -1683,17 +2022,27 @@ config_referral(ConfigArgs *c) { } else { return 1; } + } else if ( c->op == LDAP_MOD_DELETE ) { + if ( c->valx < 0 ) { + ber_bvarray_free( default_referral ); + default_referral = NULL; + } else { + int i = c->valx; + ch_free( default_referral[i].bv_val ); + for (; default_referral[i].bv_val; i++ ) + default_referral[i] = default_referral[i+1]; + } + return 0; } if(validate_global_referral(c->argv[1])) { - Debug(LDAP_DEBUG_ANY, "%s: " - "invalid URL (%s) in \"referral\" line.\n", - c->log, c->argv[1], 0); + sprintf( c->msg, "<%s> invalid URL", c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s (%s)\n", + c->log, c->msg, c->argv[1]); return(1); } - ber_str2bv(c->argv[1], 0, 0, &vals[0]); - vals[1].bv_val = NULL; vals[1].bv_len = 0; - if(value_add(&default_referral, vals)) return(LDAP_OTHER); + ber_str2bv(c->argv[1], 0, 0, &val); + if(value_add_one(&default_referral, &val)) return(LDAP_OTHER); return(0); } @@ -1750,24 +2099,24 @@ config_security(ConfigArgs *c) { } } if ( !tgt ) { - Debug(LDAP_DEBUG_ANY, "%s: " - "unknown factor %s in \"security \" line\n", - c->log, c->argv[i], 0); + sprintf( c->msg, "<%s> unknown factor", c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s %s\n", + c->log, c->msg, c->argv[i]); return(1); } *tgt = strtol(src, &next, 10); if(next == NULL || next[0] != '\0' ) { - Debug(LDAP_DEBUG_ANY, "%s: " - "unable to parse factor \"%s\" in \"security \" line\n", - c->log, c->argv[i], 0); + sprintf( c->msg, "<%s> unable to parse factor", c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", + c->log, c->msg, c->argv[i]); return(1); } } return(0); } -static char * +char * anlist_unparse( AttributeName *an, char *ptr ) { int comma = 0; @@ -1784,7 +2133,7 @@ replica_unparse( struct slap_replica_info *ri, int i, struct berval *bv ) { int len; char *ptr; - struct berval bc = {0}; + struct berval bc = BER_BVNULL; char numbuf[32]; len = sprintf(numbuf, IFMT, i ); @@ -1847,6 +2196,11 @@ config_replica(ConfigArgs *c) { return 0; } return 1; + } else if ( c->op == LDAP_MOD_DELETE ) { + /* FIXME: there is no replica_free function */ + if ( c->valx < 0 ) { + } else { + } } if(SLAP_MONITOR(c->be)) { Debug(LDAP_DEBUG_ANY, "%s: " @@ -1866,16 +2220,15 @@ config_replica(ConfigArgs *c) { break; } else if(!strncasecmp(c->argv[i], "uri=", STRLENOF("uri="))) { if(ldap_url_parse(c->argv[i] + STRLENOF("uri="), &ludp) != LDAP_SUCCESS) { - Debug(LDAP_DEBUG_ANY, "%s: " - "replica line contains invalid " - "uri definition.\n", c->log, 0, 0); + sprintf( c->msg, "<%s> invalid uri", c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->msg, 0 ); return(1); } if(!ludp->lud_host) { - Debug(LDAP_DEBUG_ANY, "%s: " - "replica line contains invalid " - "uri definition - missing hostname.\n", - c->log, 0, 0); + ldap_free_urldesc(ludp); + sprintf( c->msg, "<%s> invalid uri - missing hostname", + c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->msg, 0 ); return(1); } ldap_free_urldesc(ludp); @@ -1888,28 +2241,34 @@ config_replica(ConfigArgs *c) { } } if(i == c->argc) { - Debug(LDAP_DEBUG_ANY, "%s: " - "missing host or uri in \"replica\" line\n", - c->log, 0, 0); + sprintf( c->msg, "<%s> missing host or uri", c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->msg, 0 ); return(1); } else if(nr == -1) { - Debug(LDAP_DEBUG_ANY, "%s: " - "unable to add replica \"%s\"\n", - c->log, replicauri, 0); + sprintf( c->msg, "<%s> unable to add replica", c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", c->log, c->msg, replicauri ); return(1); } else { for(i = 1; i < c->argc; i++) { if(!strncasecmp(c->argv[i], "suffix=", STRLENOF( "suffix="))) { switch(add_replica_suffix(c->be, nr, c->argv[i] + STRLENOF("suffix="))) { case 1: - Debug(LDAP_DEBUG_ANY, "%s: " - "suffix \"%s\" in \"replica\" line is not valid for backend (ignored)\n", + Debug( SLAPD_DEBUG_CONFIG_ERROR, "%s: " + "suffix \"%s\" in \"replica\" line is not valid for backend" + SLAPD_CONF_UNKNOWN_IGNORED ".\n", c->log, c->argv[i] + STRLENOF("suffix="), 0); +#ifdef SLAPD_CONF_UNKNOWN_BAILOUT + return 1; +#endif /* SLAPD_CONF_UNKNOWN_BAILOUT */ break; case 2: - Debug(LDAP_DEBUG_ANY, "%s: " - "unable to normalize suffix in \"replica\" line (ignored)\n", + Debug( SLAPD_DEBUG_CONFIG_ERROR, "%s: " + "unable to normalize suffix in \"replica\" line" + SLAPD_CONF_UNKNOWN_IGNORED ".\n", c->log, 0, 0); +#ifdef SLAPD_CONF_UNKNOWN_BAILOUT + return 1; +#endif /* SLAPD_CONF_UNKNOWN_BAILOUT */ break; } @@ -1924,9 +2283,9 @@ config_replica(ConfigArgs *c) { continue; } if(add_replica_attrs(c->be, nr, arg + 1, exclude)) { - Debug(LDAP_DEBUG_ANY, "%s: " - "attribute \"%s\" in \"replica\" line is unknown\n", - c->log, arg + 1, 0); + sprintf( c->msg, "<%s> unknown attribute", c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", + c->log, c->msg, arg + 1); return(1); } } else if ( bindconf_parse( c->argv[i], @@ -1940,8 +2299,6 @@ config_replica(ConfigArgs *c) { static int config_updatedn(ConfigArgs *c) { - struct berval dn; - int rc; if (c->op == SLAP_CONFIG_EMIT) { if (!BER_BVISEMPTY(&c->be->be_update_ndn)) { value_add_one(&c->rvalue_vals, &c->be->be_update_ndn); @@ -1949,24 +2306,26 @@ config_updatedn(ConfigArgs *c) { return 0; } return 1; + } else if ( c->op == LDAP_MOD_DELETE ) { + ch_free( c->be->be_update_ndn.bv_val ); + BER_BVZERO( &c->be->be_update_ndn ); + SLAP_DBFLAGS(c->be) ^= (SLAP_DBFLAG_SHADOW | SLAP_DBFLAG_SLURP_SHADOW); + return 0; } if(SLAP_SHADOW(c->be)) { - Debug(LDAP_DEBUG_ANY, "%s: " - "updatedn: database already shadowed.\n", - c->log, 0, 0); + sprintf( c->msg, "<%s> database already shadowed", c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s\n", + c->log, c->msg, 0); return(1); } - ber_str2bv(c->argv[1], 0, 0, &dn); - - rc = dnNormalize(0, NULL, NULL, &dn, &c->be->be_update_ndn, NULL); - - if(rc != LDAP_SUCCESS) { - Debug(LDAP_DEBUG_ANY, "%s: " - "updatedn DN is invalid: %d (%s)\n", - c->log, rc, ldap_err2string( rc )); - return(1); + ber_memfree_x( c->value_dn.bv_val, NULL ); + if ( !BER_BVISNULL( &c->be->be_update_ndn ) ) { + ber_memfree_x( c->be->be_update_ndn.bv_val, NULL ); } + c->be->be_update_ndn = c->value_ndn; + BER_BVZERO( &c->value_dn ); + BER_BVZERO( &c->value_ndn ); SLAP_DBFLAGS(c->be) |= (SLAP_DBFLAG_SHADOW | SLAP_DBFLAG_SLURP_SHADOW); return(0); @@ -1974,7 +2333,7 @@ config_updatedn(ConfigArgs *c) { static int config_updateref(ConfigArgs *c) { - struct berval vals[2]; + struct berval val; if (c->op == SLAP_CONFIG_EMIT) { if ( c->be->be_update_refs ) { value_add( &c->rvalue_vals, c->be->be_update_refs ); @@ -1982,29 +2341,40 @@ config_updateref(ConfigArgs *c) { } else { return 1; } + } else if ( c->op == LDAP_MOD_DELETE ) { + if ( c->valx < 0 ) { + ber_bvarray_free( c->be->be_update_refs ); + c->be->be_update_refs = NULL; + } else { + int i = c->valx; + ch_free( c->be->be_update_refs[i].bv_val ); + for (; c->be->be_update_refs[i].bv_val; i++) + c->be->be_update_refs[i] = c->be->be_update_refs[i+1]; + } + return 0; } if(!SLAP_SHADOW(c->be)) { - Debug(LDAP_DEBUG_ANY, "%s: " - "updateref line must come after syncrepl or updatedn.\n", - c->log, 0, 0); + sprintf( c->msg, "<%s> must appear after syncrepl or updatedn", + c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s\n", + c->log, c->msg, 0); return(1); } if(validate_global_referral(c->argv[1])) { - Debug(LDAP_DEBUG_ANY, "%s: " - "invalid URL (%s) in \"updateref\" line.\n", - c->log, c->argv[1], 0); + sprintf( c->msg, "<%s> invalid URL", c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s (%s)\n", + c->log, c->msg, c->argv[1]); return(1); } - ber_str2bv(c->argv[1], 0, 0, &vals[0]); - vals[1].bv_val = NULL; - if(value_add(&c->be->be_update_refs, vals)) return(LDAP_OTHER); + ber_str2bv(c->argv[1], 0, 0, &val); + if(value_add_one(&c->be->be_update_refs, &val)) return(LDAP_OTHER); return(0); } static int config_include(ConfigArgs *c) { - unsigned long savelineno = c->lineno; + int savelineno = c->lineno; int rc; ConfigFile *cf; ConfigFile *cfsave = cfn; @@ -2016,6 +2386,7 @@ config_include(ConfigArgs *c) { return 0; } return 1; + } else if ( c->op == LDAP_MOD_DELETE ) { } cf = ch_calloc( 1, sizeof(ConfigFile)); if ( cfn->c_kids ) { @@ -2026,7 +2397,7 @@ config_include(ConfigArgs *c) { } cfn = cf; ber_str2bv( c->argv[1], 0, 1, &cf->c_file ); - rc = read_config_file(c->argv[1], c->depth + 1, c); + rc = read_config_file(c->argv[1], c->depth + 1, c, config_back_cf_table); c->lineno = savelineno - 1; cfn = cfsave; if ( rc ) { @@ -2034,6 +2405,8 @@ config_include(ConfigArgs *c) { else cfn->c_kids = NULL; ch_free( cf->c_file.bv_val ); ch_free( cf ); + } else { + c->private = cf; } return(rc); } @@ -2055,6 +2428,8 @@ config_tls_option(ConfigArgs *c) { } if (c->op == SLAP_CONFIG_EMIT) { return ldap_pvt_tls_get_option( NULL, flag, &c->value_string ); + } else if ( c->op == LDAP_MOD_DELETE ) { + return ldap_pvt_tls_set_option( NULL, flag, NULL ); } ch_free(c->value_string); return(ldap_pvt_tls_set_option(NULL, flag, c->argv[1])); @@ -2094,6 +2469,9 @@ config_tls_config(ConfigArgs *c) { } } return 1; + } else if ( c->op == LDAP_MOD_DELETE ) { + int i = 0; + return ldap_pvt_tls_set_option( NULL, flag, &i ); } ch_free( c->value_string ); if(isdigit((unsigned char)c->argv[1][0])) { @@ -2105,522 +2483,6 @@ config_tls_config(ConfigArgs *c) { } #endif -static int -add_syncrepl( - Backend *be, - char **cargv, - int cargc -) -{ - syncinfo_t *si; - int rc = 0; - - si = (syncinfo_t *) ch_calloc( 1, sizeof( syncinfo_t ) ); - - if ( si == NULL ) { - Debug( LDAP_DEBUG_ANY, "out of memory in add_syncrepl\n", 0, 0, 0 ); - return 1; - } - - si->si_bindconf.sb_tls = SB_TLS_OFF; - si->si_bindconf.sb_method = LDAP_AUTH_SIMPLE; - si->si_schemachecking = 0; - ber_str2bv( "(objectclass=*)", STRLENOF("(objectclass=*)"), 1, - &si->si_filterstr ); - si->si_base.bv_val = NULL; - si->si_scope = LDAP_SCOPE_SUBTREE; - si->si_attrsonly = 0; - si->si_anlist = (AttributeName *) ch_calloc( 1, sizeof( AttributeName )); - si->si_exanlist = (AttributeName *) ch_calloc( 1, sizeof( AttributeName )); - si->si_attrs = NULL; - si->si_allattrs = 0; - si->si_allopattrs = 0; - si->si_exattrs = NULL; - si->si_type = LDAP_SYNC_REFRESH_ONLY; - si->si_interval = 86400; - si->si_retryinterval = NULL; - si->si_retrynum_init = NULL; - si->si_retrynum = NULL; - si->si_manageDSAit = 0; - si->si_tlimit = 0; - si->si_slimit = 0; - - si->si_presentlist = NULL; - LDAP_LIST_INIT( &si->si_nonpresentlist ); - ldap_pvt_thread_mutex_init( &si->si_mutex ); - - rc = parse_syncrepl_line( cargv, cargc, si ); - - if ( rc < 0 ) { - Debug( LDAP_DEBUG_ANY, "failed to add syncinfo\n", 0, 0, 0 ); - syncinfo_free( si ); - return 1; - } else { - Debug( LDAP_DEBUG_CONFIG, - "Config: ** successfully added syncrepl \"%s\"\n", - BER_BVISNULL( &si->si_provideruri ) ? - "(null)" : si->si_provideruri.bv_val, 0, 0 ); - if ( !si->si_schemachecking ) { - SLAP_DBFLAGS(be) |= SLAP_DBFLAG_NO_SCHEMA_CHECK; - } - si->si_be = be; - be->be_syncinfo = si; - return 0; - } -} - -/* NOTE: used & documented in slapd.conf(5) */ -#define IDSTR "rid" -#define PROVIDERSTR "provider" -#define TYPESTR "type" -#define INTERVALSTR "interval" -#define SEARCHBASESTR "searchbase" -#define FILTERSTR "filter" -#define SCOPESTR "scope" -#define ATTRSSTR "attrs" -#define ATTRSONLYSTR "attrsonly" -#define SLIMITSTR "sizelimit" -#define TLIMITSTR "timelimit" -#define SCHEMASTR "schemachecking" - -/* FIXME: undocumented */ -#define OLDAUTHCSTR "bindprincipal" -#define EXATTRSSTR "exattrs" -#define RETRYSTR "retry" - -/* FIXME: unused */ -#define LASTMODSTR "lastmod" -#define LMGENSTR "gen" -#define LMNOSTR "no" -#define LMREQSTR "req" -#define SRVTABSTR "srvtab" -#define SUFFIXSTR "suffix" -#define MANAGEDSAITSTR "manageDSAit" - -/* mandatory */ -#define GOT_ID 0x0001 -#define GOT_PROVIDER 0x0002 - -/* check */ -#define GOT_ALL (GOT_ID|GOT_PROVIDER) - -static struct { - struct berval key; - int val; -} scopes[] = { - { BER_BVC("base"), LDAP_SCOPE_BASE }, - { BER_BVC("one"), LDAP_SCOPE_ONELEVEL }, -#ifdef LDAP_SCOPE_SUBORDINATE - { BER_BVC("children"), LDAP_SCOPE_SUBORDINATE }, - { BER_BVC("subordinate"), 0 }, -#endif - { BER_BVC("sub"), LDAP_SCOPE_SUBTREE }, - { BER_BVNULL, 0 } -}; - -static int -parse_syncrepl_line( - char **cargv, - int cargc, - syncinfo_t *si -) -{ - int gots = 0; - int i; - char *val; - - for ( i = 1; i < cargc; i++ ) { - if ( !strncasecmp( cargv[ i ], IDSTR "=", - STRLENOF( IDSTR "=" ) ) ) - { - int tmp; - /* '\0' string terminator accounts for '=' */ - val = cargv[ i ] + STRLENOF( IDSTR "=" ); - tmp= atoi( val ); - if ( tmp >= 1000 || tmp < 0 ) { - fprintf( stderr, "Error: parse_syncrepl_line: " - "syncrepl id %d is out of range [0..999]\n", tmp ); - return -1; - } - si->si_rid = tmp; - gots |= GOT_ID; - } else if ( !strncasecmp( cargv[ i ], PROVIDERSTR "=", - STRLENOF( PROVIDERSTR "=" ) ) ) - { - val = cargv[ i ] + STRLENOF( PROVIDERSTR "=" ); - ber_str2bv( val, 0, 1, &si->si_provideruri ); - gots |= GOT_PROVIDER; - } else if ( !strncasecmp( cargv[ i ], SCHEMASTR "=", - STRLENOF( SCHEMASTR "=" ) ) ) - { - val = cargv[ i ] + STRLENOF( SCHEMASTR "=" ); - if ( !strncasecmp( val, "on", STRLENOF( "on" ) )) { - si->si_schemachecking = 1; - } else if ( !strncasecmp( val, "off", STRLENOF( "off" ) ) ) { - si->si_schemachecking = 0; - } else { - si->si_schemachecking = 1; - } - } else if ( !strncasecmp( cargv[ i ], FILTERSTR "=", - STRLENOF( FILTERSTR "=" ) ) ) - { - val = cargv[ i ] + STRLENOF( FILTERSTR "=" ); - ber_str2bv( val, 0, 1, &si->si_filterstr ); - } else if ( !strncasecmp( cargv[ i ], SEARCHBASESTR "=", - STRLENOF( SEARCHBASESTR "=" ) ) ) - { - struct berval bv; - int rc; - - val = cargv[ i ] + STRLENOF( SEARCHBASESTR "=" ); - if ( si->si_base.bv_val ) { - ch_free( si->si_base.bv_val ); - } - ber_str2bv( val, 0, 0, &bv ); - rc = dnNormalize( 0, NULL, NULL, &bv, &si->si_base, NULL ); - if ( rc != LDAP_SUCCESS ) { - fprintf( stderr, "Invalid base DN \"%s\": %d (%s)\n", - val, rc, ldap_err2string( rc ) ); - return -1; - } - } else if ( !strncasecmp( cargv[ i ], SCOPESTR "=", - STRLENOF( SCOPESTR "=" ) ) ) - { - int j; - val = cargv[ i ] + STRLENOF( SCOPESTR "=" ); - for ( j=0; !BER_BVISNULL(&scopes[j].key); j++ ) { - if (!strncasecmp( val, scopes[j].key.bv_val, - scopes[j].key.bv_len )) { - while (!scopes[j].val) j--; - si->si_scope = scopes[j].val; - break; - } - } - if ( BER_BVISNULL(&scopes[j].key) ) { - fprintf( stderr, "Error: parse_syncrepl_line: " - "unknown scope \"%s\"\n", val); - return -1; - } - } else if ( !strncasecmp( cargv[ i ], ATTRSONLYSTR "=", - STRLENOF( ATTRSONLYSTR "=" ) ) ) - { - si->si_attrsonly = 1; - } else if ( !strncasecmp( cargv[ i ], ATTRSSTR "=", - STRLENOF( ATTRSSTR "=" ) ) ) - { - val = cargv[ i ] + STRLENOF( ATTRSSTR "=" ); - if ( !strncasecmp( val, ":include:", STRLENOF(":include:") ) ) { - char *attr_fname; - attr_fname = ch_strdup( val + STRLENOF(":include:") ); - si->si_anlist = file2anlist( si->si_anlist, attr_fname, " ,\t" ); - if ( si->si_anlist == NULL ) { - ch_free( attr_fname ); - return -1; - } - si->si_anfile = attr_fname; - } else { - char *str, *s, *next; - char delimstr[] = " ,\t"; - str = ch_strdup( val ); - for ( s = ldap_pvt_strtok( str, delimstr, &next ); - s != NULL; - s = ldap_pvt_strtok( NULL, delimstr, &next ) ) - { - if ( strlen(s) == 1 && *s == '*' ) { - si->si_allattrs = 1; - *(val + ( s - str )) = delimstr[0]; - } - if ( strlen(s) == 1 && *s == '+' ) { - si->si_allopattrs = 1; - *(val + ( s - str )) = delimstr[0]; - } - } - ch_free( str ); - si->si_anlist = str2anlist( si->si_anlist, val, " ,\t" ); - if ( si->si_anlist == NULL ) { - return -1; - } - } - } else if ( !strncasecmp( cargv[ i ], EXATTRSSTR "=", - STRLENOF( EXATTRSSTR "=" ) ) ) - { - val = cargv[ i ] + STRLENOF( EXATTRSSTR "=" ); - if ( !strncasecmp( val, ":include:", STRLENOF(":include:") )) { - char *attr_fname; - attr_fname = ch_strdup( val + STRLENOF(":include:") ); - si->si_exanlist = file2anlist( - si->si_exanlist, attr_fname, " ,\t" ); - if ( si->si_exanlist == NULL ) { - ch_free( attr_fname ); - return -1; - } - ch_free( attr_fname ); - } else { - si->si_exanlist = str2anlist( si->si_exanlist, val, " ,\t" ); - if ( si->si_exanlist == NULL ) { - return -1; - } - } - } else if ( !strncasecmp( cargv[ i ], TYPESTR "=", - STRLENOF( TYPESTR "=" ) ) ) - { - val = cargv[ i ] + STRLENOF( TYPESTR "=" ); - if ( !strncasecmp( val, "refreshOnly", - STRLENOF("refreshOnly") )) - { - si->si_type = LDAP_SYNC_REFRESH_ONLY; - } else if ( !strncasecmp( val, "refreshAndPersist", - STRLENOF("refreshAndPersist") )) - { - si->si_type = LDAP_SYNC_REFRESH_AND_PERSIST; - si->si_interval = 60; - } else { - fprintf( stderr, "Error: parse_syncrepl_line: " - "unknown sync type \"%s\"\n", val); - return -1; - } - } else if ( !strncasecmp( cargv[ i ], INTERVALSTR "=", - STRLENOF( INTERVALSTR "=" ) ) ) - { - val = cargv[ i ] + STRLENOF( INTERVALSTR "=" ); - if ( si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST ) { - si->si_interval = 0; - } else { - char *hstr; - char *mstr; - char *dstr; - char *sstr; - int dd, hh, mm, ss; - dstr = val; - hstr = strchr( dstr, ':' ); - if ( hstr == NULL ) { - fprintf( stderr, "Error: parse_syncrepl_line: " - "invalid interval \"%s\"\n", val ); - return -1; - } - *hstr++ = '\0'; - mstr = strchr( hstr, ':' ); - if ( mstr == NULL ) { - fprintf( stderr, "Error: parse_syncrepl_line: " - "invalid interval \"%s\"\n", val ); - return -1; - } - *mstr++ = '\0'; - sstr = strchr( mstr, ':' ); - if ( sstr == NULL ) { - fprintf( stderr, "Error: parse_syncrepl_line: " - "invalid interval \"%s\"\n", val ); - return -1; - } - *sstr++ = '\0'; - - dd = atoi( dstr ); - hh = atoi( hstr ); - mm = atoi( mstr ); - ss = atoi( sstr ); - if (( hh > 24 ) || ( hh < 0 ) || - ( mm > 60 ) || ( mm < 0 ) || - ( ss > 60 ) || ( ss < 0 ) || ( dd < 0 )) { - fprintf( stderr, "Error: parse_syncrepl_line: " - "invalid interval \"%s\"\n", val ); - return -1; - } - si->si_interval = (( dd * 24 + hh ) * 60 + mm ) * 60 + ss; - } - if ( si->si_interval < 0 ) { - fprintf( stderr, "Error: parse_syncrepl_line: " - "invalid interval \"%ld\"\n", - (long) si->si_interval); - return -1; - } - } else if ( !strncasecmp( cargv[ i ], RETRYSTR "=", - STRLENOF( RETRYSTR "=" ) ) ) - { - char **retry_list; - int j, k, n; - - val = cargv[ i ] + STRLENOF( RETRYSTR "=" ); - retry_list = (char **) ch_calloc( 1, sizeof( char * )); - retry_list[0] = NULL; - - slap_str2clist( &retry_list, val, " ,\t" ); - - for ( k = 0; retry_list && retry_list[k]; k++ ) ; - n = k / 2; - if ( k % 2 ) { - fprintf( stderr, - "Error: incomplete syncrepl retry list\n" ); - for ( k = 0; retry_list && retry_list[k]; k++ ) { - ch_free( retry_list[k] ); - } - ch_free( retry_list ); - exit( EXIT_FAILURE ); - } - si->si_retryinterval = (time_t *) ch_calloc( n + 1, sizeof( time_t )); - si->si_retrynum = (int *) ch_calloc( n + 1, sizeof( int )); - si->si_retrynum_init = (int *) ch_calloc( n + 1, sizeof( int )); - for ( j = 0; j < n; j++ ) { - si->si_retryinterval[j] = atoi( retry_list[j*2] ); - if ( *retry_list[j*2+1] == '+' ) { - si->si_retrynum_init[j] = -1; - si->si_retrynum[j] = -1; - j++; - break; - } else { - si->si_retrynum_init[j] = atoi( retry_list[j*2+1] ); - si->si_retrynum[j] = atoi( retry_list[j*2+1] ); - } - } - si->si_retrynum_init[j] = -2; - si->si_retrynum[j] = -2; - si->si_retryinterval[j] = 0; - - for ( k = 0; retry_list && retry_list[k]; k++ ) { - ch_free( retry_list[k] ); - } - ch_free( retry_list ); - } else if ( !strncasecmp( cargv[ i ], MANAGEDSAITSTR "=", - STRLENOF( MANAGEDSAITSTR "=" ) ) ) - { - val = cargv[ i ] + STRLENOF( MANAGEDSAITSTR "=" ); - si->si_manageDSAit = atoi( val ); - } else if ( !strncasecmp( cargv[ i ], SLIMITSTR "=", - STRLENOF( SLIMITSTR "=") ) ) - { - val = cargv[ i ] + STRLENOF( SLIMITSTR "=" ); - si->si_slimit = atoi( val ); - } else if ( !strncasecmp( cargv[ i ], TLIMITSTR "=", - STRLENOF( TLIMITSTR "=" ) ) ) - { - val = cargv[ i ] + STRLENOF( TLIMITSTR "=" ); - si->si_tlimit = atoi( val ); - } else if ( bindconf_parse( cargv[i], &si->si_bindconf )) { - fprintf( stderr, "Error: parse_syncrepl_line: " - "unknown keyword \"%s\"\n", cargv[ i ] ); - return -1; - } - } - - if ( gots != GOT_ALL ) { - fprintf( stderr, - "Error: Malformed \"syncrepl\" line in slapd config file" ); - return -1; - } - - return 0; -} - -static void -syncrepl_unparse( syncinfo_t *si, struct berval *bv ) -{ - struct berval bc; - char buf[BUFSIZ*2], *ptr; - int i, len; - - bindconf_unparse( &si->si_bindconf, &bc ); - ptr = buf; - ptr += sprintf( ptr, IDSTR "=%03d " PROVIDERSTR "=%s", - si->si_rid, si->si_provideruri.bv_val ); - if ( !BER_BVISNULL( &bc )) { - ptr = lutil_strcopy( ptr, bc.bv_val ); - free( bc.bv_val ); - } - if ( !BER_BVISEMPTY( &si->si_filterstr )) { - ptr = lutil_strcopy( ptr, " " FILTERSTR "=\"" ); - ptr = lutil_strcopy( ptr, si->si_filterstr.bv_val ); - *ptr++ = '"'; - } - if ( !BER_BVISNULL( &si->si_base )) { - ptr = lutil_strcopy( ptr, " " SEARCHBASESTR "=\"" ); - ptr = lutil_strcopy( ptr, si->si_base.bv_val ); - *ptr++ = '"'; - } - for (i=0; !BER_BVISNULL(&scopes[i].key);i++) { - if ( si->si_scope == scopes[i].val ) { - ptr = lutil_strcopy( ptr, " " SCOPESTR "=" ); - ptr = lutil_strcopy( ptr, scopes[i].key.bv_val ); - break; - } - } - if ( si->si_attrsonly ) { - ptr = lutil_strcopy( ptr, " " ATTRSONLYSTR "=yes" ); - } - if ( si->si_anfile ) { - ptr = lutil_strcopy( ptr, " " ATTRSSTR "=:include:" ); - ptr = lutil_strcopy( ptr, si->si_anfile ); - } else if ( si->si_allattrs || si->si_allopattrs || - ( si->si_anlist && !BER_BVISNULL(&si->si_anlist[0].an_name) )) { - char *old; - ptr = lutil_strcopy( ptr, " " ATTRSSTR "=\"" ); - old = ptr; - ptr = anlist_unparse( si->si_anlist, ptr ); - if ( si->si_allattrs ) { - if ( old != ptr ) *ptr++ = ','; - *ptr++ = '*'; - } - if ( si->si_allopattrs ) { - if ( old != ptr ) *ptr++ = ','; - *ptr++ = '+'; - } - *ptr++ = '"'; - } - if ( si->si_exanlist && !BER_BVISNULL(&si->si_exanlist[0].an_name) ) { - ptr = lutil_strcopy( ptr, " " EXATTRSSTR "=" ); - ptr = anlist_unparse( si->si_exanlist, ptr ); - } - ptr = lutil_strcopy( ptr, " " SCHEMASTR "=" ); - ptr = lutil_strcopy( ptr, si->si_schemachecking ? "on" : "off" ); - - ptr = lutil_strcopy( ptr, " " TYPESTR "=" ); - ptr = lutil_strcopy( ptr, si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST ? - "refreshAndPersist" : "refreshOnly" ); - - if ( si->si_type == LDAP_SYNC_REFRESH_ONLY ) { - int dd, hh, mm, ss; - - dd = si->si_interval; - ss = dd % 60; - dd /= 60; - mm = dd % 60; - dd /= 60; - hh = dd % 24; - dd /= 24; - ptr = lutil_strcopy( ptr, " " INTERVALSTR "=" ); - ptr += sprintf( ptr, "%02d:%02d:%02d:%02d", dd, hh, mm, ss ); - } else if ( si->si_retryinterval ) { - int space=0; - ptr = lutil_strcopy( ptr, " " RETRYSTR "=\"" ); - for (i=0; si->si_retryinterval[i]; i++) { - if ( space ) *ptr++ = ' '; - space = 1; - ptr += sprintf( ptr, "%d", si->si_retryinterval[i] ); - if ( si->si_retrynum_init[i] == -1 ) - *ptr++ = '+'; - else - ptr += sprintf( ptr, "%d", si->si_retrynum_init ); - } - *ptr++ = '"'; - } - -#if 0 /* FIXME: unused in syncrepl.c, should remove it */ - ptr = lutil_strcopy( ptr, " " MANAGEDSAITSTR "=" ); - ptr += sprintf( ptr, "%d", si->si_manageDSAit ); -#endif - - if ( si->si_slimit ) { - ptr = lutil_strcopy( ptr, " " SLIMITSTR "=" ); - ptr += sprintf( ptr, "%d", si->si_slimit ); - } - - if ( si->si_tlimit ) { - ptr = lutil_strcopy( ptr, " " TLIMITSTR "=" ); - ptr += sprintf( ptr, "%d", si->si_tlimit ); - } - bc.bv_len = ptr - buf; - bc.bv_val = buf; - ber_dupbv( bv, &bc ); -} - static CfEntryInfo * config_find_base( CfEntryInfo *root, struct berval *dn, CfEntryInfo **last ) { @@ -2660,26 +2522,32 @@ config_find_base( CfEntryInfo *root, struct berval *dn, CfEntryInfo **last ) return root; } +typedef struct setup_cookie { + CfBackInfo *cfb; + ConfigArgs *ca; +} setup_cookie; + static int config_ldif_resp( Operation *op, SlapReply *rs ) { if ( rs->sr_type == REP_SEARCH ) { - CfBackInfo *cfb = op->o_callback->sc_private; + setup_cookie *sc = op->o_callback->sc_private; - cfb->cb_got_ldif = 1; - rs->sr_err = config_add_internal( cfb, rs->sr_entry, NULL, NULL ); + sc->cfb->cb_got_ldif = 1; + rs->sr_err = config_add_internal( sc->cfb, rs->sr_entry, sc->ca, NULL, NULL ); } return rs->sr_err; } /* Configure and read the underlying back-ldif store */ static int -config_setup_ldif( BackendDB *be, const char *dir ) { +config_setup_ldif( BackendDB *be, const char *dir, int readit ) { CfBackInfo *cfb = be->be_private; ConfigArgs c = {0}; ConfigTable *ct; char *argv[3]; - int rc; + int rc = 0; + setup_cookie sc; slap_callback cb = { NULL, config_ldif_resp, NULL, NULL }; Connection conn = {0}; char opbuf[OPERATION_BUFFER_SIZE]; @@ -2687,7 +2555,16 @@ config_setup_ldif( BackendDB *be, const char *dir ) { SlapReply rs = {REP_RESULT}; Filter filter = { LDAP_FILTER_PRESENT }; struct berval filterstr = BER_BVC("(objectclass=*)"); + struct stat st; + /* Is the config directory available? */ + if ( stat( dir, &st ) < 0 ) { + /* No, so don't bother using the backing store. + * All changes will be in-memory only. + */ + return 0; + } + cfb->cb_db.bd_info = backend_info( "ldif" ); if ( !cfb->cb_db.bd_info ) return 0; /* FIXME: eventually this will be a fatal error */ @@ -2712,7 +2589,7 @@ config_setup_ldif( BackendDB *be, const char *dir ) { argv[2] = NULL; c.argv = argv; - ct = config_find_keyword( c.be->be_cf_table, &c ); + ct = config_find_keyword( c.be->be_cf_ocs->co_table, &c ); if ( !ct ) return 1; @@ -2722,42 +2599,50 @@ config_setup_ldif( BackendDB *be, const char *dir ) { if ( backend_startup_one( &cfb->cb_db )) return 1; - op = (Operation *)opbuf; - connection_fake_init( &conn, op, cfb ); + if ( readit ) { + op = (Operation *)opbuf; + connection_fake_init( &conn, op, cfb ); - filter.f_desc = slap_schema.si_ad_objectClass; - - op->o_tag = LDAP_REQ_SEARCH; + filter.f_desc = slap_schema.si_ad_objectClass; - op->ors_filter = &filter; - op->ors_filterstr = filterstr; - op->ors_scope = LDAP_SCOPE_SUBTREE; + op->o_tag = LDAP_REQ_SEARCH; - op->o_dn = be->be_rootdn; - op->o_ndn = be->be_rootndn; + op->ors_filter = &filter; + op->ors_filterstr = filterstr; + op->ors_scope = LDAP_SCOPE_SUBTREE; - op->o_req_dn = be->be_suffix[0]; - op->o_req_ndn = be->be_nsuffix[0]; + op->o_dn = be->be_rootdn; + op->o_ndn = be->be_rootndn; - op->ors_tlimit = SLAP_NO_LIMIT; - op->ors_slimit = SLAP_NO_LIMIT; + op->o_req_dn = be->be_suffix[0]; + op->o_req_ndn = be->be_nsuffix[0]; - op->ors_attrs = slap_anlist_all_attributes; - op->ors_attrsonly = 0; + op->ors_tlimit = SLAP_NO_LIMIT; + op->ors_slimit = SLAP_NO_LIMIT; - op->o_callback = &cb; - cb.sc_private = cfb; + op->ors_attrs = slap_anlist_all_attributes; + op->ors_attrsonly = 0; - op->o_bd = &cfb->cb_db; - op->o_bd->be_search( op, &rs ); - - return 0; + op->o_callback = &cb; + sc.cfb = cfb; + sc.ca = &c; + cb.sc_private = ≻ + + op->o_bd = &cfb->cb_db; + rc = op->o_bd->be_search( op, &rs ); + + slap_sl_mem_destroy( NULL, op->o_tmpmemctx ); + } + + cfb->cb_use_ldif = 1; + + return rc; } static int -CfOcInfo_cmp( const void *c1, const void *c2 ) { - const CfOcInfo *co1 = c1; - const CfOcInfo *co2 = c2; +CfOc_cmp( const void *c1, const void *c2 ) { + const ConfigOCs *co1 = c1; + const ConfigOCs *co2 = c2; return ber_bvcmp( co1->co_name, co2->co_name ); } @@ -2765,7 +2650,6 @@ CfOcInfo_cmp( const void *c1, const void *c2 ) { int config_register_schema(ConfigTable *ct, ConfigOCs *ocs) { int i; - CfOcInfo *co; i = init_config_attrs( ct ); if ( i ) return i; @@ -2774,14 +2658,12 @@ config_register_schema(ConfigTable *ct, ConfigOCs *ocs) { i = init_config_ocs( ocs ); if ( i ) return i; - for (i=0; ocs[i].def; i++) { - if ( ocs[i].oc ) { - co = ch_malloc( sizeof(CfOcInfo) ); - co->co_oc = *ocs[i].oc; - co->co_name = &co->co_oc->soc_cname; - co->co_table = ct; - co->co_type = ocs[i].cft; - avl_insert( &CfOcTree, co, CfOcInfo_cmp, avl_dup_error ); + for (i=0; ocs[i].co_def; i++) { + if ( ocs[i].co_oc ) { + ocs[i].co_name = &ocs[i].co_oc->soc_cname; + if ( !ocs[i].co_table ) + ocs[i].co_table = ct; + avl_insert( &CfOcTree, &ocs[i], CfOc_cmp, avl_dup_error ); } } return 0; @@ -2791,6 +2673,8 @@ int read_config(const char *fname, const char *dir) { BackendDB *be; CfBackInfo *cfb; + const char *cfdir, *cfname; + int rc; /* Setup the config backend */ be = backend_db_init( "config" ); @@ -2799,18 +2683,79 @@ read_config(const char *fname, const char *dir) { cfb = be->be_private; - /* Setup the underlying back-ldif backend */ - if ( config_setup_ldif( be, dir )) - return 1; + /* If no .conf, or a dir was specified, setup the dir */ + if ( !fname || dir ) { + if ( dir ) { + /* If explicitly given, check for existence */ + struct stat st; -#ifdef SLAP_USE_CONFDIR - /* If we read the config from back-ldif, nothing to do here */ - if ( cfb->cb_got_ldif ) - return 0; -#endif - ber_str2bv( fname, 0, 1, &cf_prv.c_file ); + if ( stat( dir, &st ) < 0 ) { + Debug( LDAP_DEBUG_ANY, + "invalid config directory %s, error %d\n", + dir, errno, 0 ); + return 1; + } + cfdir = dir; + } else { + cfdir = SLAPD_DEFAULT_CONFIGDIR; + } + /* if fname is defaulted, try reading .d */ + rc = config_setup_ldif( be, cfdir, !fname ); + + /* It's OK if the base object doesn't exist yet */ + if ( rc && rc != LDAP_NO_SUCH_OBJECT ) + return 1; + + /* If we read the config from back-ldif, nothing to do here */ + if ( cfb->cb_got_ldif ) { + rc = 0; + goto done; + } + } + + if ( fname ) + cfname = fname; + else + cfname = SLAPD_DEFAULT_CONFIGFILE; + + rc = read_config_file(cfname, 0, NULL, config_back_cf_table); + + if ( rc == 0 ) + ber_str2bv( cfname, 0, 1, &cfb->cb_config->c_file ); + + /* If we got this far and failed, it may be a serious problem. In server + * mode, we should never come to this. However, it may be alright if we're + * using slapadd to create the conf dir. + */ + while ( rc ) { + if ( slapMode & (SLAP_SERVER_MODE|SLAP_TOOL_READMAIN|SLAP_TOOL_READONLY)) + break; + /* If a config file was explicitly given, fail */ + if ( fname ) + break; + + /* Seems to be slapadd with a config dir, let it continue */ + if ( cfb->cb_use_ldif ) { + rc = 0; + cfb->cb_got_ldif = 1; + } + break; + } - return read_config_file(fname, 0, NULL); +done: + if ( rc == 0 && BER_BVISNULL( &frontendDB->be_schemadn ) ) { + ber_str2bv( SLAPD_SCHEMA_DN, STRLENOF( SLAPD_SCHEMA_DN ), 1, + &frontendDB->be_schemadn ); + rc = dnNormalize( 0, NULL, NULL, &frontendDB->be_schemadn, &frontendDB->be_schemandn, NULL ); + if ( rc != LDAP_SUCCESS ) { + Debug(LDAP_DEBUG_ANY, "read_config: " + "unable to normalize default schema DN \"%s\"\n", + frontendDB->be_schemadn.bv_val, 0, 0 ); + /* must not happen */ + assert( 0 ); + } + } + return rc; } static int @@ -2855,95 +2800,16 @@ config_send( Operation *op, SlapReply *rs, CfEntryInfo *ce, int depth ) } static ConfigTable * -config_find_table( CfOcInfo *co, AttributeDescription *ad ) +config_find_table( ConfigOCs **colst, int nocs, AttributeDescription *ad ) { - int i; - - for (i=0; co->co_table[i].name; i++) - if ( co->co_table[i].ad == ad ) - return &co->co_table[i]; - return NULL; -} - -/* Sort the values in an X-ORDERED VALUES attribute. - * If the values have no index, leave them in their given order. - * If the values have indexes, sort them. - * If some are indexed and some are not, return Error. - * - * FIXME: This function probably belongs in the frontend somewhere, - * like slap_mods_check. - */ -static int -sort_vals( Attribute *a ) -{ - int i; - int index = 0, noindex = 0; - - /* count attrs, look for index */ - for (i=0; a->a_vals[i].bv_val; i++) { - if ( a->a_vals[i].bv_val[0] == '{' ) { - char *ptr; - index = 1; - ptr = strchr( a->a_vals[i].bv_val, '}' ); - if ( !ptr || !ptr[1] ) - return LDAP_INVALID_SYNTAX; - if ( noindex ) - return LDAP_INVALID_SYNTAX; - } else { - noindex = 1; - if ( index ) - return LDAP_INVALID_SYNTAX; - } - } + int i, j; - if ( index ) { - int vals = i, *indexes, j, idx; - struct berval tmp, ntmp; - char *ptr; - -#if 0 - /* Strip index from normalized values */ - if ( !a->a_nvals || a->a_vals == a->a_nvals ) { - a->a_nvals = ch_malloc( (vals+1)*sizeof(struct berval)); - BER_BVZERO(a->a_nvals+vals); - for ( i=0; ia_vals[i].bv_val, '}') + 1; - a->a_nvals[i].bv_len = a->a_vals[i].bv_len - - (ptr - a->a_vals[i].bv_val); - a->a_nvals[i].bv_val = ch_malloc( a->a_nvals[i].bv_len + 1); - strcpy(a->a_nvals[i].bv_val, ptr ); - } - } else { - for ( i=0; ia_nvals[i].bv_val, '}') + 1; - a->a_nvals[i].bv_len -= ptr - a->a_nvals[i].bv_val; - strcpy(a->a_nvals[i].bv_val, ptr); - } - } -#endif - - indexes = ch_malloc( vals * sizeof(int) ); - for ( i=0; ia_vals[i].bv_val+1); - - /* Insertion sort */ - for ( i=1; ia_vals[i]; - ntmp = a->a_nvals[i]; - j = i; - while ((j > 0) && (indexes[j-1] > idx)) { - indexes[j] = indexes[j-1]; - a->a_vals[j] = a->a_vals[j-1]; - a->a_nvals[j] = a->a_nvals[j-1]; - j--; - } - indexes[j] = idx; - a->a_vals[j] = tmp; - a->a_nvals[j] = ntmp; - } + for (j=0; jco_table[i].name; i++) + if ( colst[j]->co_table[i].ad == ad ) + return &colst[j]->co_table[i]; } - return 0; + return NULL; } /* Sort the attributes of the entry according to the order defined @@ -2953,7 +2819,7 @@ sort_vals( Attribute *a ) * list the attributes in the desired sequence. */ static void -sort_attrs( Entry *e, CfOcInfo **colst, int nocs ) +sort_attrs( Entry *e, ConfigOCs **colst, int nocs ) { Attribute *a, *head = NULL, *tail = NULL, **prev; int i, j; @@ -3005,22 +2871,40 @@ sort_attrs( Entry *e, CfOcInfo **colst, int nocs ) } static int -check_attr( ConfigTable *ct, ConfigArgs *ca, Attribute *a ) +check_vals( ConfigTable *ct, ConfigArgs *ca, void *ptr, int isAttr ) { + Attribute *a = NULL; + AttributeDescription *ad; + BerVarray vals; + int i, rc = 0, sort = 0; - if ( a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED ) { + if ( isAttr ) { + a = ptr; + ad = a->a_desc; + vals = a->a_vals; + } else { + Modifications *ml = ptr; + ad = ml->sml_desc; + vals = ml->sml_values; + } + + if ( a && ( ad->ad_type->sat_flags & SLAP_AT_ORDERED_VAL )) { sort = 1; - rc = sort_vals( a ); + rc = ordered_value_sort( a, 1 ); if ( rc ) return rc; } - for ( i=0; a->a_nvals[i].bv_val; i++ ) { - ca->line = a->a_nvals[i].bv_val; - if ( sort ) ca->line = strchr( ca->line, '}' ) + 1; + for ( i=0; vals[i].bv_val; i++ ) { + ca->line = vals[i].bv_val; + if ( sort ) { + char *idx = strchr( ca->line, '}' ); + if ( idx ) ca->line = idx+1; + } rc = config_parse_vals( ct, ca, i ); - if ( rc ) + if ( rc ) { break; + } } return rc; } @@ -3055,8 +2939,13 @@ check_name_index( CfEntryInfo *parent, ConfigType ce_type, Entry *e, return LDAP_NAMING_VIOLATION; gotindex = 1; index = atoi(ptr1+1); - if ( index < 0 ) - return LDAP_NAMING_VIOLATION; + if ( index < 0 ) { + /* Special case, we allow -1 for the frontendDB */ + if ( index != -1 || ce_type != Cft_Database || + strncmp( ptr2+1, "frontend,", STRLENOF("frontend,") )) + + return LDAP_NAMING_VIOLATION; + } } /* count related kids */ @@ -3148,47 +3037,20 @@ check_name_index( CfEntryInfo *parent, ConfigType ce_type, Entry *e, return 0; } -/* Parse an LDAP entry into config directives */ -static int -config_add_internal( CfBackInfo *cfb, Entry *e, SlapReply *rs, int *renum ) +static ConfigOCs ** +count_ocs( Attribute *oc_at, int *nocs ) { - CfEntryInfo *ce, *last; - CfOcInfo co, *coptr, **colst = NULL; - Attribute *a, *oc_at, *type_attr; - AttributeDescription *type_ad = NULL; - int i, j, nocs, rc; - ConfigArgs ca = {0}; - struct berval pdn; - Entry *xe = NULL; - ConfigTable *ct, *type_ct = NULL; - - /* Make sure parent exists and entry does not */ - ce = config_find_base( cfb->cb_root, &e->e_nname, &last ); - if ( ce ) - return LDAP_ALREADY_EXISTS; - - dnParent( &e->e_nname, &pdn ); - - /* If last is NULL, the new entry is the root/suffix entry, - * otherwise last should be the parent. - */ - if ( last && !dn_match( &last->ce_entry->e_nname, &pdn )) { - if ( rs ) - rs->sr_matched = last->ce_entry->e_name.bv_val; - return LDAP_NO_SUCH_OBJECT; - } - - oc_at = attr_find( e->e_attrs, slap_schema.si_ad_objectClass ); - if ( !oc_at ) return LDAP_OBJECT_CLASS_VIOLATION; + int i, j, n; + ConfigOCs co, *coptr, **colst; /* count the objectclasses */ for ( i=0; oc_at->a_nvals[i].bv_val; i++ ); - nocs = i; - colst = (CfOcInfo **)ch_malloc( nocs * sizeof(CfOcInfo *)); + n = i; + colst = (ConfigOCs **)ch_malloc( n * sizeof(ConfigOCs *)); - for ( i=0, j=0; ia_nvals[i]; - coptr = avl_find( CfOcTree, &co, CfOcInfo_cmp ); + coptr = avl_find( CfOcTree, &co, CfOc_cmp ); /* ignore non-config objectclasses. probably should be * an error, general data doesn't belong here. @@ -3200,113 +3062,164 @@ config_add_internal( CfBackInfo *cfb, Entry *e, SlapReply *rs, int *renum ) if ( coptr->co_type == Cft_Abstract ) continue; colst[j++] = coptr; } - nocs = j; + *nocs = j; + return colst; +} - /* Only the root can be Cft_Global, everything else must - * have a parent. Only limited nesting arrangements are allowed. - */ - switch( colst[0]->co_type ) { - case Cft_Global: - if ( last ) { - rc = LDAP_CONSTRAINT_VIOLATION; - goto leave; - } - break; - case Cft_Schema: - case Cft_Backend: - case Cft_Database: - case Cft_Include: - if ( !last || ( last->ce_type != Cft_Global && - last->ce_type != colst[0]->co_type )) { - rc = LDAP_CONSTRAINT_VIOLATION; - goto leave; - } - break; - case Cft_Overlay: - if ( !last || ( last->ce_type != Cft_Global && - last->ce_type != Cft_Database && - last->ce_type != colst[0]->co_type )) { - rc = LDAP_CONSTRAINT_VIOLATION; - goto leave; - } - break; -#ifdef SLAPD_MODULES - case Cft_Module: - if ( !last || last->ce_type != Cft_Global ) { - rc = LDAP_CONSTRAINT_VIOLATION; - goto leave; - } -#endif - break; - } +static int +cfAddInclude( CfEntryInfo *p, Entry *e, ConfigArgs *ca ) +{ + if ( p->ce_type != Cft_Global && p->ce_type != Cft_Include ) + return LDAP_CONSTRAINT_VIOLATION; - sort_attrs( e, colst, nocs ); + /* If we're reading from a configdir, don't parse this entry */ + if ( ca->lineno ) + return LDAP_COMPARE_TRUE; - /* Parse all the values and check for simple syntax errors before - * performing any set actions. + cfn = p->ce_private; + ca->private = cfn; + return LDAP_SUCCESS; +} + +static int +cfAddSchema( CfEntryInfo *p, Entry *e, ConfigArgs *ca ) +{ + ConfigFile *cfo; + + /* This entry is hardcoded, don't re-parse it */ + if ( p->ce_type == Cft_Global ) { + cfn = p->ce_private; + ca->private = cfn; + return LDAP_COMPARE_TRUE; + } + if ( p->ce_type != Cft_Schema ) + return LDAP_CONSTRAINT_VIOLATION; + + cfn = ch_calloc( 1, sizeof(ConfigFile) ); + ca->private = cfn; + cfo = p->ce_private; + cfn->c_sibs = cfo->c_kids; + cfo->c_kids = cfn; + return LDAP_SUCCESS; +} + +static int +cfAddDatabase( CfEntryInfo *p, Entry *e, struct config_args_s *ca ) +{ + if ( p->ce_type != Cft_Global ) + return LDAP_CONSTRAINT_VIOLATION; + ca->be = frontendDB; /* just to get past check_vals */ + return LDAP_SUCCESS; +} + +static int +cfAddBackend( CfEntryInfo *p, Entry *e, struct config_args_s *ca ) +{ + if ( p->ce_type != Cft_Global ) + return LDAP_CONSTRAINT_VIOLATION; + return LDAP_SUCCESS; +} + +static int +cfAddModule( CfEntryInfo *p, Entry *e, struct config_args_s *ca ) +{ + if ( p->ce_type != Cft_Global ) + return LDAP_CONSTRAINT_VIOLATION; + return LDAP_SUCCESS; +} + +static int +cfAddOverlay( CfEntryInfo *p, Entry *e, struct config_args_s *ca ) +{ + if ( p->ce_type != Cft_Database ) + return LDAP_CONSTRAINT_VIOLATION; + ca->be = p->ce_be; + return LDAP_SUCCESS; +} + +/* Parse an LDAP entry into config directives */ +static int +config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca, SlapReply *rs, int *renum ) +{ + CfEntryInfo *ce, *last; + ConfigOCs **colst; + Attribute *a, *oc_at; + int i, nocs, rc = 0; + struct berval pdn; + ConfigTable *ct; + char *ptr; + + /* Make sure parent exists and entry does not */ + ce = config_find_base( cfb->cb_root, &e->e_nname, &last ); + if ( ce ) + return LDAP_ALREADY_EXISTS; + + dnParent( &e->e_nname, &pdn ); + + /* If last is NULL, the new entry is the root/suffix entry, + * otherwise last should be the parent. */ - switch (colst[0]->co_type) { - case Cft_Schema: - /* The cn=schema entry is all hardcoded, so never reparse it */ - if (last->ce_type == Cft_Global ) - goto ok; - /* FALLTHRU */ - case Cft_Global: - ca.be = LDAP_STAILQ_FIRST(&backendDB); - break; + if ( last && !dn_match( &last->ce_entry->e_nname, &pdn )) { + if ( rs ) + rs->sr_matched = last->ce_entry->e_name.bv_val; + return LDAP_NO_SUCH_OBJECT; + } - case Cft_Backend: - if ( last->ce_type == Cft_Backend ) - ca.bi = last->ce_bi; - else - type_ad = cfAd_backend; - break; - case Cft_Database: - if ( last->ce_type == Cft_Database ) { - ca.be = last->ce_be; - } else { - type_ad = cfAd_database; - /* dummy, just to get past check_attr */ - ca.be = frontendDB; - } - break; + oc_at = attr_find( e->e_attrs, slap_schema.si_ad_objectClass ); + if ( !oc_at ) return LDAP_OBJECT_CLASS_VIOLATION; - case Cft_Overlay: - ca.be = last->ce_be; - type_ad = cfAd_overlay; - break; + memset( ca, 0, sizeof(ConfigArgs)); - case Cft_Include: - if ( !rs ) { - nocs = 0; /* ignored */ - break; - } - type_ad = cfAd_include; - break; -#ifdef SLAPD_MODULES - case Cft_Module: { - ModPaths *mp; - char *ptr; - ptr = strchr( e->e_name.bv_val, '{' ); - if ( !ptr ) { - rc = LDAP_NAMING_VIOLATION; - goto leave; - } - j = atoi(ptr+1); - for (i=0, mp=&modpaths; mp && imp_next); - /* There is no corresponding modpath for this load? */ - if ( i != j ) { - rc = LDAP_NAMING_VIOLATION; - goto leave; - } - module_path( mp->mp_path.bv_val ); - ca.private = mp; + /* Fake the coordinates based on whether we're part of an + * LDAP Add or if reading the config dir + */ + if ( rs ) { + ca->fname = "slapd"; + ca->lineno = 0; + } else { + ca->fname = cfdir.bv_val; + ca->lineno = 1; + } + + colst = count_ocs( oc_at, &nocs ); + + /* Only the root can be Cft_Global, everything else must + * have a parent. Only limited nesting arrangements are allowed. + */ + rc = LDAP_CONSTRAINT_VIOLATION; + if ( colst[0]->co_type == Cft_Global && !last ) { + cfn = cfb->cb_config; + ca->private = cfn; + ca->be = frontendDB; /* just to get past check_vals */ + rc = LDAP_SUCCESS; + } + + /* Check whether the Add is allowed by its parent, and do + * any necessary arg setup + */ + if ( last ) { + for ( i=0; ico_ldadd && + ( rc = colst[i]->co_ldadd( last, e, ca )) + != LDAP_CONSTRAINT_VIOLATION ) { + break; + } } - break; -#endif } - /* If doing an LDAPadd, check for indexed names and any necessary + /* Add the entry but don't parse it, we already have its contents */ + if ( rc == LDAP_COMPARE_TRUE ) { + rc = LDAP_SUCCESS; + goto ok; + } + + if ( rc != LDAP_SUCCESS ) + goto leave; + + /* Parse all the values and check for simple syntax errors before + * performing any set actions. + * + * If doing an LDAPadd, check for indexed names and any necessary * renaming/renumbering. Entries that don't need indexed names are * ignored. Entries that need an indexed name and arrive without one * are assigned to the end. Entries that arrive with an index may @@ -3323,60 +3236,32 @@ config_add_internal( CfBackInfo *cfb, Entry *e, SlapReply *rs, int *renum ) if ( rc ) goto leave; - init_config_argv( &ca ); - if ( type_ad ) { - type_attr = attr_find( e->e_attrs, type_ad ); - if ( !type_attr ) { - rc = LDAP_OBJECT_CLASS_VIOLATION; - goto leave; - } - for ( i=0; ie_attrs; a; a=a->a_next ) { - if ( a == type_attr || a == oc_at ) continue; - ct = NULL; - for ( i=0; ia_desc ); - if ( ct ) break; - } + if ( a == oc_at ) continue; + ct = config_find_table( colst, nocs, a->a_desc ); if ( !ct ) continue; /* user data? */ - rc = check_attr( ct, &ca, a ); + rc = check_vals( ct, ca, a, 1 ); if ( rc ) goto leave; } /* Basic syntax checks are OK. Do the actual settings. */ - if ( type_ct ) { - ca.line = type_attr->a_vals[0].bv_val; - if ( type_ad->ad_type->sat_flags & SLAP_AT_ORDERED ) - ca.line = strchr( ca.line, '}' ) + 1; - rc = config_parse_add( type_ct, &ca, 0 ); - if ( rc ) { - rc = LDAP_OTHER; - goto leave; - } - } for ( a=e->e_attrs; a; a=a->a_next ) { - if ( a == type_attr || a == oc_at ) continue; - ct = NULL; - for ( i=0; ia_desc ); - if ( ct ) break; - } + if ( a == oc_at ) continue; + ct = config_find_table( colst, nocs, a->a_desc ); if ( !ct ) continue; /* user data? */ for (i=0; a->a_vals[i].bv_val; i++) { - ca.line = a->a_vals[i].bv_val; - if ( a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED ) - ca.line = strchr( ca.line, '}' ) + 1; - rc = config_parse_add( ct, &ca, i ); + ca->line = a->a_vals[i].bv_val; + if ( a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED ) { + ptr = strchr( ca->line, '}' ); + if ( ptr ) ca->line = ptr+1; + } + ca->valx = i; + rc = config_parse_add( ct, ca ); if ( rc ) { rc = LDAP_OTHER; goto leave; @@ -3384,11 +3269,36 @@ config_add_internal( CfBackInfo *cfb, Entry *e, SlapReply *rs, int *renum ) } } ok: + /* Newly added databases and overlays need to be started up */ + if ( CONFIG_ONLINE_ADD( ca )) { + if ( colst[0]->co_type == Cft_Database ) { + rc = backend_startup_one( ca->be ); + + } else if ( colst[0]->co_type == Cft_Overlay ) { + if ( ca->bi->bi_db_open ) { + BackendInfo *bi_orig = ca->be->bd_info; + ca->be->bd_info = ca->bi; + rc = ca->bi->bi_db_open( ca->be ); + ca->be->bd_info = bi_orig; + } + } + if ( rc ) { + sprintf( ca->msg, "<%s> failed startup", ca->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s (%s)!\n", + ca->log, ca->msg, ca->argv[1] ); + rc = LDAP_OTHER; + goto leave; + } + } + ce = ch_calloc( 1, sizeof(CfEntryInfo) ); ce->ce_parent = last; ce->ce_entry = entry_dup( e ); ce->ce_entry->e_private = ce; ce->ce_type = colst[0]->co_type; + ce->ce_be = ca->be; + ce->ce_bi = ca->bi; + ce->ce_private = ca->private; if ( !last ) { cfb->cb_root = ce; } else if ( last->ce_kids ) { @@ -3402,7 +3312,16 @@ ok: } leave: - ch_free( ca.argv ); + if ( rc ) { + if ( (colst[0]->co_type == Cft_Database) && ca->be ) { + if ( ca->be != frontendDB ) + backend_destroy_one( ca->be, 1 ); + } else if ( (colst[0]->co_type == Cft_Overlay) && ca->bi ) { + overlay_destroy_one( ca->be, (slap_overinst *)ca->bi ); + } + } + + ch_free( ca->argv ); if ( colst ) ch_free( colst ); return rc; } @@ -3414,12 +3333,12 @@ static int config_back_add( Operation *op, SlapReply *rs ) { CfBackInfo *cfb; - CfEntryInfo *ce, *last; int renumber; + ConfigArgs ca; if ( !be_isroot( op ) ) { rs->sr_err = LDAP_INSUFFICIENT_ACCESS; - send_ldap_result( op, rs ); + goto out; } cfb = (CfBackInfo *)op->o_bd->be_private; @@ -3433,8 +3352,10 @@ config_back_add( Operation *op, SlapReply *rs ) * 4) store entry in underlying database * 5) perform any necessary renumbering */ - rs->sr_err = config_add_internal( cfb, op->ora_e, rs, &renumber ); - if ( rs->sr_err == LDAP_SUCCESS ) { + rs->sr_err = config_add_internal( cfb, op->ora_e, &ca, rs, &renumber ); + if ( rs->sr_err != LDAP_SUCCESS ) { + rs->sr_text = ca.msg; + } else if ( cfb->cb_use_ldif ) { BackendDB *be = op->o_bd; slap_callback sc = { NULL, slap_null_cb, NULL, NULL }; op->o_bd = &cfb->cb_db; @@ -3454,23 +3375,271 @@ out: return rs->sr_err; } -/* Modify rules: - * for single-valued attributes, should just use REPLACE. - * any received DELETE/ADD on a single-valued attr will - * be checked (if a DEL value is provided) and then - * rewritten as a REPLACE. - * any DELETE received without a corresponding ADD will be - * rejected with LDAP_CONSTRAINT_VIOLATION. - */ +typedef struct delrec { + struct delrec *next; + int nidx; + int idx[1]; +} delrec; + +static int +config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs, + ConfigArgs *ca ) +{ + int rc = LDAP_UNWILLING_TO_PERFORM; + Modifications *ml; + Entry *e = ce->ce_entry; + Attribute *save_attrs = e->e_attrs, *oc_at; + ConfigTable *ct; + ConfigOCs **colst; + int i, nocs; + char *ptr; + delrec *dels = NULL, *deltail = NULL; + + oc_at = attr_find( e->e_attrs, slap_schema.si_ad_objectClass ); + if ( !oc_at ) return LDAP_OBJECT_CLASS_VIOLATION; + + colst = count_ocs( oc_at, &nocs ); + + e->e_attrs = attrs_dup( e->e_attrs ); + + init_config_argv( ca ); + ca->be = ce->ce_be; + ca->bi = ce->ce_bi; + ca->private = ce->ce_private; + ca->ca_entry = e; + strcpy( ca->log, "back-config" ); + + for (ml = op->orm_modlist; ml; ml=ml->sml_next) { + ct = config_find_table( colst, nocs, ml->sml_desc ); + switch (ml->sml_op) { + case LDAP_MOD_DELETE: + case LDAP_MOD_REPLACE: { + BerVarray vals = NULL, nvals; + int *idx = NULL; + if ( ct && ( ct->arg_type & ARG_NO_DELETE )) { + rc = LDAP_OTHER; + snprintf(ca->msg, sizeof(ca->msg), "cannot delete %s", + ml->sml_desc->ad_cname.bv_val ); + goto out; + } + if ( ml->sml_op == LDAP_MOD_REPLACE ) { + vals = ml->sml_values; + nvals = ml->sml_nvalues; + ml->sml_values = NULL; + ml->sml_nvalues = NULL; + } + /* If we're deleting by values, remember the indexes of the + * values we deleted. + */ + if ( ct && ml->sml_values ) { + delrec *d; + for (i=0; ml->sml_values[i].bv_val; i++); + d = ch_malloc( sizeof(delrec) + (i - 1)* sizeof(int)); + d->nidx = i; + d->next = NULL; + if ( dels ) { + deltail->next = d; + } else { + dels = d; + } + deltail = d; + idx = d->idx; + } + rc = modify_delete_vindex(e, &ml->sml_mod, + get_permissiveModify(op), + &rs->sr_text, ca->msg, sizeof(ca->msg), idx ); + if ( ml->sml_op == LDAP_MOD_REPLACE ) { + ml->sml_values = vals; + ml->sml_nvalues = nvals; + } + if ( !vals ) + break; + } + /* FALLTHRU: LDAP_MOD_REPLACE && vals */ + + case LDAP_MOD_ADD: + case SLAP_MOD_SOFTADD: { + int mop = ml->sml_op; + int navals = -1; + ml->sml_op = LDAP_MOD_ADD; + if ( ct ) { + if ( ct->arg_type & ARG_NO_INSERT ) { + Attribute *a = attr_find( e->e_attrs, ml->sml_desc ); + if ( a ) { + for (i = 0; a->a_vals[i].bv_val; i++ ); + navals = i; + } + } + for ( i=0; !BER_BVISNULL( &ml->sml_values[i] ); i++ ) { + if ( ml->sml_values[i].bv_val[0] == '{' && + navals >= 0 ) { + int j = strtol( ml->sml_values[i].bv_val+1, NULL, 0 ); + if ( j < navals ) { + rc = LDAP_OTHER; + snprintf(ca->msg, sizeof(ca->msg), "cannot insert %s", + ml->sml_desc->ad_cname.bv_val ); + goto out; + } + } + rc = check_vals( ct, ca, ml, 0 ); + if ( rc ) goto out; + } + } + rc = modify_add_values(e, &ml->sml_mod, + get_permissiveModify(op), + &rs->sr_text, ca->msg, sizeof(ca->msg) ); + + /* If value already exists, show success here + * and ignore this operation down below. + */ + if ( mop == SLAP_MOD_SOFTADD ) { + if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) + rc = LDAP_SUCCESS; + else + mop = LDAP_MOD_ADD; + } + ml->sml_op = mop; + break; + } + + break; + case LDAP_MOD_INCREMENT: /* FIXME */ + break; + default: + break; + } + if(rc != LDAP_SUCCESS) break; + } + + if(rc == LDAP_SUCCESS) { + /* check that the entry still obeys the schema */ + rc = entry_schema_check(op, e, NULL, 0, + &rs->sr_text, ca->msg, sizeof(ca->msg) ); + } + if ( rc == LDAP_SUCCESS ) { + /* Basic syntax checks are OK. Do the actual settings. */ + for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) { + ct = config_find_table( colst, nocs, ml->sml_desc ); + if ( !ct ) continue; + + switch (ml->sml_op) { + case LDAP_MOD_DELETE: + case LDAP_MOD_REPLACE: { + BerVarray vals = NULL, nvals; + Attribute *a; + delrec *d; + + a = attr_find( e->e_attrs, ml->sml_desc ); + + if ( ml->sml_op == LDAP_MOD_REPLACE ) { + vals = ml->sml_values; + nvals = ml->sml_nvalues; + ml->sml_values = NULL; + ml->sml_nvalues = NULL; + } + + if ( ml->sml_values ) + d = dels; + + /* If we didn't delete the whole attribute */ + if ( ml->sml_values && a ) { + struct berval *mvals; + int j; + + if ( ml->sml_nvalues ) + mvals = ml->sml_nvalues; + else + mvals = ml->sml_values; + + /* use the indexes we saved up above */ + for (i=0; i < d->nidx; i++) { + struct berval bv = *mvals++; + if ( a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED && + bv.bv_val[0] == '{' ) { + ptr = strchr( bv.bv_val, '}' ) + 1; + bv.bv_len -= ptr - bv.bv_val; + bv.bv_val = ptr; + } + ca->line = bv.bv_val; + ca->valx = d->idx[i]; + rc = config_del_vals( ct, ca ); + if ( rc != LDAP_SUCCESS ) break; + for (j=i+1; j < d->nidx; j++) + if ( d->idx[j] >d->idx[i] ) + d->idx[j]--; + } + } else { + ca->valx = -1; + ca->line = NULL; + rc = config_del_vals( ct, ca ); + if ( rc ) rc = LDAP_OTHER; + } + if ( ml->sml_values ) { + ch_free( dels ); + dels = d->next; + } + if ( ml->sml_op == LDAP_MOD_REPLACE ) { + ml->sml_values = vals; + ml->sml_nvalues = nvals; + } + if ( !vals || rc != LDAP_SUCCESS ) + break; + } + /* FALLTHRU: LDAP_MOD_REPLACE && vals */ + + case LDAP_MOD_ADD: + for (i=0; ml->sml_values[i].bv_val; i++) { + ca->line = ml->sml_values[i].bv_val; + ca->valx = -1; + if ( ml->sml_desc->ad_type->sat_flags & SLAP_AT_ORDERED && + ca->line[0] == '{' ) { + ptr = strchr( ca->line, '}' ); + if ( ptr ) { + ca->valx = strtol( ca->line+1, NULL, 0 ); + ca->line = ptr+1; + } + } + rc = config_parse_add( ct, ca ); + if ( rc ) { + rc = LDAP_OTHER; + goto out; + } + } + + break; + } + } + } + +out: + if ( ca->cleanup ) + ca->cleanup( ca ); + if ( rc == LDAP_SUCCESS ) { + attrs_free( save_attrs ); + } else { + attrs_free( e->e_attrs ); + e->e_attrs = save_attrs; + } + ch_free( ca->argv ); + if ( colst ) ch_free( colst ); + + return rc; +} + static int config_back_modify( Operation *op, SlapReply *rs ) { CfBackInfo *cfb; CfEntryInfo *ce, *last; + Modifications *ml; + ConfigArgs ca = {0}; + struct berval rdn; + char *ptr; + AttributeDescription *rad = NULL; if ( !be_isroot( op ) ) { rs->sr_err = LDAP_INSUFFICIENT_ACCESS; - send_ldap_result( op, rs ); + goto out; } cfb = (CfBackInfo *)op->o_bd->be_private; @@ -3482,6 +3651,23 @@ config_back_modify( Operation *op, SlapReply *rs ) rs->sr_err = LDAP_NO_SUCH_OBJECT; goto out; } + + /* Get type of RDN */ + 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 ); + + /* Some basic validation... */ + for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) { + /* Don't allow Modify of RDN; must use ModRdn for that. */ + if ( ml->sml_desc == rad ) { + rs->sr_err = LDAP_NOT_ALLOWED_ON_RDN; + rs->sr_text = "Use modrdn to change the entry name"; + goto out; + } + } + ldap_pvt_thread_pool_pause( &connection_pool ); /* Strategy: @@ -3490,6 +3676,20 @@ config_back_modify( Operation *op, SlapReply *rs ) * 3) perform the individual config operations. * 4) store Modified entry in underlying LDIF backend. */ + rs->sr_err = config_modify_internal( ce, op, rs, &ca ); + if ( rs->sr_err ) { + rs->sr_text = ca.msg; + } else if ( cfb->cb_use_ldif ) { + BackendDB *be = op->o_bd; + slap_callback sc = { NULL, slap_null_cb, NULL, NULL }; + op->o_bd = &cfb->cb_db; + sc.sc_next = op->o_callback; + op->o_callback = ≻ + op->o_bd->be_modify( op, rs ); + op->o_bd = be; + op->o_callback = sc.sc_next; + } + ldap_pvt_thread_pool_resume( &connection_pool ); out: send_ldap_result( op, rs ); @@ -3504,7 +3704,7 @@ config_back_modrdn( Operation *op, SlapReply *rs ) if ( !be_isroot( op ) ) { rs->sr_err = LDAP_INSUFFICIENT_ACCESS; - send_ldap_result( op, rs ); + goto out; } cfb = (CfBackInfo *)op->o_bd->be_private; @@ -3537,11 +3737,10 @@ config_back_search( Operation *op, SlapReply *rs ) { CfBackInfo *cfb; CfEntryInfo *ce, *last; - int rc; if ( !be_isroot( op ) ) { rs->sr_err = LDAP_INSUFFICIENT_ACCESS; - send_ldap_result( op, rs ); + goto out; } cfb = (CfBackInfo *)op->o_bd->be_private; @@ -3572,114 +3771,119 @@ out: return 0; } -static Entry * -config_alloc_entry( CfEntryInfo *parent, struct berval *rdn ) +static void +config_build_attrs( Entry *e, AttributeType **at, AttributeDescription *ad, + ConfigTable *ct, ConfigArgs *c ) +{ + int i, rc; + + for (; at && *at; at++) { + /* Skip the naming attr */ + if ((*at)->sat_ad == ad || (*at)->sat_ad == slap_schema.si_ad_cn ) + continue; + for (i=0;ct[i].name;i++) { + if (ct[i].ad == (*at)->sat_ad) { + rc = config_get_vals(&ct[i], c); + if (rc == LDAP_SUCCESS) { + if ( c->rvalue_nvals ) + attr_merge(e, ct[i].ad, c->rvalue_vals, + c->rvalue_nvals); + else + attr_merge_normalize(e, ct[i].ad, + c->rvalue_vals, NULL); + ber_bvarray_free( c->rvalue_nvals ); + ber_bvarray_free( c->rvalue_vals ); + } + break; + } + } + } +} + +Entry * +config_build_entry( Operation *op, SlapReply *rs, CfEntryInfo *parent, + ConfigArgs *c, struct berval *rdn, ConfigOCs *main, ConfigOCs *extra ) { Entry *e = ch_calloc( 1, sizeof(Entry) ); CfEntryInfo *ce = ch_calloc( 1, sizeof(CfEntryInfo) ); + struct berval val; + struct berval ad_name; + AttributeDescription *ad = NULL; + int rc; + char *ptr; + const char *text; + Attribute *oc_at; struct berval pdn; + ObjectClass *oc; + CfEntryInfo *ceprev = NULL; e->e_private = ce; ce->ce_entry = e; ce->ce_parent = parent; if ( parent ) { pdn = parent->ce_entry->e_nname; + if ( parent->ce_kids ) + for ( ceprev = parent->ce_kids; ceprev->ce_sibs; + ceprev = ceprev->ce_sibs ); } else { BER_BVZERO( &pdn ); } + ce->ce_type = main->co_type; + ce->ce_private = c->private; + ce->ce_be = c->be; + ce->ce_bi = c->bi; + build_new_dn( &e->e_name, &pdn, rdn, NULL ); ber_dupbv( &e->e_nname, &e->e_name ); - return e; -} - -#define NO_TABLE 0 -#define BI_TABLE 1 -#define BE_TABLE 2 - -static int -config_build_entry( ConfigArgs *c, Entry *e, ObjectClass *oc, - struct berval *rdn, ConfigTable *ct, int table ) -{ - struct berval vals[2]; - struct berval ad_name; - AttributeDescription *ad = NULL; - int rc, i; - char *ptr; - const char *text; - char textbuf[SLAP_TEXT_BUFLEN]; - size_t textlen = sizeof(textbuf); - AttributeType **at; - Attribute *oc_at; - BER_BVZERO( &vals[1] ); - - vals[0] = oc->soc_cname; - attr_merge(e, slap_schema.si_ad_objectClass, vals, NULL ); + attr_merge_normalize_one(e, slap_schema.si_ad_objectClass, + main->co_name, NULL ); + 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 ( rc ) { - return rc; + return NULL; } - vals[0].bv_val = ptr+1; - vals[0].bv_len = rdn->bv_len - (vals[0].bv_val - rdn->bv_val); - attr_merge(e, ad, vals, NULL ); + 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 ); - for (at=oc->soc_required; at && *at; at++) { - /* Skip the naming attr */ - if ((*at)->sat_ad == ad || (*at)->sat_ad == slap_schema.si_ad_cn ) - continue; - for (i=0;ct[i].name;i++) { - if (ct[i].ad == (*at)->sat_ad) { - rc = config_get_vals(&ct[i], c); - if (rc == LDAP_SUCCESS) { - attr_merge(e, ct[i].ad, c->rvalue_vals, c->rvalue_nvals); - ber_bvarray_free( c->rvalue_nvals ); - ber_bvarray_free( c->rvalue_vals ); - } - break; - } - } - } + oc = main->co_oc; + if ( oc->soc_required ) + config_build_attrs( e, oc->soc_required, ad, main->co_table, c ); - for (at=oc->soc_allowed; at && *at; at++) { - /* Skip the naming attr */ - if ((*at)->sat_ad == ad || (*at)->sat_ad == slap_schema.si_ad_cn ) - continue; - for (i=0;ct[i].name;i++) { - if (ct[i].ad == (*at)->sat_ad) { - rc = config_get_vals(&ct[i], c); - if (rc == LDAP_SUCCESS) { - attr_merge(e, ct[i].ad, c->rvalue_vals, c->rvalue_nvals); - ber_bvarray_free( c->rvalue_nvals ); - ber_bvarray_free( c->rvalue_vals ); - } - break; - } - } - } + if ( oc->soc_allowed ) + config_build_attrs( e, oc->soc_allowed, ad, main->co_table, c ); - if ( table ) { - if ( table == BI_TABLE ) - ct = c->bi->bi_cf_table; - else - ct = c->be->be_cf_table; - for (;ct && ct->name;ct++) { - if (!ct->ad) continue; - rc = config_get_vals(ct, c); - if (rc == LDAP_SUCCESS) { - attr_merge(e, ct->ad, c->rvalue_vals, c->rvalue_nvals); - } - } + if ( extra ) { + oc = extra->co_oc; + if ( oc->soc_required ) + config_build_attrs( e, oc->soc_required, ad, extra->co_table, c ); + + if ( oc->soc_allowed ) + config_build_attrs( e, oc->soc_allowed, ad, extra->co_table, c ); } + oc_at = attr_find( e->e_attrs, slap_schema.si_ad_objectClass ); - rc = structural_class(oc_at->a_vals, vals, NULL, &text, textbuf, textlen); - BER_BVZERO( &vals[1] ); - attr_merge(e, slap_schema.si_ad_structuralObjectClass, vals, NULL ); + rc = structural_class(oc_at->a_vals, &val, NULL, &text, c->msg, + sizeof(c->msg)); + attr_merge_normalize_one(e, slap_schema.si_ad_structuralObjectClass, &val, NULL ); + if ( op ) { + op->ora_e = e; + op->o_bd->be_add( op, rs ); + } + if ( ceprev ) { + ceprev->ce_sibs = ce; + } else if ( parent ) { + parent->ce_kids = ce; + } - return 0; + return e; } static void @@ -3688,15 +3892,9 @@ config_build_schema_inc( ConfigArgs *c, CfEntryInfo *ceparent, { Entry *e; ConfigFile *cf = c->private; - CfEntryInfo *ce, *ceprev; char *ptr; struct berval bv; - if ( ceparent->ce_kids ) { - for ( ceprev = ceparent->ce_kids; ceprev->ce_sibs; - ceprev = ceprev->ce_sibs ); - } - for (; cf; cf=cf->c_sibs, c->depth++) { c->value_dn.bv_val = c->log; bv.bv_val = strrchr(cf->c_file.bv_val, LDAP_DIRSEP[0]); @@ -3715,106 +3913,55 @@ config_build_schema_inc( ConfigArgs *c, CfEntryInfo *ceparent, c->value_dn.bv_len += bv.bv_len; c->value_dn.bv_val[c->value_dn.bv_len] ='\0'; - e = config_alloc_entry( ceparent, &c->value_dn ); c->private = cf; - config_build_entry( c, e, cfOc_schema, &c->value_dn, - c->bi->bi_cf_table, NO_TABLE ); - ce = e->e_private; - ce->ce_type = Cft_Schema; - op->ora_e = e; - op->o_bd->be_add( op, rs ); - ce->ce_bi = c->bi; - if ( !ceparent->ce_kids ) { - ceparent->ce_kids = ce; - } else { - ceprev->ce_sibs = ce; - } - ceprev = ce; - if ( cf->c_kids ) { + e = config_build_entry( op, rs, ceparent, c, &c->value_dn, + &CFOC_SCHEMA, NULL ); + if ( e && cf->c_kids ) { c->private = cf->c_kids; - config_build_schema_inc( c, ceparent, op, rs ); + config_build_schema_inc( c, e->e_private, op, rs ); } } } -static CfEntryInfo * +static void config_build_includes( ConfigArgs *c, CfEntryInfo *ceparent, Operation *op, SlapReply *rs ) { Entry *e; int i; ConfigFile *cf = c->private; - CfEntryInfo *ce, *ceprev; - - if ( ceparent->ce_kids ) { - for ( ceprev = ceparent->ce_kids; ceprev->ce_sibs; - ceprev = ceprev->ce_sibs ); - } for (i=0; cf; cf=cf->c_sibs, i++) { c->value_dn.bv_val = c->log; c->value_dn.bv_len = sprintf(c->value_dn.bv_val, "cn=include" IFMT, i); - e = config_alloc_entry( ceparent, &c->value_dn ); c->private = cf; - config_build_entry( c, e, cfOc_include, &c->value_dn, - c->bi->bi_cf_table, NO_TABLE ); - op->ora_e = e; - op->o_bd->be_add( op, rs ); - ce = e->e_private; - ce->ce_type = Cft_Include; - ce->ce_bi = c->bi; - if ( !ceparent->ce_kids ) { - ceparent->ce_kids = ce; - } else { - ceprev->ce_sibs = ce; - } - ceprev = ce; - if ( cf->c_kids ) { + e = config_build_entry( op, rs, ceparent, c, &c->value_dn, + &CFOC_INCLUDE, NULL ); + if ( e && cf->c_kids ) { c->private = cf->c_kids; - config_build_includes( c, ce, op, rs ); + config_build_includes( c, e->e_private, op, rs ); } } - return ce; } #ifdef SLAPD_MODULES -static CfEntryInfo * +static void config_build_modules( ConfigArgs *c, CfEntryInfo *ceparent, Operation *op, SlapReply *rs ) { - Entry *e; int i; - CfEntryInfo *ce, *ceprev; ModPaths *mp; - if ( ceparent->ce_kids ) { - for ( ceprev = ceparent->ce_kids; ceprev->ce_sibs; - ceprev = ceprev->ce_sibs ); - } - for (i=0, mp=&modpaths; mp; mp=mp->mp_next, i++) { if ( BER_BVISNULL( &mp->mp_path ) && !mp->mp_loads ) continue; c->value_dn.bv_val = c->log; c->value_dn.bv_len = sprintf(c->value_dn.bv_val, "cn=module" IFMT, i); - e = config_alloc_entry( ceparent, &c->value_dn ); - ce = e->e_private; - ce->ce_type = Cft_Include; c->private = mp; - config_build_entry( c, e, cfOc_module, &c->value_dn, - c->bi->bi_cf_table, NO_TABLE ); - op->ora_e = e; - op->o_bd->be_add( op, rs ); - ce->ce_bi = c->bi; - if ( !ceparent->ce_kids ) { - ceparent->ce_kids = ce; - } else { - ceprev->ce_sibs = ce; - } - ceprev = ce; + config_build_entry( op, rs, ceparent, c, &c->value_dn, + &CFOC_MODULE, NULL ); } - return ce; } #endif @@ -3824,12 +3971,10 @@ config_back_db_open( BackendDB *be ) CfBackInfo *cfb = be->be_private; struct berval rdn; Entry *e, *parent; - CfEntryInfo *ce, *ceparent, *ceprev; - int i, rc; + CfEntryInfo *ce, *ceparent; + int i; BackendInfo *bi; - BackendDB *bptr; ConfigArgs c; - ConfigTable *ct; Connection conn = {0}; char opbuf[OPERATION_BUFFER_SIZE]; Operation *op; @@ -3840,180 +3985,206 @@ config_back_db_open( BackendDB *be ) if ( cfb->cb_got_ldif ) return 0; - op = (Operation *)opbuf; - connection_fake_init( &conn, op, cfb ); + if ( cfb->cb_use_ldif ) { + op = (Operation *)opbuf; + connection_fake_init( &conn, op, cfb ); - op->o_dn = be->be_rootdn; - op->o_ndn = be->be_rootndn; + op->o_dn = be->be_rootdn; + op->o_ndn = be->be_rootndn; - op->o_tag = LDAP_REQ_ADD; - op->o_callback = &cb; - op->o_bd = &cfb->cb_db; + op->o_tag = LDAP_REQ_ADD; + op->o_callback = &cb; + op->o_bd = &cfb->cb_db; + } else { + op = NULL; + } /* create root of tree */ rdn = config_rdn; - e = config_alloc_entry( NULL, &rdn ); + c.private = cfb->cb_config; + c.be = frontendDB; + e = config_build_entry( op, &rs, NULL, &c, &rdn, &CFOC_GLOBAL, NULL ); ce = e->e_private; - ce->ce_type = Cft_Global; cfb->cb_root = ce; - c.be = be; - c.bi = be->bd_info; - c.private = cfb->cb_config; - ct = c.bi->bi_cf_table; - config_build_entry( &c, e, cfOc_global, &rdn, ct, NO_TABLE ); - op->ora_e = e; - op->o_bd->be_add( op, &rs ); - ce->ce_bi = c.bi; parent = e; ceparent = ce; + /* Create includeFile nodes */ + if ( cfb->cb_config->c_kids ) { + c.depth = 0; + c.private = cfb->cb_config->c_kids; + config_build_includes( &c, ceparent, op, &rs ); + } + +#ifdef SLAPD_MODULES + /* Create Module nodes... */ + if ( modpaths.mp_loads ) { + config_build_modules( &c, ceparent, op, &rs ); + } +#endif + /* Create schema nodes... cn=schema will contain the hardcoded core * schema, read-only. Child objects will contain runtime loaded schema * files. */ rdn = schema_rdn; - e = config_alloc_entry( ceparent, &rdn ); - ce = e->e_private; - ce->ce_type = Cft_Schema; c.private = NULL; - config_build_entry( &c, e, cfOc_schema, &rdn, ct, NO_TABLE ); - op->ora_e = e; - op->o_bd->be_add( op, &rs ); - if ( !ceparent->ce_kids ) { - ceparent->ce_kids = ce; - } else { - ceprev->ce_sibs = ce; - } - ceprev = ce; + e = config_build_entry( op, &rs, ceparent, &c, &rdn, &CFOC_SCHEMA, NULL ); + ce = e->e_private; - /* Create includeFile nodes and schema nodes for included schema... */ + /* Create schema nodes for included schema... */ if ( cfb->cb_config->c_kids ) { c.depth = 0; c.private = cfb->cb_config->c_kids; config_build_schema_inc( &c, ce, op, &rs ); - c.private = cfb->cb_config->c_kids; - ceprev = config_build_includes( &c, ceparent, op, &rs ); } -#ifdef SLAPD_MODULES - /* Create Module nodes... */ - if ( modpaths.mp_loads ) { - ceprev = config_build_modules( &c, ceparent, op, &rs ); - } -#endif - /* Create backend nodes. Skip if they don't provide a cf_table. * There usually aren't any of these. */ c.line = 0; LDAP_STAILQ_FOREACH( bi, &backendInfo, bi_next) { - if (!bi->bi_cf_table) continue; + if (!bi->bi_cf_ocs) continue; if (!bi->bi_private) continue; rdn.bv_val = c.log; rdn.bv_len = sprintf(rdn.bv_val, "%s=%s", cfAd_backend->ad_cname.bv_val, bi->bi_type); - e = config_alloc_entry( ceparent, &rdn ); - ce = e->e_private; - ce->ce_type = Cft_Backend; - ce->ce_bi = bi; c.bi = bi; - config_build_entry( &c, e, cfOc_backend, &rdn, ct, BI_TABLE ); - op->ora_e = e; - op->o_bd->be_add( op, &rs ); - if ( !ceparent->ce_kids ) { - ceparent->ce_kids = ce; - } else { - ceprev->ce_sibs = ce; - } - ceprev = ce; + e = config_build_entry( op, &rs, ceparent, &c, &rdn, &CFOC_BACKEND, + bi->bi_cf_ocs ); } /* Create database nodes... */ - i = -1; - LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) { + frontendDB->be_cf_ocs = &CFOC_FRONTEND; + LDAP_STAILQ_NEXT(frontendDB, be_next) = LDAP_STAILQ_FIRST(&backendDB); + for ( i = -1, be = frontendDB ; be; + i++, be = LDAP_STAILQ_NEXT( be, be_next )) { slap_overinfo *oi = NULL; - i++; - if ( i == 0 ) { - bptr = frontendDB; - } else { - bptr = be; - } - if ( overlay_is_over( bptr )) { - oi = bptr->bd_info->bi_private; + + if ( overlay_is_over( be )) { + oi = be->bd_info->bi_private; bi = oi->oi_orig; } else { - bi = bptr->bd_info; + bi = be->bd_info; } rdn.bv_val = c.log; rdn.bv_len = sprintf(rdn.bv_val, "%s=" IFMT "%s", cfAd_database->ad_cname.bv_val, i, bi->bi_type); - e = config_alloc_entry( ceparent, &rdn ); - ce = e->e_private; - c.be = bptr; + c.be = be; c.bi = bi; - ce->ce_type = Cft_Database; - ce->ce_be = c.be; - ce->ce_bi = c.bi; - config_build_entry( &c, e, cfOc_database, &rdn, ct, BE_TABLE ); - op->ora_e = e; - op->o_bd->be_add( op, &rs ); - if ( !ceparent->ce_kids ) { - ceparent->ce_kids = ce; - } else { - ceprev->ce_sibs = ce; - } - ceprev = ce; + e = config_build_entry( op, &rs, ceparent, &c, &rdn, &CFOC_DATABASE, + be->be_cf_ocs ); + ce = e->e_private; + if ( be->be_cf_ocs && be->be_cf_ocs->co_cfadd ) + be->be_cf_ocs->co_cfadd( op, &rs, e, &c ); /* Iterate through overlays */ if ( oi ) { slap_overinst *on; Entry *oe; - CfEntryInfo *opar = ce, *oprev = NULL; int j; for (j=0,on=oi->oi_list; on; j++,on=on->on_next) { rdn.bv_val = c.log; rdn.bv_len = sprintf(rdn.bv_val, "%s=" IFMT "%s", cfAd_overlay->ad_cname.bv_val, j, on->on_bi.bi_type ); - oe = config_alloc_entry( opar, &rdn ); - ce = oe->e_private; - c.be = bptr; + c.be = be; c.bi = &on->on_bi; - ce->ce_type = Cft_Overlay; - ce->ce_be = c.be; - ce->ce_bi = c.bi; - config_build_entry( &c, oe, cfOc_overlay, &rdn, ct, BI_TABLE ); - op->ora_e = oe; - op->o_bd->be_add( op, &rs ); - if ( !opar->ce_kids ) { - opar->ce_kids = ce; - } else { - oprev->ce_sibs = ce; - } - oprev = ce; + oe = config_build_entry( op, &rs, ce, &c, &rdn, + &CFOC_OVERLAY, c.bi->bi_cf_ocs ); + if ( c.bi->bi_cf_ocs && c.bi->bi_cf_ocs->co_cfadd ) + c.bi->bi_cf_ocs->co_cfadd( op, &rs, oe, &c ); } } } + if ( op ) + slap_sl_mem_destroy( NULL, op->o_tmpmemctx ); return 0; } +static void +cfb_free_cffile( ConfigFile *cf ) +{ + ConfigFile *next; + + for (; cf; cf=next) { + next = cf->c_sibs; + if ( cf->c_kids ) + cfb_free_cffile( cf->c_kids ); + ch_free( cf->c_file.bv_val ); + ber_bvarray_free( cf->c_dseFiles ); + ch_free( cf ); + } +} + +static void +cfb_free_entries( CfEntryInfo *ce ) +{ + CfEntryInfo *next; + + for (; ce; ce=next) { + next = ce->ce_sibs; + if ( ce->ce_kids ) + cfb_free_entries( ce->ce_kids ); + ce->ce_entry->e_private = NULL; + entry_free( ce->ce_entry ); + ch_free( ce ); + } +} + static int -config_back_db_destroy( Backend *be ) +config_back_db_close( BackendDB *be ) { + CfBackInfo *cfb = be->be_private; + + cfb_free_entries( cfb->cb_root ); + cfb->cb_root = NULL; + + if ( cfb->cb_db.bd_info ) { + backend_shutdown( &cfb->cb_db ); + } + + return 0; +} + +static int +config_back_db_destroy( BackendDB *be ) +{ + CfBackInfo *cfb = be->be_private; + + cfb_free_cffile( cfb->cb_config ); + + ch_free( cfdir.bv_val ); + + avl_free( CfOcTree, NULL ); + + if ( cfb->cb_db.bd_info ) { + cfb->cb_db.be_suffix = NULL; + cfb->cb_db.be_nsuffix = NULL; + BER_BVZERO( &cfb->cb_db.be_rootdn ); + BER_BVZERO( &cfb->cb_db.be_rootndn ); + + backend_destroy_one( &cfb->cb_db, 0 ); + } + free( be->be_private ); + + loglevel_destroy(); + return 0; } static int -config_back_db_init( Backend *be ) +config_back_db_init( BackendDB *be ) { struct berval dn; CfBackInfo *cfb; cfb = ch_calloc( 1, sizeof(CfBackInfo)); - cfb->cb_config = &cf_prv; + cfb->cb_config = ch_calloc( 1, sizeof(ConfigFile)); + cfn = cfb->cb_config; be->be_private = cfb; ber_dupbv( &be->be_rootdn, &config_rdn ); @@ -4029,6 +4200,88 @@ config_back_db_init( Backend *be ) return 0; } +static int +config_back_destroy( BackendInfo *bi ) +{ + ldif_must_b64_encode_release(); + return 0; +} + +static int +config_tool_entry_open( BackendDB *be, int mode ) +{ + CfBackInfo *cfb = be->be_private; + BackendInfo *bi = cfb->cb_db.bd_info; + + if ( bi && bi->bi_tool_entry_open ) + return bi->bi_tool_entry_open( &cfb->cb_db, mode ); + else + return -1; + +} + +static int +config_tool_entry_close( BackendDB *be ) +{ + CfBackInfo *cfb = be->be_private; + BackendInfo *bi = cfb->cb_db.bd_info; + + if ( bi && bi->bi_tool_entry_close ) + return bi->bi_tool_entry_close( &cfb->cb_db ); + else + return -1; +} + +static ID +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 ) + return bi->bi_tool_entry_first( &cfb->cb_db ); + else + return NOID; +} + +static ID +config_tool_entry_next( BackendDB *be ) +{ + CfBackInfo *cfb = be->be_private; + BackendInfo *bi = cfb->cb_db.bd_info; + + if ( bi && bi->bi_tool_entry_next ) + return bi->bi_tool_entry_next( &cfb->cb_db ); + else + return NOID; +} + +static Entry * +config_tool_entry_get( BackendDB *be, ID id ) +{ + CfBackInfo *cfb = be->be_private; + BackendInfo *bi = cfb->cb_db.bd_info; + + if ( bi && bi->bi_tool_entry_get ) + return bi->bi_tool_entry_get( &cfb->cb_db, id ); + else + return NULL; +} + +static ID +config_tool_entry_put( BackendDB *be, Entry *e, struct berval *text ) +{ + CfBackInfo *cfb = be->be_private; + BackendInfo *bi = cfb->cb_db.bd_info; + ConfigArgs ca; + + if ( bi && bi->bi_tool_entry_put && + config_add_internal( cfb, e, &ca, NULL, NULL ) == 0 ) + return bi->bi_tool_entry_put( &cfb->cb_db, e, text ); + else + return NOID; +} + static struct { char *name; AttributeDescription **desc; @@ -4066,10 +4319,12 @@ static struct { int config_back_initialize( BackendInfo *bi ) { - ConfigTable *ct = config_back_cf_table; - char *argv[4]; - int i; - static char *controls[] = { + ConfigTable *ct = config_back_cf_table; + char *argv[4]; + int i; + AttributeDescription *ad = NULL; + const char *text; + static char *controls[] = { LDAP_CONTROL_MANAGEDSAIT, NULL }; @@ -4079,12 +4334,12 @@ config_back_initialize( BackendInfo *bi ) bi->bi_open = 0; bi->bi_close = 0; bi->bi_config = 0; - bi->bi_destroy = 0; + bi->bi_destroy = config_back_destroy; bi->bi_db_init = config_back_db_init; bi->bi_db_config = 0; bi->bi_db_open = config_back_db_open; - bi->bi_db_close = 0; + bi->bi_db_close = config_back_db_close; bi->bi_db_destroy = config_back_db_destroy; bi->bi_op_bind = config_back_bind; @@ -4101,9 +4356,23 @@ config_back_initialize( BackendInfo *bi ) bi->bi_chk_referrals = 0; +#ifdef SLAP_OVERLAY_ACCESS + bi->bi_access_allowed = slap_access_always_allowed; +#endif /* SLAP_OVERLAY_ACCESS */ + bi->bi_connection_init = 0; bi->bi_connection_destroy = 0; + 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_next = config_tool_entry_next; + bi->bi_tool_entry_get = config_tool_entry_get; + bi->bi_tool_entry_put = config_tool_entry_put; + + /* Make sure we don't exceed the bits reserved for userland */ + assert( ( ( CFG_LAST - 1 ) & ARGS_USERLAND ) == ( CFG_LAST - 1 ) ); + argv[3] = NULL; for (i=0; OidMacros[i].name; i++ ) { argv[1] = OidMacros[i].name; @@ -4111,11 +4380,24 @@ config_back_initialize( BackendInfo *bi ) parse_oidm( "slapd", i, 3, argv, 0, NULL ); } - bi->bi_cf_table = ct; + bi->bi_cf_ocs = cf_ocs; i = config_register_schema( ct, cf_ocs ); 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 ); + if ( i ) { + Debug( LDAP_DEBUG_ANY, "config_back_initialize: " + "warning, unable to get \"olcRootPW\" " + "attribute description: %d: %s\n", + i, text, 0 ); + } else { + (void)ldif_must_b64_encode_register( ad->ad_cname.bv_val, + ad->ad_type->sat_oid ); + } + /* set up the notable AttributeDescriptions */ i = 0; for (;ct->name;ct++) {