X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fbconfig.c;h=7dee51a505810a064e41b55a5a4529edcff6be6b;hb=9992d5c43a31265cf840d3972eb132732f8dccf2;hp=79b99d1fec32cde3da176ac389333daf91bf9a7a;hpb=d316b89bc3be5cebd0b659637df3337a2d588371;p=openldap diff --git a/servers/slapd/bconfig.c b/servers/slapd/bconfig.c index 79b99d1fec..7dee51a505 100644 --- a/servers/slapd/bconfig.c +++ b/servers/slapd/bconfig.c @@ -2,7 +2,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 2005-2007 The OpenLDAP Foundation. + * Copyright 2005-2009 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,6 +25,7 @@ #include #include #include +#include #include "slap.h" @@ -63,6 +64,7 @@ typedef struct ConfigFile { ContentRule *c_cr_head, *c_cr_tail; ObjectClass *c_oc_head, *c_oc_tail; OidMacro *c_om_head, *c_om_tail; + Syntax *c_syn_head, *c_syn_tail; BerVarray c_dseFiles; } ConfigFile; @@ -77,6 +79,7 @@ typedef struct { static CfBackInfo cfBackInfo; static char *passwd_salt; +static FILE *logfile; static char *logfileName; #ifdef SLAP_AUTH_REWRITE static BerVarray authz_rewrites; @@ -86,7 +89,7 @@ static struct berval cfdir; /* Private state */ static AttributeDescription *cfAd_backend, *cfAd_database, *cfAd_overlay, - *cfAd_include, *cfAd_attr, *cfAd_oc, *cfAd_om; + *cfAd_include, *cfAd_attr, *cfAd_oc, *cfAd_om, *cfAd_syntax; static ConfigFile *cfn; @@ -96,9 +99,11 @@ static Avlnode *CfOcTree; extern AttributeType *at_sys_tail; /* at.c */ extern ObjectClass *oc_sys_tail; /* oc.c */ extern OidMacro *om_sys_tail; /* oidm.c */ +extern Syntax *syn_sys_tail; /* syntax.c */ static AttributeType *cf_at_tail; static ObjectClass *cf_oc_tail; static OidMacro *cf_om_tail; +static Syntax *cf_syn_tail; static int config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca, SlapReply *rs, int *renumber, Operation *op ); @@ -116,6 +121,9 @@ static ConfigDriver config_timelimit; static ConfigDriver config_overlay; static ConfigDriver config_subordinate; static ConfigDriver config_suffix; +#ifdef LDAP_TCP_BUFFER +static ConfigDriver config_tcp_buffer; +#endif /* LDAP_TCP_BUFFER */ static ConfigDriver config_rootdn; static ConfigDriver config_rootpw; static ConfigDriver config_restrict; @@ -141,6 +149,7 @@ enum { CFG_DATABASE, CFG_TLS_RAND, CFG_TLS_CIPHER, + CFG_TLS_PROTOCOL_MIN, CFG_TLS_CERT_FILE, CFG_TLS_CERT_KEY, CFG_TLS_CA_PATH, @@ -177,6 +186,11 @@ enum { CFG_HIDDEN, CFG_MONITORING, CFG_SERVERID, + CFG_SORTVALS, + CFG_IX_INTLEN, + CFG_SYNTAX, + CFG_ACL_ADD, + CFG_SYNC_SUBENTRY, CFG_LAST }; @@ -186,18 +200,20 @@ typedef struct { } OidRec; static OidRec OidMacros[] = { - /* OpenLDAProot:666.11.1 */ - { "OLcfg", "1.3.6.1.4.1.4203.666.11.1" }, + /* OpenLDAProot:1.12.2 */ + { "OLcfg", "1.3.6.1.4.1.4203.1.12.2" }, { "OLcfgAt", "OLcfg:3" }, { "OLcfgGlAt", "OLcfgAt:0" }, { "OLcfgBkAt", "OLcfgAt:1" }, { "OLcfgDbAt", "OLcfgAt:2" }, { "OLcfgOvAt", "OLcfgAt:3" }, + { "OLcfgCtAt", "OLcfgAt:4" }, /* contrib modules */ { "OLcfgOc", "OLcfg:4" }, { "OLcfgGlOc", "OLcfgOc:0" }, { "OLcfgBkOc", "OLcfgOc:1" }, { "OLcfgDbOc", "OLcfgOc:2" }, { "OLcfgOvOc", "OLcfgOc:3" }, + { "OLcfgCtOc", "OLcfgOc:4" }, /* contrib modules */ /* Syntaxes. We should just start using the standard names and * document that they are predefined and available for users @@ -208,6 +224,7 @@ static OidRec OidMacros[] = { { "OMsBoolean", "OMsyn:7" }, { "OMsDN", "OMsyn:12" }, { "OMsDirectoryString", "OMsyn:15" }, + { "OMsIA5String", "OMsyn:26" }, { "OMsInteger", "OMsyn:27" }, { "OMsOID", "OMsyn:38" }, { "OMsOctetString", "OMsyn:40" }, @@ -224,6 +241,7 @@ static OidRec OidMacros[] = { * OLcfg{Bk|Db}{Oc|At}:4 -> back-monitor * OLcfg{Bk|Db}{Oc|At}:5 -> back-relay * OLcfg{Bk|Db}{Oc|At}:6 -> back-sql + * OLcfg{Bk|Db}{Oc|At}:7 -> back-sock */ /* @@ -234,8 +252,6 @@ static OidRec OidMacros[] = { * OLcfgOv{Oc|At}:3 -> chain * OLcfgOv{Oc|At}:4 -> accesslog * OLcfgOv{Oc|At}:5 -> valsort - * (FIXME: separate arc for contribware?) - * OLcfgOv{Oc|At}:6 -> smbk5pwd * OLcfgOv{Oc|At}:7 -> distproc * OLcfgOv{Oc|At}:8 -> dynlist * OLcfgOv{Oc|At}:9 -> dds @@ -249,6 +265,8 @@ static OidRec OidMacros[] = { * OLcfgOv{Oc|At}:17 -> dyngroup * OLcfgOv{Oc|At}:18 -> memberof * OLcfgOv{Oc|At}:19 -> collect + * OLcfgOv{Oc|At}:20 -> retcode + * OLcfgOv{Oc|At}:21 -> sssvlv */ /* alphabetical ordering */ @@ -270,6 +288,10 @@ static ConfigTable config_back_cf_table[] = { "DESC 'Access Control List' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL }, + { "add_content_acl", NULL, 0, 0, 0, ARG_MAY_DB|ARG_ON_OFF|ARG_MAGIC|CFG_ACL_ADD, + &config_generic, "( OLcfgGlAt:86 NAME 'olcAddContentAcl' " + "DESC 'Check ACLs against content of Add ops' " + "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, { "allows", "features", 2, 0, 5, ARG_PRE_DB|ARG_MAGIC, &config_allows, "( OLcfgGlAt:2 NAME 'olcAllows' " "DESC 'Allowed set of deprecated features' " @@ -304,7 +326,7 @@ static ConfigTable config_back_cf_table[] = { &config_generic, "( OLcfgGlAt:7 NAME 'olcAuthzPolicy' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, - { "authz-regexp", NULL, 3, 3, 0, ARG_MAGIC|CFG_AZREGEXP|ARG_NO_INSERT, + { "authz-regexp", "regexp> ] [{read|write}=]size", 0, 0, 0, +#ifndef LDAP_TCP_BUFFER + ARG_IGNORED, NULL, +#else /* LDAP_TCP_BUFFER */ + ARG_MAGIC, &config_tcp_buffer, +#endif /* LDAP_TCP_BUFFER */ + "( OLcfgGlAt:90 NAME 'olcTCPBuffer' " + "DESC 'Custom TCP buffer size' " + "SYNTAX OMsDirectoryString )", NULL, NULL }, { "threads", "count", 2, 2, 0, #ifdef NO_THREADS ARG_IGNORED, NULL, @@ -653,6 +713,14 @@ static ConfigTable config_back_cf_table[] = { #endif "( OLcfgGlAt:77 NAME 'olcTLSDHParamFile' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, + { "TLSProtocolMin", NULL, 0, 0, 0, +#ifdef HAVE_TLS + CFG_TLS_PROTOCOL_MIN|ARG_STRING|ARG_MAGIC, &config_tls_config, +#else + ARG_IGNORED, NULL, +#endif + "( OLcfgGlAt:87 NAME 'olcTLSProtocolMin' " + "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, { "tool-threads", "count", 2, 2, 0, ARG_INT|ARG_MAGIC|CFG_TTHREADS, &config_generic, "( OLcfgGlAt:80 NAME 'olcToolThreads' " "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, @@ -665,10 +733,22 @@ static ConfigTable config_back_cf_table[] = { &config_updateref, "( OLcfgDbAt:0.13 NAME 'olcUpdateRef' " "EQUALITY caseIgnoreMatch " "SUP labeledURI )", NULL, NULL }, + { "writetimeout", "timeout", 2, 2, 0, ARG_INT, + &global_writetimeout, "( OLcfgGlAt:88 NAME 'olcWriteTimeout' " + "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, { NULL, NULL, 0, 0, 0, ARG_IGNORED, NULL, NULL, NULL, NULL } }; +/* Need to no-op this keyword for dynamic config */ +ConfigTable olcDatabaseDummy[] = { + { "", "", 0, 0, 0, ARG_IGNORED, + NULL, "( OLcfgGlAt:13 NAME 'olcDatabase' " + "DESC 'The backend type for a database instance' " + "SUP olcBackend SINGLE-VALUE X-ORDERED 'SIBLINGS' )", NULL, NULL }, + { NULL, NULL, 0, 0, 0, ARG_IGNORED } +}; + /* Routines to check if a child can be added to this type */ static ConfigLDAPadd cfAddSchema, cfAddInclude, cfAddDatabase, cfAddBackend, cfAddModule, cfAddOverlay; @@ -701,28 +781,29 @@ static ConfigOCs cf_ocs[] = { "olcConnMaxPending $ olcConnMaxPendingAuth $ " "olcDisallows $ olcGentleHUP $ olcIdleTimeout $ " "olcIndexSubstrIfMaxLen $ olcIndexSubstrIfMinLen $ " - "olcIndexSubstrAnyLen $ olcIndexSubstrAnyStep $ olcLocalSSF $ " - "olcLogLevel $ " + "olcIndexSubstrAnyLen $ olcIndexSubstrAnyStep $ olcIndexIntLen $ " + "olcLocalSSF $ olcLogFile $ olcLogLevel $ " "olcPasswordCryptSaltFormat $ olcPasswordHash $ olcPidFile $ " "olcPluginLogFile $ olcReadOnly $ olcReferral $ " "olcReplogFile $ olcRequires $ olcRestrict $ olcReverseLookup $ " "olcRootDSE $ " - "olcSaslHost $ olcSaslRealm $ olcSaslSecProps $ " + "olcSaslAuxprops $ olcSaslHost $ olcSaslRealm $ olcSaslSecProps $ " "olcSecurity $ olcServerID $ olcSizeLimit $ " "olcSockbufMaxIncoming $ olcSockbufMaxIncomingAuth $ " + "olcTCPBuffer $ " "olcThreads $ olcTimeLimit $ olcTLSCACertificateFile $ " "olcTLSCACertificatePath $ olcTLSCertificateFile $ " "olcTLSCertificateKeyFile $ olcTLSCipherSuite $ olcTLSCRLCheck $ " "olcTLSRandFile $ olcTLSVerifyClient $ olcTLSDHParamFile $ " - "olcTLSCRLFile $ olcToolThreads $ " + "olcTLSCRLFile $ olcToolThreads $ olcWriteTimeout $ " "olcObjectIdentifier $ olcAttributeTypes $ olcObjectClasses $ " - "olcDitContentRules ) )", Cft_Global }, + "olcDitContentRules $ olcLdapSyntaxes ) )", Cft_Global }, { "( OLcfgGlOc:2 " "NAME 'olcSchemaConfig' " "DESC 'OpenLDAP schema object' " "SUP olcConfig STRUCTURAL " "MAY ( cn $ olcObjectIdentifier $ olcAttributeTypes $ " - "olcObjectClasses $ olcDitContentRules ) )", + "olcObjectClasses $ olcDitContentRules $ olcLdapSyntaxes ) )", Cft_Schema, NULL, cfAddSchema }, { "( OLcfgGlOc:3 " "NAME 'olcBackendConfig' " @@ -735,11 +816,11 @@ static ConfigOCs cf_ocs[] = { "SUP olcConfig STRUCTURAL " "MUST olcDatabase " "MAY ( olcHidden $ olcSuffix $ olcSubordinate $ olcAccess $ " - "olcLastMod $ olcLimits $ " + "olcAddContentAcl $ olcLastMod $ olcLimits $ " "olcMaxDerefDepth $ olcPlugin $ olcReadOnly $ olcReplica $ " "olcReplicaArgsFile $ olcReplicaPidFile $ olcReplicationInterval $ " "olcReplogFile $ olcRequires $ olcRestrict $ olcRootDN $ olcRootPW $ " - "olcSchemaDN $ olcSecurity $ olcSizeLimit $ olcSyncrepl $ " + "olcSchemaDN $ olcSecurity $ olcSizeLimit $ olcSyncUseSubentry $ olcSyncrepl $ " "olcTimeLimit $ olcUpdateDN $ olcUpdateRef $ olcMirrorMode $ " "olcMonitoring ) )", Cft_Database, NULL, cfAddDatabase }, @@ -764,7 +845,7 @@ static ConfigOCs cf_ocs[] = { "NAME 'olcFrontendConfig' " "DESC 'OpenLDAP frontend configuration' " "AUXILIARY " - "MAY ( olcDefaultSearchBase $ olcPasswordHash ) )", + "MAY ( olcDefaultSearchBase $ olcPasswordHash $ olcSortVals ) )", Cft_Database, NULL, NULL }, #ifdef SLAPD_MODULES { "( OLcfgGlOc:8 " @@ -785,6 +866,18 @@ typedef struct ServerID { static ServerID *sid_list; +typedef struct voidList { + struct voidList *vl_next; + void *vl_ptr; +} voidList; + +typedef struct ADlist { + struct ADlist *al_next; + AttributeDescription *al_desc; +} ADlist; + +static ADlist *sortVals; + static int config_generic(ConfigArgs *c) { int i; @@ -831,8 +924,7 @@ config_generic(ConfigArgs *c) { if ( !c->rvalue_vals ) rc = 1; break; case CFG_RO: - c->value_int = (c->be->be_restrictops & SLAP_RESTRICT_OP_WRITES) == - SLAP_RESTRICT_OP_WRITES; + c->value_int = (c->be->be_restrictops & SLAP_RESTRICT_READONLY); break; case CFG_AZPOLICY: c->value_string = ch_strdup( slap_sasl_getpolicy()); @@ -864,7 +956,7 @@ config_generic(ConfigArgs *c) { } break; case CFG_OID: { - ConfigFile *cf = c->private; + ConfigFile *cf = c->ca_private; if ( !cf ) oidm_unparse( &c->rvalue_vals, NULL, NULL, 1 ); else if ( cf->c_om_head ) @@ -878,7 +970,7 @@ config_generic(ConfigArgs *c) { ad_unparse_options( &c->rvalue_vals ); break; case CFG_OC: { - ConfigFile *cf = c->private; + ConfigFile *cf = c->ca_private; if ( !cf ) oc_unparse( &c->rvalue_vals, NULL, NULL, 1 ); else if ( cf->c_oc_head ) @@ -889,7 +981,7 @@ config_generic(ConfigArgs *c) { } break; case CFG_ATTR: { - ConfigFile *cf = c->private; + ConfigFile *cf = c->ca_private; if ( !cf ) at_unparse( &c->rvalue_vals, NULL, NULL, 1 ); else if ( cf->c_at_head ) @@ -899,8 +991,19 @@ config_generic(ConfigArgs *c) { rc = 1; } break; + case CFG_SYNTAX: { + ConfigFile *cf = c->ca_private; + if ( !cf ) + syn_unparse( &c->rvalue_vals, NULL, NULL, 1 ); + else if ( cf->c_syn_head ) + syn_unparse( &c->rvalue_vals, cf->c_syn_head, + cf->c_syn_tail, 0 ); + if ( !c->rvalue_vals ) + rc = 1; + } + break; case CFG_DIT: { - ConfigFile *cf = c->private; + ConfigFile *cf = c->ca_private; if ( !cf ) cr_unparse( &c->rvalue_vals, NULL, NULL, 1 ); else if ( cf->c_cr_head ) @@ -942,8 +1045,11 @@ config_generic(ConfigArgs *c) { rc = (!i); break; } + case CFG_ACL_ADD: + c->value_int = (SLAP_DBACL_ADD(c->be) != 0); + break; case CFG_ROOTDSE: { - ConfigFile *cf = c->private; + ConfigFile *cf = c->ca_private; if ( cf->c_dseFiles ) { value_add( &c->rvalue_vals, cf->c_dseFiles ); } else { @@ -961,7 +1067,7 @@ config_generic(ConfigArgs *c) { if ( !BER_BVISEMPTY( &si->si_url )) { bv.bv_len = si->si_url.bv_len + 6; bv.bv_val = ch_malloc( bv.bv_len ); - sprintf( bv.bv_val, "%d %s", si->si_num, + bv.bv_len = sprintf( bv.bv_val, "%d %s", si->si_num, si->si_url.bv_val ); ber_bvarray_add( &c->rvalue_vals, &bv ); } else { @@ -984,6 +1090,9 @@ config_generic(ConfigArgs *c) { case CFG_LASTMOD: c->value_int = (SLAP_NOLASTMOD(c->be) == 0); break; + case CFG_SYNC_SUBENTRY: + c->value_int = (SLAP_SYNC_SUBENTRY(c->be) != 0); + break; case CFG_MIRRORMODE: if ( SLAP_SHADOW(c->be)) c->value_int = (SLAP_SINGLE_SHADOW(c->be) == 0); @@ -994,14 +1103,25 @@ config_generic(ConfigArgs *c) { c->value_int = (SLAP_DBMONITORING(c->be) != 0); break; case CFG_SSTR_IF_MAX: - c->value_int = index_substr_if_maxlen; + c->value_uint = index_substr_if_maxlen; break; case CFG_SSTR_IF_MIN: - c->value_int = index_substr_if_minlen; + c->value_uint = index_substr_if_minlen; + break; + case CFG_IX_INTLEN: + c->value_int = index_intlen; break; + case CFG_SORTVALS: { + ADlist *sv; + rc = 1; + for ( sv = sortVals; sv; sv = sv->al_next ) { + value_add_one( &c->rvalue_vals, &sv->al_desc->ad_cname ); + rc = 0; + } + } break; #ifdef SLAPD_MODULES case CFG_MODLOAD: { - ModPaths *mp = c->private; + ModPaths *mp = c->ca_private; if (mp->mp_loads) { int i; for (i=0; !BER_BVISNULL(&mp->mp_loads[i]); i++) { @@ -1023,7 +1143,7 @@ config_generic(ConfigArgs *c) { } break; case CFG_MODPATH: { - ModPaths *mp = c->private; + ModPaths *mp = c->ca_private; if ( !BER_BVISNULL( &mp->mp_path )) value_add_one( &c->rvalue_vals, &mp->mp_path ); @@ -1084,6 +1204,8 @@ config_generic(ConfigArgs *c) { case CFG_SASLSECP: case CFG_SSTR_IF_MAX: case CFG_SSTR_IF_MIN: + case CFG_ACL_ADD: + case CFG_SYNC_SUBENTRY: break; /* no-ops, requires slapd restart */ @@ -1102,6 +1224,10 @@ config_generic(ConfigArgs *c) { case CFG_LOGFILE: ch_free( logfileName ); logfileName = NULL; + if ( logfile ) { + fclose( logfile ); + logfile = NULL; + } break; case CFG_SERVERID: { @@ -1124,15 +1250,16 @@ config_generic(ConfigArgs *c) { c->be->be_flags &= ~SLAP_DBFLAG_HIDDEN; break; + case CFG_IX_INTLEN: + index_intlen = SLAP_INDEX_INTLEN_DEFAULT; + index_intlen_strlen = SLAP_INDEX_INTLEN_STRLEN( + SLAP_INDEX_INTLEN_DEFAULT ); + 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 ); - c->be->be_acl = end; + acl_destroy( c->be->be_acl ); + c->be->be_acl = NULL; } else { AccessControl **prev, *a; @@ -1158,7 +1285,7 @@ config_generic(ConfigArgs *c) { return 1; } } - cfn = c->private; + cfn = c->ca_private; if ( c->valx < 0 ) { ObjectClass *oc; @@ -1196,7 +1323,7 @@ config_generic(ConfigArgs *c) { return 1; } } - cfn = c->private; + cfn = c->ca_private; if ( c->valx < 0 ) { AttributeType *at; @@ -1224,8 +1351,97 @@ config_generic(ConfigArgs *c) { } break; + case CFG_SYNTAX: { + CfEntryInfo *ce; + /* Can be NULL when undoing a failed add */ + if ( c->ca_entry ) { + ce = c->ca_entry->e_private; + /* can't modify the hardcoded schema */ + if ( ce->ce_parent->ce_type == Cft_Global ) + return 1; + } + } + cfn = c->ca_private; + if ( c->valx < 0 ) { + Syntax *syn; + + for( syn = cfn->c_syn_head; syn; syn_next( &syn )) { + syn_delete( syn ); + if ( syn == cfn->c_syn_tail ) + break; + } + cfn->c_syn_head = cfn->c_syn_tail = NULL; + } else { + Syntax *syn, *prev = NULL; + + for ( i = 0, syn = cfn->c_syn_head; i < c->valx; i++) { + prev = syn; + syn_next( &syn ); + } + syn_delete( syn ); + if ( cfn->c_syn_tail == syn ) { + cfn->c_syn_tail = prev; + } + if ( cfn->c_syn_head == syn ) { + syn_next( &syn ); + cfn->c_syn_head = syn; + } + } + break; + case CFG_SORTVALS: + if ( c->valx < 0 ) { + ADlist *sv; + for ( sv = sortVals; sv; sv = sortVals ) { + sortVals = sv->al_next; + sv->al_desc->ad_type->sat_flags &= ~SLAP_AT_SORTED_VAL; + ch_free( sv ); + } + } else { + ADlist *sv, **prev; + int i = 0; + + for ( prev = &sortVals, sv = sortVals; i < c->valx; i++ ) { + prev = &sv->al_next; + sv = sv->al_next; + } + sv->al_desc->ad_type->sat_flags &= ~SLAP_AT_SORTED_VAL; + *prev = sv->al_next; + ch_free( sv ); + } + break; + case CFG_LIMITS: /* FIXME: there is no limits_free function */ + if ( c->valx < 0 ) { + limits_destroy( c->be->be_limits ); + c->be->be_limits = NULL; + + } else { + int cnt, num = -1; + + if ( c->be->be_limits ) { + for ( num = 0; c->be->be_limits[ num ]; num++ ) + /* just count */ ; + } + + if ( c->valx >= num ) { + return 1; + } + + if ( num == 1 ) { + limits_destroy( c->be->be_limits ); + c->be->be_limits = NULL; + + } else { + limits_free_one( c->be->be_limits[ c->valx ] ); + + for ( cnt = c->valx; cnt < num; cnt++ ) { + c->be->be_limits[ cnt ] = c->be->be_limits[ cnt + 1 ]; + } + } + } + break; + case CFG_ATOPT: /* FIXME: there is no ad_option_free function */ case CFG_ROOTDSE: @@ -1314,9 +1530,9 @@ config_generic(ConfigArgs *c) { case CFG_RO: if(c->value_int) - c->be->be_restrictops |= SLAP_RESTRICT_OP_WRITES; + c->be->be_restrictops |= SLAP_RESTRICT_READONLY; else - c->be->be_restrictops &= ~SLAP_RESTRICT_OP_WRITES; + c->be->be_restrictops &= ~SLAP_RESTRICT_READONLY; break; case CFG_AZPOLICY: @@ -1355,8 +1571,8 @@ config_generic(ConfigArgs *c) { case CFG_OID: { OidMacro *om; - if ( c->op == LDAP_MOD_ADD && c->private && cfn != c->private ) - cfn = c->private; + if ( c->op == LDAP_MOD_ADD && c->ca_private && cfn != c->ca_private ) + cfn = c->ca_private; if(parse_oidm(c, 1, &om)) return(1); if (!cfn->c_om_head) cfn->c_om_head = om; @@ -1367,8 +1583,8 @@ config_generic(ConfigArgs *c) { case CFG_OC: { ObjectClass *oc, *prev; - if ( c->op == LDAP_MOD_ADD && c->private && cfn != c->private ) - cfn = c->private; + if ( c->op == LDAP_MOD_ADD && c->ca_private && cfn != c->ca_private ) + cfn = c->ca_private; if ( c->valx < 0 ) { prev = cfn->c_oc_tail; } else { @@ -1399,8 +1615,8 @@ config_generic(ConfigArgs *c) { case CFG_ATTR: { AttributeType *at, *prev; - if ( c->op == LDAP_MOD_ADD && c->private && cfn != c->private ) - cfn = c->private; + if ( c->op == LDAP_MOD_ADD && c->ca_private && cfn != c->ca_private ) + cfn = c->ca_private; if ( c->valx < 0 ) { prev = cfn->c_at_tail; } else { @@ -1428,11 +1644,43 @@ config_generic(ConfigArgs *c) { } break; + case CFG_SYNTAX: { + Syntax *syn, *prev; + + if ( c->op == LDAP_MOD_ADD && c->ca_private && cfn != c->ca_private ) + cfn = c->ca_private; + if ( c->valx < 0 ) { + prev = cfn->c_syn_tail; + } else { + prev = NULL; + /* If adding anything after the first, prev is easy */ + if ( c->valx ) { + int i; + for ( i = 0, syn = cfn->c_syn_head; i < c->valx; i++ ) { + prev = syn; + syn_next( &syn ); + } + } else + /* If adding the first, and head exists, find its prev */ + if (cfn->c_syn_head) { + for ( syn_start( &syn ); syn != cfn->c_syn_head; ) { + prev = syn; + syn_next( &syn ); + } + } + /* else prev is NULL, append to end of global list */ + } + if ( parse_syn( c, &syn, prev ) ) return(1); + if ( !cfn->c_syn_head ) cfn->c_syn_head = syn; + if ( cfn->c_syn_tail == prev ) cfn->c_syn_tail = syn; + } + break; + case CFG_DIT: { ContentRule *cr; - if ( c->op == LDAP_MOD_ADD && c->private && cfn != c->private ) - cfn = c->private; + if ( c->op == LDAP_MOD_ADD && c->ca_private && cfn != c->ca_private ) + cfn = c->ca_private; if(parse_cr(c, &cr)) return(1); if (!cfn->c_cr_head) cfn->c_cr_head = cr; cfn->c_cr_tail = cr; @@ -1446,14 +1694,70 @@ config_generic(ConfigArgs *c) { return(1); break; + case CFG_IX_INTLEN: + if ( c->value_int < SLAP_INDEX_INTLEN_DEFAULT ) + c->value_int = SLAP_INDEX_INTLEN_DEFAULT; + else if ( c->value_int > 255 ) + c->value_int = 255; + index_intlen = c->value_int; + index_intlen_strlen = SLAP_INDEX_INTLEN_STRLEN( + index_intlen ); + break; + + case CFG_SORTVALS: { + ADlist *svnew = NULL, *svtail, *sv; + + for ( i = 1; i < c->argc; i++ ) { + AttributeDescription *ad = NULL; + const char *text; + int rc; + + rc = slap_str2ad( c->argv[i], &ad, &text ); + if ( rc ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown attribute type #%d", + c->argv[0], i ); +sortval_reject: + Debug(LDAP_DEBUG_ANY, "%s: %s %s\n", + c->log, c->cr_msg, c->argv[i] ); + for ( sv = svnew; sv; sv = svnew ) { + svnew = sv->al_next; + ch_free( sv ); + } + return 1; + } + if (( ad->ad_type->sat_flags & SLAP_AT_ORDERED ) || + ad->ad_type->sat_single_value ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> inappropriate attribute type #%d", + c->argv[0], i ); + goto sortval_reject; + } + sv = ch_malloc( sizeof( ADlist )); + sv->al_desc = ad; + if ( !svnew ) { + svnew = sv; + } else { + svtail->al_next = sv; + } + svtail = sv; + } + sv->al_next = NULL; + for ( sv = svnew; sv; sv = sv->al_next ) + sv->al_desc->ad_type->sat_flags |= SLAP_AT_SORTED_VAL; + for ( sv = sortVals; sv && sv->al_next; sv = sv->al_next ); + if ( sv ) + sv->al_next = svnew; + else + sortVals = svnew; + } + break; + case CFG_ACL: /* Don't append to the global ACL if we're on a specific DB */ i = c->valx; - if ( c->be != frontendDB && frontendDB->be_acl && c->valx == -1 ) { + if ( c->valx == -1 ) { AccessControl *a; i = 0; - for ( a=c->be->be_acl; a && a != frontendDB->be_acl; - a = a->acl_next ) + for ( a=c->be->be_acl; a; a = a->acl_next ) i++; } if ( parse_acl(c->be, c->fname, c->lineno, c->argc, c->argv, i ) ) { @@ -1461,6 +1765,13 @@ config_generic(ConfigArgs *c) { } break; + case CFG_ACL_ADD: + if(c->value_int) + SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_ACL_ADD; + else + SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_ACL_ADD; + break; + case CFG_ROOTDSE: if(root_dse_read_file(c->argv[1])) { snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> could not read file", c->argv[0] ); @@ -1471,8 +1782,8 @@ config_generic(ConfigArgs *c) { { struct berval bv; ber_str2bv( c->argv[1], 0, 1, &bv ); - if ( c->op == LDAP_MOD_ADD && c->private && cfn != c->private ) - cfn = c->private; + if ( c->op == LDAP_MOD_ADD && c->ca_private && cfn != c->ca_private ) + cfn = c->ca_private; ber_bvarray_add( &cfn->c_dseFiles, &bv ); } break; @@ -1482,7 +1793,8 @@ config_generic(ConfigArgs *c) { ServerID *si, **sip; LDAPURLDesc *lud; int num; - if ( lutil_atoi( &num, c->argv[1] ) || + if (( lutil_atoi( &num, c->argv[1] ) && + lutil_atoix( &num, c->argv[1], 16 )) || num < 0 || num > SLAP_SYNC_SID_MAX ) { snprintf( c->cr_msg, sizeof( c->cr_msg ), @@ -1527,7 +1839,7 @@ config_generic(ConfigArgs *c) { BER_BVZERO( &si->si_url ); slap_serverID = num; Debug( LDAP_DEBUG_CONFIG, - "%s: SID=%d\n", + "%s: SID=0x%03x\n", c->log, slap_serverID, 0 ); } si->si_next = NULL; @@ -1536,56 +1848,13 @@ config_generic(ConfigArgs *c) { *sip = si; if (( slapMode & SLAP_SERVER_MODE ) && c->argc > 2 ) { - /* If hostname is empty, or is localhost, or matches - * our hostname, this serverID refers to this host. - * Compare it against listeners and ports. - */ - if ( !lud->lud_host || !lud->lud_host[0] || - !strncasecmp("localhost", lud->lud_host, - STRLENOF("localhost")) || - !strcasecmp( global_host, lud->lud_host )) { - Listener **l = slapd_get_listeners(); - int i; - - for ( i=0; l[i]; i++ ) { - LDAPURLDesc *lu2; - int isMe = 0; - ldap_url_parse( l[i]->sl_url.bv_val, &lu2 ); - do { - if ( strcasecmp( lud->lud_scheme, - lu2->lud_scheme )) - break; - if ( lud->lud_port != lu2->lud_port ) - break; - /* Listener on ANY address */ - if ( !lu2->lud_host || !lu2->lud_host[0] ) { - isMe = 1; - break; - } - /* URL on ANY address */ - if ( !lud->lud_host || !lud->lud_host[0] ) { - isMe = 1; - break; - } - /* Listener has specific host, must - * match it - */ - if ( !strcasecmp( lud->lud_host, - lu2->lud_host )) { - isMe = 1; - break; - } - } while(0); - ldap_free_urldesc( lu2 ); - if ( isMe ) { - slap_serverID = si->si_num; - Debug( LDAP_DEBUG_CONFIG, - "%s: SID=%d (listener=%s)\n", - c->log, slap_serverID, - l[i]->sl_url.bv_val ); - break; - } - } + Listener *l = config_check_my_url( c->argv[2], lud ); + if ( l ) { + slap_serverID = si->si_num; + Debug( LDAP_DEBUG_CONFIG, + "%s: SID=0x%03x (listener=%s)\n", + c->log, slap_serverID, + l->sl_url.bv_val ); } } if ( c->argc > 2 ) @@ -1593,7 +1862,6 @@ config_generic(ConfigArgs *c) { } break; case CFG_LOGFILE: { - FILE *logfile; if ( logfileName ) ch_free( logfileName ); logfileName = c->value_string; logfile = fopen(logfileName, "w"); @@ -1615,7 +1883,7 @@ config_generic(ConfigArgs *c) { break; case CFG_MIRRORMODE: - if(!SLAP_SHADOW(c->be)) { + if(c->value_int && !SLAP_SHADOW(c->be)) { snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> database is not a shadow", c->argv[0] ); Debug(LDAP_DEBUG_ANY, "%s: %s\n", @@ -1642,24 +1910,31 @@ config_generic(ConfigArgs *c) { SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_HIDDEN; break; + case CFG_SYNC_SUBENTRY: + if (c->value_int) + SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_SYNC_SUBENTRY; + else + SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_SYNC_SUBENTRY; + break; + case CFG_SSTR_IF_MAX: - if (c->value_int < index_substr_if_minlen) { + if (c->value_uint < index_substr_if_minlen) { snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid value", c->argv[0] ); Debug(LDAP_DEBUG_ANY, "%s: %s (%d)\n", c->log, c->cr_msg, c->value_int ); return(1); } - index_substr_if_maxlen = c->value_int; + index_substr_if_maxlen = c->value_uint; break; case CFG_SSTR_IF_MIN: - if (c->value_int > index_substr_if_maxlen) { + if (c->value_uint > index_substr_if_maxlen) { snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid value", c->argv[0] ); Debug(LDAP_DEBUG_ANY, "%s: %s (%d)\n", c->log, c->cr_msg, c->value_int ); return(1); } - index_substr_if_minlen = c->value_int; + index_substr_if_minlen = c->value_uint; break; #ifdef SLAPD_MODULES @@ -1667,8 +1942,8 @@ config_generic(ConfigArgs *c) { /* 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; + if ( c->op == LDAP_MOD_ADD && c->ca_private && modcur != c->ca_private ) { + modcur = c->ca_private; /* This should never fail */ if ( module_path( modcur->mp_path.bv_val )) { snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> module path no longer valid", @@ -1716,7 +1991,7 @@ config_generic(ConfigArgs *c) { mp->mp_next = NULL; mp->mp_loads = NULL; modlast = mp; - c->private = mp; + c->ca_private = mp; modcur = mp; } @@ -1735,29 +2010,40 @@ config_generic(ConfigArgs *c) { case CFG_REWRITE: { struct berval bv; char *line; - + int rc = 0; + + if ( c->op == LDAP_MOD_ADD ) { + c->argv++; + c->argc--; + } if(slap_sasl_rewrite_config(c->fname, c->lineno, c->argc, c->argv)) - return(1); + rc = 1; + if ( rc == 0 ) { - if ( c->argc > 1 ) { - char *s; + if ( c->argc > 1 ) { + char *s; - /* quote all args but the first */ - line = ldap_charray2str( c->argv, "\" \"" ); - ber_str2bv( line, 0, 0, &bv ); - s = ber_bvchr( &bv, '"' ); - assert( s != NULL ); - /* move the trailing quote of argv[0] to the end */ - AC_MEMCPY( s, s + 1, bv.bv_len - ( s - bv.bv_val ) ); - bv.bv_val[ bv.bv_len - 1 ] = '"'; + /* quote all args but the first */ + line = ldap_charray2str( c->argv, "\" \"" ); + ber_str2bv( line, 0, 0, &bv ); + s = ber_bvchr( &bv, '"' ); + assert( s != NULL ); + /* move the trailing quote of argv[0] to the end */ + AC_MEMCPY( s, s + 1, bv.bv_len - ( s - bv.bv_val ) ); + bv.bv_val[ bv.bv_len - 1 ] = '"'; - } else { - ber_str2bv( c->argv[ 0 ], 0, 1, &bv ); + } else { + ber_str2bv( c->argv[ 0 ], 0, 1, &bv ); + } + + ber_bvarray_add( &authz_rewrites, &bv ); } - - ber_bvarray_add( &authz_rewrites, &bv ); + if ( c->op == LDAP_MOD_ADD ) { + c->argv--; + c->argc++; + } + return rc; } - break; #endif @@ -1775,8 +2061,8 @@ config_generic(ConfigArgs *c) { static int config_fname(ConfigArgs *c) { if(c->op == SLAP_CONFIG_EMIT) { - if (c->private) { - ConfigFile *cf = c->private; + if (c->ca_private) { + ConfigFile *cf = c->ca_private; value_add_one( &c->rvalue_vals, &cf->c_file ); return 0; } @@ -2012,13 +2298,13 @@ config_overlay(ConfigArgs *c) { assert(0); } if(c->argv[1][0] == '-' && overlay_config(c->be, &c->argv[1][1], - c->valx, &c->bi)) { + c->valx, &c->bi, &c->reply)) { /* log error */ Debug( LDAP_DEBUG_ANY, "%s: (optional) %s overlay \"%s\" configuration failed.\n", c->log, c->be == frontendDB ? "global " : "", &c->argv[1][1]); return 1; - } else if(overlay_config(c->be, c->argv[1], c->valx, &c->bi)) { + } else if(overlay_config(c->be, c->argv[1], c->valx, &c->bi, &c->reply)) { return(1); } return(0); @@ -2028,7 +2314,7 @@ static int config_subordinate(ConfigArgs *c) { int rc = 1; - int advertise; + int advertise = 0; switch( c->op ) { case SLAP_CONFIG_EMIT: @@ -2053,13 +2339,369 @@ config_subordinate(ConfigArgs *c) break; case LDAP_MOD_ADD: case SLAP_CONFIG_ADD: - advertise = ( c->argc == 2 && !strcasecmp( c->argv[1], "advertise" )); + if ( c->be->be_nsuffix == NULL ) { + /* log error */ + snprintf( c->cr_msg, sizeof( c->cr_msg), + "subordinate configuration needs a suffix" ); + Debug( LDAP_DEBUG_ANY, + "%s: %s.\n", + c->log, c->cr_msg, 0 ); + rc = 1; + break; + } + + if ( c->argc == 2 ) { + if ( strcasecmp( c->argv[1], "advertise" ) == 0 ) { + advertise = 1; + + } else if ( strcasecmp( c->argv[1], "TRUE" ) != 0 ) { + /* log error */ + snprintf( c->cr_msg, sizeof( c->cr_msg), + "subordinate must be \"TRUE\" or \"advertise\"" ); + Debug( LDAP_DEBUG_ANY, + "%s: suffix \"%s\": %s.\n", + c->log, c->be->be_suffix[0].bv_val, c->cr_msg ); + rc = 1; + break; + } + } + rc = glue_sub_add( c->be, advertise, CONFIG_ONLINE_ADD( c )); break; } + + return rc; +} + +/* + * [listener=] [{read|write}=] + */ + +#ifdef LDAP_TCP_BUFFER +static BerVarray tcp_buffer; +int tcp_buffer_num; + +#define SLAP_TCP_RMEM (0x1U) +#define SLAP_TCP_WMEM (0x2U) + +static int +tcp_buffer_parse( struct berval *val, int argc, char **argv, + int *size, int *rw, Listener **l ) +{ + int i, rc = LDAP_SUCCESS; + LDAPURLDesc *lud = NULL; + char *ptr; + + if ( val != NULL && argv == NULL ) { + char *s = val->bv_val; + + argv = ldap_str2charray( s, " \t" ); + if ( argv == NULL ) { + return LDAP_OTHER; + } + } + + i = 0; + if ( strncasecmp( argv[ i ], "listener=", STRLENOF( "listener=" ) ) + == 0 ) + { + char *url = argv[ i ] + STRLENOF( "listener=" ); + + if ( ldap_url_parse( url, &lud ) ) { + rc = LDAP_INVALID_SYNTAX; + goto done; + } + + *l = config_check_my_url( url, lud ); + if ( *l == NULL ) { + rc = LDAP_NO_SUCH_ATTRIBUTE; + goto done; + } + + i++; + } + + ptr = argv[ i ]; + if ( strncasecmp( ptr, "read=", STRLENOF( "read=" ) ) == 0 ) { + *rw |= SLAP_TCP_RMEM; + ptr += STRLENOF( "read=" ); + + } else if ( strncasecmp( ptr, "write=", STRLENOF( "write=" ) ) == 0 ) { + *rw |= SLAP_TCP_WMEM; + ptr += STRLENOF( "write=" ); + + } else { + *rw |= ( SLAP_TCP_RMEM | SLAP_TCP_WMEM ); + } + + /* accept any base */ + if ( lutil_atoix( size, ptr, 0 ) ) { + rc = LDAP_INVALID_SYNTAX; + goto done; + } + +done:; + if ( val != NULL && argv != NULL ) { + ldap_charray_free( argv ); + } + + if ( lud != NULL ) { + ldap_free_urldesc( lud ); + } + + return rc; +} + +static int +tcp_buffer_delete_one( struct berval *val ) +{ + int rc = 0; + int size = -1, rw = 0; + Listener *l = NULL; + + rc = tcp_buffer_parse( val, 0, NULL, &size, &rw, &l ); + if ( rc != 0 ) { + return rc; + } + + if ( l != NULL ) { + int i; + Listener **ll = slapd_get_listeners(); + + for ( i = 0; ll[ i ] != NULL; i++ ) { + if ( ll[ i ] == l ) break; + } + + if ( ll[ i ] == NULL ) { + return LDAP_NO_SUCH_ATTRIBUTE; + } + + if ( rw & SLAP_TCP_RMEM ) l->sl_tcp_rmem = -1; + if ( rw & SLAP_TCP_WMEM ) l->sl_tcp_wmem = -1; + + for ( i++ ; ll[ i ] != NULL && bvmatch( &l->sl_url, &ll[ i ]->sl_url ); i++ ) { + if ( rw & SLAP_TCP_RMEM ) ll[ i ]->sl_tcp_rmem = -1; + if ( rw & SLAP_TCP_WMEM ) ll[ i ]->sl_tcp_wmem = -1; + } + + } else { + /* NOTE: this affects listeners without a specific setting, + * does not reset all listeners. If a listener without + * specific settings was assigned a buffer because of + * a global setting, it will not be reset. In any case, + * buffer changes will only take place at restart. */ + if ( rw & SLAP_TCP_RMEM ) slapd_tcp_rmem = -1; + if ( rw & SLAP_TCP_WMEM ) slapd_tcp_wmem = -1; + } + + return rc; +} + +static int +tcp_buffer_delete( BerVarray vals ) +{ + int i; + + for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { + tcp_buffer_delete_one( &vals[ i ] ); + } + + return 0; +} + +static int +tcp_buffer_unparse( int size, int rw, Listener *l, struct berval *val ) +{ + char buf[sizeof("2147483648")], *ptr; + + /* unparse for later use */ + val->bv_len = snprintf( buf, sizeof( buf ), "%d", size ); + if ( l != NULL ) { + val->bv_len += STRLENOF( "listener=" " " ) + l->sl_url.bv_len; + } + + if ( rw != ( SLAP_TCP_RMEM | SLAP_TCP_WMEM ) ) { + if ( rw & SLAP_TCP_RMEM ) { + val->bv_len += STRLENOF( "read=" ); + } else if ( rw & SLAP_TCP_WMEM ) { + val->bv_len += STRLENOF( "write=" ); + } + } + + val->bv_val = SLAP_MALLOC( val->bv_len + 1 ); + + ptr = val->bv_val; + + if ( l != NULL ) { + ptr = lutil_strcopy( ptr, "listener=" ); + ptr = lutil_strncopy( ptr, l->sl_url.bv_val, l->sl_url.bv_len ); + *ptr++ = ' '; + } + + if ( rw != ( SLAP_TCP_RMEM | SLAP_TCP_WMEM ) ) { + if ( rw & SLAP_TCP_RMEM ) { + ptr = lutil_strcopy( ptr, "read=" ); + } else if ( rw & SLAP_TCP_WMEM ) { + ptr = lutil_strcopy( ptr, "write=" ); + } + } + + ptr = lutil_strcopy( ptr, buf ); + *ptr = '\0'; + + assert( val->bv_val + val->bv_len == ptr ); + + return LDAP_SUCCESS; +} + +static int +tcp_buffer_add_one( int argc, char **argv ) +{ + int rc = 0; + int size = -1, rw = 0; + Listener *l = NULL; + + struct berval val; + + /* parse */ + rc = tcp_buffer_parse( NULL, argc, argv, &size, &rw, &l ); + if ( rc != 0 ) { + return rc; + } + + /* unparse for later use */ + rc = tcp_buffer_unparse( size, rw, l, &val ); + if ( rc != LDAP_SUCCESS ) { + return rc; + } + + /* use parsed values */ + if ( l != NULL ) { + int i; + Listener **ll = slapd_get_listeners(); + + for ( i = 0; ll[ i ] != NULL; i++ ) { + if ( ll[ i ] == l ) break; + } + + if ( ll[ i ] == NULL ) { + return LDAP_NO_SUCH_ATTRIBUTE; + } + + /* buffer only applies to TCP listeners; + * we do not do any check here, and delegate them + * to setsockopt(2) */ + if ( rw & SLAP_TCP_RMEM ) l->sl_tcp_rmem = size; + if ( rw & SLAP_TCP_WMEM ) l->sl_tcp_wmem = size; + + for ( i++ ; ll[ i ] != NULL && bvmatch( &l->sl_url, &ll[ i ]->sl_url ); i++ ) { + if ( rw & SLAP_TCP_RMEM ) ll[ i ]->sl_tcp_rmem = size; + if ( rw & SLAP_TCP_WMEM ) ll[ i ]->sl_tcp_wmem = size; + } + + } else { + /* NOTE: this affects listeners without a specific setting, + * does not set all listeners */ + if ( rw & SLAP_TCP_RMEM ) slapd_tcp_rmem = size; + if ( rw & SLAP_TCP_WMEM ) slapd_tcp_wmem = size; + } + + tcp_buffer = SLAP_REALLOC( tcp_buffer, sizeof( struct berval ) * ( tcp_buffer_num + 2 ) ); + /* append */ + tcp_buffer[ tcp_buffer_num ] = val; + + tcp_buffer_num++; + BER_BVZERO( &tcp_buffer[ tcp_buffer_num ] ); + return rc; } +static int +config_tcp_buffer( ConfigArgs *c ) +{ + if ( c->op == SLAP_CONFIG_EMIT ) { + if ( tcp_buffer == NULL || BER_BVISNULL( &tcp_buffer[ 0 ] ) ) { + return 1; + } + value_add( &c->rvalue_vals, tcp_buffer ); + value_add( &c->rvalue_nvals, tcp_buffer ); + + } else if ( c->op == LDAP_MOD_DELETE ) { + if ( !c->line ) { + tcp_buffer_delete( tcp_buffer ); + ber_bvarray_free( tcp_buffer ); + tcp_buffer = NULL; + tcp_buffer_num = 0; + + } else { + int rc = 0; + int size = -1, rw = 0; + Listener *l = NULL; + + struct berval val = BER_BVNULL; + + int i; + + if ( tcp_buffer_num == 0 ) { + return 1; + } + + /* parse */ + rc = tcp_buffer_parse( NULL, c->argc - 1, &c->argv[ 1 ], &size, &rw, &l ); + if ( rc != 0 ) { + return 1; + } + + /* unparse for later use */ + rc = tcp_buffer_unparse( size, rw, l, &val ); + if ( rc != LDAP_SUCCESS ) { + return 1; + } + + for ( i = 0; !BER_BVISNULL( &tcp_buffer[ i ] ); i++ ) { + if ( bvmatch( &tcp_buffer[ i ], &val ) ) { + break; + } + } + + if ( BER_BVISNULL( &tcp_buffer[ i ] ) ) { + /* not found */ + rc = 1; + goto done; + } + + tcp_buffer_delete_one( &tcp_buffer[ i ] ); + ber_memfree( tcp_buffer[ i ].bv_val ); + for ( ; i < tcp_buffer_num; i++ ) { + tcp_buffer[ i ] = tcp_buffer[ i + 1 ]; + } + tcp_buffer_num--; + +done:; + if ( !BER_BVISNULL( &val ) ) { + SLAP_FREE( val.bv_val ); + } + + } + + } else { + int rc; + + rc = tcp_buffer_add_one( c->argc - 1, &c->argv[ 1 ] ); + if ( rc ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), + "<%s> unable to add value #%d", + c->argv[0], tcp_buffer_num ); + Debug( LDAP_DEBUG_ANY, "%s: %s\n", + c->log, c->cr_msg, 0 ); + return 1; + } + } + + return 0; +} +#endif /* LDAP_TCP_BUFFER */ + static int config_suffix(ConfigArgs *c) { @@ -2150,8 +2792,17 @@ config_suffix(ConfigArgs *c) } #endif + if (SLAP_DB_ONE_SUFFIX( c->be ) && c->be->be_suffix ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> Only one suffix is allowed on this %s backend", + c->argv[0], c->be->bd_info->bi_type ); + Debug(LDAP_DEBUG_ANY, "%s: %s\n", + c->log, c->cr_msg, 0); + return(1); + } + pdn = c->value_dn; ndn = c->value_ndn; + if (SLAP_DBHIDDEN( c->be )) tbe = NULL; else @@ -2346,6 +2997,8 @@ config_disallows(ConfigArgs *c) { { BER_BVC("bind_simple"), SLAP_DISALLOW_BIND_SIMPLE }, { BER_BVC("tls_2_anon"), SLAP_DISALLOW_TLS_2_ANON }, { BER_BVC("tls_authc"), SLAP_DISALLOW_TLS_AUTHC }, + { BER_BVC("proxy_authz_non_critical"), SLAP_DISALLOW_PROXY_AUTHZ_N_CRIT }, + { BER_BVC("dontusecopy_non_critical"), SLAP_DISALLOW_DONTUSECOPY_N_CRIT }, { BER_BVNULL, 0 } }; if (c->op == SLAP_CONFIG_EMIT) { @@ -2424,7 +3077,7 @@ static int loglevel_init( void ) { slap_verbmasks lo[] = { - { BER_BVC("Any"), -1 }, + { BER_BVC("Any"), (slap_mask_t) LDAP_DEBUG_ANY }, { BER_BVC("Trace"), LDAP_DEBUG_TRACE }, { BER_BVC("Packets"), LDAP_DEBUG_PACKETS }, { BER_BVC("Args"), LDAP_DEBUG_ARGS }, @@ -2576,9 +3229,11 @@ loglevel_print( FILE *out ) fprintf( out, "Installed log subsystems:\n\n" ); for ( i = 0; !BER_BVISNULL( &loglevel_ops[ i ].word ); i++ ) { - fprintf( out, "\t%-30s (%lu)\n", - loglevel_ops[ i ].word.bv_val, - loglevel_ops[ i ].mask ); + unsigned mask = loglevel_ops[ i ].mask & 0xffffffffUL; + fprintf( out, + (mask == ((slap_mask_t) -1 & 0xffffffffUL) + ? "\t%-30s (-1, 0xffffffff)\n" : "\t%-30s (%u, 0x%x)\n"), + loglevel_ops[ i ].word.bv_val, mask, mask ); } fprintf( out, "\nNOTE: custom log subsystems may be later installed " @@ -2620,7 +3275,7 @@ config_loglevel(ConfigArgs *c) { int level; if ( isdigit((unsigned char)c->argv[i][0]) || c->argv[i][0] == '-' ) { - if( lutil_atoi( &level, c->argv[i] ) != 0 ) { + if( lutil_atoix( &level, c->argv[i], 0 ) != 0 ) { snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse level", c->argv[0] ); Debug( LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", c->log, c->cr_msg, c->argv[i]); @@ -2805,7 +3460,7 @@ config_updatedn(ConfigArgs *c) { } int -config_shadow( ConfigArgs *c, int flag ) +config_shadow( ConfigArgs *c, slap_mask_t flag ) { char *notallowed = NULL; @@ -2821,7 +3476,17 @@ config_shadow( ConfigArgs *c, int flag ) return 1; } - SLAP_DBFLAGS(c->be) |= (SLAP_DBFLAG_SHADOW | SLAP_DBFLAG_SINGLE_SHADOW | flag); + if ( SLAP_SHADOW(c->be) ) { + /* if already shadow, only check consistency */ + if ( ( SLAP_DBFLAGS(c->be) & flag ) != flag ) { + Debug( LDAP_DEBUG_ANY, "%s: inconsistent shadow flag 0x%lx.\n", + c->log, flag, 0 ); + return 1; + } + + } else { + SLAP_DBFLAGS(c->be) |= (SLAP_DBFLAG_SHADOW | SLAP_DBFLAG_SINGLE_SHADOW | flag); + } return 0; } @@ -2908,12 +3573,33 @@ config_include(ConfigArgs *c) { ch_free( cf->c_file.bv_val ); ch_free( cf ); } else { - c->private = cf; + c->ca_private = cf; } return(rc); } #ifdef HAVE_TLS +static int +config_tls_cleanup(ConfigArgs *c) { + int rc = 0; + + if ( slap_tls_ld ) { + int opt = 1; + + ldap_pvt_tls_ctx_free( slap_tls_ctx ); + + /* Force new ctx to be created */ + rc = ldap_pvt_tls_set_option( slap_tls_ld, LDAP_OPT_X_TLS_NEWCTX, &opt ); + if( rc == 0 ) { + /* The ctx's refcount is bumped up here */ + ldap_pvt_tls_get_option( slap_tls_ld, LDAP_OPT_X_TLS_CTX, &slap_tls_ctx ); + /* This is a no-op if it's already loaded */ + load_extop( &slap_EXOP_START_TLS, 0, starttls_extop ); + } + } + return rc; +} + static int config_tls_option(ConfigArgs *c) { int flag; @@ -2937,9 +3623,11 @@ config_tls_option(ConfigArgs *c) { if (c->op == SLAP_CONFIG_EMIT) { return ldap_pvt_tls_get_option( ld, flag, &c->value_string ); } else if ( c->op == LDAP_MOD_DELETE ) { + c->cleanup = config_tls_cleanup; return ldap_pvt_tls_set_option( ld, flag, NULL ); } ch_free(c->value_string); + c->cleanup = config_tls_cleanup; return(ldap_pvt_tls_set_option(ld, flag, c->argv[1])); } @@ -2950,6 +3638,7 @@ config_tls_config(ConfigArgs *c) { switch(c->type) { case CFG_TLS_CRLCHECK: flag = LDAP_OPT_X_TLS_CRLCHECK; break; case CFG_TLS_VERIFY: flag = LDAP_OPT_X_TLS_REQUIRE_CERT; break; + case CFG_TLS_PROTOCOL_MIN: flag = LDAP_OPT_X_TLS_PROTOCOL_MIN; break; default: Debug(LDAP_DEBUG_ANY, "%s: " "unknown tls_option <0x%x>\n", @@ -2960,9 +3649,11 @@ config_tls_config(ConfigArgs *c) { return slap_tls_get_config( slap_tls_ld, flag, &c->value_string ); } else if ( c->op == LDAP_MOD_DELETE ) { int i = 0; + c->cleanup = config_tls_cleanup; return ldap_pvt_tls_set_option( slap_tls_ld, flag, &i ); } ch_free( c->value_string ); + c->cleanup = config_tls_cleanup; if ( isdigit( (unsigned char)c->argv[1][0] ) ) { if ( lutil_atoi( &i, c->argv[1] ) != 0 ) { Debug(LDAP_DEBUG_ANY, "%s: " @@ -2972,7 +3663,7 @@ config_tls_config(ConfigArgs *c) { } return(ldap_pvt_tls_set_option(slap_tls_ld, flag, &i)); } else { - return(ldap_int_tls_config(slap_tls_ld, flag, c->argv[1])); + return(ldap_pvt_tls_config(slap_tls_ld, flag, c->argv[1])); } } #endif @@ -3021,7 +3712,7 @@ typedef struct setup_cookie { ConfigArgs *ca; Entry *frontend; Entry *config; - int got_frontend; + int got_frontend; int got_config; } setup_cookie; @@ -3030,15 +3721,18 @@ config_ldif_resp( Operation *op, SlapReply *rs ) { if ( rs->sr_type == REP_SEARCH ) { setup_cookie *sc = op->o_callback->sc_private; + struct berval pdn; sc->cfb->cb_got_ldif = 1; /* Does the frontend exist? */ if ( !sc->got_frontend ) { if ( !strncmp( rs->sr_entry->e_nname.bv_val, - "olcDatabase", STRLENOF( "olcDatabase" ))) { + "olcDatabase", STRLENOF( "olcDatabase" ))) + { if ( strncmp( rs->sr_entry->e_nname.bv_val + STRLENOF( "olcDatabase" ), "={-1}frontend", - STRLENOF( "={-1}frontend" ))) { + STRLENOF( "={-1}frontend" ))) + { struct berval rdn; int i = op->o_noop; sc->ca->be = frontendDB; @@ -3061,13 +3755,19 @@ config_ldif_resp( Operation *op, SlapReply *rs ) } } } + + dnParent( &rs->sr_entry->e_nname, &pdn ); + /* Does the configDB exist? */ if ( sc->got_frontend && !sc->got_config && !strncmp( rs->sr_entry->e_nname.bv_val, - "olcDatabase", STRLENOF( "olcDatabase" ))) { + "olcDatabase", STRLENOF( "olcDatabase" )) && + dn_match( &config_rdn, &pdn ) ) + { if ( strncmp( rs->sr_entry->e_nname.bv_val + STRLENOF( "olcDatabase" ), "={0}config", - STRLENOF( "={0}config" ))) { + STRLENOF( "={0}config" ))) + { struct berval rdn; int i = op->o_noop; sc->ca->be = LDAP_STAILQ_FIRST( &backendDB ); @@ -3368,6 +4068,9 @@ config_send( Operation *op, SlapReply *rs, CfEntryInfo *ce, int depth ) rs->sr_entry = ce->ce_entry; rs->sr_flags = 0; rc = send_search_entry( op, rs ); + if ( rc != LDAP_SUCCESS ) { + return rc; + } } if ( op->ors_scope == LDAP_SCOPE_SUBTREE ) { if ( ce->ce_kids ) { @@ -3530,14 +4233,15 @@ config_rename_kids( CfEntryInfo *ce ) struct berval rdn, nrdn; for (ce2 = ce->ce_kids; ce2; ce2 = ce2->ce_sibs) { + struct berval newdn, newndn; dnRdn ( &ce2->ce_entry->e_name, &rdn ); dnRdn ( &ce2->ce_entry->e_nname, &nrdn ); + build_new_dn( &newdn, &ce->ce_entry->e_name, &rdn, NULL ); + build_new_dn( &newndn, &ce->ce_entry->e_nname, &nrdn, NULL ); free( ce2->ce_entry->e_name.bv_val ); free( ce2->ce_entry->e_nname.bv_val ); - build_new_dn( &ce2->ce_entry->e_name, &ce->ce_entry->e_name, - &rdn, NULL ); - build_new_dn( &ce2->ce_entry->e_nname, &ce->ce_entry->e_nname, - &nrdn, NULL ); + ce2->ce_entry->e_name = newdn; + ce2->ce_entry->e_nname = newndn; config_rename_kids( ce2 ); } } @@ -3698,10 +4402,10 @@ check_name_index( CfEntryInfo *parent, ConfigType ce_type, Entry *e, isconfig = 1; } ptr1 = ber_bvchr( &e->e_name, '{' ); - if ( ptr1 && ptr1 - e->e_name.bv_val < rdn.bv_len ) { + if ( ptr1 && ptr1 < &e->e_name.bv_val[ rdn.bv_len ] ) { char *next; ptr2 = strchr( ptr1, '}' ); - if (!ptr2 || ptr2 - e->e_name.bv_val > rdn.bv_len) + if ( !ptr2 || ptr2 > &e->e_name.bv_val[ rdn.bv_len ] ) return LDAP_NAMING_VIOLATION; if ( ptr2-ptr1 == 1) return LDAP_NAMING_VIOLATION; @@ -3742,7 +4446,7 @@ check_name_index( CfEntryInfo *parent, ConfigType ce_type, Entry *e, if ( isconfig && index == -1 ) { index = 0; } - if ( !isfrontend && index == -1 ) { + if (( !isfrontend && index == -1 ) || ( index > nsibs ) ){ index = nsibs; } @@ -3833,14 +4537,14 @@ cfAddSchema( CfEntryInfo *p, Entry *e, ConfigArgs *ca ) /* This entry is hardcoded, don't re-parse it */ if ( p->ce_type == Cft_Global ) { cfn = p->ce_private; - ca->private = cfn; + ca->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; + ca->ca_private = cfn; cfo = p->ce_private; cfn->c_sibs = cfo->c_kids; cfo->c_kids = cfn; @@ -3853,6 +4557,11 @@ cfAddDatabase( CfEntryInfo *p, Entry *e, struct config_args_s *ca ) if ( p->ce_type != Cft_Global ) { return LDAP_CONSTRAINT_VIOLATION; } + /* config must be {0}, nothing else allowed */ + if ( !strncmp( e->e_nname.bv_val, "olcDatabase={0}", STRLENOF("olcDatabase={0}")) && + strncmp( e->e_nname.bv_val + STRLENOF("olcDatabase={0}"), "config,", STRLENOF("config,") )) { + return LDAP_CONSTRAINT_VIOLATION; + } ca->be = frontendDB; /* just to get past check_vals */ return LDAP_SUCCESS; } @@ -3896,6 +4605,7 @@ schema_destroy_one( ConfigArgs *ca, ConfigOCs **colst, int nocs, ca->valx = -1; ca->line = NULL; + ca->argc = 1; if ( cfn->c_cr_head ) { struct berval bv = BER_BVC("olcDitContentRules"); ad = NULL; @@ -3917,6 +4627,13 @@ schema_destroy_one( ConfigArgs *ca, ConfigOCs **colst, int nocs, ct = config_find_table( colst, nocs, ad, ca ); config_del_vals( ct, ca ); } + if ( cfn->c_syn_head ) { + struct berval bv = BER_BVC("olcLdapSyntaxes"); + ad = NULL; + slap_bv2ad( &bv, &ad, &text ); + ct = config_find_table( colst, nocs, ad, ca ); + config_del_vals( ct, ca ); + } if ( cfn->c_om_head ) { struct berval bv = BER_BVC("olcObjectIdentifier"); ad = NULL; @@ -3988,6 +4705,9 @@ config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca, SlapReply *rs, Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: " "DN=\"%s\" already exists\n", log_prefix, e->e_name.bv_val, 0 ); + /* global schema ignores all writes */ + if ( ce->ce_type == Cft_Schema && ce->ce_parent->ce_type == Cft_Global ) + return LDAP_COMPARE_TRUE; return LDAP_ALREADY_EXISTS; } } @@ -4092,16 +4812,31 @@ config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca, SlapReply *rs, rc = LDAP_CONSTRAINT_VIOLATION; if ( coptr->co_type == Cft_Global && !last ) { cfn = cfb->cb_config; - ca->private = cfn; + ca->ca_private = cfn; ca->be = frontendDB; /* just to get past check_vals */ rc = LDAP_SUCCESS; } + colst = count_ocs( oc_at, &nocs ); + /* Check whether the Add is allowed by its parent, and do * any necessary arg setup */ if ( last ) { rc = config_add_oc( &coptr, last, e, ca ); + if ( rc == LDAP_CONSTRAINT_VIOLATION ) { + for ( i = 0; ico_oc->soc_kind == LDAP_SCHEMA_STRUCTURAL ) + continue; + if ( colst[i]->co_ldadd && + ( rc = colst[i]->co_ldadd( last, e, ca )) + != LDAP_CONSTRAINT_VIOLATION ) { + coptr = colst[i]; + break; + } + } + } if ( rc == LDAP_CONSTRAINT_VIOLATION ) { Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: " "DN=\"%s\" no structural objectClass add function\n", @@ -4110,8 +4845,6 @@ config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca, SlapReply *rs, } } - colst = count_ocs( oc_at, &nocs ); - /* Add the entry but don't parse it, we already have its contents */ if ( rc == LDAP_COMPARE_TRUE ) { rc = LDAP_SUCCESS; @@ -4173,6 +4906,7 @@ config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca, SlapReply *rs, if ( !ct ) continue; /* user data? */ for (i=0; a->a_vals[i].bv_val; i++) { char *iptr = NULL; + ca->valx = -1; ca->line = a->a_vals[i].bv_val; if ( a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED ) { ptr = strchr( ca->line, '}' ); @@ -4184,8 +4918,6 @@ config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca, SlapReply *rs, if ( a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED_SIB ) { if ( iptr ) { ca->valx = strtol( iptr+1, NULL, 0 ); - } else { - ca->valx = -1; } } else { ca->valx = i; @@ -4210,6 +4942,8 @@ ok: rc = ca->bi->bi_db_open( ca->be, &ca->reply ); ca->be->bd_info = bi_orig; } + } else if ( ca->cleanup ) { + rc = ca->cleanup( ca ); } if ( rc ) { if (ca->cr_msg[0] == '\0') @@ -4230,7 +4964,7 @@ ok: ce->ce_type = colst[0]->co_type; ce->ce_be = ca->be; ce->ce_bi = ca->bi; - ce->ce_private = ca->private; + ce->ce_private = ca->ca_private; ca->ca_entry = ce->ce_entry; if ( !last ) { cfb->cb_root = ce; @@ -4374,13 +5108,22 @@ config_back_add( Operation *op, SlapReply *rs ) goto out; } + /* + * Check for attribute ACL + */ + if ( !acl_check_modlist( op, op->ora_e, op->orm_modlist )) { + rs->sr_err = LDAP_INSUFFICIENT_ACCESS; + rs->sr_text = "no write access to attribute"; + goto out; + } + cfb = (CfBackInfo *)op->o_bd->be_private; /* add opattrs for syncprov */ { char textbuf[SLAP_TEXT_BUFLEN]; size_t textlen = sizeof textbuf; - rs->sr_err = entry_schema_check(op, op->ora_e, NULL, 0, 1, + rs->sr_err = entry_schema_check(op, op->ora_e, NULL, 0, 1, NULL, &rs->sr_text, textbuf, sizeof( textbuf ) ); if ( rs->sr_err != LDAP_SUCCESS ) goto out; @@ -4393,6 +5136,10 @@ config_back_add( Operation *op, SlapReply *rs ) } } + if ( op->o_abandon ) { + rs->sr_err = SLAPD_ABANDON; + goto out; + } ldap_pvt_thread_pool_pause( &connection_pool ); /* Strategy: @@ -4446,7 +5193,14 @@ out2:; ldap_pvt_thread_pool_resume( &connection_pool ); out:; - send_ldap_result( op, rs ); + { int repl = op->o_dont_replicate; + if ( rs->sr_err == LDAP_COMPARE_TRUE ) { + rs->sr_err = LDAP_SUCCESS; + op->o_dont_replicate = 1; + } + send_ldap_result( op, rs ); + op->o_dont_replicate = repl; + } slap_graduate_commit_csn( op ); return rs->sr_err; } @@ -4463,6 +5217,7 @@ config_modify_add( ConfigTable *ct, ConfigArgs *ca, AttributeDescription *ad, { int rc; + ca->valx = -1; if (ad->ad_type->sat_flags & SLAP_AT_ORDERED && ca->line[0] == '{' ) { @@ -4513,7 +5268,7 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs, init_config_argv( ca ); ca->be = ce->ce_be; ca->bi = ce->ce_bi; - ca->private = ce->ce_private; + ca->ca_private = ce->ce_private; ca->ca_entry = e; ca->fname = "slapd"; ca->ca_op = op; @@ -4543,7 +5298,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++); + i = ml->sml_numvals; d = ch_malloc( sizeof(delrec) + (i - 1)* sizeof(int)); d->nidx = i; d->next = NULL; @@ -4576,8 +5331,7 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs, 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; + navals = a->a_numvals; } } for ( i=0; !BER_BVISNULL( &ml->sml_values[i] ); i++ ) { @@ -4627,10 +5381,11 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs, if ( rc == LDAP_SUCCESS) { /* check that the entry still obeys the schema */ - rc = entry_schema_check(op, e, NULL, 0, 0, + rc = entry_schema_check(op, e, NULL, 0, 0, NULL, &rs->sr_text, ca->cr_msg, sizeof(ca->cr_msg) ); - if ( rc ) goto out_noop; } + if ( rc ) goto out_noop; + /* 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, ca ); @@ -4676,6 +5431,7 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs, } ca->line = bv.bv_val; ca->valx = d->idx[i]; + config_parse_vals(ct, ca, d->idx[i] ); rc = config_del_vals( ct, ca ); if ( rc != LDAP_SUCCESS ) break; if ( s ) @@ -4687,6 +5443,7 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs, } else { ca->valx = -1; ca->line = NULL; + ca->argc = 1; rc = config_del_vals( ct, ca ); if ( rc ) rc = LDAP_OTHER; if ( s ) @@ -4722,6 +5479,7 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs, out: /* Undo for a failed operation */ if ( rc != LDAP_SUCCESS ) { + ConfigReply msg = ca->reply; for ( s = save_attrs; s; s = s->a_next ) { if ( s->a_flags & SLAP_ATTR_IXDEL ) { s->a_flags &= ~(SLAP_ATTR_IXDEL|SLAP_ATTR_IXADD); @@ -4732,6 +5490,7 @@ out: a->a_flags &= ~(SLAP_ATTR_IXDEL|SLAP_ATTR_IXADD); ca->valx = -1; ca->line = NULL; + ca->argc = 1; config_del_vals( ct, ca ); } for ( i=0; !BER_BVISNULL( &s->a_vals[i] ); i++ ) { @@ -4746,6 +5505,7 @@ out: ct = config_find_table( colst, nocs, a->a_desc, ca ); ca->valx = -1; ca->line = NULL; + ca->argc = 1; config_del_vals( ct, ca ); s = attr_find( save_attrs, a->a_desc ); if ( s ) { @@ -4758,6 +5518,7 @@ out: } } } + ca->reply = msg; } if ( ca->cleanup ) @@ -4790,6 +5551,7 @@ config_back_modify( Operation *op, SlapReply *rs ) struct berval rdn; char *ptr; AttributeDescription *rad = NULL; + int do_pause = 1; cfb = (CfBackInfo *)op->o_bd->be_private; @@ -4820,12 +5582,22 @@ config_back_modify( Operation *op, SlapReply *rs ) rs->sr_text = "Use modrdn to change the entry name"; goto out; } + /* Internal update of contextCSN? */ + if ( ml->sml_desc == slap_schema.si_ad_contextCSN && op->o_conn->c_conn_idx == -1 ) { + do_pause = 0; + break; + } } slap_mods_opattrs( op, &op->orm_modlist, 1 ); - if ( !slapd_shutdown ) + if ( do_pause ) { + if ( op->o_abandon ) { + rs->sr_err = SLAPD_ABANDON; + goto out; + } ldap_pvt_thread_pool_pause( &connection_pool ); + } /* Strategy: * 1) perform the Modify on the cached Entry. @@ -4857,7 +5629,7 @@ config_back_modify( Operation *op, SlapReply *rs ) op->o_ndn = ndn; } - if ( !slapd_shutdown ) + if ( do_pause ) ldap_pvt_thread_pool_resume( &connection_pool ); out: send_ldap_result( op, rs ); @@ -4989,6 +5761,10 @@ config_back_modrdn( Operation *op, SlapReply *rs ) goto out; } + if ( op->o_abandon ) { + rs->sr_err = SLAPD_ABANDON; + goto out; + } ldap_pvt_thread_pool_pause( &connection_pool ); if ( ce->ce_type == Cft_Schema ) { @@ -5065,7 +5841,104 @@ out: static int config_back_delete( Operation *op, SlapReply *rs ) { - send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, NULL ); +#ifdef SLAP_CONFIG_DELETE + CfBackInfo *cfb; + CfEntryInfo *ce, *last, *ce2; + + cfb = (CfBackInfo *)op->o_bd->be_private; + + ce = config_find_base( cfb->cb_root, &op->o_req_ndn, &last ); + if ( !ce ) { + if ( last ) + rs->sr_matched = last->ce_entry->e_name.bv_val; + rs->sr_err = LDAP_NO_SUCH_OBJECT; + } else if ( ce->ce_kids ) { + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + } else if ( op->o_abandon ) { + rs->sr_err = SLAPD_ABANDON; + } else if ( ce->ce_type == Cft_Overlay || ce->ce_type == Cft_Database ){ + char *iptr; + int count, ixold; + + ldap_pvt_thread_pool_pause( &connection_pool ); + + if ( ce->ce_type == Cft_Overlay ){ + overlay_remove( ce->ce_be, (slap_overinst *)ce->ce_bi ); + } else { /* Cft_Database*/ + if ( ce->ce_be == frontendDB || ce->ce_be == op->o_bd ){ + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_text = "Cannot delete config or frontend database"; + ldap_pvt_thread_pool_resume( &connection_pool ); + goto out; + } + if ( ce->ce_be->bd_info->bi_db_close ) { + ce->ce_be->bd_info->bi_db_close( ce->ce_be, NULL ); + } + backend_destroy_one( ce->ce_be, 1); + } + + /* remove CfEntryInfo from the siblings list */ + if ( ce->ce_parent->ce_kids == ce ) { + ce->ce_parent->ce_kids = ce->ce_sibs; + } else { + for ( ce2 = ce->ce_parent->ce_kids ; ce2; ce2 = ce2->ce_sibs ) { + if ( ce2->ce_sibs == ce ) { + ce2->ce_sibs = ce->ce_sibs; + break; + } + } + } + + /* remove from underlying database */ + if ( cfb->cb_use_ldif ) { + BackendDB *be = op->o_bd; + slap_callback sc = { NULL, slap_null_cb, NULL, NULL }, *scp; + struct berval dn, ndn, req_dn, req_ndn; + + op->o_bd = &cfb->cb_db; + + dn = op->o_dn; + ndn = op->o_ndn; + req_dn = op->o_req_dn; + req_ndn = op->o_req_ndn; + + op->o_dn = op->o_bd->be_rootdn; + op->o_ndn = op->o_bd->be_rootndn; + op->o_req_dn = ce->ce_entry->e_name; + op->o_req_ndn = ce->ce_entry->e_nname; + + scp = op->o_callback; + op->o_callback = ≻ + op->o_bd->be_delete( op, rs ); + op->o_bd = be; + op->o_callback = scp; + op->o_dn = dn; + op->o_ndn = ndn; + op->o_req_dn = req_dn; + op->o_req_ndn = req_ndn; + } + + /* renumber siblings */ + iptr = ber_bvchr( &op->o_req_ndn, '{' ) + 1; + ixold = strtol( iptr, NULL, 0 ); + for (ce2 = ce->ce_sibs, count=0; ce2; ce2=ce2->ce_sibs) { + config_renumber_one( op, rs, ce2->ce_parent, ce2->ce_entry, + count+ixold, 0, cfb->cb_use_ldif ); + count++; + } + + ce->ce_entry->e_private=NULL; + entry_free(ce->ce_entry); + ch_free(ce); + ldap_pvt_thread_pool_resume( &connection_pool ); + } else { + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + } +#else + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; +#endif /* SLAP_CONFIG_DELETE */ +out: + send_ldap_result( op, rs ); return rs->sr_err; } @@ -5098,20 +5971,22 @@ config_back_search( Operation *op, SlapReply *rs ) switch ( op->ors_scope ) { case LDAP_SCOPE_BASE: case LDAP_SCOPE_SUBTREE: - config_send( op, rs, ce, 0 ); + rs->sr_err = config_send( op, rs, ce, 0 ); break; case LDAP_SCOPE_ONELEVEL: for (ce = ce->ce_kids; ce; ce=ce->ce_sibs) { - config_send( op, rs, ce, 1 ); + rs->sr_err = config_send( op, rs, ce, 1 ); + if ( rs->sr_err ) { + break; + } } break; } - - rs->sr_err = LDAP_SUCCESS; + out: send_ldap_result( op, rs ); - return 0; + return rs->sr_err; } /* no-op, we never free entries */ @@ -5138,21 +6013,26 @@ int config_back_entry_get( { CfBackInfo *cfb; CfEntryInfo *ce, *last; + int rc = LDAP_NO_SUCH_OBJECT; cfb = (CfBackInfo *)op->o_bd->be_private; ce = config_find_base( cfb->cb_root, ndn, &last ); if ( ce ) { *ent = ce->ce_entry; - if ( *ent && oc && !is_entry_objectclass_or_sub( *ent, oc ) ) { - *ent = NULL; + if ( *ent ) { + rc = LDAP_SUCCESS; + if ( oc && !is_entry_objectclass_or_sub( *ent, oc ) ) { + rc = LDAP_NO_SUCH_ATTRIBUTE; + *ent = NULL; + } } } - return ( *ent == NULL ? 1 : 0 ); + return rc; } -static void +static int config_build_attrs( Entry *e, AttributeType **at, AttributeDescription *ad, ConfigTable *ct, ConfigArgs *c ) { @@ -5169,18 +6049,42 @@ config_build_attrs( Entry *e, AttributeType **at, AttributeDescription *ad, * returns success with no values */ if (rc == LDAP_SUCCESS && c->rvalue_vals != NULL ) { if ( c->rvalue_nvals ) - attr_merge(e, ct[i].ad, c->rvalue_vals, + rc = attr_merge(e, ct[i].ad, c->rvalue_vals, c->rvalue_nvals); - else - attr_merge_normalize(e, ct[i].ad, + else { + slap_syntax_validate_func *validate = + ct[i].ad->ad_type->sat_syntax->ssyn_validate; + if ( validate ) { + int j; + for ( j=0; c->rvalue_vals[j].bv_val; j++ ) { + rc = ordered_value_validate( ct[i].ad, + &c->rvalue_vals[j], LDAP_MOD_ADD ); + if ( rc ) { + Debug( LDAP_DEBUG_ANY, + "config_build_attrs: error %d on %s value #%d\n", + rc, ct[i].ad->ad_cname.bv_val, j ); + return rc; + } + } + } + + rc = attr_merge_normalize(e, ct[i].ad, c->rvalue_vals, NULL); + } ber_bvarray_free( c->rvalue_nvals ); ber_bvarray_free( c->rvalue_vals ); + if ( rc ) { + Debug( LDAP_DEBUG_ANY, + "config_build_attrs: error %d on %s\n", + rc, ct[i].ad->ad_cname.bv_val, 0 ); + return rc; + } } break; } } } + return 0; } Entry * @@ -5194,7 +6098,7 @@ config_build_entry( Operation *op, SlapReply *rs, CfEntryInfo *parent, AttributeDescription *ad = NULL; int rc; char *ptr; - const char *text; + const char *text = ""; Attribute *oc_at; struct berval pdn; ObjectClass *oc; @@ -5207,7 +6111,7 @@ config_build_entry( Operation *op, SlapReply *rs, CfEntryInfo *parent, ce->ce_parent = parent; if ( parent ) { pdn = parent->ce_entry->e_nname; - if ( parent->ce_kids ) + if ( parent->ce_kids && parent->ce_kids->ce_type <= ce->ce_type ) for ( ceprev = parent->ce_kids; ceprev->ce_sibs && ceprev->ce_type <= ce->ce_type; ceprev = ceprev->ce_sibs ); @@ -5215,7 +6119,7 @@ config_build_entry( Operation *op, SlapReply *rs, CfEntryInfo *parent, BER_BVZERO( &pdn ); } - ce->ce_private = c->private; + ce->ce_private = c->ca_private; ce->ce_be = c->be; ce->ce_bi = c->bi; @@ -5232,7 +6136,7 @@ config_build_entry( Operation *op, SlapReply *rs, CfEntryInfo *parent, ad_name.bv_len = ptr - rdn->bv_val; rc = slap_bv2ad( &ad_name, &ad, &text ); if ( rc ) { - return NULL; + goto fail; } val.bv_val = ptr+1; val.bv_len = rdn->bv_len - (val.bv_val - rdn->bv_val); @@ -5240,33 +6144,51 @@ config_build_entry( Operation *op, SlapReply *rs, CfEntryInfo *parent, oc = main->co_oc; c->table = main->co_type; - if ( oc->soc_required ) - config_build_attrs( e, oc->soc_required, ad, main->co_table, c ); + if ( oc->soc_required ) { + rc = config_build_attrs( e, oc->soc_required, ad, main->co_table, c ); + if ( rc ) goto fail; + } - if ( oc->soc_allowed ) - config_build_attrs( e, oc->soc_allowed, ad, main->co_table, c ); + if ( oc->soc_allowed ) { + rc = config_build_attrs( e, oc->soc_allowed, ad, main->co_table, c ); + if ( rc ) goto fail; + } if ( extra ) { oc = extra->co_oc; c->table = extra->co_type; - if ( oc->soc_required ) - config_build_attrs( e, oc->soc_required, ad, extra->co_table, c ); + if ( oc->soc_required ) { + rc = config_build_attrs( e, oc->soc_required, ad, extra->co_table, c ); + if ( rc ) goto fail; + } - if ( oc->soc_allowed ) - config_build_attrs( e, oc->soc_allowed, ad, extra->co_table, c ); + if ( oc->soc_allowed ) { + rc = config_build_attrs( e, oc->soc_allowed, ad, extra->co_table, c ); + if ( rc ) goto fail; + } } oc_at = attr_find( e->e_attrs, slap_schema.si_ad_objectClass ); rc = structural_class(oc_at->a_vals, &oc, NULL, &text, c->cr_msg, sizeof(c->cr_msg), op ? op->o_tmpmemctx : NULL ); + if ( rc != LDAP_SUCCESS ) { +fail: + Debug( LDAP_DEBUG_ANY, + "config_build_entry: build \"%s\" failed: \"%s\"\n", + rdn->bv_val, text, 0); + return NULL; + } attr_merge_normalize_one(e, slap_schema.si_ad_structuralObjectClass, &oc->soc_cname, NULL ); - if ( op && !op->o_noop ) { + if ( op ) { op->ora_e = e; op->ora_modlist = NULL; - op->o_bd->be_add( op, rs ); - if ( ( rs->sr_err != LDAP_SUCCESS ) - && (rs->sr_err != LDAP_ALREADY_EXISTS) ) { - return NULL; + slap_add_opattrs( op, NULL, NULL, 0, 0 ); + if ( !op->o_noop ) { + op->o_bd->be_add( op, rs ); + if ( ( rs->sr_err != LDAP_SUCCESS ) + && (rs->sr_err != LDAP_ALREADY_EXISTS) ) { + goto fail; + } } } if ( ceprev ) { @@ -5285,13 +6207,13 @@ config_build_schema_inc( ConfigArgs *c, CfEntryInfo *ceparent, Operation *op, SlapReply *rs ) { Entry *e; - ConfigFile *cf = c->private; + ConfigFile *cf = c->ca_private; char *ptr; - struct berval bv; + struct berval bv, rdn; for (; cf; cf=cf->c_sibs, c->depth++) { if ( !cf->c_at_head && !cf->c_cr_head && !cf->c_oc_head && - !cf->c_om_head ) continue; + !cf->c_om_head && !cf->c_syn_head ) continue; c->value_dn.bv_val = c->log; LUTIL_SLASHPATH( cf->c_file.bv_val ); bv.bv_val = strrchr(cf->c_file.bv_val, LDAP_DIRSEP[0]); @@ -5313,14 +6235,15 @@ config_build_schema_inc( ConfigArgs *c, CfEntryInfo *ceparent, bv.bv_len ); c->value_dn.bv_len += bv.bv_len; c->value_dn.bv_val[c->value_dn.bv_len] ='\0'; + rdn = c->value_dn; - c->private = cf; - e = config_build_entry( op, rs, ceparent, c, &c->value_dn, + c->ca_private = cf; + e = config_build_entry( op, rs, ceparent, c, &rdn, &CFOC_SCHEMA, NULL ); if ( !e ) { return -1; } else if ( e && cf->c_kids ) { - c->private = cf->c_kids; + c->ca_private = cf->c_kids; config_build_schema_inc( c, e->e_private, op, rs ); } } @@ -5345,7 +6268,7 @@ config_build_modules( ConfigArgs *c, CfEntryInfo *ceparent, /* FIXME: how can indicate error? */ return -1; } - c->private = mp; + c->ca_private = mp; if ( ! config_build_entry( op, rs, ceparent, c, &c->value_dn, &CFOC_MODULE, NULL )) { return -1; } @@ -5383,6 +6306,7 @@ config_check_schema(Operation *op, CfBackInfo *cfb) ber_bvarray_free( a->a_vals ); a->a_vals = NULL; a->a_nvals = NULL; + a->a_numvals = 0; } oidm_unparse( &bv, NULL, NULL, 1 ); attr_merge_normalize( e, cfAd_om, bv, NULL ); @@ -5397,6 +6321,7 @@ config_check_schema(Operation *op, CfBackInfo *cfb) ber_bvarray_free( a->a_vals ); a->a_vals = NULL; a->a_nvals = NULL; + a->a_numvals = 0; } at_unparse( &bv, NULL, NULL, 1 ); attr_merge_normalize( e, cfAd_attr, bv, NULL ); @@ -5411,15 +6336,31 @@ config_check_schema(Operation *op, CfBackInfo *cfb) ber_bvarray_free( a->a_vals ); a->a_vals = NULL; a->a_nvals = NULL; + a->a_numvals = 0; } oc_unparse( &bv, NULL, NULL, 1 ); attr_merge_normalize( e, cfAd_oc, bv, NULL ); ber_bvarray_free( bv ); cf_oc_tail = oc_sys_tail; } + if ( cf_syn_tail != syn_sys_tail ) { + a = attr_find( e->e_attrs, cfAd_syntax ); + if ( a ) { + if ( a->a_nvals != a->a_vals ) + ber_bvarray_free( a->a_nvals ); + ber_bvarray_free( a->a_vals ); + a->a_vals = NULL; + a->a_nvals = NULL; + a->a_numvals = 0; + } + syn_unparse( &bv, NULL, NULL, 1 ); + attr_merge_normalize( e, cfAd_syntax, bv, NULL ); + ber_bvarray_free( bv ); + cf_syn_tail = syn_sys_tail; + } } else { SlapReply rs = {REP_RESULT}; - c.private = NULL; + c.ca_private = NULL; e = config_build_entry( op, &rs, cfb->cb_root, &c, &schema_rdn, &CFOC_SCHEMA, NULL ); if ( !e ) { @@ -5430,6 +6371,7 @@ config_check_schema(Operation *op, CfBackInfo *cfb) cf_at_tail = at_sys_tail; cf_oc_tail = oc_sys_tail; cf_om_tail = om_sys_tail; + cf_syn_tail = syn_sys_tail; } return 0; } @@ -5460,7 +6402,7 @@ config_back_db_open( BackendDB *be, ConfigReply *cr ) /* If we have no explicitly configured ACLs, don't just use * the global ACLs. Explicitly deny access to everything. */ - if ( frontendDB->be_acl && be->be_acl == frontendDB->be_acl ) { + if ( !be->be_acl ) { parse_acl(be, "config_back_db_open", 0, 6, (char **)defacl, 0 ); } @@ -5485,7 +6427,7 @@ config_back_db_open( BackendDB *be, ConfigReply *cr ) /* create root of tree */ rdn = config_rdn; - c.private = cfb->cb_config; + c.ca_private = cfb->cb_config; c.be = frontendDB; e = config_build_entry( op, &rs, NULL, &c, &rdn, &CFOC_GLOBAL, NULL ); if ( !e ) { @@ -5511,7 +6453,7 @@ config_back_db_open( BackendDB *be, ConfigReply *cr ) * files. */ rdn = schema_rdn; - c.private = NULL; + c.ca_private = NULL; e = config_build_entry( op, &rs, ceparent, &c, &rdn, &CFOC_SCHEMA, NULL ); if ( !e ) { return -1; @@ -5521,11 +6463,12 @@ config_back_db_open( BackendDB *be, ConfigReply *cr ) cf_at_tail = at_sys_tail; cf_oc_tail = oc_sys_tail; cf_om_tail = om_sys_tail; + cf_syn_tail = syn_sys_tail; /* Create schema nodes for included schema... */ if ( cfb->cb_config->c_kids ) { c.depth = 0; - c.private = cfb->cb_config->c_kids; + c.ca_private = cfb->cb_config->c_kids; if (config_build_schema_inc( &c, ce, op, &rs )) { return -1; } @@ -5608,8 +6551,19 @@ config_back_db_open( BackendDB *be, ConfigReply *cr ) slap_overinst *on; Entry *oe; int j; - - for (j=0,on=oi->oi_list; on; j++,on=on->on_next) { + voidList *vl, *v0 = NULL; + + /* overlays are in LIFO order, must reverse stack */ + for (on=oi->oi_list; on; on=on->on_next) { + vl = ch_malloc( sizeof( voidList )); + vl->vl_next = v0; + v0 = vl; + vl->vl_ptr = on; + } + for (j=0; vl; j++,vl=v0) { + on = vl->vl_ptr; + v0 = vl->vl_next; + ch_free( vl ); if ( on->on_bi.bi_db_config && !on->on_bi.bi_cf_ocs ) { Debug( LDAP_DEBUG_ANY, "WARNING: No dynamic config support for overlay %s.\n", @@ -5737,6 +6691,9 @@ config_back_db_init( BackendDB *be, ConfigReply* cr ) /* Hide from namingContexts */ SLAP_BFLAGS(be) |= SLAP_BFLAG_CONFIG; + /* Check ACLs on content of Adds by default */ + SLAP_DBFLAGS(be) |= SLAP_DBFLAG_ACL_ADD; + return 0; } @@ -5823,6 +6780,7 @@ config_tool_entry_put( BackendDB *be, Entry *e, struct berval *text ) Connection conn = {0}; Operation *op = NULL; void *thrctx; + int isFrontend = 0; /* Create entry for frontend database if it does not exist already */ if ( !entry_put_got_frontend ) { @@ -5872,11 +6830,12 @@ config_tool_entry_put( BackendDB *be, Entry *e, struct berval *text ) } } else { entry_put_got_frontend++; + isFrontend = 1; } } } /* Create entry for config database if it does not exist already */ - if ( !entry_put_got_config ) { + if ( !entry_put_got_config && !isFrontend ) { if ( !strncmp( e->e_nname.bv_val, "olcDatabase", STRLENOF( "olcDatabase" ))) { if ( strncmp( e->e_nname.bv_val + @@ -5941,6 +6900,7 @@ static struct { { "backend", &cfAd_backend }, { "database", &cfAd_database }, { "include", &cfAd_include }, + { "ldapsyntax", &cfAd_syntax }, { "objectclass", &cfAd_oc }, { "objectidentifier", &cfAd_om }, { "overlay", &cfAd_overlay }, @@ -6047,6 +7007,9 @@ config_back_initialize( BackendInfo *bi ) i = config_register_schema( ct, cf_ocs ); if ( i ) return i; + i = slap_str2ad( "olcDatabase", &olcDatabaseDummy[0].ad, &text ); + if ( i ) return i; + /* setup olcRootPW to be base64-encoded when written in LDIF form; * basically, we don't care if it fails */ i = slap_str2ad( "olcRootPW", &ad, &text ); @@ -6071,4 +7034,3 @@ config_back_initialize( BackendInfo *bi ) return 0; } -