X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fbconfig.c;h=d050122be294e76f174044fb3474f2d60a8f41bb;hb=5631f25839a4a83521993639a96909267ea7bce6;hp=dc8f429b718d5de23ec0c334e619ea59b0ddf76f;hpb=735ee711fe95d07d4d0d31c56f62b2ed42e95233;p=openldap diff --git a/servers/slapd/bconfig.c b/servers/slapd/bconfig.c index dc8f429b71..d050122be2 100644 --- a/servers/slapd/bconfig.c +++ b/servers/slapd/bconfig.c @@ -32,6 +32,7 @@ #include "slapi/slapi.h" #endif +#include #include #include "config.h" @@ -62,24 +63,6 @@ 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; - void *ce_private; -} CfEntryInfo; - typedef struct { ConfigFile *cb_config; CfEntryInfo *cb_root; @@ -96,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; @@ -104,15 +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 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; @@ -124,7 +106,6 @@ static ConfigDriver config_sizelimit; static ConfigDriver config_timelimit; static ConfigDriver config_overlay; static ConfigDriver config_suffix; -static ConfigDriver config_deref_depth; static ConfigDriver config_rootdn; static ConfigDriver config_rootpw; static ConfigDriver config_restrict; @@ -168,7 +149,6 @@ enum { CFG_DIT, CFG_ATTR, CFG_ATOPT, - CFG_CHECK, CFG_REPLOG, CFG_ROOTDSE, CFG_LOGFILE, @@ -181,6 +161,8 @@ enum { CFG_SASLSECP, CFG_SSTR_IF_MAX, CFG_SSTR_IF_MIN, + + CFG_LAST }; typedef struct { @@ -218,7 +200,7 @@ static OidRec OidMacros[] = { /* 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, "( OLcfgGlAt:78 NAME 'olcConfigFile' " @@ -245,6 +227,10 @@ ConfigTable config_back_cf_table[] = { "DESC 'File for slapd command line options' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, + { "attributeoptions", NULL, 0, 0, 0, ARG_MAGIC|CFG_ATOPT, + &config_generic, "( OLcfgGlAt:5 NAME 'olcAttributeOptions' " + "EQUALITY caseIgnoreMatch " + "SYNTAX OMsDirectoryString )", NULL, NULL }, { "attribute", "attribute", 2, 0, 9, ARG_PAREN|ARG_MAGIC|CFG_ATTR|ARG_NO_DELETE|ARG_NO_INSERT, &config_generic, "( OLcfgGlAt:4 NAME 'olcAttributeTypes' " @@ -252,11 +238,7 @@ ConfigTable config_back_cf_table[] = { "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL }, - { "attributeoptions", NULL, 0, 0, 0, ARG_MAGIC|CFG_ATOPT, - &config_generic, "( OLcfgGlAt:5 NAME 'olcAttributeOptions' " - "EQUALITY caseIgnoreMatch " - "SYNTAX OMsDirectoryString )", NULL, NULL }, - { "authid-rewrite", NULL, 2, 0, 0, + { "authid-rewrite", NULL, 2, 0, STRLENOF( "authid-rewrite" ), #ifdef SLAP_AUTH_REWRITE ARG_MAGIC|CFG_REWRITE|ARG_NO_INSERT, &config_generic, #else @@ -292,7 +274,7 @@ ConfigTable config_back_cf_table[] = { &config_generic, "( OLcfgGlAt:13 NAME 'olcDatabase' " "DESC 'The backend type for a database instance' " "SUP olcBackend SINGLE-VALUE X-ORDERED 'SIBLINGS' )", NULL, NULL }, - { "defaultSearchBase", "dn", 2, 2, 0, ARG_PRE_BI|ARG_PRE_DB|ARG_DN|ARG_MAGIC, + { "defaultSearchBase", "dn", 2, 2, 0, ARG_PRE_BI|ARG_PRE_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC, &config_search_base, "( OLcfgGlAt:14 NAME 'olcDefaultSearchBase' " "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL }, { "disallows", "features", 2, 0, 8, ARG_PRE_DB|ARG_MAGIC, @@ -328,7 +310,7 @@ ConfigTable config_back_cf_table[] = { { "index_substr_any_len", "len", 2, 2, 0, ARG_INT|ARG_NONZERO, &index_substr_any_len, "( OLcfgGlAt:22 NAME 'olcIndexSubstrAnyLen' " "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, - { "index_substr_step", "step", 2, 2, 0, ARG_INT|ARG_NONZERO, + { "index_substr_any_step", "step", 2, 2, 0, ARG_INT|ARG_NONZERO, &index_substr_any_step, "( OLcfgGlAt:23 NAME 'olcIndexSubstrAnyStep' " "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, { "lastmod", "on|off", 2, 2, 0, ARG_DB|ARG_ON_OFF|ARG_MAGIC|CFG_LASTMOD, @@ -437,7 +419,7 @@ ConfigTable config_back_cf_table[] = { #endif "( OLcfgGlAt:49 NAME 'olcReverseLookup' " "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, - { "rootdn", "dn", 2, 2, 0, ARG_DB|ARG_DN|ARG_MAGIC, + { "rootdn", "dn", 2, 2, 0, ARG_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC, &config_rootdn, "( OLcfgDbAt:0.8 NAME 'olcRootDN' " "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL }, { "rootDSE", "file", 2, 2, 0, ARG_MAGIC|CFG_ROOTDSE, @@ -476,10 +458,7 @@ ConfigTable config_back_cf_table[] = { "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, { "saslRegexp", NULL, 3, 3, 0, ARG_MAGIC|CFG_AZREGEXP, &config_generic, NULL, NULL, NULL }, - { "schemacheck", "on|off", 2, 2, 0, ARG_ON_OFF|ARG_MAGIC|CFG_CHECK, - &config_generic, "( OLcfgGlAt:57 NAME 'olcSchemaCheck' " - "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, - { "schemadn", "dn", 2, 2, 0, ARG_MAY_DB|ARG_DN|ARG_MAGIC, + { "schemadn", "dn", 2, 2, 0, ARG_MAY_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC, &config_schema_dn, "( OLcfgGlAt:58 NAME 'olcSchemaDN' " "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL }, { "security", "factors", 2, 0, 0, ARG_MAY_DB|ARG_MAGIC, @@ -502,7 +481,7 @@ ConfigTable config_back_cf_table[] = { #endif "( OLcfgGlAt:63 NAME 'olcSrvtab' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, - { "suffix", "suffix", 2, 2, 0, ARG_DB|ARG_DN|ARG_MAGIC, + { "suffix", "suffix", 2, 2, 0, ARG_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC, &config_suffix, "( OLcfgDbAt:0.10 NAME 'olcSuffix' " "SYNTAX OMsDN )", NULL, NULL }, { "syncrepl", NULL, 0, 0, 0, ARG_DB|ARG_MAGIC, @@ -580,7 +559,7 @@ ConfigTable config_back_cf_table[] = { "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, { "ucdata-path", "path", 2, 2, 0, ARG_IGNORED, NULL, NULL, NULL, NULL }, - { "updatedn", "dn", 2, 2, 0, ARG_DB|ARG_MAGIC, + { "updatedn", "dn", 2, 2, 0, ARG_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC, &config_updatedn, "( OLcfgDbAt:0.12 NAME 'olcUpdateDN' " "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL }, { "updateref", "url", 2, 2, 0, ARG_DB|ARG_MAGIC, @@ -590,12 +569,29 @@ ConfigTable config_back_cf_table[] = { 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[] = { - { "( OLcfgGlOc:1 " + { "( OLcfgGlOc:0 " "NAME 'olcConfig' " "DESC 'OpenLDAP configuration object' " "ABSTRACT SUP top )", Cft_Abstract, NULL }, - { "( OLcfgGlOc:2 " + { "( OLcfgGlOc:1 " "NAME 'olcGlobal' " "DESC 'OpenLDAP Global configuration options' " "SUP olcConfig STRUCTURAL " @@ -611,29 +607,29 @@ static ConfigOCs cf_ocs[] = { "olcPluginLogFile $ olcReadOnly $ olcReferral $ " "olcReplicaPidFile $ olcReplicaArgsFile $ olcReplicationInterval $ " "olcReplogFile $ olcRequires $ olcRestrict $ olcReverseLookup $ " - "olcRootDSE $ olcRootPW $ " + "olcRootDSE $ " "olcSaslHost $ olcSaslRealm $ olcSaslSecProps $ " - "olcSchemaCheck $ olcSecurity $ olcSizeLimit $ " + "olcSecurity $ olcSizeLimit $ " "olcSockbufMaxIncoming $ olcSockbufMaxIncomingAuth $ olcSrvtab $ " "olcThreads $ olcTimeLimit $ olcTLSCACertificateFile $ " "olcTLSCACertificatePath $ olcTLSCertificateFile $ " "olcTLSCertificateKeyFile $ olcTLSCipherSuite $ olcTLSCRLCheck $ " "olcTLSRandFile $ olcTLSVerifyClient $ " "olcObjectIdentifier $ olcAttributeTypes $ olcObjectClasses $ " - "olcDitContentRules ) )", Cft_Global, &cfOc_global }, - { "( OLcfgGlOc: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 }, - { "( OLcfgGlOc:4 " + Cft_Schema, NULL, cfAddSchema }, + { "( OLcfgGlOc:3 " "NAME 'olcBackendConfig' " "DESC 'OpenLDAP Backend-specific options' " "SUP olcConfig STRUCTURAL " - "MUST olcBackend )", Cft_Backend, &cfOc_backend }, - { "( OLcfgGlOc:5 " + "MUST olcBackend )", Cft_Backend, NULL, cfAddBackend }, + { "( OLcfgGlOc:4 " "NAME 'olcDatabaseConfig' " "DESC 'OpenLDAP Database-specific options' " "SUP olcConfig STRUCTURAL " @@ -643,26 +639,36 @@ static ConfigOCs cf_ocs[] = { "olcReplogFile $ olcRequires $ olcRestrict $ olcRootDN $ olcRootPW $ " "olcSchemaDN $ olcSecurity $ olcSizeLimit $ olcSyncrepl $ " "olcTimeLimit $ olcUpdateDN $ olcUpdateRef ) )", - Cft_Database, &cfOc_database }, - { "( OLcfgGlOc:6 " + Cft_Database, NULL, cfAddDatabase }, + { "( OLcfgGlOc:5 " "NAME 'olcOverlayConfig' " "DESC 'OpenLDAP Overlay-specific options' " "SUP olcConfig STRUCTURAL " - "MUST olcOverlay )", Cft_Overlay, &cfOc_overlay }, - { "( OLcfgGlOc: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 { "( OLcfgGlOc:8 " "NAME 'olcModuleList' " "DESC 'OpenLDAP dynamic module info' " "SUP olcConfig STRUCTURAL " - "MUST ( olcModulePath $ olcModuleLoad ) " - "MAY cn )", Cft_Module, &cfOc_module }, + "MAY ( cn $ olcModulePath $ olcModuleLoad ) )", + Cft_Module, NULL, cfAddModule }, #endif { NULL, 0, NULL } }; @@ -705,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()); @@ -774,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]; @@ -849,7 +853,8 @@ config_generic(ConfigArgs *c) { break; case CFG_MODPATH: { ModPaths *mp = c->private; - value_add_one( &c->rvalue_vals, &mp->mp_path ); + if ( !BER_BVISNULL( &mp->mp_path )) + value_add_one( &c->rvalue_vals, &mp->mp_path ); rc = c->rvalue_vals ? 0 : 1; } @@ -894,7 +899,6 @@ config_generic(ConfigArgs *c) { case CFG_RO: case CFG_AZPOLICY: case CFG_DEPTH: - case CFG_CHECK: case CFG_LASTMOD: case CFG_SASLSECP: case CFG_SSTR_IF_MAX: @@ -985,11 +989,14 @@ config_generic(ConfigArgs *c) { c->be = LDAP_STAILQ_FIRST(&backendDB); } else if ( !strcasecmp( c->argv[1], "frontend" )) { c->be = frontendDB; - } else if(!(c->be = backend_db_init(c->argv[1]))) { - sprintf( c->msg, "<%s> failed init", c->argv[0] ); - Debug(LDAP_DEBUG_ANY, "%s: %s (%s)!\n", - c->log, c->msg, c->argv[1] ); - return(1); + } else { + c->be = backend_db_init(c->argv[1]); + if ( !c->be ) { + sprintf( c->msg, "<%s> failed init", c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s (%s)!\n", + c->log, c->msg, c->argv[1] ); + return(1); + } } break; @@ -1097,13 +1104,6 @@ config_generic(ConfigArgs *c) { return(1); break; - case CFG_CHECK: - global_schemacheck = c->value_int; - if(!global_schemacheck) Debug(LDAP_DEBUG_ANY, "%s: " - "schema checking disabled! your mileage may vary!\n", - c->log, 0, 0); - break; - case CFG_ACL: parse_acl(c->be, c->fname, c->lineno, c->argc, c->argv, c->valx); break; @@ -1178,21 +1178,35 @@ config_generic(ConfigArgs *c) { #ifdef SLAPD_MODULES case CFG_MODLOAD: + /* If we're just adding a module on an existing modpath, + * make sure we've selected the current path. + */ + if ( c->op == LDAP_MOD_ADD && c->private && modcur != c->private ) { + modcur = c->private; + /* This should never fail */ + if ( module_path( modcur->mp_path.bv_val )) { + sprintf( c->msg, "<%s> module path no longer valid", + c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s (%s)\n", + c->log, c->msg, modcur->mp_path.bv_val ); + return(1); + } + } if(module_load(c->argv[1], c->argc - 2, (c->argc > 2) ? c->argv + 2 : NULL)) return(1); /* Record this load on the current path */ { struct berval bv; - ModPaths *mp; - char *ptr = c->line + STRLENOF("moduleload"); - while (!isspace(*ptr)) ptr++; - while (isspace(*ptr)) ptr++; + char *ptr; + if ( c->op == SLAP_CONFIG_ADD ) { + ptr = c->line + STRLENOF("moduleload"); + while (!isspace(*ptr)) ptr++; + while (isspace(*ptr)) ptr++; + } else { + ptr = c->line; + } ber_str2bv(ptr, 0, 1, &bv); - if ( c->op == SLAP_CONFIG_ADD ) - mp = modcur; - else - mp = c->private; - ber_bvarray_add( &mp->mp_loads, &bv ); + ber_bvarray_add( &modcur->mp_loads, &bv ); } break; @@ -1213,8 +1227,7 @@ config_generic(ConfigArgs *c) { mp->mp_loads = NULL; modlast = mp; c->private = mp; - if ( c->op == SLAP_CONFIG_ADD ) - modcur = mp; + modcur = mp; } break; @@ -1231,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; @@ -1241,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); @@ -1276,8 +1312,6 @@ config_cfdir(ConfigArgs *c) { static int config_search_base(ConfigArgs *c) { - struct berval dn; - if(c->op == SLAP_CONFIG_EMIT) { int rc = 1; if (!BER_BVISEMPTY(&default_search_base)) { @@ -1427,9 +1461,13 @@ config_sizelimit(ConfigArgs *c) { 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; @@ -1480,9 +1518,13 @@ config_timelimit(ConfigArgs *c) { 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; @@ -1493,6 +1535,7 @@ 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 ) { @@ -1500,22 +1543,73 @@ config_overlay(ConfigArgs *c) { } 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"; + + } 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; + } - if (c->be == frontendDB || SLAP_MONITOR(c->be) || - SLAP_CONFIG(c->be)) return 1; + return 1; + } if (c->op == SLAP_CONFIG_EMIT) { if ( c->be->be_suffix == NULL @@ -1544,6 +1638,7 @@ config_suffix(ConfigArgs *c) { } return 0; } + #ifdef SLAPD_MONITOR_DN if(!strcasecmp(c->argv[1], SLAPD_MONITOR_DN)) { sprintf( c->msg, "<%s> DN is reserved for monitoring slapd", @@ -1558,8 +1653,13 @@ 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) { @@ -1609,9 +1709,12 @@ 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; @@ -1784,11 +1887,13 @@ config_requires(ConfigArgs *c) { return(0); } +static slap_verbmasks *loglevel_ops; + static int -config_loglevel(ConfigArgs *c) { - int i; - char *next; - slap_verbmasks loglevel_ops[] = { +loglevel_init( void ) +{ + slap_verbmasks lo[] = { + { BER_BVC("Any"), -1 }, { BER_BVC("Trace"), LDAP_DEBUG_TRACE }, { BER_BVC("Packets"), LDAP_DEBUG_PACKETS }, { BER_BVC("Args"), LDAP_DEBUG_ARGS }, @@ -1803,10 +1908,72 @@ config_loglevel(ConfigArgs *c) { { BER_BVC("Parse"), LDAP_DEBUG_PARSE }, { BER_BVC("Cache"), LDAP_DEBUG_CACHE }, { BER_BVC("Index"), LDAP_DEBUG_INDEX }, - { BER_BVC("Any"), -1 }, + { BER_BVC("Sync"), LDAP_DEBUG_SYNC }, { BER_BVNULL, 0 } }; + return slap_verbmasks_init( &loglevel_ops, lo ); +} + +static void +loglevel_destroy( void ) +{ + if ( loglevel_ops ) { + (void)slap_verbmasks_destroy( loglevel_ops ); + } + loglevel_ops = NULL; +} + +static slap_mask_t loglevel_ignore[] = { -1, 0 }; + +int +slap_loglevel_register( slap_mask_t m, struct berval *s ) +{ + int rc; + + if ( loglevel_ops == NULL ) { + loglevel_init(); + } + + rc = slap_verbmasks_append( &loglevel_ops, m, s, loglevel_ignore ); + + if ( rc != 0 ) { + Debug( LDAP_DEBUG_ANY, "slap_loglevel_register(%lu, \"%s\") failed\n", + m, s->bv_val, 0 ); + } + + return rc; +} + +int +str2loglevel( const char *s, int *l ) +{ + int i; + + if ( loglevel_ops == NULL ) { + loglevel_init(); + } + + i = verb_to_mask( s, loglevel_ops ); + + if ( BER_BVISNULL( &loglevel_ops[ i ].word) ) { + return -1; + } + + *l = loglevel_ops[ i ].mask; + + return 0; +} + +static int +config_loglevel(ConfigArgs *c) { + int i; + char *next; + + if ( loglevel_ops == NULL ) { + loglevel_init(); + } + if (c->op == SLAP_CONFIG_EMIT) { return mask_to_verbs( loglevel_ops, ldap_syslog, &c->rvalue_vals ); } else if ( c->op == LDAP_MOD_DELETE ) { @@ -1824,7 +1991,7 @@ config_loglevel(ConfigArgs *c) { for( i=1; i < c->argc; i++ ) { int level; - if ( isdigit( c->argv[i][0] ) ) { + if ( isdigit( c->argv[i][0] ) || c->argv[i][0] == '-' ) { level = strtol( c->argv[i], &next, 10 ); if ( next == NULL || next[0] != '\0' ) { sprintf( c->msg, "<%s> unable to parse level", c->argv[0] ); @@ -1833,14 +2000,12 @@ config_loglevel(ConfigArgs *c) { return( 1 ); } } else { - int j = verb_to_mask(c->argv[i], loglevel_ops); - if(BER_BVISNULL(&loglevel_ops[j].word)) { + if ( str2loglevel( c->argv[i], &level ) ) { sprintf( c->msg, "<%s> unknown level", c->argv[0] ); Debug( LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", c->log, c->msg, c->argv[i]); return( 1 ); } - level = loglevel_ops[j].mask; } ldap_syslog |= level; } @@ -1968,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 ); @@ -2060,6 +2225,7 @@ config_replica(ConfigArgs *c) { return(1); } if(!ludp->lud_host) { + ldap_free_urldesc(ludp); sprintf( c->msg, "<%s> invalid uri - missing hostname", c->argv[0] ); Debug(LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->msg, 0 ); @@ -2087,14 +2253,22 @@ config_replica(ConfigArgs *c) { 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; } @@ -2125,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); @@ -2136,7 +2308,7 @@ config_updatedn(ConfigArgs *c) { return 1; } else if ( c->op == LDAP_MOD_DELETE ) { ch_free( c->be->be_update_ndn.bv_val ); - c->be->be_update_ndn.bv_val = NULL; + BER_BVZERO( &c->be->be_update_ndn ); SLAP_DBFLAGS(c->be) ^= (SLAP_DBFLAG_SHADOW | SLAP_DBFLAG_SLURP_SHADOW); return 0; } @@ -2147,17 +2319,13 @@ config_updatedn(ConfigArgs *c) { return(1); } - ber_str2bv(c->argv[1], 0, 0, &dn); - - rc = dnNormalize(0, NULL, NULL, &dn, &c->be->be_update_ndn, NULL); - - if(rc != LDAP_SUCCESS) { - sprintf( c->msg, "<%s> invalid DN %d (%s)", c->argv[0], - rc, ldap_err2string(rc)); - Debug(LDAP_DEBUG_ANY, "%s: %s\n", - c->log, c->msg, 0 ); - return(1); + ber_memfree_x( c->value_dn.bv_val, NULL ); + if ( !BER_BVISNULL( &c->be->be_update_ndn ) ) { + ber_memfree_x( c->be->be_update_ndn.bv_val, NULL ); } + c->be->be_update_ndn = c->value_ndn; + BER_BVZERO( &c->value_dn ); + BER_BVZERO( &c->value_ndn ); SLAP_DBFLAGS(c->be) |= (SLAP_DBFLAG_SHADOW | SLAP_DBFLAG_SLURP_SHADOW); return(0); @@ -2206,7 +2374,7 @@ config_updateref(ConfigArgs *c) { static int config_include(ConfigArgs *c) { - unsigned long savelineno = c->lineno; + int savelineno = c->lineno; int rc; ConfigFile *cf; ConfigFile *cfsave = cfn; @@ -2229,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 ) { @@ -2354,14 +2522,19 @@ config_find_base( CfEntryInfo *root, struct berval *dn, CfEntryInfo **last ) return root; } +typedef struct setup_cookie { + CfBackInfo *cfb; + ConfigArgs *ca; +} setup_cookie; + static int config_ldif_resp( Operation *op, SlapReply *rs ) { if ( rs->sr_type == REP_SEARCH ) { - CfBackInfo *cfb = op->o_callback->sc_private; + setup_cookie *sc = op->o_callback->sc_private; - cfb->cb_got_ldif = 1; - rs->sr_err = config_add_internal( cfb, rs->sr_entry, NULL, NULL ); + sc->cfb->cb_got_ldif = 1; + rs->sr_err = config_add_internal( sc->cfb, rs->sr_entry, sc->ca, NULL, NULL ); } return rs->sr_err; } @@ -2373,7 +2546,8 @@ config_setup_ldif( BackendDB *be, const char *dir, int readit ) { 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]; @@ -2415,7 +2589,7 @@ config_setup_ldif( BackendDB *be, const char *dir, int readit ) { 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; @@ -2450,21 +2624,25 @@ config_setup_ldif( BackendDB *be, const char *dir, int readit ) { op->ors_attrsonly = 0; op->o_callback = &cb; - cb.sc_private = cfb; + sc.cfb = cfb; + sc.ca = &c; + cb.sc_private = ≻ op->o_bd = &cfb->cb_db; - op->o_bd->be_search( op, &rs ); + rc = op->o_bd->be_search( op, &rs ); + + slap_sl_mem_destroy( NULL, op->o_tmpmemctx ); } cfb->cb_use_ldif = 1; - return 0; + 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 ); } @@ -2472,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; @@ -2481,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; @@ -2525,12 +2700,17 @@ read_config(const char *fname, const char *dir) { cfdir = SLAPD_DEFAULT_CONFIGDIR; } /* if fname is defaulted, try reading .d */ - if ( config_setup_ldif( be, cfdir, !fname )) + rc = config_setup_ldif( be, cfdir, !fname ); + + /* It's OK if the base object doesn't exist yet */ + if ( rc && rc != LDAP_NO_SUCH_OBJECT ) return 1; /* If we read the config from back-ldif, nothing to do here */ - if ( cfb->cb_got_ldif ) - return 0; + if ( cfb->cb_got_ldif ) { + rc = 0; + goto done; + } } if ( fname ) @@ -2538,10 +2718,10 @@ read_config(const char *fname, const char *dir) { else cfname = SLAPD_DEFAULT_CONFIGFILE; - rc = read_config_file(cfname, 0, NULL); + rc = read_config_file(cfname, 0, NULL, config_back_cf_table); if ( rc == 0 ) - ber_str2bv( cfname, 0, 1, &cf_prv.c_file ); + ber_str2bv( cfname, 0, 1, &cfb->cb_config->c_file ); /* If we got this far and failed, it may be a serious problem. In server * mode, we should never come to this. However, it may be alright if we're @@ -2561,6 +2741,20 @@ read_config(const char *fname, const char *dir) { } break; } + +done: + if ( rc == 0 && BER_BVISNULL( &frontendDB->be_schemadn ) ) { + ber_str2bv( SLAPD_SCHEMA_DN, STRLENOF( SLAPD_SCHEMA_DN ), 1, + &frontendDB->be_schemadn ); + rc = dnNormalize( 0, NULL, NULL, &frontendDB->be_schemadn, &frontendDB->be_schemandn, NULL ); + if ( rc != LDAP_SUCCESS ) { + Debug(LDAP_DEBUG_ANY, "read_config: " + "unable to normalize default schema DN \"%s\"\n", + frontendDB->be_schemadn.bv_val, 0, 0 ); + /* must not happen */ + assert( 0 ); + } + } return rc; } @@ -2606,7 +2800,7 @@ config_send( Operation *op, SlapReply *rs, CfEntryInfo *ce, int depth ) } static ConfigTable * -config_find_table( CfOcInfo **colst, int nocs, AttributeDescription *ad ) +config_find_table( ConfigOCs **colst, int nocs, AttributeDescription *ad ) { int i, j; @@ -2625,7 +2819,7 @@ config_find_table( CfOcInfo **colst, int nocs, AttributeDescription *ad ) * 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; @@ -2708,8 +2902,9 @@ check_vals( ConfigTable *ct, ConfigArgs *ca, void *ptr, int isAttr ) if ( idx ) ca->line = idx+1; } rc = config_parse_vals( ct, ca, i ); - if ( rc ) + if ( rc ) { break; + } } return rc; } @@ -2744,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 */ @@ -2837,20 +3037,20 @@ check_name_index( CfEntryInfo *parent, ConfigType ce_type, Entry *e, return 0; } -static CfOcInfo ** +static ConfigOCs ** count_ocs( Attribute *oc_at, int *nocs ) { int i, j, n; - CfOcInfo co, *coptr, **colst; + ConfigOCs co, *coptr, **colst; /* count the objectclasses */ for ( i=0; oc_at->a_nvals[i].bv_val; i++ ); n = i; - colst = (CfOcInfo **)ch_malloc( n * sizeof(CfOcInfo *)); + 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. @@ -2866,18 +3066,87 @@ count_ocs( Attribute *oc_at, int *nocs ) return colst; } +static int +cfAddInclude( CfEntryInfo *p, Entry *e, ConfigArgs *ca ) +{ + if ( p->ce_type != Cft_Global && p->ce_type != Cft_Include ) + return LDAP_CONSTRAINT_VIOLATION; + + /* If we're reading from a configdir, don't parse this entry */ + if ( ca->lineno ) + return LDAP_COMPARE_TRUE; + + 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, SlapReply *rs, int *renum ) +config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca, SlapReply *rs, int *renum ) { CfEntryInfo *ce, *last; - CfOcInfo **colst; - Attribute *a, *oc_at, *type_attr; - AttributeDescription *type_ad = NULL; - int i, j, nocs, rc = 0; - ConfigArgs ca = {0}; + ConfigOCs **colst; + Attribute *a, *oc_at; + int i, nocs, rc = 0; struct berval pdn; - ConfigTable *ct, *type_ct = NULL; + ConfigTable *ct; char *ptr; /* Make sure parent exists and entry does not */ @@ -2899,121 +3168,58 @@ config_add_internal( CfBackInfo *cfb, Entry *e, SlapReply *rs, int *renum ) oc_at = attr_find( e->e_attrs, slap_schema.si_ad_objectClass ); if ( !oc_at ) return LDAP_OBJECT_CLASS_VIOLATION; + memset( ca, 0, sizeof(ConfigArgs)); + + /* Fake the coordinates based on whether we're part of an + * LDAP Add or if reading the config dir + */ + if ( rs ) { + ca->fname = "slapd"; + ca->lineno = 0; + } 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. */ - 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; + 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; } - sort_attrs( e, colst, nocs ); - - /* Parse all the values and check for simple syntax errors before - * performing any set actions. + /* Check whether the Add is allowed by its parent, and do + * any necessary arg setup */ - 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 */ - ca.private = ch_calloc( 1, sizeof(ConfigFile) ); - cfn = ca.private; - case Cft_Global: - ca.be = LDAP_STAILQ_FIRST(&backendDB); - break; - - 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; + if ( last ) { + for ( i=0; ico_ldadd && + ( rc = colst[i]->co_ldadd( last, e, ca )) + != LDAP_CONSTRAINT_VIOLATION ) { + break; + } } - break; - - case Cft_Overlay: - ca.be = last->ce_be; - type_ad = cfAd_overlay; - break; + } - case Cft_Include: - if ( !rs ) { - nocs = 0; /* ignored */ - break; - } - if ( last->ce_type == Cft_Global ) - cfn = &cf_prv; - else - cfn = last->ce_private; - type_ad = cfAd_include; - break; -#ifdef SLAPD_MODULES - case Cft_Module: { -#if 0 - 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; -#endif - } - break; -#endif + /* Add the entry but don't parse it, we already have its contents */ + if ( rc == LDAP_COMPARE_TRUE ) { + rc = LDAP_SUCCESS; + goto ok; } - /* If doing an LDAPadd, check for indexed names and any necessary + 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 @@ -3030,55 +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; - } - type_ct = config_find_table( colst, nocs, type_ad ); - if ( !type_ct ) { - rc = LDAP_OBJECT_CLASS_VIOLATION; - goto leave; - } - rc = check_vals( type_ct, &ca, type_attr, 1); - if ( rc ) goto leave; - } + init_config_argv( ca ); + + /* Make sure we process attrs in the required order */ + sort_attrs( e, colst, nocs ); + for ( a=e->e_attrs; a; a=a->a_next ) { - if ( a == type_attr || a == oc_at ) continue; + if ( a == oc_at ) continue; ct = config_find_table( colst, nocs, a->a_desc ); if ( !ct ) continue; /* user data? */ - rc = check_vals( ct, &ca, a, 1 ); + rc = check_vals( ct, ca, a, 1 ); if ( rc ) goto leave; } /* 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 ) { - ptr = strchr( ca.line, '}' ); - if ( ptr ) ca.line = ptr+1; - } - ca.valx = 0; - rc = config_parse_add( type_ct, &ca ); - 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; + 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; + ca->line = a->a_vals[i].bv_val; if ( a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED ) { - ptr = strchr( ca.line, '}' ); - if ( ptr ) ca.line = ptr+1; + ptr = strchr( ca->line, '}' ); + if ( ptr ) ca->line = ptr+1; } - ca.valx = i; - rc = config_parse_add( ct, &ca ); + ca->valx = i; + rc = config_parse_add( ct, ca ); if ( rc ) { rc = LDAP_OTHER; goto leave; @@ -3086,14 +3269,36 @@ config_add_internal( CfBackInfo *cfb, Entry *e, SlapReply *rs, int *renum ) } } ok: + /* Newly added databases and overlays need to be started up */ + if ( CONFIG_ONLINE_ADD( ca )) { + if ( colst[0]->co_type == Cft_Database ) { + rc = backend_startup_one( ca->be ); + + } else if ( colst[0]->co_type == Cft_Overlay ) { + if ( ca->bi->bi_db_open ) { + BackendInfo *bi_orig = ca->be->bd_info; + ca->be->bd_info = ca->bi; + rc = ca->bi->bi_db_open( ca->be ); + ca->be->bd_info = bi_orig; + } + } + if ( rc ) { + sprintf( ca->msg, "<%s> failed startup", ca->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s (%s)!\n", + ca->log, ca->msg, ca->argv[1] ); + rc = LDAP_OTHER; + goto leave; + } + } + ce = ch_calloc( 1, sizeof(CfEntryInfo) ); ce->ce_parent = last; ce->ce_entry = entry_dup( e ); ce->ce_entry->e_private = ce; ce->ce_type = colst[0]->co_type; - ce->ce_be = ca.be; - ce->ce_bi = ca.bi; - ce->ce_private = ca.private; + ce->ce_be = ca->be; + ce->ce_bi = ca->bi; + ce->ce_private = ca->private; if ( !last ) { cfb->cb_root = ce; } else if ( last->ce_kids ) { @@ -3107,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; } @@ -3119,8 +3333,8 @@ static int config_back_add( Operation *op, SlapReply *rs ) { CfBackInfo *cfb; - CfEntryInfo *ce, *last; int renumber; + ConfigArgs ca; if ( !be_isroot( op ) ) { rs->sr_err = LDAP_INSUFFICIENT_ACCESS; @@ -3138,8 +3352,10 @@ config_back_add( Operation *op, SlapReply *rs ) * 4) store entry in underlying database * 5) perform any necessary renumbering */ - rs->sr_err = config_add_internal( cfb, op->ora_e, rs, &renumber ); - if ( rs->sr_err == LDAP_SUCCESS && cfb->cb_use_ldif ) { + rs->sr_err = config_add_internal( cfb, op->ora_e, &ca, rs, &renumber ); + if ( rs->sr_err != LDAP_SUCCESS ) { + rs->sr_text = ca.msg; + } else if ( cfb->cb_use_ldif ) { BackendDB *be = op->o_bd; slap_callback sc = { NULL, slap_null_cb, NULL, NULL }; op->o_bd = &cfb->cb_db; @@ -3162,20 +3378,19 @@ out: typedef struct delrec { struct delrec *next; int nidx; - int idx[0]; + int idx[1]; } delrec; static int config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs, ConfigArgs *ca ) { - CfBackInfo *cfb = (CfBackInfo *)op->o_bd->be_private; int rc = LDAP_UNWILLING_TO_PERFORM; Modifications *ml; Entry *e = ce->ce_entry; Attribute *save_attrs = e->e_attrs, *oc_at; ConfigTable *ct; - CfOcInfo **colst; + ConfigOCs **colst; int i, nocs; char *ptr; delrec *dels = NULL, *deltail = NULL; @@ -3191,6 +3406,7 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs, 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) { @@ -3202,8 +3418,6 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs, int *idx = NULL; if ( ct && ( ct->arg_type & ARG_NO_DELETE )) { rc = LDAP_OTHER; - snprintf( ca->msg, sizeof(ca->msg), - "<%s> cannot be deleted" ); snprintf(ca->msg, sizeof(ca->msg), "cannot delete %s", ml->sml_desc->ad_cname.bv_val ); goto out; @@ -3220,7 +3434,7 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs, if ( ct && ml->sml_values ) { delrec *d; for (i=0; ml->sml_values[i].bv_val; i++); - d = ch_malloc( sizeof(delrec) + i * sizeof(int)); + d = ch_malloc( sizeof(delrec) + (i - 1)* sizeof(int)); d->nidx = i; d->next = NULL; if ( dels ) { @@ -3299,8 +3513,8 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs, if(rc == LDAP_SUCCESS) { /* check that the entry still obeys the schema */ - rc = entry_schema_check(op->o_bd, e, NULL, - &rs->sr_text, ca->msg, sizeof(ca->msg) ); + rc = entry_schema_check(op, e, NULL, 0, + &rs->sr_text, ca->msg, sizeof(ca->msg) ); } if ( rc == LDAP_SUCCESS ) { /* Basic syntax checks are OK. Do the actual settings. */ @@ -3523,7 +3737,6 @@ config_back_search( Operation *op, SlapReply *rs ) { CfBackInfo *cfb; CfEntryInfo *ce, *last; - int rc; if ( !be_isroot( op ) ) { rs->sr_err = LDAP_INSUFFICIENT_ACCESS; @@ -3558,121 +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 val; - struct berval ad_name; - AttributeDescription *ad = NULL; - int rc, i; - char *ptr; - const char *text; - AttributeType **at; - Attribute *oc_at; - val = oc->soc_cname; - attr_merge_normalize_one(e, slap_schema.si_ad_objectClass, &val, 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; } 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) { - 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; - } - } - } + 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) { - 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; - } - } - } + 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) { - if ( c->rvalue_nvals ) - attr_merge(e, ct->ad, c->rvalue_vals, c->rvalue_nvals); - else - attr_merge_normalize(e, ct->ad, c->rvalue_vals, NULL); - } - } + 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, &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 @@ -3681,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]); @@ -3708,115 +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_private = cf; - ce->ce_type = Cft_Schema; - if ( op ) { - 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 ); - if ( op ) { - op->ora_e = e; - op->o_bd->be_add( op, rs ); - } - ce = e->e_private; - ce->ce_private = cf; - 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; - ce->ce_private = mp; - config_build_entry( c, e, cfOc_module, &c->value_dn, - c->bi->bi_cf_table, NO_TABLE ); - if ( op ) { - 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 @@ -3826,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; @@ -3858,61 +4001,44 @@ config_back_db_open( BackendDB *be ) /* 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; - ce->ce_private = c.private; - config_build_entry( &c, e, cfOc_global, &rdn, ct, NO_TABLE ); - if ( op ) { - 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 ); - if ( op ) { - 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. @@ -3920,117 +4046,145 @@ config_back_db_open( BackendDB *be ) 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 ); - if ( op ) { - 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 ); - if ( op ) { - 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 ); - if ( op ) { - 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 ); @@ -4119,9 +4273,10 @@ config_tool_entry_put( BackendDB *be, Entry *e, struct berval *text ) { CfBackInfo *cfb = be->be_private; BackendInfo *bi = cfb->cb_db.bd_info; + ConfigArgs ca; if ( bi && bi->bi_tool_entry_put && - config_add_internal( cfb, e, NULL, NULL ) == 0 ) + config_add_internal( cfb, e, &ca, NULL, NULL ) == 0 ) return bi->bi_tool_entry_put( &cfb->cb_db, e, text ); else return NOID; @@ -4184,7 +4339,7 @@ config_back_initialize( BackendInfo *bi ) bi->bi_db_init = config_back_db_init; bi->bi_db_config = 0; bi->bi_db_open = config_back_db_open; - bi->bi_db_close = 0; + bi->bi_db_close = config_back_db_close; bi->bi_db_destroy = config_back_db_destroy; bi->bi_op_bind = config_back_bind; @@ -4215,6 +4370,9 @@ config_back_initialize( BackendInfo *bi ) bi->bi_tool_entry_get = config_tool_entry_get; bi->bi_tool_entry_put = config_tool_entry_put; + /* Make sure we don't exceed the bits reserved for userland */ + assert( ( ( CFG_LAST - 1 ) & ARGS_USERLAND ) == ( CFG_LAST - 1 ) ); + argv[3] = NULL; for (i=0; OidMacros[i].name; i++ ) { argv[1] = OidMacros[i].name; @@ -4222,7 +4380,7 @@ 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;