X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fbconfig.c;h=7979dc57f5ce4da084ed99b0b7008cf752bd1ce3;hb=9767c87531d193a4bef19286b77623aff18590fb;hp=e2486ca65260476265431baa79938b45baaab02c;hpb=204b035a9c594323be07d62c74aecd97d4e91cc5;p=openldap diff --git a/servers/slapd/bconfig.c b/servers/slapd/bconfig.c index e2486ca652..7979dc57f5 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-2008 The OpenLDAP Foundation. + * Copyright 2005-2009 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -63,6 +63,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; @@ -87,7 +88,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; @@ -97,9 +98,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 ); @@ -142,6 +145,7 @@ enum { CFG_DATABASE, CFG_TLS_RAND, CFG_TLS_CIPHER, + CFG_TLS_PROTOCOL_MIN, CFG_TLS_CERT_FILE, CFG_TLS_CERT_KEY, CFG_TLS_CA_PATH, @@ -180,6 +184,8 @@ enum { CFG_SERVERID, CFG_SORTVALS, CFG_IX_INTLEN, + CFG_SYNTAX, + CFG_ACL_ADD, CFG_LAST }; @@ -254,6 +260,7 @@ static OidRec OidMacros[] = { * OLcfgOv{Oc|At}:17 -> dyngroup * OLcfgOv{Oc|At}:18 -> memberof * OLcfgOv{Oc|At}:19 -> collect + * OLcfgOv{Oc|At}:20 -> retcode */ /* alphabetical ordering */ @@ -275,6 +282,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' " @@ -380,6 +391,13 @@ static ConfigTable config_back_cf_table[] = { { "lastmod", "on|off", 2, 2, 0, ARG_DB|ARG_ON_OFF|ARG_MAGIC|CFG_LASTMOD, &config_generic, "( OLcfgDbAt:0.4 NAME 'olcLastMod' " "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, + { "ldapsyntax", "syntax", 2, 0, 0, + ARG_PAREN|ARG_MAGIC|CFG_SYNTAX, + &config_generic, "( OLcfgGlAt:85 NAME 'olcLdapSyntaxes' " + "DESC 'OpenLDAP ldapSyntax' " + "EQUALITY caseIgnoreMatch " + "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", + NULL, NULL }, { "limits", "limits", 2, 0, 0, ARG_DB|ARG_MAGIC|CFG_LIMITS, &config_generic, "( OLcfgDbAt:0.5 NAME 'olcLimits' " "EQUALITY caseIgnoreMatch " @@ -501,6 +519,7 @@ static ConfigTable config_back_cf_table[] = { "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, { "rootdn", "dn", 2, 2, 0, ARG_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC, &config_rootdn, "( OLcfgDbAt:0.8 NAME 'olcRootDN' " + "EQUALITY distinguishedNameMatch " "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL }, { "rootDSE", "file", 2, 2, 0, ARG_MAGIC|CFG_ROOTDSE, &config_generic, "( OLcfgGlAt:51 NAME 'olcRootDSE' " @@ -541,6 +560,7 @@ static ConfigTable config_back_cf_table[] = { &config_generic, NULL, NULL, NULL }, { "schemadn", "dn", 2, 2, 0, ARG_MAY_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC, &config_schema_dn, "( OLcfgGlAt:58 NAME 'olcSchemaDN' " + "EQUALITY distinguishedNameMatch " "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL }, { "security", "factors", 2, 0, 0, ARG_MAY_DB|ARG_MAGIC, &config_security, "( OLcfgGlAt:59 NAME 'olcSecurity' " @@ -666,6 +686,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 }, @@ -678,10 +706,22 @@ static ConfigTable config_back_cf_table[] = { &config_updateref, "( OLcfgDbAt:0.13 NAME 'olcUpdateRef' " "EQUALITY caseIgnoreMatch " "SUP labeledURI )", NULL, NULL }, + { "writetimeout", "timeout", 2, 2, 0, ARG_INT, + &global_writetimeout, "( OLcfgGlAt:88 NAME 'olcWriteTimeout' " + "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, { NULL, NULL, 0, 0, 0, ARG_IGNORED, NULL, NULL, NULL, NULL } }; +/* Need to no-op this keyword for dynamic config */ +ConfigTable olcDatabaseDummy[] = { + { "", "", 0, 0, 0, ARG_IGNORED, + NULL, "( OLcfgGlAt:13 NAME 'olcDatabase' " + "DESC 'The backend type for a database instance' " + "SUP olcBackend SINGLE-VALUE X-ORDERED 'SIBLINGS' )", NULL, NULL }, + { NULL, NULL, 0, 0, 0, ARG_IGNORED } +}; + /* Routines to check if a child can be added to this type */ static ConfigLDAPadd cfAddSchema, cfAddInclude, cfAddDatabase, cfAddBackend, cfAddModule, cfAddOverlay; @@ -715,7 +755,7 @@ static ConfigOCs cf_ocs[] = { "olcDisallows $ olcGentleHUP $ olcIdleTimeout $ " "olcIndexSubstrIfMaxLen $ olcIndexSubstrIfMinLen $ " "olcIndexSubstrAnyLen $ olcIndexSubstrAnyStep $ olcIndexIntLen $ " - "olcLocalSSF $ olcLogLevel $ " + "olcLocalSSF $ olcLogFile $ olcLogLevel $ " "olcPasswordCryptSaltFormat $ olcPasswordHash $ olcPidFile $ " "olcPluginLogFile $ olcReadOnly $ olcReferral $ " "olcReplogFile $ olcRequires $ olcRestrict $ olcReverseLookup $ " @@ -727,15 +767,15 @@ static ConfigOCs cf_ocs[] = { "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' " @@ -748,7 +788,7 @@ 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 $ " @@ -924,6 +964,17 @@ config_generic(ConfigArgs *c) { rc = 1; } break; + case CFG_SYNTAX: { + ConfigFile *cf = c->ca_private; + if ( !cf ) + syn_unparse( &c->rvalue_vals, NULL, NULL, 1 ); + else if ( cf->c_syn_head ) + syn_unparse( &c->rvalue_vals, cf->c_syn_head, + cf->c_syn_tail, 0 ); + if ( !c->rvalue_vals ) + rc = 1; + } + break; case CFG_DIT: { ConfigFile *cf = c->ca_private; if ( !cf ) @@ -940,12 +991,7 @@ config_generic(ConfigArgs *c) { AccessControl *a; char *src, *dst, ibuf[11]; struct berval bv, abv; - AccessControl *end; - if ( c->be == frontendDB ) - end = NULL; - else - end = frontendDB->be_acl; - for (i=0, a=c->be->be_acl; a && a != end; i++,a=a->acl_next) { + for (i=0, a=c->be->be_acl; a; i++,a=a->acl_next) { abv.bv_len = snprintf( ibuf, sizeof( ibuf ), SLAP_X_ORDERED_FMT, i ); if ( abv.bv_len >= sizeof( ibuf ) ) { ber_bvarray_free_x( c->rvalue_vals, NULL ); @@ -972,6 +1018,9 @@ config_generic(ConfigArgs *c) { rc = (!i); break; } + case CFG_ACL_ADD: + c->value_int = (SLAP_DBACL_ADD(c->be) != 0); + break; case CFG_ROOTDSE: { ConfigFile *cf = c->ca_private; if ( cf->c_dseFiles ) { @@ -991,7 +1040,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 { @@ -1125,6 +1174,7 @@ config_generic(ConfigArgs *c) { case CFG_SASLSECP: case CFG_SSTR_IF_MAX: case CFG_SSTR_IF_MIN: + case CFG_ACL_ADD: break; /* no-ops, requires slapd restart */ @@ -1177,13 +1227,8 @@ config_generic(ConfigArgs *c) { case CFG_ACL: if ( c->valx < 0 ) { - AccessControl *end; - if ( c->be == frontendDB ) - end = NULL; - else - end = frontendDB->be_acl; - acl_destroy( c->be->be_acl, end ); - c->be->be_acl = end; + acl_destroy( c->be->be_acl ); + c->be->be_acl = NULL; } else { AccessControl **prev, *a; @@ -1274,6 +1319,44 @@ config_generic(ConfigArgs *c) { } } break; + + case CFG_SYNTAX: { + CfEntryInfo *ce; + /* Can be NULL when undoing a failed add */ + if ( c->ca_entry ) { + ce = c->ca_entry->e_private; + /* can't modify the hardcoded schema */ + if ( ce->ce_parent->ce_type == Cft_Global ) + return 1; + } + } + cfn = c->ca_private; + if ( c->valx < 0 ) { + Syntax *syn; + + for( syn = cfn->c_syn_head; syn; syn_next( &syn )) { + syn_delete( syn ); + if ( syn == cfn->c_syn_tail ) + break; + } + cfn->c_syn_head = cfn->c_syn_tail = NULL; + } else { + Syntax *syn, *prev = NULL; + + for ( i = 0, syn = cfn->c_syn_head; i < c->valx; i++) { + prev = syn; + syn_next( &syn ); + } + syn_delete( syn ); + if ( cfn->c_syn_tail == syn ) { + cfn->c_syn_tail = prev; + } + if ( cfn->c_syn_head == syn ) { + syn_next( &syn ); + cfn->c_syn_head = syn; + } + } + break; case CFG_SORTVALS: if ( c->valx < 0 ) { ADlist *sv; @@ -1500,6 +1583,38 @@ 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; @@ -1578,11 +1693,10 @@ sortval_reject: 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 ) ) { @@ -1590,6 +1704,13 @@ sortval_reject: } 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] ); @@ -1665,20 +1786,28 @@ sortval_reject: *sip = si; if (( slapMode & SLAP_SERVER_MODE ) && c->argc > 2 ) { + Listener **l = slapd_get_listeners(); + int i, isMe = 0; + + /* Try a straight compare with Listener strings */ + for ( i=0; l && l[i]; i++ ) { + if ( !strcasecmp( c->argv[2], l[i]->sl_url.bv_val )) { + isMe = 1; + break; + } + } + /* 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] || + if ( !isMe && ( !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; + !strcasecmp( global_host, lud->lud_host ))) { - for ( i=0; l[i]; i++ ) { + for ( i=0; l && l[i]; i++ ) { LDAPURLDesc *lu2; - int isMe = 0; ldap_url_parse( l[i]->sl_url.bv_val, &lu2 ); do { if ( strcasecmp( lud->lud_scheme, @@ -1707,15 +1836,17 @@ sortval_reject: } 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; } } } + 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 ); + } } if ( c->argc > 2 ) ldap_free_urldesc( lud ); @@ -2140,13 +2271,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); @@ -2483,6 +2614,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) { @@ -2958,7 +3091,16 @@ 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%x.\n", c->log, flag, 0 ); + return 1; + } + + } else { + SLAP_DBFLAGS(c->be) |= (SLAP_DBFLAG_SHADOW | SLAP_DBFLAG_SINGLE_SHADOW | flag); + } return 0; } @@ -3087,6 +3229,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", @@ -3109,7 +3252,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 @@ -3158,7 +3301,7 @@ typedef struct setup_cookie { ConfigArgs *ca; Entry *frontend; Entry *config; - int got_frontend; + int got_frontend; int got_config; } setup_cookie; @@ -3167,15 +3310,18 @@ config_ldif_resp( Operation *op, SlapReply *rs ) { if ( rs->sr_type == REP_SEARCH ) { setup_cookie *sc = op->o_callback->sc_private; + struct berval pdn; sc->cfb->cb_got_ldif = 1; /* Does the frontend exist? */ if ( !sc->got_frontend ) { if ( !strncmp( rs->sr_entry->e_nname.bv_val, - "olcDatabase", STRLENOF( "olcDatabase" ))) { + "olcDatabase", STRLENOF( "olcDatabase" ))) + { if ( strncmp( rs->sr_entry->e_nname.bv_val + STRLENOF( "olcDatabase" ), "={-1}frontend", - STRLENOF( "={-1}frontend" ))) { + STRLENOF( "={-1}frontend" ))) + { struct berval rdn; int i = op->o_noop; sc->ca->be = frontendDB; @@ -3198,13 +3344,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 ); @@ -3505,6 +3657,9 @@ config_send( Operation *op, SlapReply *rs, CfEntryInfo *ce, int depth ) rs->sr_entry = ce->ce_entry; rs->sr_flags = 0; rc = send_search_entry( op, rs ); + if ( rc != LDAP_SUCCESS ) { + return rc; + } } if ( op->ors_scope == LDAP_SCOPE_SUBTREE ) { if ( ce->ce_kids ) { @@ -3667,14 +3822,15 @@ config_rename_kids( CfEntryInfo *ce ) struct berval rdn, nrdn; for (ce2 = ce->ce_kids; ce2; ce2 = ce2->ce_sibs) { + struct berval newdn, newndn; dnRdn ( &ce2->ce_entry->e_name, &rdn ); dnRdn ( &ce2->ce_entry->e_nname, &nrdn ); + build_new_dn( &newdn, &ce->ce_entry->e_name, &rdn, NULL ); + build_new_dn( &newndn, &ce->ce_entry->e_nname, &nrdn, NULL ); free( ce2->ce_entry->e_name.bv_val ); free( ce2->ce_entry->e_nname.bv_val ); - build_new_dn( &ce2->ce_entry->e_name, &ce->ce_entry->e_name, - &rdn, NULL ); - build_new_dn( &ce2->ce_entry->e_nname, &ce->ce_entry->e_nname, - &nrdn, NULL ); + ce2->ce_entry->e_name = newdn; + ce2->ce_entry->e_nname = newndn; config_rename_kids( ce2 ); } } @@ -3835,10 +3991,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; @@ -3879,7 +4035,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; } @@ -3990,6 +4146,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; } @@ -4054,6 +4215,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; @@ -4323,6 +4491,7 @@ config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca, SlapReply *rs, if ( !ct ) continue; /* user data? */ for (i=0; a->a_vals[i].bv_val; i++) { char *iptr = NULL; + ca->valx = -1; ca->line = a->a_vals[i].bv_val; if ( a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED ) { ptr = strchr( ca->line, '}' ); @@ -4334,8 +4503,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; @@ -4526,13 +4693,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; @@ -4615,6 +4791,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] == '{' ) { @@ -4778,7 +4955,7 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs, if ( rc == LDAP_SUCCESS) { /* check that the entry still obeys the schema */ - rc = entry_schema_check(op, e, NULL, 0, 0, + rc = entry_schema_check(op, e, NULL, 0, 0, NULL, &rs->sr_text, ca->cr_msg, sizeof(ca->cr_msg) ); } if ( rc ) goto out_noop; @@ -5225,7 +5402,102 @@ 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 ( 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; } @@ -5258,20 +5530,22 @@ config_back_search( Operation *op, SlapReply *rs ) switch ( op->ors_scope ) { case LDAP_SCOPE_BASE: case LDAP_SCOPE_SUBTREE: - config_send( op, rs, ce, 0 ); + rs->sr_err = config_send( op, rs, ce, 0 ); break; case LDAP_SCOPE_ONELEVEL: for (ce = ce->ce_kids; ce; ce=ce->ce_sibs) { - config_send( op, rs, ce, 1 ); + rs->sr_err = config_send( op, rs, ce, 1 ); + if ( rs->sr_err ) { + break; + } } break; } - - rs->sr_err = LDAP_SUCCESS; + out: send_ldap_result( op, rs ); - return 0; + return rs->sr_err; } /* no-op, we never free entries */ @@ -5317,7 +5591,7 @@ int config_back_entry_get( return rc; } -static void +static int config_build_attrs( Entry *e, AttributeType **at, AttributeDescription *ad, ConfigTable *ct, ConfigArgs *c ) { @@ -5334,18 +5608,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 * @@ -5359,7 +5657,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; @@ -5372,7 +5670,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 ); @@ -5397,7 +5695,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); @@ -5405,25 +5703,40 @@ 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->ora_e = e; @@ -5433,7 +5746,7 @@ config_build_entry( Operation *op, SlapReply *rs, CfEntryInfo *parent, op->o_bd->be_add( op, rs ); if ( ( rs->sr_err != LDAP_SUCCESS ) && (rs->sr_err != LDAP_ALREADY_EXISTS) ) { - return NULL; + goto fail; } } } @@ -5455,11 +5768,11 @@ config_build_schema_inc( ConfigArgs *c, CfEntryInfo *ceparent, Entry *e; ConfigFile *cf = c->ca_private; char *ptr; - struct berval bv; + struct berval bv, rdn; for (; cf; cf=cf->c_sibs, c->depth++) { if ( !cf->c_at_head && !cf->c_cr_head && !cf->c_oc_head && - !cf->c_om_head ) continue; + !cf->c_om_head && !cf->c_syn_head ) 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]); @@ -5481,9 +5794,10 @@ 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->ca_private = cf; - e = config_build_entry( op, rs, ceparent, c, &c->value_dn, + e = config_build_entry( op, rs, ceparent, c, &rdn, &CFOC_SCHEMA, NULL ); if ( !e ) { return -1; @@ -5588,6 +5902,21 @@ config_check_schema(Operation *op, CfBackInfo *cfb) ber_bvarray_free( bv ); cf_oc_tail = oc_sys_tail; } + if ( cf_syn_tail != syn_sys_tail ) { + a = attr_find( e->e_attrs, cfAd_syntax ); + if ( a ) { + if ( a->a_nvals != a->a_vals ) + ber_bvarray_free( a->a_nvals ); + ber_bvarray_free( a->a_vals ); + a->a_vals = NULL; + a->a_nvals = NULL; + a->a_numvals = 0; + } + syn_unparse( &bv, NULL, NULL, 1 ); + attr_merge_normalize( e, cfAd_syntax, bv, NULL ); + ber_bvarray_free( bv ); + cf_syn_tail = syn_sys_tail; + } } else { SlapReply rs = {REP_RESULT}; c.ca_private = NULL; @@ -5601,6 +5930,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; } @@ -5631,7 +5961,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 ); } @@ -5692,6 +6022,7 @@ 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 ) { @@ -5919,6 +6250,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; } @@ -6125,6 +6459,7 @@ static struct { { "backend", &cfAd_backend }, { "database", &cfAd_database }, { "include", &cfAd_include }, + { "ldapsyntax", &cfAd_syntax }, { "objectclass", &cfAd_oc }, { "objectidentifier", &cfAd_om }, { "overlay", &cfAd_overlay }, @@ -6231,6 +6566,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 );