From 9649281f7b4908031694e4e439ce622f50b018aa Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Sun, 26 May 2013 18:43:46 -0700 Subject: [PATCH] ITS#7609 add per-target filter patterns --- doc/man/man5/slapd-meta.5 | 13 +++++ servers/slapd/back-meta/back-meta.h | 10 ++++ servers/slapd/back-meta/config.c | 76 +++++++++++++++++++++++++++++ servers/slapd/back-meta/init.c | 4 ++ servers/slapd/back-meta/search.c | 14 ++++++ 5 files changed, 117 insertions(+) diff --git a/doc/man/man5/slapd-meta.5 b/doc/man/man5/slapd-meta.5 index 30d6b63d60..a4020b5178 100644 --- a/doc/man/man5/slapd-meta.5 +++ b/doc/man/man5/slapd-meta.5 @@ -338,6 +338,19 @@ The optional number marks target as the default one, starting from 1. Target must be defined. +.TP +.B filter +This directive allows specifying a +.BR regex (5) +pattern to indicate what search filter terms are actually served by a target. + +In a search request, if the search filter matches the \fIpattern\fP +the target is considered while fulfilling the request; otherwise +the target is ignored. There may be multiple occurrences of +the +.B filter +directive for each target. + .TP .B idassert\-authzFrom if defined, selects what diff --git a/servers/slapd/back-meta/back-meta.h b/servers/slapd/back-meta/back-meta.h index 90104d82f5..341c05571a 100644 --- a/servers/slapd/back-meta/back-meta.h +++ b/servers/slapd/back-meta/back-meta.h @@ -278,6 +278,12 @@ typedef struct metasubtree_t { struct metasubtree_t *ms_next; } metasubtree_t; +typedef struct metafilter_t { + struct metafilter_t *mf_next; + struct berval mf_regex_pattern; + regex_t mf_regex; +} metafilter_t; + typedef struct metacommon_t { int mc_version; int mc_nretries; @@ -324,6 +330,7 @@ typedef struct metatarget_t { LDAP_URLLIST_PROC *mt_urllist_f; void *mt_urllist_p; + metafilter_t *mt_filter; metasubtree_t *mt_subtree; /* F: subtree-include; T: subtree-exclude */ int mt_subtree_exclude; @@ -681,6 +688,9 @@ meta_back_map_free( struct ldapmap *lm ); extern int meta_subtree_destroy( metasubtree_t *ms ); +extern void +meta_filter_destroy( metafilter_t *mf ); + extern int meta_target_finish( metainfo_t *mi, metatarget_t *mt, const char *log, char *msg, size_t msize diff --git a/servers/slapd/back-meta/config.c b/servers/slapd/back-meta/config.c index 81e6c355ea..0be9ed8de9 100644 --- a/servers/slapd/back-meta/config.c +++ b/servers/slapd/back-meta/config.c @@ -101,6 +101,7 @@ enum { LDAP_BACK_CFG_PSEUDOROOTDN, LDAP_BACK_CFG_PSEUDOROOTPW, LDAP_BACK_CFG_KEEPALIVE, + LDAP_BACK_CFG_FILTER, LDAP_BACK_CFG_LAST }; @@ -417,6 +418,15 @@ static ConfigTable metacfg[] = { "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 } }; @@ -477,6 +487,7 @@ static ConfigOCs metaocs[] = { "$ olcDbSubtreeInclude " "$ olcDbTimeout " "$ olcDbKeepalive " + "$ olcDbFilter " /* defaults may be inherited */ COMMON_ATTRS @@ -729,6 +740,22 @@ meta_subtree_destroy( metasubtree_t *ms ) 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"), @@ -1603,6 +1630,16 @@ meta_back_cf_gen( ConfigArgs *c ) rc = meta_subtree_unparse( c, mt ); break; + case LDAP_BACK_CFG_FILTER: + if ( mt->mt_filter == NULL ) { + rc = 1; + } else { + metafilter_t *mf; + for ( mf = mt->mt_filter; mf; mf = mf->mf_next ) + value_add_one( &c->rvalue_vals, &mf->mf_regex_pattern ); + } + break; + /* replaced by idassert */ case LDAP_BACK_CFG_PSEUDOROOTDN: case LDAP_BACK_CFG_PSEUDOROOTPW: @@ -1833,6 +1870,26 @@ meta_back_cf_gen( ConfigArgs *c ) } break; + case LDAP_BACK_CFG_FILTER: + if ( c->valx < 0 ) { + meta_filter_destroy( mt->mt_filter ); + mt->mt_filter = NULL; + } else { + metafilter_t *mf, **mprev; + for (i=0, mprev = &mt->mt_filter, mf = *mprev; mf; mf = *mprev) { + if ( i == c->valx ) { + *mprev = mf->mf_next; + meta_filter_free( mf ); + break; + } + i++; + mprev = &mf->mf_next; + } + if ( i != c->valx ) + rc = 1; + } + break; + case LDAP_BACK_CFG_KEEPALIVE: mt->mt_tls.sb_keepalive.sk_idle = 0; mt->mt_tls.sb_keepalive.sk_probes = 0; @@ -2081,6 +2138,25 @@ meta_back_cf_gen( ConfigArgs *c ) } break; + case LDAP_BACK_CFG_FILTER: { + metafilter_t *mf, **m2; + mf = ch_malloc( sizeof( metafilter_t )); + rc = regcomp( &mf->mf_regex, c->argv[1], REG_EXTENDED ); + if ( rc ) { + char regerr[ SLAP_TEXT_BUFLEN ]; + regerror( rc, &mf->mf_regex, regerr, sizeof(regerr) ); + snprintf( c->cr_msg, sizeof( c->cr_msg ), + "regular expression \"%s\" bad because of %s", + c->argv[1], regerr ); + ch_free( mf ); + return 1; + } + ber_str2bv( c->argv[1], 0, 1, &mf->mf_regex_pattern ); + for ( m2 = &mt->mt_filter; *m2; m2 = &(*m2)->mf_next ) + ; + *m2 = mf; + } break; + case LDAP_BACK_CFG_DEFAULT_T: /* default target directive */ i = mi->mi_ntargets - 1; diff --git a/servers/slapd/back-meta/init.c b/servers/slapd/back-meta/init.c index b6daaf1740..42ca371f17 100644 --- a/servers/slapd/back-meta/init.c +++ b/servers/slapd/back-meta/init.c @@ -340,6 +340,10 @@ target_free( meta_subtree_destroy( mt->mt_subtree ); mt->mt_subtree = NULL; } + if ( mt->mt_filter ) { + meta_filter_destroy( mt->mt_filter ); + mt->mt_filter = NULL; + } if ( !BER_BVISNULL( &mt->mt_psuffix ) ) { free( mt->mt_psuffix.bv_val ); } diff --git a/servers/slapd/back-meta/search.c b/servers/slapd/back-meta/search.c index 9aabda0b23..e0c6e910f6 100644 --- a/servers/slapd/back-meta/search.c +++ b/servers/slapd/back-meta/search.c @@ -548,6 +548,20 @@ meta_back_search_start( } } + /* check filter expression */ + if ( mt->mt_filter ) { + metafilter_t *mf; + for ( mf = mt->mt_filter; mf; mf = mf->mf_next ) { + if ( regexec( &mf->mf_regex, op->ors_filterstr.bv_val, 0, NULL, 0 ) == 0 ) + break; + } + /* nothing matched, this target is no longer a candidate */ + if ( !mf ) { + retcode = META_SEARCH_NOT_CANDIDATE; + goto doreturn; + } + } + /* initiate dobind */ retcode = meta_search_dobind_init( op, rs, mcp, candidate, candidates );