/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software .
*
* Copyright 1999-2021 The OpenLDAP Foundation.
* Portions Copyright 2001-2003 Pierangelo Masarati.
* Portions Copyright 1999-2003 Howard Chu.
* 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 initially developed by the Howard Chu for inclusion
* in OpenLDAP Software and subsequently enhanced by Pierangelo
* Masarati.
*/
#include "portable.h"
#include
#include
#include
#include
#include "slap.h"
#include "config.h"
#include "lutil.h"
#include "ldif.h"
#include "../back-ldap/back-ldap.h"
#include "back-meta.h"
#ifdef LDAP_DEVEL
#define SLAP_AUTH_DN 1
#endif
static ConfigDriver meta_back_cf_gen;
static ConfigLDAPadd meta_ldadd;
static ConfigCfAdd meta_cfadd;
static int ldap_back_map_config(
ConfigArgs *c,
struct ldapmap *oc_map,
struct ldapmap *at_map );
/* 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_CONN_TTL = 1,
LDAP_BACK_CFG_DNCACHE_TTL,
LDAP_BACK_CFG_IDLE_TIMEOUT,
LDAP_BACK_CFG_ONERR,
LDAP_BACK_CFG_PSEUDOROOT_BIND_DEFER,
LDAP_BACK_CFG_SINGLECONN,
LDAP_BACK_CFG_USETEMP,
LDAP_BACK_CFG_CONNPOOLMAX,
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_ACL_AUTHCDN,
LDAP_BACK_CFG_ACL_PASSWD,
LDAP_BACK_CFG_IDASSERT_AUTHZFROM,
LDAP_BACK_CFG_IDASSERT_BIND,
LDAP_BACK_CFG_REWRITE,
LDAP_BACK_CFG_SUFFIXM,
LDAP_BACK_CFG_MAP,
LDAP_BACK_CFG_SUBTREE_EX,
LDAP_BACK_CFG_SUBTREE_IN,
LDAP_BACK_CFG_PSEUDOROOTDN,
LDAP_BACK_CFG_PSEUDOROOTPW,
LDAP_BACK_CFG_KEEPALIVE,
LDAP_BACK_CFG_FILTER,
LDAP_BACK_CFG_LAST
};
static ConfigTable metacfg[] = {
{ "uri", "uri", 2, 0, 0,
ARG_MAGIC|LDAP_BACK_CFG_URI,
meta_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,
meta_back_cf_gen, "( OLcfgDbAt:3.1 "
"NAME 'olcDbStartTLS' "
"DESC 'StartTLS' "
"SYNTAX OMsDirectoryString "
"SINGLE-VALUE )",
NULL, NULL },
{ "acl-authcDN", "DN", 2, 2, 0,
ARG_DN|ARG_MAGIC|LDAP_BACK_CFG_ACL_AUTHCDN,
meta_back_cf_gen, "( OLcfgDbAt:3.2 "
"NAME 'olcDbACLAuthcDn' "
"DESC 'Remote ACL administrative identity' "
"OBSOLETE "
"SYNTAX OMsDN "
"SINGLE-VALUE )",
NULL, NULL },
/* deprecated, will be removed; aliases "acl-authcDN" */
{ "binddn", "DN", 2, 2, 0,
ARG_DN|ARG_MAGIC|LDAP_BACK_CFG_ACL_AUTHCDN,
meta_back_cf_gen, NULL, NULL, NULL },
{ "acl-passwd", "cred", 2, 2, 0,
ARG_MAGIC|LDAP_BACK_CFG_ACL_PASSWD,
meta_back_cf_gen, "( OLcfgDbAt:3.3 "
"NAME 'olcDbACLPasswd' "
"DESC 'Remote ACL administrative identity credentials' "
"OBSOLETE "
"SYNTAX OMsDirectoryString "
"SINGLE-VALUE )",
NULL, NULL },
/* deprecated, will be removed; aliases "acl-passwd" */
{ "bindpw", "cred", 2, 2, 0,
ARG_MAGIC|LDAP_BACK_CFG_ACL_PASSWD,
meta_back_cf_gen, NULL, NULL, NULL },
{ "idassert-bind", "args", 2, 0, 0,
ARG_MAGIC|LDAP_BACK_CFG_IDASSERT_BIND,
meta_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,
meta_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,
meta_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,
meta_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,
meta_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,
meta_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,
meta_back_cf_gen, "( OLcfgDbAt:3.15 "
"NAME 'olcDbIdleTimeout' "
"DESC 'connection idle timeout' "
"SYNTAX OMsDirectoryString "
"SINGLE-VALUE )",
NULL, NULL },
{ "conn-ttl", "ttl", 2, 2, 0,
ARG_MAGIC|LDAP_BACK_CFG_CONN_TTL,
meta_back_cf_gen, "( OLcfgDbAt:3.16 "
"NAME 'olcDbConnTtl' "
"DESC 'connection ttl' "
"SYNTAX OMsDirectoryString "
"SINGLE-VALUE )",
NULL, NULL },
{ "network-timeout", "timeout", 2, 2, 0,
ARG_MAGIC|LDAP_BACK_CFG_NETWORK_TIMEOUT,
meta_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,
meta_back_cf_gen, "( OLcfgDbAt:3.18 "
"NAME 'olcDbProtocolVersion' "
"DESC 'protocol version' "
"SYNTAX OMsInteger "
"SINGLE-VALUE )",
NULL, NULL },
{ "single-conn", "true|FALSE", 2, 2, 0,
ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_SINGLECONN,
meta_back_cf_gen, "( OLcfgDbAt:3.19 "
"NAME 'olcDbSingleConn' "
"DESC 'cache a single connection per identity' "
"SYNTAX OMsBoolean "
"SINGLE-VALUE )",
NULL, NULL },
{ "cancel", "ABANDON|ignore|exop", 2, 2, 0,
ARG_MAGIC|LDAP_BACK_CFG_CANCEL,
meta_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,
meta_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 },
{ "use-temporary-conn", "true|FALSE", 2, 2, 0,
ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_USETEMP,
meta_back_cf_gen, "( OLcfgDbAt:3.22 "
"NAME 'olcDbUseTemporaryConn' "
"DESC 'Use temporary connections if the cached one is busy' "
"SYNTAX OMsBoolean "
"SINGLE-VALUE )",
NULL, NULL },
{ "conn-pool-max", "", 2, 2, 0,
ARG_MAGIC|ARG_INT|LDAP_BACK_CFG_CONNPOOLMAX,
meta_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,
meta_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,
meta_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,
meta_back_cf_gen, "( OLcfgDbAt:3.26 "
"NAME 'olcDbNoUndefFilter' "
"DESC 'Do not propagate undefined search filters' "
"SYNTAX OMsBoolean "
"SINGLE-VALUE )",
NULL, NULL },
{ "rewrite", "arglist", 2, 0, STRLENOF( "rewrite" ),
ARG_MAGIC|LDAP_BACK_CFG_REWRITE,
meta_back_cf_gen, "( OLcfgDbAt:3.101 "
"NAME 'olcDbRewrite' "
"DESC 'DN rewriting rules' "
"EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString "
"X-ORDERED 'VALUES' )",
NULL, NULL },
{ "suffixmassage", "virtual> [*|] *|]", 1, 2, 0,
ARG_MAGIC|LDAP_BACK_CFG_DEFAULT_T,
meta_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,
meta_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,
meta_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,
meta_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,
meta_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,
meta_back_cf_gen, NULL, NULL, NULL },
{ "pseudorootdn", "dn", 2, 2, 0,
ARG_MAGIC|ARG_DN|LDAP_BACK_CFG_PSEUDOROOTDN,
meta_back_cf_gen, NULL, NULL, NULL },
{ "pseudorootpw", "password", 2, 2, 0,
ARG_MAGIC|ARG_STRING|LDAP_BACK_CFG_PSEUDOROOTDN,
meta_back_cf_gen, NULL, NULL, NULL },
{ "nretries", "NEVER|forever|", 2, 2, 0,
ARG_MAGIC|LDAP_BACK_CFG_NRETRIES,
meta_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,
meta_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.100 NAME 'olcMetaSub' "
"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,
meta_back_cf_gen, "( OLcfgDbAt:3.29 "
"NAME 'olcDbKeepalive' "
"DESC 'TCP keepalive' "
"SYNTAX OMsDirectoryString "
"SINGLE-VALUE )",
NULL, NULL },
{ "filter", "pattern", 2, 2, 0,
ARG_MAGIC|LDAP_BACK_CFG_FILTER,
meta_back_cf_gen, "( OLcfgDbAt:3.112 "
"NAME 'olcDbFilter' "
"DESC 'Filter regex pattern to include in target' "
"EQUALITY caseExactMatch "
"SYNTAX OMsDirectoryString )",
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 metaocs[] = {
{ "( OLcfgDbOc:3.2 "
"NAME 'olcMetaConfig' "
"DESC 'Meta backend configuration' "
"SUP olcDatabaseConfig "
"MAY ( olcDbConnTtl "
"$ olcDbDnCacheTtl "
"$ olcDbIdleTimeout "
"$ olcDbOnErr "
"$ olcDbPseudoRootBindDefer "
"$ olcDbSingleConn "
"$ olcDbUseTemporaryConn "
"$ olcDbConnectionPoolMax "
/* defaults, may be overridden per-target */
COMMON_ATTRS
") )",
Cft_Database, metacfg, NULL, meta_cfadd },
{ "( OLcfgDbOc:3.3 "
"NAME 'olcMetaTargetConfig' "
"DESC 'Meta target configuration' "
"SUP olcConfig STRUCTURAL "
"MUST ( olcMetaSub $ olcDbURI ) "
"MAY ( olcDbACLAuthcDn "
"$ olcDbACLPasswd "
"$ olcDbIDAssertAuthzFrom "
"$ olcDbIDAssertBind "
"$ olcDbMap "
"$ olcDbRewrite "
"$ olcDbSubtreeExclude "
"$ olcDbSubtreeInclude "
"$ olcDbTimeout "
"$ olcDbKeepalive "
"$ olcDbFilter "
/* defaults may be inherited */
COMMON_ATTRS
") )",
Cft_Misc, metacfg, meta_ldadd },
{ NULL, 0, NULL }
};
static int
meta_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *c )
{
if ( p->ce_type != Cft_Database || !p->ce_be ||
p->ce_be->be_cf_ocs != metaocs )
return LDAP_CONSTRAINT_VIOLATION;
c->be = p->ce_be;
return LDAP_SUCCESS;
}
static int
meta_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *c )
{
metainfo_t *mi = ( 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),
"olcMetaSub=" 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, &metaocs[1], NULL );
}
return LDAP_SUCCESS;
}
static int
meta_rwi_init( struct rewrite_info **rwm_rw )
{
char *rargv[ 3 ];
*rwm_rw = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
if ( *rwm_rw == NULL ) {
return -1;
}
/*
* the filter rewrite as a string must be disabled
* by default; it can be re-enabled by adding rules;
* this creates an empty rewriteContext
*/
rargv[ 0 ] = "rewriteContext";
rargv[ 1 ] = "searchFilter";
rargv[ 2 ] = NULL;
rewrite_parse( *rwm_rw, "", 1, 2, rargv );
rargv[ 0 ] = "rewriteContext";
rargv[ 1 ] = "default";
rargv[ 2 ] = NULL;
rewrite_parse( *rwm_rw, "", 1, 2, rargv );
return 0;
}
static int
meta_back_new_target(
metatarget_t **mtp )
{
metatarget_t *mt;
*mtp = NULL;
mt = ch_calloc( sizeof( metatarget_t ), 1 );
if ( meta_rwi_init( &mt->mt_rwmap.rwm_rw )) {
ch_free( mt );
return -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;
}
/* Validation for suffixmassage_config */
static int
meta_suffixm_config(
ConfigArgs *c,
int argc,
char **argv,
metatarget_t *mt
)
{
BackendDB *tmp_bd;
struct berval dn, nvnc, pvnc, nrnc, prnc;
int j, rc;
/*
* 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, 0 );
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, 0 );
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, 0 );
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, 0 );
}
/*
* The suffix massaging is emulated by means of the
* rewrite capabilities
*/
rc = suffix_massage_config( mt->mt_rwmap.rwm_rw,
&pvnc, &nvnc, &prnc, &nrnc );
free( pvnc.bv_val );
free( nvnc.bv_val );
free( prnc.bv_val );
free( nrnc.bv_val );
return rc;
}
static int
slap_bv_x_ordered_unparse( BerVarray in, BerVarray *out )
{
int i;
BerVarray bva = NULL;
char ibuf[32], *ptr;
struct berval idx;
assert( in != NULL );
for ( i = 0; !BER_BVISNULL( &in[i] ); i++ )
/* count'em */ ;
if ( i == 0 ) {
return 1;
}
idx.bv_val = ibuf;
bva = ch_malloc( ( i + 1 ) * sizeof(struct berval) );
BER_BVZERO( &bva[ 0 ] );
for ( i = 0; !BER_BVISNULL( &in[i] ); i++ ) {
idx.bv_len = snprintf( idx.bv_val, sizeof( ibuf ), SLAP_X_ORDERED_FMT, i );
if ( idx.bv_len >= sizeof( ibuf ) ) {
ber_bvarray_free( bva );
return 1;
}
bva[i].bv_len = idx.bv_len + in[i].bv_len;
bva[i].bv_val = ch_malloc( bva[i].bv_len + 1 );
ptr = lutil_strcopy( bva[i].bv_val, ibuf );
ptr = lutil_strcopy( ptr, in[i].bv_val );
*ptr = '\0';
BER_BVZERO( &bva[ i + 1 ] );
}
*out = bva;
return 0;
}
int
meta_subtree_free( 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
meta_subtree_destroy( metasubtree_t *ms )
{
if ( ms->ms_next ) {
meta_subtree_destroy( ms->ms_next );
}
return meta_subtree_free( ms );
}
static void
meta_filter_free( metafilter_t *mf )
{
regfree( &mf->mf_regex );
ber_memfree( mf->mf_regex_pattern.bv_val );
ch_free( mf );
}
void
meta_filter_destroy( metafilter_t *mf )
{
if ( mf->mf_next )
meta_filter_destroy( mf->mf_next );
meta_filter_free( mf );
}
static struct berval st_styles[] = {
BER_BVC("subtree"),
BER_BVC("children"),
BER_BVC("regex")
};
static int
meta_subtree_unparse(
ConfigArgs *c,
metatarget_t *mt )
{
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
meta_subtree_config(
metatarget_t *mt,
ConfigArgs *c )
{
meta_st_t type = META_ST_SUBTREE;
char *pattern;
struct berval ndn = BER_BVNULL;
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.