Matched Values implementation (ITS#1776) based upon submission

form Mikhail Sahalaev <M.Sahalayev@pgr.salford.ac.uk>.
Further work needed:
	add testxxx-matchedvalues
	rework ldapsearch(1) portion of patch to generalize use of options
---
Copyright 2001, Mikhail Sahalaev, All rights reserved.
This software is not subject to any license of University Of
Salford.

Redistribution and use in source and binary forms are permitted
without restriction or fee of any kind as long as this notice
is preserved.
This commit is contained in:
Kurt Zeilenga 2002-05-02 18:56:56 +00:00
parent 71aa1c5dc9
commit 8c152396b9
14 changed files with 1742 additions and 4 deletions

View file

@ -202,6 +202,8 @@ typedef struct ldapcontrol {
#define LDAP_CONTROL_VLVREQUEST "2.16.840.1.113730.3.4.9"
#define LDAP_CONTROL_VLVRESPONSE "2.16.840.1.113730.3.4.10"
#define LDAP_CONTROL_VALUESRETURNFILTER "1.2.826.0.1.334810.2.3"
/* LDAP Unsolicited Notifications */
#define LDAP_NOTICE_OF_DISCONNECTION "1.3.6.1.4.1.1466.20036"
#define LDAP_NOTICE_DISCONNECT LDAP_NOTICE_OF_DISCONNECTION

View file

@ -22,6 +22,14 @@
#include "ldap-int.h"
static int put_simple_vrFilter LDAP_P((
BerElement *ber,
char *str ));
static int put_vrFilter_list LDAP_P((
BerElement *ber,
char *str ));
static char *put_complex_filter LDAP_P((
BerElement *ber,
char *str,
@ -799,3 +807,387 @@ put_substring_filter( BerElement *ber, char *type, char *val )
return 0;
}
int
ldap_pvt_put_vrFilter( BerElement *ber, const char *str_in )
{
int rc;
char *freeme;
char *str;
char *next;
int parens, balance, escape;
/*
* A ValuesReturnFilter looks like this:
*
* ValuesReturnFilter ::= SEQUENCE OF SimpleFilterItem
* SimpleFilterItem ::= CHOICE {
* equalityMatch [3] AttributeValueAssertion,
* substrings [4] SubstringFilter,
* greaterOrEqual [5] AttributeValueAssertion,
* lessOrEqual [6] AttributeValueAssertion,
* present [7] AttributeType,
* approxMatch [8] AttributeValueAssertion,
* extensibleMatch [9] SimpleMatchingAssertion -- LDAPv3
* }
*
* SubstringFilter ::= SEQUENCE {
* type AttributeType,
* SEQUENCE OF CHOICE {
* initial [0] IA5String,
* any [1] IA5String,
* final [2] IA5String
* }
* }
*
* SimpleMatchingAssertion ::= SEQUENCE { -- LDAPv3
* matchingRule [1] MatchingRuleId OPTIONAL,
* type [2] AttributeDescription OPTIONAL,
* matchValue [3] AssertionValue }
*/
#ifdef NEW_LOGGING
LDAP_LOG (( "filter", LDAP_LEVEL_ARGS, "ldap_pvt_put_vrFilter: \"%s\"\n",
str_in ));
#else
Debug( LDAP_DEBUG_TRACE, "put_vrFilter: \"%s\"\n", str_in, 0, 0 );
#endif
freeme = LDAP_STRDUP( str_in );
if( freeme == NULL ) return LDAP_NO_MEMORY;
str = freeme;
parens = 0;
while ( *str ) {
switch ( *str ) {
case '(': /*')'*/
str++;
parens++;
/* skip spaces */
while( LDAP_SPACE( *str ) ) str++;
switch ( *str ) {
case '(':
if ( (next = find_right_paren( str )) == NULL ) {
rc = -1;
goto done;
}
*next = '\0';
if ( put_vrFilter_list( ber, str ) == -1 ) {
rc = -1;
goto done;
}
/* close the '(' */
*next++ = ')';
str = next;
parens--;
break;
default:
#ifdef NEW_LOGGING
LDAP_LOG (( "filter", LDAP_LEVEL_DETAIL1,
"ldap_pvt_put_vrFilter: simple\n" ));
#else
Debug( LDAP_DEBUG_TRACE, "put_vrFilter: simple\n",
0, 0, 0 );
#endif
balance = 1;
escape = 0;
next = str;
while ( *next && balance ) {
if ( escape == 0 ) {
if ( *next == '(' ) {
balance++;
} else if ( *next == ')' ) {
balance--;
}
}
if ( *next == '\\' && ! escape ) {
escape = 1;
} else {
escape = 0;
}
if ( balance ) next++;
}
if ( balance != 0 ) {
rc = -1;
goto done;
}
*next = '\0';
if ( put_simple_vrFilter( ber, str ) == -1 ) {
rc = -1;
goto done;
}
*next++ = /*'('*/ ')';
str = next;
parens--;
break;
}
break;
case /*'('*/ ')':
#ifdef NEW_LOGGING
LDAP_LOG (( "filter", LDAP_LEVEL_DETAIL1,
"ldap_pvt_put_filter: end\n" ));
#else
Debug( LDAP_DEBUG_TRACE, "put_filter: end\n",
0, 0, 0 );
#endif
if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) {
rc = -1;
goto done;
}
str++;
parens--;
break;
case ' ':
str++;
break;
default: /* assume it's a simple type=value filter */
#ifdef NEW_LOGGING
LDAP_LOG (( "filter", LDAP_LEVEL_DETAIL1,
"ldap_pvt_put_filter: default\n" ));
#else
Debug( LDAP_DEBUG_TRACE, "put_filter: default\n",
0, 0, 0 );
#endif
next = strchr( str, '\0' );
if ( put_simple_filter( ber, str ) == -1 ) {
rc = -1;
goto done;
}
str = next;
break;
}
}
rc = parens ? -1 : 0;
done:
LDAP_FREE( freeme );
return rc;
}
int
put_vrFilter( BerElement *ber, const char *str_in )
{
int rc =0;
if ( ber_printf( ber, "{" /*"}"*/ ) == -1 ) {
rc = -1;
}
rc = ldap_pvt_put_vrFilter( ber, str_in );
if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 ) {
rc = -1;
}
return rc;
}
static int
put_vrFilter_list( BerElement *ber, char *str )
{
char *next = NULL;
char save;
#ifdef NEW_LOGGING
LDAP_LOG (( "filter", LDAP_LEVEL_ARGS,
"put_vrFilter_list \"%s\"\n", str ));
#else
Debug( LDAP_DEBUG_TRACE, "put_vrFilter_list \"%s\"\n",
str, 0, 0 );
#endif
while ( *str ) {
while ( *str && LDAP_SPACE( (unsigned char) *str ) ) {
str++;
}
if ( *str == '\0' ) break;
if ( (next = find_right_paren( str + 1 )) == NULL ) {
return -1;
}
save = *++next;
/* now we have "(filter)" with str pointing to it */
*next = '\0';
if ( ldap_pvt_put_vrFilter( ber, str ) == -1 ) return -1;
*next = save;
str = next;
}
return 0;
}
static int
put_simple_vrFilter(
BerElement *ber,
char *str )
{
char *s;
char *value;
ber_tag_t ftype;
int rc = -1;
#ifdef NEW_LOGGING
LDAP_LOG (( "filter", LDAP_LEVEL_ARGS,
"put_simple_vrFilter: \"%s\"\n", str ));
#else
Debug( LDAP_DEBUG_TRACE, "put_simple_vrFilter: \"%s\"\n",
str, 0, 0 );
#endif
str = LDAP_STRDUP( str );
if( str == NULL ) return -1;
if ( (s = strchr( str, '=' )) == NULL ) {
goto done;
}
value = s + 1;
*s-- = '\0';
switch ( *s ) {
case '<':
ftype = LDAP_FILTER_LE;
*s = '\0';
break;
case '>':
ftype = LDAP_FILTER_GE;
*s = '\0';
break;
case '~':
ftype = LDAP_FILTER_APPROX;
*s = '\0';
break;
case ':':
/* According to ValuesReturnFilter control definition
* extensible filters are off the form:
* type [:rule] := value
* or :rule := value
*/
ftype = LDAP_FILTER_EXT;
*s = '\0';
{
char *rule = strchr( str, ':' );
*rule++ = '\0';
if( rule == NULL ) {
/* must have attribute */
if( !ldap_is_desc( str ) ) {
goto done;
}
rule = "";
} else {
*rule++ = '\0';
}
if ( *str == '\0' && ( !rule || *rule == '\0' ) ) {
/* must have either type or rule */
goto done;
}
if ( *str != '\0' && !ldap_is_desc( str ) ) {
goto done;
}
if ( rule && *rule != '\0' && !ldap_is_oid( rule ) ) {
goto done;
}
rc = ber_printf( ber, "t{" /*"}"*/, ftype );
if( rc != -1 && rule && *rule != '\0' ) {
rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule );
}
if( rc != -1 && *str != '\0' ) {
rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str );
}
if( rc != -1 ) {
ber_slen_t len = ldap_pvt_filter_value_unescape( value );
if( len >= 0 ) {
rc = ber_printf( ber, "to",
LDAP_FILTER_EXT_VALUE, value, len );
} else {
rc = -1;
}
}
if( rc != -1 ) {
rc = ber_printf( ber, /*"{"*/ "N}" );
}
}
goto done;
default:
if( !ldap_is_desc( str ) ) {
goto done;
} else {
char *nextstar = ldap_pvt_find_wildcard( value );
if ( nextstar == NULL ) {
goto done;
} else if ( *nextstar == '\0' ) {
ftype = LDAP_FILTER_EQUALITY;
} else if ( strcmp( value, "*" ) == 0 ) {
ftype = LDAP_FILTER_PRESENT;
} else {
rc = put_substring_filter( ber, str, value );
goto done;
}
} break;
}
if( !ldap_is_desc( str ) ) goto done;
if ( ftype == LDAP_FILTER_PRESENT ) {
rc = ber_printf( ber, "ts", ftype, str );
} else {
ber_slen_t len = ldap_pvt_filter_value_unescape( value );
if( len >= 0 ) {
rc = ber_printf( ber, "t{soN}",
ftype, str, value, len );
}
}
done:
if( rc != -1 ) rc = 0;
LDAP_FREE( str );
return rc;
}

View file

@ -19,7 +19,7 @@ SRCS = main.c daemon.c connection.c search.c filter.c add.c charray.c \
schemaparse.c ad.c at.c mr.c syntax.c oc.c saslauthz.c \
oidm.c starttls.c index.c sets.c referral.c \
root_dse.c sasl.c module.c suffixalias.c mra.c mods.c \
limits.c backglue.c operational.c \
limits.c backglue.c operational.c matchedValues.c \
$(@PLAT@_SRCS)
OBJS = main.o daemon.o connection.o search.o filter.o add.o charray.o \
@ -32,7 +32,7 @@ OBJS = main.o daemon.o connection.o search.o filter.o add.o charray.o \
schemaparse.o ad.o at.o mr.o syntax.o oc.o saslauthz.o \
oidm.o starttls.o index.o sets.o referral.o \
root_dse.o sasl.o module.o suffixalias.o mra.o mods.o \
limits.o backglue.o operational.o \
limits.o backglue.o operational.o matchedValues.o \
$(@PLAT@_OBJS)
LDAP_INCDIR= ../../include

View file

@ -479,6 +479,9 @@ bdb_initialize(
#endif
#ifdef LDAP_CONTROL_NOOP
LDAP_CONTROL_NOOP,
#endif
#ifdef LDAP_CONTROL_VALUESRETURNFILTER
LDAP_CONTROL_VALUESRETURNFILTER,
#endif
NULL
};

View file

@ -36,6 +36,7 @@ dnssrv_back_initialize(
{
static char *controls[] = {
LDAP_CONTROL_MANAGEDSAIT,
LDAP_CONTROL_VALUESRETURNFILTER,
NULL
};

View file

@ -37,6 +37,7 @@ ldbm_back_initialize(
{
static char *controls[] = {
LDAP_CONTROL_MANAGEDSAIT,
LDAP_CONTROL_VALUESRETURNFILTER,
NULL
};

View file

@ -163,6 +163,7 @@ monitor_back_initialize(
{
static char *controls[] = {
LDAP_CONTROL_MANAGEDSAIT,
LDAP_CONTROL_VALUESRETURNFILTER,
NULL
};

View file

@ -1423,6 +1423,8 @@ connection_input(
op = slap_op_alloc( ber, msgid, tag, conn->c_n_ops_received++ );
op->vrFilter = NULL;
op->o_pagedresults_state = conn->c_pagedresults_state;
#ifdef LDAP_CONNECTIONLESS

View file

@ -47,6 +47,7 @@ static SLAP_CTRL_PARSE_FN parseManageDSAit;
static SLAP_CTRL_PARSE_FN parseSubentries;
static SLAP_CTRL_PARSE_FN parseNoOp;
static SLAP_CTRL_PARSE_FN parsePagedResults;
static SLAP_CTRL_PARSE_FN parseValuesReturnFilter;
static struct slap_control {
char *sc_oid;
@ -72,6 +73,11 @@ static struct slap_control {
{ LDAP_CONTROL_PAGEDRESULTS_REQUEST,
SLAP_CTRL_SEARCH, NULL,
parsePagedResults },
#endif
#ifdef LDAP_CONTROL_VALUESRETURNFILTER
{ LDAP_CONTROL_VALUESRETURNFILTER,
SLAP_CTRL_SEARCH, NULL,
parseValuesReturnFilter },
#endif
{ NULL }
};
@ -527,3 +533,61 @@ static int parsePagedResults (
return LDAP_SUCCESS;
}
#endif
#ifdef LDAP_CONTROL_VALUESRETURNFILTER
int parseValuesReturnFilter (
Connection *conn,
Operation *op,
LDAPControl *ctrl,
const char **text )
{
int rc;
BerElement *ber;
struct berval fstr = { 0, NULL };
const char *err_msg = "";
if ( op->o_valuesreturnfilter != SLAP_NO_CONTROL ) {
*text = "valuesreturnfilter control specified multiple times";
return LDAP_PROTOCOL_ERROR;
}
ber = ber_init( &(ctrl->ldctl_value) );
if (ber == NULL) {
*text = "internal error";
return LDAP_OTHER;
}
rc = get_vrFilter( conn, ber, &(op->vrFilter), &err_msg);
if( rc != LDAP_SUCCESS ) {
text = &err_msg;
if( rc == SLAPD_DISCONNECT ) {
send_ldap_disconnect( conn, op,
LDAP_PROTOCOL_ERROR, *text );
} else {
send_ldap_result( conn, op, rc,
NULL, *text, NULL, NULL );
}
if( fstr.bv_val != NULL) free( fstr.bv_val );
if( op->vrFilter != NULL) vrFilter_free( op->vrFilter );
} else {
vrFilter2bv( op->vrFilter, &fstr );
}
#ifdef NEW_LOGGING
LDAP_LOG(( "operation", LDAP_LEVEL_ARGS,
"parseValuesReturnFilter: conn %d vrFilter: %s\n", conn->c_connid,
fstr.bv_len ? fstr.bv_val : "empty" ));
#else
Debug( LDAP_DEBUG_ARGS, " vrFilter: %s\n",
fstr.bv_len ? fstr.bv_val : "empty", 0, 0 );
#endif
op->o_valuesreturnfilter = ctrl->ldctl_iscritical
? SLAP_CRITICAL_CONTROL
: SLAP_NONCRITICAL_CONTROL;
return LDAP_SUCCESS;
}
#endif

View file

@ -30,6 +30,17 @@ static int filter_escape_value(
struct berval *in,
struct berval *out );
static void simple_vrFilter2bv(
ValuesReturnFilter *f,
struct berval *fstr );
static int get_simple_vrFilter(
Connection *conn,
BerElement *ber,
ValuesReturnFilter **f,
const char **text );
int
get_filter(
Connection *conn,
@ -796,3 +807,719 @@ static int filter_escape_value(
out->bv_val[out->bv_len] = '\0';
return LDAP_SUCCESS;
}
static int
get_simple_vrFilter(
Connection *conn,
BerElement *ber,
ValuesReturnFilter **filt,
const char **text )
{
ber_tag_t tag;
ber_len_t len;
int err;
ValuesReturnFilter *f;
#ifdef NEW_LOGGING
LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY, "get_simple_vrFilter: conn %d\n",
conn->c_connid ));
#else
Debug( LDAP_DEBUG_FILTER, "begin get_simple_vrFilter\n", 0, 0, 0 );
#endif
tag = ber_peek_tag( ber, &len );
if( tag == LBER_ERROR ) {
*text = "error decoding filter";
return SLAPD_DISCONNECT;
}
f = (ValuesReturnFilter *) ch_malloc( sizeof(ValuesReturnFilter) );
f->f_next = NULL;
err = LDAP_SUCCESS;
f->f_choice = tag;
switch ( f->f_choice ) {
case LDAP_FILTER_EQUALITY:
#ifdef NEW_LOGGING
LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL2,
"get_simple_vrFilter: conn %d EQUALITY\n", conn->c_connid ));
#else
Debug( LDAP_DEBUG_FILTER, "EQUALITY\n", 0, 0, 0 );
#endif
err = get_ava( ber, &f->f_ava, SLAP_MR_EQUALITY, text );
if ( err != LDAP_SUCCESS ) {
break;
}
assert( f->f_ava != NULL );
break;
case LDAP_FILTER_SUBSTRINGS:
#ifdef NEW_LOGGING
LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
"get_simple_vrFilter: conn %d SUBSTRINGS\n", conn->c_connid ));
#else
Debug( LDAP_DEBUG_FILTER, "SUBSTRINGS\n", 0, 0, 0 );
#endif
err = get_substring_filter( conn, ber, (Filter *)f, text );
break;
case LDAP_FILTER_GE:
#ifdef NEW_LOGGING
LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
"get_simple_vrFilter: conn %d GE\n", conn->c_connid ));
#else
Debug( LDAP_DEBUG_FILTER, "GE\n", 0, 0, 0 );
#endif
err = get_ava( ber, &f->f_ava, SLAP_MR_ORDERING, text );
if ( err != LDAP_SUCCESS ) {
break;
}
break;
case LDAP_FILTER_LE:
#ifdef NEW_LOGGING
LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
"get_simple_vrFilter: conn %d LE\n", conn->c_connid ));
#else
Debug( LDAP_DEBUG_FILTER, "LE\n", 0, 0, 0 );
#endif
err = get_ava( ber, &f->f_ava, SLAP_MR_ORDERING, text );
if ( err != LDAP_SUCCESS ) {
break;
}
break;
case LDAP_FILTER_PRESENT: {
struct berval type;
#ifdef NEW_LOGGING
LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
"get_simple_vrFilter: conn %d PRESENT\n", conn->c_connid ));
#else
Debug( LDAP_DEBUG_FILTER, "PRESENT\n", 0, 0, 0 );
#endif
if ( ber_scanf( ber, "m", &type ) == LBER_ERROR ) {
err = SLAPD_DISCONNECT;
*text = "error decoding filter";
break;
}
f->f_desc = NULL;
err = slap_bv2ad( &type, &f->f_desc, text );
if( err != LDAP_SUCCESS ) {
/* unrecognized attribute description or other error */
f->f_choice = SLAPD_FILTER_COMPUTED;
f->f_result = LDAP_COMPARE_FALSE;
err = LDAP_SUCCESS;
break;
}
} break;
case LDAP_FILTER_APPROX:
#ifdef NEW_LOGGING
LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
"get_simple_vrFilter: conn %d APPROX\n", conn->c_connid ));
#else
Debug( LDAP_DEBUG_FILTER, "APPROX\n", 0, 0, 0 );
#endif
err = get_ava( ber, &f->f_ava, SLAP_MR_EQUALITY_APPROX, text );
if ( err != LDAP_SUCCESS ) {
break;
}
break;
case LDAP_FILTER_EXT:
#ifdef NEW_LOGGING
LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
"get_simple_vrFilter: conn %d EXTENSIBLE\n", conn->c_connid ));
#else
Debug( LDAP_DEBUG_FILTER, "EXTENSIBLE\n", 0, 0, 0 );
#endif
err = get_mra( ber, &f->f_mra, text );
if ( err != LDAP_SUCCESS ) {
break;
}
assert( f->f_mra != NULL );
break;
default:
(void) ber_scanf( ber, "x" ); /* skip the element */
#ifdef NEW_LOGGING
LDAP_LOG(( "filter", LDAP_LEVEL_ERR,
"get_simple_vrFilter: conn %d unknown filter type=%lu\n",
conn->c_connid, f->f_choice ));
#else
Debug( LDAP_DEBUG_ANY, "get_simple_vrFilter: unknown filter type=%lu\n",
f->f_choice, 0, 0 );
#endif
f->f_choice = SLAPD_FILTER_COMPUTED;
f->f_result = SLAPD_COMPARE_UNDEFINED;
break;
}
if ( err != LDAP_SUCCESS ) {
if( err != SLAPD_DISCONNECT ) {
/* ignore error */
f->f_choice = SLAPD_FILTER_COMPUTED;
f->f_result = SLAPD_COMPARE_UNDEFINED;
err = LDAP_SUCCESS;
*filt = f;
} else {
free(f);
}
} else {
*filt = f;
}
#ifdef NEW_LOGGING
LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL2,
"get_simple_vrFilter: conn %d exit\n", conn->c_connid ));
#else
Debug( LDAP_DEBUG_FILTER, "end get_simple_vrFilter %d\n", err, 0, 0 );
#endif
return( err );
}
int
get_vrFilter( Connection *conn, BerElement *ber,
ValuesReturnFilter **f,
const char **text )
{
/*
* A ValuesReturnFilter looks like this:
*
* ValuesReturnFilter ::= SEQUENCE OF SimpleFilterItem
* SimpleFilterItem ::= CHOICE {
* equalityMatch [3] AttributeValueAssertion,
* substrings [4] SubstringFilter,
* greaterOrEqual [5] AttributeValueAssertion,
* lessOrEqual [6] AttributeValueAssertion,
* present [7] AttributeType,
* approxMatch [8] AttributeValueAssertion,
* extensibleMatch [9] SimpleMatchingAssertion -- LDAPv3
* }
*
* SubstringFilter ::= SEQUENCE {
* type AttributeType,
* SEQUENCE OF CHOICE {
* initial [0] IA5String,
* any [1] IA5String,
* final [2] IA5String
* }
* }
*
* SimpleMatchingAssertion ::= SEQUENCE { -- LDAPv3
* matchingRule [1] MatchingRuleId OPTIONAL,
* type [2] AttributeDescription OPTIONAL,
* matchValue [3] AssertionValue }
*/
ValuesReturnFilter **new;
int err;
ber_tag_t tag;
ber_len_t len;
char *last;
#ifdef NEW_LOGGING
LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY,
"get_vrFilter: conn %d start\n", conn->c_connid ));
#else
Debug( LDAP_DEBUG_FILTER, "begin get_vrFilter\n", 0, 0, 0 );
#endif
tag = ber_peek_tag( ber, &len );
if( tag == LBER_ERROR ) {
*text = "error decoding vrFilter";
return SLAPD_DISCONNECT;
}
if( tag != LBER_SEQUENCE ) {
*text = "error decoding vrFilter, expect SEQUENCE tag";
return SLAPD_DISCONNECT;
}
new = f;
for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
tag = ber_next_element( ber, &len, last ) )
{
err = get_simple_vrFilter( conn, ber, new, text );
if ( err != LDAP_SUCCESS )
return( err );
new = &(*new)->f_next;
}
*new = NULL;
#ifdef NEW_LOGGING
LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY,
"get_vrFilter: conn %d exit\n", conn->c_connid ));
#else
Debug( LDAP_DEBUG_FILTER, "end get_vrFilter %d\n", err, 0, 0 );
#endif
return( LDAP_SUCCESS );
}
void
vrFilter_free( ValuesReturnFilter *f )
{
ValuesReturnFilter *p, *next;
if ( f == NULL ) {
return;
}
for ( p = f; p != NULL; p = next ) {
next = p->f_next;
switch ( f->f_choice ) {
case LDAP_FILTER_PRESENT:
break;
case LDAP_FILTER_EQUALITY:
case LDAP_FILTER_GE:
case LDAP_FILTER_LE:
case LDAP_FILTER_APPROX:
ava_free( f->f_ava, 1 );
break;
case LDAP_FILTER_SUBSTRINGS:
if ( f->f_sub_initial.bv_val != NULL ) {
free( f->f_sub_initial.bv_val );
}
ber_bvarray_free( f->f_sub_any );
if ( f->f_sub_final.bv_val != NULL ) {
free( f->f_sub_final.bv_val );
}
ch_free( f->f_sub );
break;
case LDAP_FILTER_EXT:
mra_free( f->f_mra, 1 );
break;
case SLAPD_FILTER_COMPUTED:
break;
default:
#ifdef NEW_LOGGING
LDAP_LOG(( "filter", LDAP_LEVEL_ERR,
"filter_free: unknown filter type %lu\n", f->f_choice ));
#else
Debug( LDAP_DEBUG_ANY, "filter_free: unknown filter type=%lu\n",
f->f_choice, 0, 0 );
#endif
break;
}
free( f );
}
}
void
vrFilter2bv( ValuesReturnFilter *f, struct berval *fstr )
{
int i;
ValuesReturnFilter *p;
struct berval tmp;
ber_len_t len;
if ( f == NULL ) {
ber_str2bv( "No filter!", sizeof("No filter!")-1, 1, fstr );
return;
}
fstr->bv_len = sizeof("()") - 1;
fstr->bv_val = malloc( fstr->bv_len + 128 );
snprintf( fstr->bv_val, fstr->bv_len + 1, "()");
for ( p = f; p != NULL; p = p->f_next ) {
len = fstr->bv_len;
simple_vrFilter2bv( p, &tmp );
fstr->bv_len += tmp.bv_len;
fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 );
snprintf( &fstr->bv_val[len-1], tmp.bv_len + 2,
/*"("*/ "%s)", tmp.bv_val );
ch_free( tmp.bv_val );
}
}
static void
simple_vrFilter2bv( ValuesReturnFilter *f, struct berval *fstr )
{
int i;
ValuesReturnFilter *p;
struct berval tmp;
ber_len_t len;
if ( f == NULL ) {
ber_str2bv( "No filter!", sizeof("No filter!")-1, 1, fstr );
return;
}
switch ( f->f_choice ) {
case LDAP_FILTER_EQUALITY:
filter_escape_value( &f->f_av_value, &tmp );
fstr->bv_len = f->f_av_desc->ad_cname.bv_len +
tmp.bv_len + ( sizeof("(=)") - 1 );
fstr->bv_val = malloc( fstr->bv_len + 1 );
snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=%s)",
f->f_av_desc->ad_cname.bv_val,
tmp.bv_val );
ber_memfree( tmp.bv_val );
break;
case LDAP_FILTER_GE:
filter_escape_value( &f->f_av_value, &tmp );
fstr->bv_len = f->f_av_desc->ad_cname.bv_len +
tmp.bv_len + ( sizeof("(>=)") - 1 );
fstr->bv_val = malloc( fstr->bv_len + 1 );
snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s>=%s)",
f->f_av_desc->ad_cname.bv_val,
tmp.bv_val );
ber_memfree( tmp.bv_val );
break;
case LDAP_FILTER_LE:
filter_escape_value( &f->f_av_value, &tmp );
fstr->bv_len = f->f_av_desc->ad_cname.bv_len +
tmp.bv_len + ( sizeof("(<=)") - 1 );
fstr->bv_val = malloc( fstr->bv_len + 1 );
snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s<=%s)",
f->f_av_desc->ad_cname.bv_val,
tmp.bv_val );
ber_memfree( tmp.bv_val );
break;
case LDAP_FILTER_APPROX:
filter_escape_value( &f->f_av_value, &tmp );
fstr->bv_len = f->f_av_desc->ad_cname.bv_len +
tmp.bv_len + ( sizeof("(~=)") - 1 );
fstr->bv_val = malloc( fstr->bv_len + 1 );
snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s~=%s)",
f->f_av_desc->ad_cname.bv_val,
tmp.bv_val );
ber_memfree( tmp.bv_val );
break;
case LDAP_FILTER_SUBSTRINGS:
fstr->bv_len = f->f_sub_desc->ad_cname.bv_len +
( sizeof("(=*)") - 1 );
fstr->bv_val = malloc( fstr->bv_len + 128 );
snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)",
f->f_sub_desc->ad_cname.bv_val );
if ( f->f_sub_initial.bv_val != NULL ) {
len = fstr->bv_len;
filter_escape_value( &f->f_sub_initial, &tmp );
fstr->bv_len += tmp.bv_len;
fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 );
snprintf( &fstr->bv_val[len-2], tmp.bv_len+3,
/* "(attr=" */ "%s*)",
tmp.bv_val );
ber_memfree( tmp.bv_val );
}
if ( f->f_sub_any != NULL ) {
for ( i = 0; f->f_sub_any[i].bv_val != NULL; i++ ) {
len = fstr->bv_len;
filter_escape_value( &f->f_sub_any[i], &tmp );
fstr->bv_len += tmp.bv_len + 1;
fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 );
snprintf( &fstr->bv_val[len-1], tmp.bv_len+3,
/* "(attr=[init]*[any*]" */ "%s*)",
tmp.bv_val );
ber_memfree( tmp.bv_val );
}
}
if ( f->f_sub_final.bv_val != NULL ) {
len = fstr->bv_len;
filter_escape_value( &f->f_sub_final, &tmp );
fstr->bv_len += tmp.bv_len;
fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 );
snprintf( &fstr->bv_val[len-1], tmp.bv_len+3,
/* "(attr=[init*][any*]" */ "%s)",
tmp.bv_val );
ber_memfree( tmp.bv_val );
}
break;
case LDAP_FILTER_PRESENT:
fstr->bv_len = f->f_desc->ad_cname.bv_len +
( sizeof("(=*)") - 1 );
fstr->bv_val = malloc( fstr->bv_len + 1 );
snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)",
f->f_desc->ad_cname.bv_val );
break;
case LDAP_FILTER_EXT:
filter_escape_value( &f->f_mr_value, &tmp );
fstr->bv_len = f->f_mr_desc->ad_cname.bv_len +
( f->f_mr_dnattrs ? sizeof(":dn")-1 : 0 ) +
( f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_len+1 : 0 ) +
tmp.bv_len + ( sizeof("(:=)") - 1 );
fstr->bv_val = malloc( fstr->bv_len + 1 );
snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s%s%s%s:=%s)",
f->f_mr_desc->ad_cname.bv_val,
f->f_mr_dnattrs ? ":dn" : "",
f->f_mr_rule_text.bv_len ? ":" : "",
f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_val : "",
tmp.bv_val );
ber_memfree( tmp.bv_val );
break;
case SLAPD_FILTER_COMPUTED:
ber_str2bv(
f->f_result == LDAP_COMPARE_FALSE ? "(?=false)" :
f->f_result == LDAP_COMPARE_TRUE ? "(?=true)" :
f->f_result == SLAPD_COMPARE_UNDEFINED ? "(?=undefined)" :
"(?=error)",
f->f_result == LDAP_COMPARE_FALSE ? sizeof("(?=false)")-1 :
f->f_result == LDAP_COMPARE_TRUE ? sizeof("(?=true)")-1 :
f->f_result == SLAPD_COMPARE_UNDEFINED ? sizeof("(?=undefined)")-1 :
sizeof("(?=error)")-1,
1, fstr );
break;
default:
ber_str2bv( "(?=unknown)", sizeof("(?=unknown)")-1, 1, fstr );
break;
}
}
static int
get_substring_vrFilter(
Connection *conn,
BerElement *ber,
ValuesReturnFilter *f,
const char **text )
{
ber_tag_t tag;
ber_len_t len;
ber_tag_t rc;
struct berval value;
char *last;
struct berval bv;
*text = "error decoding filter";
#ifdef NEW_LOGGING
LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY,
"get_substring_filter: conn %d begin\n", conn->c_connid ));
#else
Debug( LDAP_DEBUG_FILTER, "begin get_substring_filter\n", 0, 0, 0 );
#endif
if ( ber_scanf( ber, "{m" /*}*/, &bv ) == LBER_ERROR ) {
return SLAPD_DISCONNECT;
}
f->f_sub = ch_calloc( 1, sizeof(SubstringsAssertion) );
f->f_sub_desc = NULL;
rc = slap_bv2ad( &bv, &f->f_sub_desc, text );
if( rc != LDAP_SUCCESS ) {
text = NULL;
ch_free( f->f_sub );
f->f_choice = SLAPD_FILTER_COMPUTED;
f->f_result = SLAPD_COMPARE_UNDEFINED;
return LDAP_SUCCESS;
}
f->f_sub_initial.bv_val = NULL;
f->f_sub_any = NULL;
f->f_sub_final.bv_val = NULL;
for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
tag = ber_next_element( ber, &len, last ) )
{
unsigned usage;
rc = ber_scanf( ber, "m", &value );
if ( rc == LBER_ERROR ) {
rc = SLAPD_DISCONNECT;
goto return_error;
}
if ( value.bv_val == NULL || value.bv_len == 0 ) {
rc = LDAP_INVALID_SYNTAX;
goto return_error;
}
switch ( tag ) {
case LDAP_SUBSTRING_INITIAL:
usage = SLAP_MR_SUBSTR_INITIAL;
break;
case LDAP_SUBSTRING_ANY:
usage = SLAP_MR_SUBSTR_ANY;
break;
case LDAP_SUBSTRING_FINAL:
usage = SLAP_MR_SUBSTR_FINAL;
break;
default:
rc = LDAP_PROTOCOL_ERROR;
#ifdef NEW_LOGGING
LDAP_LOG(( "filter", LDAP_LEVEL_ERR,
"get_filter_substring: conn %d unknown substring choice=%ld\n",
conn->c_connid, (long)tag ));
#else
Debug( LDAP_DEBUG_FILTER,
" unknown substring choice=%ld\n",
(long) tag, 0, 0 );
#endif
goto return_error;
}
/* valiate using equality matching rule validator! */
rc = value_validate( f->f_sub_desc->ad_type->sat_equality,
&value, text );
if( rc != LDAP_SUCCESS ) {
goto return_error;
}
rc = value_normalize( f->f_sub_desc, usage,
&value, &bv, text );
if( rc != LDAP_SUCCESS ) {
goto return_error;
}
value = bv;
rc = LDAP_PROTOCOL_ERROR;
switch ( tag ) {
case LDAP_SUBSTRING_INITIAL:
#ifdef NEW_LOGGING
LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
"get_substring_filter: conn %d INITIAL\n",
conn->c_connid ));
#else
Debug( LDAP_DEBUG_FILTER, " INITIAL\n", 0, 0, 0 );
#endif
if ( f->f_sub_initial.bv_val != NULL
|| f->f_sub_any != NULL
|| f->f_sub_final.bv_val != NULL )
{
free( value.bv_val );
goto return_error;
}
f->f_sub_initial = value;
break;
case LDAP_SUBSTRING_ANY:
#ifdef NEW_LOGGING
LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
"get_substring_filter: conn %d ANY\n",
conn->c_connid ));
#else
Debug( LDAP_DEBUG_FILTER, " ANY\n", 0, 0, 0 );
#endif
if ( f->f_sub_final.bv_val != NULL ) {
free( value.bv_val );
goto return_error;
}
ber_bvarray_add( &f->f_sub_any, &value );
break;
case LDAP_SUBSTRING_FINAL:
#ifdef NEW_LOGGING
LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
"get_substring_filter: conn %d FINAL\n",
conn->c_connid ));
#else
Debug( LDAP_DEBUG_FILTER, " FINAL\n", 0, 0, 0 );
#endif
if ( f->f_sub_final.bv_val != NULL ) {
free( value.bv_val );
goto return_error;
}
f->f_sub_final = value;
break;
default:
#ifdef NEW_LOGGING
LDAP_LOG(( "filter", LDAP_LEVEL_INFO,
"get_substring_filter: conn %d unknown substring type %ld\n",
conn->c_connid, (long)tag ));
#else
Debug( LDAP_DEBUG_FILTER,
" unknown substring type=%ld\n",
(long) tag, 0, 0 );
#endif
free( value.bv_val );
return_error:
#ifdef NEW_LOGGING
LDAP_LOG(( "filter", LDAP_LEVEL_INFO,
"get_substring_filter: conn %d error %ld\n",
conn->c_connid, (long)rc ));
#else
Debug( LDAP_DEBUG_FILTER, " error=%ld\n",
(long) rc, 0, 0 );
#endif
free( f->f_sub_initial.bv_val );
ber_bvarray_free( f->f_sub_any );
free( f->f_sub_final.bv_val );
ch_free( f->f_sub );
return rc;
}
}
#ifdef NEW_LOGGING
LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY,
"get_substring_filter: conn %d exit\n", conn->c_connid ));
#else
Debug( LDAP_DEBUG_FILTER, "end get_substring_filter\n", 0, 0, 0 );
#endif
return( LDAP_SUCCESS );
}

View file

@ -0,0 +1,423 @@
/* $OpenLDAP$ */
/*
* Copyright 1999-2002 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted only
* as authorized by the OpenLDAP Public License. A copy of this
* license is available at http://www.OpenLDAP.org/license.html or
* in file LICENSE in the top-level directory of the distribution.
*/
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "slap.h"
#include "../../libraries/liblber/lber-int.h"
static int test_mra_vrFilter(
Backend *be,
Connection *conn,
Operation *op,
Entry *e,
MatchingRuleAssertion *mra,
char ***e_flags
);
static int
test_substrings_vrFilter(
Backend *be,
Connection *conn,
Operation *op,
Entry *e,
ValuesReturnFilter *f,
char ***e_flags
);
static int
test_presence_vrFilter(
Backend *be,
Connection *conn,
Operation *op,
Entry *e,
AttributeDescription *desc,
char ***e_flags
);
static int
test_ava_vrFilter(
Backend *be,
Connection *conn,
Operation *op,
Entry *e,
AttributeAssertion *ava,
int type,
char ***e_flags
);
int
filter_matched_values(
Backend *be,
Connection *conn,
Operation *op,
Entry *e,
char ***e_flags
)
{
ValuesReturnFilter *f;
Attribute *a;
struct berval *bv;
char filter_found;
int i, j;
int rc = LDAP_SUCCESS;
#ifdef NEW_LOGGING
LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY,
"filter_matched_values: begin\n" ));
#else
Debug( LDAP_DEBUG_FILTER, "=> filter_matched_values\n", 0, 0, 0 );
#endif
for ( f = op->vrFilter; f != NULL; f = f->f_next ) {
switch ( f->f_choice ) {
case SLAPD_FILTER_COMPUTED:
#ifdef NEW_LOGGING
LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
"test_vrFilter: COMPUTED %s (%d)\n",
f->f_result == LDAP_COMPARE_FALSE ? "false" :
f->f_result == LDAP_COMPARE_TRUE ? "true" :
f->f_result == SLAPD_COMPARE_UNDEFINED ? "undefined" :
"error",
f->f_result ));
#else
Debug( LDAP_DEBUG_FILTER, " COMPUTED %s (%d)\n",
f->f_result == LDAP_COMPARE_FALSE ? "false" :
f->f_result == LDAP_COMPARE_TRUE ? "true" :
f->f_result == SLAPD_COMPARE_UNDEFINED ? "undefined" : "error",
f->f_result, 0 );
#endif
/*This type of filter does not affect the result */
rc = LDAP_SUCCESS;
break;
case LDAP_FILTER_EQUALITY:
#ifdef NEW_LOGGING
LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
"test_vrFilter: EQUALITY\n" ));
#else
Debug( LDAP_DEBUG_FILTER, " EQUALITY\n", 0, 0, 0 );
#endif
rc = test_ava_vrFilter( be, conn, op, e, f->f_ava,
LDAP_FILTER_EQUALITY, e_flags );
if( rc == -1 ) {
return rc;
}
break;
case LDAP_FILTER_SUBSTRINGS:
#ifdef NEW_LOGGING
LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
"test_vrFilter SUBSTRINGS\n" ));
#else
Debug( LDAP_DEBUG_FILTER, " SUBSTRINGS\n", 0, 0, 0 );
#endif
rc = test_substrings_vrFilter( be, conn, op, e,
f, e_flags );
if( rc == -1 ) {
return rc;
}
break;
case LDAP_FILTER_PRESENT:
#ifdef NEW_LOGGING
LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
"test_vrFilter: PRESENT\n" ));
#else
Debug( LDAP_DEBUG_FILTER, " PRESENT\n", 0, 0, 0 );
#endif
rc = test_presence_vrFilter( be, conn, op, e,
f->f_desc, e_flags );
if( rc == -1 ) {
return rc;
}
break;
case LDAP_FILTER_GE:
rc = test_ava_vrFilter( be, conn, op, e, f->f_ava,
LDAP_FILTER_GE, e_flags );
if( rc == -1 ) {
return rc;
}
break;
case LDAP_FILTER_LE:
rc = test_ava_vrFilter( be, conn, op, e, f->f_ava,
LDAP_FILTER_LE, e_flags );
if( rc == -1 ) {
return rc;
}
break;
case LDAP_FILTER_EXT:
#ifdef NEW_LOGGING
LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
"test_vrFilter: EXT\n" ));
#else
Debug( LDAP_DEBUG_FILTER, " EXT\n", 0, 0, 0 );
#endif
rc = test_mra_vrFilter( be, conn, op, e,
f->f_mra, e_flags );
if( rc == -1 ) {
return rc;
}
break;
default:
#ifdef NEW_LOGGING
LDAP_LOG(( "filter", LDAP_LEVEL_INFO,
"test_vrFilter: unknown filter type %lu\n",
f->f_choice ));
#else
Debug( LDAP_DEBUG_ANY, " unknown filter type %lu\n",
f->f_choice, 0, 0 );
#endif
rc = LDAP_PROTOCOL_ERROR;
}
}
#ifdef NEW_LOGGING
LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY,
"filter_matched_values: return=%d\n", rc ));
#else
Debug( LDAP_DEBUG_FILTER, "<= filter_matched_values %d\n", rc, 0, 0 );
#endif
return( rc );
}
static int
test_ava_vrFilter(
Backend *be,
Connection *conn,
Operation *op,
Entry *e,
AttributeAssertion *ava,
int type,
char ***e_flags
)
{
int rc;
int i, j;
Attribute *a;
if ( !access_allowed( be, conn, op, e,
ava->aa_desc, &ava->aa_value, ACL_SEARCH, NULL ) )
{
return LDAP_INSUFFICIENT_ACCESS;
}
for (a = e->e_attrs, i=0; a != NULL; a = a->a_next, i++ ) {
MatchingRule *mr;
struct berval *bv;
if ( !is_ad_subtype( a->a_desc, ava->aa_desc ) ) {
continue;
}
switch ( type ) {
case LDAP_FILTER_APPROX:
mr = a->a_desc->ad_type->sat_approx;
if( mr != NULL ) break;
/* use EQUALITY matching rule if no APPROX rule */
case LDAP_FILTER_EQUALITY:
mr = a->a_desc->ad_type->sat_equality;
break;
case LDAP_FILTER_GE:
case LDAP_FILTER_LE:
mr = a->a_desc->ad_type->sat_ordering;
break;
default:
mr = NULL;
}
if( mr == NULL ) {
continue;
}
for ( bv = a->a_vals, j=0; bv->bv_val != NULL; bv++, j++ ) {
int ret;
int rc;
const char *text;
rc = value_match( &ret, a->a_desc, mr,
SLAP_MR_ASSERTION_SYNTAX_MATCH, bv, &ava->aa_value, &text );
if( rc != LDAP_SUCCESS ) {
return rc;
}
switch ( type ) {
case LDAP_FILTER_EQUALITY:
case LDAP_FILTER_APPROX:
if ( ret == 0 ) {
(*e_flags)[i][j] = 1;
}
break;
case LDAP_FILTER_GE:
if ( ret >= 0 ) {
(*e_flags)[i][j] = 1;
}
break;
case LDAP_FILTER_LE:
if ( ret <= 0 ) {
(*e_flags)[i][j] = 1;
}
break;
}
}
}
return( LDAP_SUCCESS );
}
static int
test_presence_vrFilter(
Backend *be,
Connection *conn,
Operation *op,
Entry *e,
AttributeDescription *desc,
char ***e_flags
)
{
int i, j;
Attribute *a;
if ( !access_allowed( be, conn, op, e, desc, NULL, ACL_SEARCH, NULL ) ) {
return LDAP_INSUFFICIENT_ACCESS;
}
for (a = e->e_attrs, i=0; a != NULL; a = a->a_next, i++ ) {
struct berval *bv;
if ( !is_ad_subtype( a->a_desc, desc ) ) {
continue;
}
for ( bv = a->a_vals, j=0; bv->bv_val != NULL; bv++, j++ );
memset( (*e_flags)[i], 1, j);
}
return( LDAP_SUCCESS );
}
static int
test_substrings_vrFilter(
Backend *be,
Connection *conn,
Operation *op,
Entry *e,
ValuesReturnFilter *f,
char ***e_flags
)
{
int i, j;
Attribute *a;
if ( !access_allowed( be, conn, op, e,
f->f_sub_desc, NULL, ACL_SEARCH, NULL ) )
{
return LDAP_INSUFFICIENT_ACCESS;
}
for (a = e->e_attrs, i=0; a != NULL; a = a->a_next, i++ ) {
MatchingRule *mr = a->a_desc->ad_type->sat_substr;
struct berval *bv;
if ( !is_ad_subtype( a->a_desc, f->f_sub_desc ) ) {
continue;
}
if( mr == NULL ) {
continue;
}
for ( bv = a->a_vals, j = 0; bv->bv_val != NULL; bv++, j++ ) {
int ret;
int rc;
const char *text;
rc = value_match( &ret, a->a_desc, mr,
SLAP_MR_ASSERTION_SYNTAX_MATCH,
bv, f->f_sub, &text );
if( rc != LDAP_SUCCESS ) {
return rc;
}
if ( ret == 0 ) {
(*e_flags)[i][j] = 1;
}
}
}
return LDAP_SUCCESS;
}
static int test_mra_vrFilter(
Backend *be,
Connection *conn,
Operation *op,
Entry *e,
MatchingRuleAssertion *mra,
char ***e_flags
)
{
int i, j;
Attribute *a;
if( !access_allowed( be, conn, op, e,
mra->ma_desc, &mra->ma_value, ACL_SEARCH, NULL ) )
{
return LDAP_INSUFFICIENT_ACCESS;
}
for (a = e->e_attrs, i=0; a != NULL; a = a->a_next, i++ ) {
struct berval *bv;
if ( !is_ad_subtype( a->a_desc, mra->ma_desc ) ) {
return( LDAP_SUCCESS );
}
for ( bv = a->a_vals, j = 0; bv->bv_val != NULL; bv++, j++ ) {
int ret;
int rc;
const char *text;
rc = value_match( &ret, a->a_desc, mra->ma_rule,
SLAP_MR_ASSERTION_SYNTAX_MATCH,
bv, &mra->ma_value,
&text );
if( rc != LDAP_SUCCESS ) {
return rc;
}
if ( ret ) {
(*e_flags)[i][j] = 1;
}
}
}
return LDAP_SUCCESS;
}

View file

@ -464,6 +464,14 @@ LDAP_SLAPD_F (int) get_filter LDAP_P((
LDAP_SLAPD_F (void) filter_free LDAP_P(( Filter *f ));
LDAP_SLAPD_F (void) filter2bv LDAP_P(( Filter *f, struct berval *bv ));
LDAP_SLAPD_F (int) get_vrFilter( Connection *conn, BerElement *ber,
ValuesReturnFilter **f,
const char **text );
LDAP_SLAPD_F (void) vrFilter_free( ValuesReturnFilter *f );
LDAP_SLAPD_F (void) vrFilter2bv( ValuesReturnFilter *f, struct berval *fstr );
/*
* filterentry.c
*/
@ -511,6 +519,16 @@ LDAP_SLAPD_F (FILE *) lock_fopen LDAP_P(( const char *fname,
const char *type, FILE **lfp ));
LDAP_SLAPD_F (int) lock_fclose LDAP_P(( FILE *fp, FILE *lfp ));
/*
* matchedValues.c
*/
LDAP_SLAPD_F (int) filter_matched_values(
Backend *be,
Connection *conn,
Operation *op,
Entry *e,
char ***e_flags );
/*
* modify.c
*/

View file

@ -628,7 +628,7 @@ send_search_entry(
char berbuf[256];
BerElement *ber = (BerElement *)berbuf;
Attribute *a, *aa;
int i, rc=-1, bytes;
int i, j, rc=-1, bytes;
char *edn;
int userattrs;
int opattrs;
@ -637,6 +637,12 @@ send_search_entry(
AttributeDescription *ad_entry = slap_schema.si_ad_entry;
/* a_flags: array of flags telling if the i-th element will be
* returned or filtered out
* e_flags: array of a_flags
*/
char *a_flags, **e_flags;
if (op->o_callback && op->o_callback->sc_sendentry) {
return op->o_callback->sc_sendentry( be, conn, op, e, attrs,
attrsonly, ctrls );
@ -721,7 +727,52 @@ send_search_entry(
opattrs = ( attrs == NULL ) ? 0
: an_find( attrs, &AllOper );
for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
/* create an array of arrays of flags. Each flag corresponds
* to particular value of attribute an equals 1 if value matches
* to ValuesReturnFilter or 0 if not
*/
for ( a = e->e_attrs; a != NULL; a = a->a_next ) i++;
e_flags = ch_malloc ( i * sizeof(a_flags) );
for ( a = e->e_attrs, i=0; a != NULL; a = a->a_next, i++ ) {
for ( j = 0; a->a_vals[j].bv_val != NULL; j++ );
a_flags = ch_calloc ( j, sizeof(char) );
/* If no ValuesReturnFilter control return everything */
if ( op->vrFilter == NULL ){
memset(a_flags, 1, j);
}
e_flags[i] = a_flags;
}
if ( op->vrFilter != NULL ){
rc = filter_matched_values(be, conn, op, e, &e_flags) ;
if ( rc == -1 ) {
#ifdef NEW_LOGGING
LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
"send_search_entry: conn %d matched values fitering failed\n",
conn ? conn->c_connid : 0 ));
#else
Debug( LDAP_DEBUG_ANY,
"matched values fitering failed\n", 0, 0, 0 );
#endif
ber_free( ber, 1 );
/* free e_flags */
for ( a = e->e_attrs, i=0; a != NULL; a = a->a_next, i++ ) {
free( e_flags[i] );
}
free( e_flags );
send_ldap_result( conn, op, LDAP_OTHER,
NULL, "matched values fitering error", NULL, NULL );
goto error_return;
}
}
for ( a = e->e_attrs, j = 0; a != NULL; a = a->a_next, j++ ) {
AttributeDescription *desc = a->a_desc;
if ( attrs == NULL ) {
@ -771,6 +822,11 @@ send_search_entry(
#endif
ber_free_buf( ber );
/* free e_flags */
for ( a = e->e_attrs, i=0; a != NULL; a = a->a_next, i++ ) {
free( e_flags[i] );
}
free( e_flags );
send_ldap_result( conn, op, LDAP_OTHER,
NULL, "encoding description error", NULL, NULL );
goto error_return;
@ -795,6 +851,10 @@ send_search_entry(
continue;
}
if ( e_flags[j][i] == 0 ){
continue;
}
if (( rc = ber_printf( ber, "O", &a->a_vals[i] )) == -1 ) {
#ifdef NEW_LOGGING
LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
@ -806,6 +866,11 @@ send_search_entry(
#endif
ber_free_buf( ber );
/* free e_flags */
for ( a = e->e_attrs, i=0; a != NULL; a = a->a_next, i++ ) {
free( e_flags[i] );
}
free( e_flags );
send_ldap_result( conn, op, LDAP_OTHER,
NULL, "encoding values error", NULL, NULL );
goto error_return;
@ -823,12 +888,23 @@ send_search_entry(
#endif
ber_free_buf( ber );
/* free e_flags */
for ( a = e->e_attrs, i=0; a != NULL; a = a->a_next, i++ ) {
free( e_flags[i] );
}
free( e_flags );
send_ldap_result( conn, op, LDAP_OTHER,
NULL, "encode end error", NULL, NULL );
goto error_return;
}
}
/* free e_flags */
for ( a = e->e_attrs, i=0; a != NULL; a = a->a_next, i++ ) {
free( e_flags[i] );
}
free( e_flags );
/* eventually will loop through generated operational attributes */
/* only have subschemaSubentry implemented */
aa = backend_operational( be, conn, op, e, attrs, opattrs );

View file

@ -723,6 +723,32 @@ typedef struct slap_filter {
/* compare routines can return undefined */
#define SLAPD_COMPARE_UNDEFINED ((ber_int_t) -1)
typedef struct slap_valuesreturnfilter {
ber_tag_t f_choice;
union vrf_un_u {
/* precomputed result */
ber_int_t f_un_result;
/* DN */
char *f_un_dn;
/* present */
AttributeDescription *f_un_desc;
/* simple value assertion */
AttributeAssertion *f_un_ava;
/* substring assertion */
SubstringsAssertion *f_un_ssa;
/* matching rule assertion */
MatchingRuleAssertion *f_un_mra;
} f_un;
struct slap_valuesreturnfilter *f_next;
} ValuesReturnFilter;
/*
* represents an attribute (description + values)
*/
@ -1453,6 +1479,7 @@ typedef struct slap_op {
char o_noop;
char o_subentries;
char o_subentries_visibility;
char o_valuesreturnfilter;
char o_pagedresults;
ber_int_t o_pagedresults_size;
@ -1470,6 +1497,7 @@ typedef struct slap_op {
void *o_private; /* anything the backend needs */
LDAP_STAILQ_ENTRY(slap_op) o_next; /* next operation in list */
ValuesReturnFilter *vrFilter; /* Structure represents ValuesReturnFilter */
} Operation;
#define get_manageDSAit(op) ((int)(op)->o_managedsait)