From b527294153be3b79563c82c66102adc0004736c0 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 15 Apr 2024 19:54:12 +0200 Subject: Adding upstream version 2.6.7+dfsg. Signed-off-by: Daniel Baumann --- servers/slapd/back-asyncmeta/config.c | 2536 +++++++++++++++++++++++++++++++++ 1 file changed, 2536 insertions(+) create mode 100644 servers/slapd/back-asyncmeta/config.c (limited to 'servers/slapd/back-asyncmeta/config.c') diff --git a/servers/slapd/back-asyncmeta/config.c b/servers/slapd/back-asyncmeta/config.c new file mode 100644 index 0000000..e4cc5ea --- /dev/null +++ b/servers/slapd/back-asyncmeta/config.c @@ -0,0 +1,2536 @@ +/* config.c - configuration parsing for back-asyncmeta */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software . + * + * Copyright 2016-2022 The OpenLDAP Foundation. + * Portions Copyright 2016 Symas Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ + +/* ACKNOWLEDGEMENTS: + * This work was developed by Symas Corporation + * based on back-meta module for inclusion in OpenLDAP Software. + * This work was sponsored by Ericsson. */ + +#include "portable.h" + +#include +#include + +#include +#include + +#include "slap.h" +#include "slap-config.h" +#include "lutil.h" +#include "ldif.h" +#include "../back-ldap/back-ldap.h" +#include "back-asyncmeta.h" + +#ifdef LDAP_DEVEL +#define SLAP_AUTH_DN 1 +#endif + +static ConfigDriver asyncmeta_back_cf_gen; +static ConfigLDAPadd asyncmeta_ldadd; +static ConfigCfAdd asyncmeta_cfadd; + +/* Three sets of enums: + * 1) attrs that are only valid in the base config + * 2) attrs that are valid in base or target + * 3) attrs that are only valid in a target + */ + +/* Base attrs */ +enum { + LDAP_BACK_CFG_DNCACHE_TTL = 1, + LDAP_BACK_CFG_IDLE_TIMEOUT, + LDAP_BACK_CFG_ONERR, + LDAP_BACK_CFG_PSEUDOROOT_BIND_DEFER, + LDAP_BACK_CFG_CONNPOOLMAX, + LDAP_BACK_CFG_MAX_TIMEOUT_OPS, + LDAP_BACK_CFG_MAX_PENDING_OPS, + LDAP_BACK_CFG_MAX_TARGET_CONNS, + LDAP_BACK_CFG_LAST_BASE, +}; + +/* Base or target */ +enum { + LDAP_BACK_CFG_BIND_TIMEOUT = LDAP_BACK_CFG_LAST_BASE, + LDAP_BACK_CFG_CANCEL, + LDAP_BACK_CFG_CHASE, + LDAP_BACK_CFG_CLIENT_PR, + LDAP_BACK_CFG_DEFAULT_T, + LDAP_BACK_CFG_NETWORK_TIMEOUT, + LDAP_BACK_CFG_NOREFS, + LDAP_BACK_CFG_NOUNDEFFILTER, + LDAP_BACK_CFG_NRETRIES, + LDAP_BACK_CFG_QUARANTINE, + LDAP_BACK_CFG_REBIND, + LDAP_BACK_CFG_TIMEOUT, + LDAP_BACK_CFG_VERSION, + LDAP_BACK_CFG_ST_REQUEST, + LDAP_BACK_CFG_T_F, + LDAP_BACK_CFG_TLS, + LDAP_BACK_CFG_LAST_BOTH +}; + +/* Target attrs */ +enum { + LDAP_BACK_CFG_URI = LDAP_BACK_CFG_LAST_BOTH, + LDAP_BACK_CFG_IDASSERT_AUTHZFROM, + LDAP_BACK_CFG_IDASSERT_BIND, + LDAP_BACK_CFG_SUFFIXM, + LDAP_BACK_CFG_SUBTREE_EX, + LDAP_BACK_CFG_SUBTREE_IN, + LDAP_BACK_CFG_KEEPALIVE, + LDAP_BACK_CFG_FILTER, + LDAP_BACK_CFG_TCP_USER_TIMEOUT, + LDAP_BACK_CFG_LAST +}; + +static ConfigTable a_metacfg[] = { + { "uri", "uri", 2, 0, 0, + ARG_MAGIC|LDAP_BACK_CFG_URI, + asyncmeta_back_cf_gen, "( OLcfgDbAt:0.14 " + "NAME 'olcDbURI' " + "DESC 'URI (list) for remote DSA' " + "SYNTAX OMsDirectoryString " + "SINGLE-VALUE )", + NULL, NULL }, + { "tls", "what", 2, 0, 0, + ARG_MAGIC|LDAP_BACK_CFG_TLS, + asyncmeta_back_cf_gen, "( OLcfgDbAt:3.1 " + "NAME 'olcDbStartTLS' " + "DESC 'StartTLS' " + "SYNTAX OMsDirectoryString " + "SINGLE-VALUE )", + NULL, NULL }, + { "idassert-bind", "args", 2, 0, 0, + ARG_MAGIC|LDAP_BACK_CFG_IDASSERT_BIND, + asyncmeta_back_cf_gen, "( OLcfgDbAt:3.7 " + "NAME 'olcDbIDAssertBind' " + "DESC 'Remote Identity Assertion administrative identity auth bind configuration' " + "SYNTAX OMsDirectoryString " + "SINGLE-VALUE )", + NULL, NULL }, + { "idassert-authzFrom", "authzRule", 2, 2, 0, + ARG_MAGIC|LDAP_BACK_CFG_IDASSERT_AUTHZFROM, + asyncmeta_back_cf_gen, "( OLcfgDbAt:3.9 " + "NAME 'olcDbIDAssertAuthzFrom' " + "DESC 'Remote Identity Assertion authz rules' " + "EQUALITY caseIgnoreMatch " + "SYNTAX OMsDirectoryString " + "X-ORDERED 'VALUES' )", + NULL, NULL }, + { "rebind-as-user", "true|FALSE", 1, 2, 0, + ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_REBIND, + asyncmeta_back_cf_gen, "( OLcfgDbAt:3.10 " + "NAME 'olcDbRebindAsUser' " + "DESC 'Rebind as user' " + "SYNTAX OMsBoolean " + "SINGLE-VALUE )", + NULL, NULL }, + { "chase-referrals", "true|FALSE", 2, 2, 0, + ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_CHASE, + asyncmeta_back_cf_gen, "( OLcfgDbAt:3.11 " + "NAME 'olcDbChaseReferrals' " + "DESC 'Chase referrals' " + "SYNTAX OMsBoolean " + "SINGLE-VALUE )", + NULL, NULL }, + { "t-f-support", "true|FALSE|discover", 2, 2, 0, + ARG_MAGIC|LDAP_BACK_CFG_T_F, + asyncmeta_back_cf_gen, "( OLcfgDbAt:3.12 " + "NAME 'olcDbTFSupport' " + "DESC 'Absolute filters support' " + "SYNTAX OMsDirectoryString " + "SINGLE-VALUE )", + NULL, NULL }, + { "timeout", "timeout(list)", 2, 0, 0, + ARG_MAGIC|LDAP_BACK_CFG_TIMEOUT, + asyncmeta_back_cf_gen, "( OLcfgDbAt:3.14 " + "NAME 'olcDbTimeout' " + "DESC 'Per-operation timeouts' " + "SYNTAX OMsDirectoryString " + "SINGLE-VALUE )", + NULL, NULL }, + { "idle-timeout", "timeout", 2, 2, 0, + ARG_MAGIC|LDAP_BACK_CFG_IDLE_TIMEOUT, + asyncmeta_back_cf_gen, "( OLcfgDbAt:3.15 " + "NAME 'olcDbIdleTimeout' " + "DESC 'connection idle timeout' " + "SYNTAX OMsDirectoryString " + "SINGLE-VALUE )", + NULL, NULL }, + { "network-timeout", "timeout", 2, 2, 0, + ARG_MAGIC|LDAP_BACK_CFG_NETWORK_TIMEOUT, + asyncmeta_back_cf_gen, "( OLcfgDbAt:3.17 " + "NAME 'olcDbNetworkTimeout' " + "DESC 'connection network timeout' " + "SYNTAX OMsDirectoryString " + "SINGLE-VALUE )", + NULL, NULL }, + { "protocol-version", "version", 2, 2, 0, + ARG_MAGIC|ARG_INT|LDAP_BACK_CFG_VERSION, + asyncmeta_back_cf_gen, "( OLcfgDbAt:3.18 " + "NAME 'olcDbProtocolVersion' " + "DESC 'protocol version' " + "SYNTAX OMsInteger " + "SINGLE-VALUE )", + NULL, NULL }, + + { "cancel", "ABANDON|ignore|exop", 2, 2, 0, + ARG_MAGIC|LDAP_BACK_CFG_CANCEL, + asyncmeta_back_cf_gen, "( OLcfgDbAt:3.20 " + "NAME 'olcDbCancel' " + "DESC 'abandon/ignore/exop operations when appropriate' " + "SYNTAX OMsDirectoryString " + "SINGLE-VALUE )", + NULL, NULL }, + { "quarantine", "retrylist", 2, 2, 0, + ARG_MAGIC|LDAP_BACK_CFG_QUARANTINE, + asyncmeta_back_cf_gen, "( OLcfgDbAt:3.21 " + "NAME 'olcDbQuarantine' " + "DESC 'Quarantine database if connection fails and retry according to rule' " + "SYNTAX OMsDirectoryString " + "SINGLE-VALUE )", + NULL, NULL }, + + { "conn-pool-max", "", 2, 2, 0, + ARG_MAGIC|ARG_INT|LDAP_BACK_CFG_CONNPOOLMAX, + asyncmeta_back_cf_gen, "( OLcfgDbAt:3.23 " + "NAME 'olcDbConnectionPoolMax' " + "DESC 'Max size of privileged connections pool' " + "SYNTAX OMsInteger " + "SINGLE-VALUE )", + NULL, NULL }, +#ifdef SLAP_CONTROL_X_SESSION_TRACKING + { "session-tracking-request", "true|FALSE", 2, 2, 0, + ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_ST_REQUEST, + asyncmeta_back_cf_gen, "( OLcfgDbAt:3.24 " + "NAME 'olcDbSessionTrackingRequest' " + "DESC 'Add session tracking control to proxied requests' " + "SYNTAX OMsBoolean " + "SINGLE-VALUE )", + NULL, NULL }, +#endif /* SLAP_CONTROL_X_SESSION_TRACKING */ + { "norefs", "true|FALSE", 2, 2, 0, + ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_NOREFS, + asyncmeta_back_cf_gen, "( OLcfgDbAt:3.25 " + "NAME 'olcDbNoRefs' " + "DESC 'Do not return search reference responses' " + "SYNTAX OMsBoolean " + "SINGLE-VALUE )", + NULL, NULL }, + { "noundeffilter", "true|FALSE", 2, 2, 0, + ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_NOUNDEFFILTER, + asyncmeta_back_cf_gen, "( OLcfgDbAt:3.26 " + "NAME 'olcDbNoUndefFilter' " + "DESC 'Do not propagate undefined search filters' " + "SYNTAX OMsBoolean " + "SINGLE-VALUE )", + NULL, NULL }, + + { "suffixmassage", "local> ]", 1, 2, 0, + ARG_MAGIC|LDAP_BACK_CFG_DEFAULT_T, + asyncmeta_back_cf_gen, "( OLcfgDbAt:3.105 " + "NAME 'olcDbDefaultTarget' " + "DESC 'Specify the default target' " + "SYNTAX OMsDirectoryString " + "SINGLE-VALUE )", + NULL, NULL }, + { "dncache-ttl", "ttl", 2, 2, 0, + ARG_MAGIC|LDAP_BACK_CFG_DNCACHE_TTL, + asyncmeta_back_cf_gen, "( OLcfgDbAt:3.106 " + "NAME 'olcDbDnCacheTtl' " + "DESC 'dncache ttl' " + "SYNTAX OMsDirectoryString " + "SINGLE-VALUE )", + NULL, NULL }, + { "bind-timeout", "microseconds", 2, 2, 0, + ARG_MAGIC|ARG_ULONG|LDAP_BACK_CFG_BIND_TIMEOUT, + asyncmeta_back_cf_gen, "( OLcfgDbAt:3.107 " + "NAME 'olcDbBindTimeout' " + "DESC 'bind timeout' " + "SYNTAX OMsDirectoryString " + "SINGLE-VALUE )", + NULL, NULL }, + { "onerr", "CONTINUE|report|stop", 2, 2, 0, + ARG_MAGIC|LDAP_BACK_CFG_ONERR, + asyncmeta_back_cf_gen, "( OLcfgDbAt:3.108 " + "NAME 'olcDbOnErr' " + "DESC 'error handling' " + "SYNTAX OMsDirectoryString " + "SINGLE-VALUE )", + NULL, NULL }, + { "pseudoroot-bind-defer", "TRUE|false", 2, 2, 0, + ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_PSEUDOROOT_BIND_DEFER, + asyncmeta_back_cf_gen, "( OLcfgDbAt:3.109 " + "NAME 'olcDbPseudoRootBindDefer' " + "DESC 'error handling' " + "SYNTAX OMsBoolean " + "SINGLE-VALUE )", + NULL, NULL }, + { "root-bind-defer", "TRUE|false", 2, 2, 0, + ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_PSEUDOROOT_BIND_DEFER, + asyncmeta_back_cf_gen, NULL, NULL, NULL }, + { "nretries", "NEVER|forever|", 2, 2, 0, + ARG_MAGIC|LDAP_BACK_CFG_NRETRIES, + asyncmeta_back_cf_gen, "( OLcfgDbAt:3.110 " + "NAME 'olcDbNretries' " + "DESC 'retry handling' " + "SYNTAX OMsDirectoryString " + "SINGLE-VALUE )", + NULL, NULL }, + { "client-pr", "accept-unsolicited|disable|", 2, 2, 0, + ARG_MAGIC|LDAP_BACK_CFG_CLIENT_PR, + asyncmeta_back_cf_gen, "( OLcfgDbAt:3.111 " + "NAME 'olcDbClientPr' " + "DESC 'PagedResults handling' " + "SYNTAX OMsDirectoryString " + "SINGLE-VALUE )", + NULL, NULL }, + + { "", "", 0, 0, 0, ARG_IGNORED, + NULL, "( OLcfgDbAt:3.116 NAME 'olcAsyncMetaSub' " + "DESC 'Placeholder to name a Target entry' " + "EQUALITY caseIgnoreMatch " + "SYNTAX OMsDirectoryString " + "SINGLE-VALUE X-ORDERED 'SIBLINGS' )", NULL, NULL }, + + { "keepalive", "keepalive", 2, 2, 0, + ARG_MAGIC|LDAP_BACK_CFG_KEEPALIVE, + asyncmeta_back_cf_gen, "( OLcfgDbAt:3.29 " + "NAME 'olcDbKeepalive' " + "DESC 'TCP keepalive' " + "SYNTAX OMsDirectoryString " + "SINGLE-VALUE )", + NULL, NULL }, + + { "tcp-user-timeout", "milliseconds", 2, 2, 0, + ARG_MAGIC|ARG_UINT|LDAP_BACK_CFG_TCP_USER_TIMEOUT, + asyncmeta_back_cf_gen, "( OLcfgDbAt:3.30 " + "NAME 'olcDbTcpUserTimeout' " + "DESC 'TCP User Timeout' " + "SYNTAX OMsInteger " + "SINGLE-VALUE )", + NULL, NULL }, + + { "filter", "pattern", 2, 2, 0, + ARG_MAGIC|LDAP_BACK_CFG_FILTER, + asyncmeta_back_cf_gen, "( OLcfgDbAt:3.112 " + "NAME 'olcDbFilter' " + "DESC 'Filter regex pattern to include in target' " + "EQUALITY caseExactMatch " + "SYNTAX OMsDirectoryString )", + NULL, NULL }, + + { "max-pending-ops", "", 2, 2, 0, + ARG_MAGIC|ARG_INT|LDAP_BACK_CFG_MAX_PENDING_OPS, + asyncmeta_back_cf_gen, "( OLcfgDbAt:3.113 " + "NAME 'olcDbMaxPendingOps' " + "DESC 'Maximum number of pending operations' " + "SYNTAX OMsInteger " + "SINGLE-VALUE )", + NULL, NULL }, + + { "max-target-conns", "", 2, 2, 0, + ARG_MAGIC|ARG_INT|LDAP_BACK_CFG_MAX_TARGET_CONNS, + asyncmeta_back_cf_gen, "( OLcfgDbAt:3.114 " + "NAME 'olcDbMaxTargetConns' " + "DESC 'Maximum number of open connections per target' " + "SYNTAX OMsInteger " + "SINGLE-VALUE )", + NULL, NULL }, + + { "max-timeout-ops", "", 2, 2, 0, + ARG_MAGIC|ARG_INT|LDAP_BACK_CFG_MAX_TIMEOUT_OPS, + asyncmeta_back_cf_gen, "( OLcfgDbAt:3.115 " + "NAME 'olcDbMaxTimeoutOps' " + "DESC 'Maximum number of consecutive timeout operations after which the connection is reset' " + "SYNTAX OMsInteger " + "SINGLE-VALUE )", + NULL, NULL }, + + { NULL, NULL, 0, 0, 0, ARG_IGNORED, + NULL, NULL, NULL, NULL } +}; + +#ifdef SLAP_CONTROL_X_SESSION_TRACKING +#define ST_ATTR "$ olcDbSessionTrackingRequest " +#else +#define ST_ATTR "" +#endif /* SLAP_CONTROL_X_SESSION_TRACKING */ + +#define COMMON_ATTRS \ + "$ olcDbBindTimeout " \ + "$ olcDbCancel " \ + "$ olcDbChaseReferrals " \ + "$ olcDbClientPr " \ + "$ olcDbDefaultTarget " \ + "$ olcDbNetworkTimeout " \ + "$ olcDbNoRefs " \ + "$ olcDbNoUndefFilter " \ + "$ olcDbNretries " \ + "$ olcDbProtocolVersion " \ + "$ olcDbQuarantine " \ + "$ olcDbRebindAsUser " \ + ST_ATTR \ + "$ olcDbStartTLS " \ + "$ olcDbTFSupport " + +static ConfigOCs a_metaocs[] = { + { "( OLcfgDbOc:3.4 " + "NAME 'olcAsyncMetaConfig' " + "DESC 'Asyncmeta backend configuration' " + "SUP olcDatabaseConfig " + "MAY ( olcDbDnCacheTtl " + "$ olcDbIdleTimeout " + "$ olcDbOnErr " + "$ olcDbPseudoRootBindDefer " + "$ olcDbConnectionPoolMax " + "$ olcDbMaxTimeoutOps" + "$ olcDbMaxPendingOps " + "$ olcDbMaxTargetConns" + /* defaults, may be overridden per-target */ + COMMON_ATTRS + ") )", + Cft_Database, a_metacfg, NULL, asyncmeta_cfadd }, + { "( OLcfgDbOc:3.5 " + "NAME 'olcAsyncMetaTargetConfig' " + "DESC 'Asyncmeta target configuration' " + "SUP olcConfig STRUCTURAL " + "MUST ( olcAsyncMetaSub $ olcDbURI ) " + "MAY ( olcDbIDAssertAuthzFrom " + "$ olcDbIDAssertBind " + "$ olcDbSuffixMassage " + "$ olcDbSubtreeExclude " + "$ olcDbSubtreeInclude " + "$ olcDbTimeout " + "$ olcDbKeepalive " + "$ olcDbFilter " + "$ olcDbTcpUserTimeout " + + /* defaults may be inherited */ + COMMON_ATTRS + ") )", + Cft_Misc, a_metacfg, asyncmeta_ldadd }, + { NULL, 0, NULL } +}; + +static int +asyncmeta_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *c ) +{ + a_metainfo_t *mi; + + if ( p->ce_type != Cft_Database || !p->ce_be || + p->ce_be->be_cf_ocs != a_metaocs ) + return LDAP_CONSTRAINT_VIOLATION; + + c->be = p->ce_be; + mi = ( a_metainfo_t * )c->be->be_private; + + if ( asyncmeta_db_has_pending_ops ( mi ) > 0 ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), + "cannot modify a working database" ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); + return 1; + } + return LDAP_SUCCESS; +} + +static int +asyncmeta_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *c ) +{ + a_metainfo_t *mi = ( a_metainfo_t * )c->be->be_private; + struct berval bv; + int i; + + bv.bv_val = c->cr_msg; + for ( i=0; imi_ntargets; i++ ) { + bv.bv_len = snprintf( c->cr_msg, sizeof(c->cr_msg), + "olcAsyncMetaSub=" SLAP_X_ORDERED_FMT "uri", i ); + c->ca_private = mi->mi_targets[i]; + c->valx = i; + config_build_entry( op, rs, p->e_private, c, + &bv, &a_metaocs[1], NULL ); + } + + return LDAP_SUCCESS; +} + +static int +asyncmeta_back_new_target( + a_metatarget_t **mtp, + a_metainfo_t *mi ) +{ + a_metatarget_t *mt; + + *mtp = NULL; + int i; + + assert ( mi != NULL ); + mt = ch_calloc( sizeof( a_metatarget_t ), 1 ); + + ldap_pvt_thread_mutex_init( &mt->mt_uri_mutex ); + + mt->mt_idassert_mode = LDAP_BACK_IDASSERT_LEGACY; + mt->mt_idassert_authmethod = LDAP_AUTH_NONE; + mt->mt_idassert_tls = SB_TLS_DEFAULT; + /* by default, use proxyAuthz control on each operation */ + mt->mt_idassert_flags = LDAP_BACK_AUTH_PRESCRIPTIVE; + + *mtp = mt; + + for ( i = 0; i < mi->mi_num_conns; i++ ) { + a_metaconn_t *mc = &mi->mi_conns[i]; + mc->mc_conns = ch_realloc( mc->mc_conns, sizeof( a_metasingleconn_t ) * mi->mi_ntargets); + memset( &(mc->mc_conns[mi->mi_ntargets-1]), 0, sizeof( a_metasingleconn_t ) ); + } + /* If this is the first target, start the timeout loop */ + if ( mi->mi_ntargets == 1 ) { + ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); + mi->mi_task = ldap_pvt_runqueue_insert( &slapd_rq, 1, + asyncmeta_timeout_loop, mi, "asyncmeta_timeout_loop", mi->mi_suffix.bv_val ); + ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); + } + return 0; +} + +/* suffixmassage config */ +static int +asyncmeta_suffixm_config( + ConfigArgs *c, + int argc, + char **argv, + a_metatarget_t *mt +) +{ + BackendDB *tmp_bd; + struct berval dn, nvnc, pvnc, nrnc, prnc; + int j; + + /* + * syntax: + * + * suffixmassage + * + * the field must be defined as a valid suffix + * (or suffixAlias?) for the current database; + * the shouldn't have already been + * defined as a valid suffix or suffixAlias for the + * current server + */ + + ber_str2bv( argv[ 1 ], 0, 0, &dn ); + if ( dnPrettyNormal( NULL, &dn, &pvnc, &nvnc, NULL ) != LDAP_SUCCESS ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), + "suffix \"%s\" is invalid", + argv[1] ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); + return 1; + } + + for ( j = 0; !BER_BVISNULL( &c->be->be_nsuffix[ j ] ); j++ ) { + if ( dnIsSuffix( &nvnc, &c->be->be_nsuffix[ 0 ] ) ) { + break; + } + } + + if ( BER_BVISNULL( &c->be->be_nsuffix[ j ] ) ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), + "suffix \"%s\" must be within the database naming context", + argv[1] ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); + free( pvnc.bv_val ); + free( nvnc.bv_val ); + return 1; + } + + ber_str2bv( argv[ 2 ], 0, 0, &dn ); + if ( dnPrettyNormal( NULL, &dn, &prnc, &nrnc, NULL ) != LDAP_SUCCESS ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), + "massaged suffix \"%s\" is invalid", + argv[2] ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); + free( pvnc.bv_val ); + free( nvnc.bv_val ); + return 1; + } + + tmp_bd = select_backend( &nrnc, 0 ); + if ( tmp_bd != NULL && tmp_bd->be_private == c->be->be_private ) { + Debug( LDAP_DEBUG_ANY, + "%s: warning: \"%s\" resolves to this database, in " + "\"suffixMassage \"\n", + c->log, prnc.bv_val ); + } + + mt->mt_lsuffixm = pvnc; + mt->mt_rsuffixm = prnc; + + free( nvnc.bv_val ); + free( nrnc.bv_val ); + + return 0; +} + +int +asyncmeta_subtree_free( a_metasubtree_t *ms ) +{ + switch ( ms->ms_type ) { + case META_ST_SUBTREE: + case META_ST_SUBORDINATE: + ber_memfree( ms->ms_dn.bv_val ); + break; + + case META_ST_REGEX: + regfree( &ms->ms_regex ); + ber_memfree( ms->ms_regex_pattern.bv_val ); + break; + + default: + return -1; + } + + ch_free( ms ); + return 0; +} + +int +asyncmeta_subtree_destroy( a_metasubtree_t *ms ) +{ + if ( ms->ms_next ) { + asyncmeta_subtree_destroy( ms->ms_next ); + } + + return asyncmeta_subtree_free( ms ); +} + +static void +asyncmeta_filter_free( metafilter_t *mf ) +{ + regfree( &mf->mf_regex ); + ber_memfree( mf->mf_regex_pattern.bv_val ); + ch_free( mf ); +} + +void +asyncmeta_filter_destroy( metafilter_t *mf ) +{ + if ( mf->mf_next ) + asyncmeta_filter_destroy( mf->mf_next ); + asyncmeta_filter_free( mf ); +} + +static struct berval st_styles[] = { + BER_BVC("subtree"), + BER_BVC("children"), + BER_BVC("regex") +}; + +static int +asyncmeta_subtree_unparse( + ConfigArgs *c, + a_metatarget_t *mt ) +{ + a_metasubtree_t *ms; + struct berval bv, *style; + + if ( !mt->mt_subtree ) + return 1; + + /* can only be one of exclude or include */ + if (( c->type == LDAP_BACK_CFG_SUBTREE_EX ) ^ mt->mt_subtree_exclude ) + return 1; + + bv.bv_val = c->cr_msg; + for ( ms=mt->mt_subtree; ms; ms=ms->ms_next ) { + if (ms->ms_type == META_ST_SUBTREE) + style = &st_styles[0]; + else if ( ms->ms_type == META_ST_SUBORDINATE ) + style = &st_styles[1]; + else if ( ms->ms_type == META_ST_REGEX ) + style = &st_styles[2]; + else { + assert(0); + continue; + } + bv.bv_len = snprintf( c->cr_msg, sizeof(c->cr_msg), + "dn.%s:%s", style->bv_val, ms->ms_dn.bv_val ); + value_add_one( &c->rvalue_vals, &bv ); + } + return 0; +} + +static int +asyncmeta_subtree_config( + a_metatarget_t *mt, + ConfigArgs *c ) +{ + meta_st_t type = META_ST_SUBTREE; + char *pattern; + struct berval ndn = BER_BVNULL; + a_metasubtree_t *ms = NULL; + + if ( c->type == LDAP_BACK_CFG_SUBTREE_EX ) { + if ( mt->mt_subtree && !mt->mt_subtree_exclude ) { + snprintf( c->cr_msg, sizeof(c->cr_msg), + "\"subtree-exclude\" incompatible with previous \"subtree-include\" directives" ); + return 1; + } + + mt->mt_subtree_exclude = 1; + + } else { + if ( mt->mt_subtree && mt->mt_subtree_exclude ) { + snprintf( c->cr_msg, sizeof(c->cr_msg), + "\"subtree-include\" incompatible with previous \"subtree-exclude\" directives" ); + return 1; + } + } + + pattern = c->argv[1]; + if ( strncasecmp( pattern, "dn", STRLENOF( "dn" ) ) == 0 ) { + char *style; + + pattern = &pattern[STRLENOF( "dn")]; + + if ( pattern[0] == '.' ) { + style = &pattern[1]; + + if ( strncasecmp( style, "subtree", STRLENOF( "subtree" ) ) == 0 ) { + type = META_ST_SUBTREE; + pattern = &style[STRLENOF( "subtree" )]; + + } else if ( strncasecmp( style, "children", STRLENOF( "children" ) ) == 0 ) { + type = META_ST_SUBORDINATE; + pattern = &style[STRLENOF( "children" )]; + + } else if ( strncasecmp( style, "sub", STRLENOF( "sub" ) ) == 0 ) { + type = META_ST_SUBTREE; + pattern = &style[STRLENOF( "sub" )]; + + } else if ( strncasecmp( style, "regex", STRLENOF( "regex" ) ) == 0 ) { + type = META_ST_REGEX; + pattern = &style[STRLENOF( "regex" )]; + + } else { + snprintf( c->cr_msg, sizeof(c->cr_msg), "unknown style in \"dn.