/* 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 )
{
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;
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_metatarget_t *mt;
*mtp = 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;
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.