/* 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.