From: Kurt Zeilenga Date: Mon, 7 Apr 2003 01:06:46 +0000 (+0000) Subject: SLAP_NVALUES code cleanup X-Git-Tag: AUTOCONF_2_57~39 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=67d6b23d22302752c64d335b54a744b824c3b08f;p=openldap SLAP_NVALUES code cleanup --- diff --git a/servers/slapd/schema_init.c b/servers/slapd/schema_init.c index 5ef9efa582..e7c8107dda 100644 --- a/servers/slapd/schema_init.c +++ b/servers/slapd/schema_init.c @@ -33,96 +33,12 @@ #define SLAP_MR_ASSOCIATED(mr, with) \ ((mr) == (with) || (mr)->smr_associated == (with)) -/* (new) normalization routines */ -#define caseExactIA5Normalize IA5StringNormalize -#define caseIgnoreIA5Normalize IA5StringNormalize -#define caseExactNormalize UTF8StringNormalize -#define caseIgnoreNormalize UTF8StringNormalize - -#define integerFirstComponentNormalize NULL -#define objectIdentifierNormalize NULL -#define objectIdentifierFirstComponentNormalize NULL - -#define distinguishedNameNormalize dnNormalize -#define distinguishedNameMatch dnMatch -#define distinguishedNameIndexer octetStringIndexer -#define distinguishedNameFilter octetStringFilter - -#define integerOrderingMatch integerMatch -#define integerFirstComponentMatch NULL -#define integerIndexer octetStringIndexer -#define integerFilter octetStringFilter - -#define generalizedTimeMatch caseIgnoreIA5Match -#define generalizedTimeOrderingMatch caseIgnoreIA5Match - -#define uniqueMemberMatch dnMatch /* FIXME! */ - -#define objectIdentifierMatch octetStringMatch -#define objectIdentifierIndexer octetStringIndexer -#define objectIdentifierFilter octetStringFilter - -#define OpenLDAPaciMatch NULL - -#define bitStringMatch octetStringMatch -#define bitStringIndexer octetStringIndexer -#define bitStringFilter octetStringFilter - -#define caseIgnoreMatch octetStringMatch -#define caseIgnoreOrderingMatch octetStringOrderingMatch -#define caseIgnoreIndexer octetStringIndexer -#define caseIgnoreFilter octetStringFilter - -#define caseIgnoreSubstringsMatch octetStringSubstringsMatch -#define caseIgnoreSubstringsIndexer octetStringSubstringsIndexer -#define caseIgnoreSubstringsFilter octetStringSubstringsFilter - -#define caseExactMatch octetStringMatch -#define caseExactOrderingMatch octetStringOrderingMatch -#define caseExactIndexer octetStringIndexer -#define caseExactFilter octetStringFilter - -#define caseExactSubstringsMatch octetStringSubstringsMatch -#define caseExactSubstringsIndexer octetStringSubstringsIndexer -#define caseExactSubstringsFilter octetStringSubstringsFilter - -#define caseExactIA5Match octetStringMatch -#define caseExactIA5Indexer octetStringIndexer -#define caseExactIA5Filter octetStringFilter - -#define caseExactIA5SubstringsMatch octetStringSubstringsMatch -#define caseExactIA5SubstringsIndexer octetStringSubstringsIndexer -#define caseExactIA5SubstringsFilter octetStringSubstringsFilter - -#define caseIgnoreIA5Match octetStringMatch -#define caseIgnoreIA5Indexer octetStringIndexer -#define caseIgnoreIA5Filter octetStringFilter - -#define caseIgnoreIA5SubstringsMatch caseExactIA5SubstringsMatch -#define caseIgnoreIA5SubstringsIndexer caseExactIA5SubstringsIndexer -#define caseIgnoreIA5SubstringsFilter caseExactIA5SubstringsFilter - -#define numericStringMatch octetStringMatch -#define numericStringIndexer octetStringIndexer -#define numericStringFilter octetStringFilter - -#define numericStringSubstringsMatch caseExactIA5SubstringsMatch -#define numericStringSubstringsIndexer caseExactIA5SubstringsIndexer -#define numericStringSubstringsFilter caseExactIA5SubstringsFilter - -#define telephoneNumberMatch octetStringMatch -#define telephoneNumberIndexer octetStringIndexer -#define telephoneNumberFilter octetStringFilter - -#define telephoneNumberSubstringsMatch caseExactIA5SubstringsMatch -#define telephoneNumberSubstringsIndexer caseExactIA5SubstringsIndexer -#define telephoneNumberSubstringsFilter caseExactIA5SubstringsFilter - -#define booleanIndexer octetStringIndexer -#define booleanFilter octetStringFilter - -/* validatation routines */ -#define berValidate blobValidate +/* not yet implemented */ +#define objectIdentifierNormalize NULL +#define integerOrderingMatch NULL +#define uniqueMemberMatch NULL +#define integerFirstComponentNormalize NULL +#define objectIdentifierFirstComponentNormalize NULL /* approx matching rules */ #ifdef SLAP_NVALUES @@ -139,22 +55,22 @@ #define IA5StringApproxFilter approxFilter #endif -static char *bvcasechr( struct berval *bv, unsigned char c, ber_len_t *len ) +static int +inValidate( + Syntax *syntax, + struct berval *in ) { - ber_len_t i; - char lower = TOLOWER( c ); - char upper = TOUPPER( c ); - - if( c == 0 ) return NULL; - - for( i=0; i < bv->bv_len; i++ ) { - if( upper == bv->bv_val[i] || lower == bv->bv_val[i] ) { - *len = i; - return &bv->bv_val[i]; - } - } + /* no value allowed */ + return LDAP_INVALID_SYNTAX; +} - return NULL; +static int +blobValidate( + Syntax *syntax, + struct berval *in ) +{ + /* any value allowed */ + return LDAP_SUCCESS; } static int @@ -303,168 +219,596 @@ int octetStringFilter( } static int -inValidate( - Syntax *syntax, - struct berval *in ) -{ - /* no value allowed */ - return LDAP_INVALID_SYNTAX; -} - -static int -blobValidate( - Syntax *syntax, - struct berval *in ) -{ - /* any value allowed */ - return LDAP_SUCCESS; -} - -static int -bitStringValidate( +octetStringSubstringsMatch ( + int *matchp, + slap_mask_t flags, Syntax *syntax, - struct berval *in ) + MatchingRule *mr, + struct berval *value, + void *assertedValue ) { - ber_len_t i; + int match = 0; + SubstringsAssertion *sub = assertedValue; + struct berval left = *value; + int i; + ber_len_t inlen=0; - /* very unforgiving validation, requires no normalization - * before simplistic matching - */ - if( in->bv_len < 3 ) { - return LDAP_INVALID_SYNTAX; + /* Add up asserted input length */ + if( sub->sa_initial.bv_val ) { + inlen += sub->sa_initial.bv_len; } - - /* - * rfc 2252 section 6.3 Bit String - * bitstring = "'" *binary-digit "'" - * binary-digit = "0" / "1" - * example: '0101111101'B - */ - - if( in->bv_val[0] != '\'' || - in->bv_val[in->bv_len-2] != '\'' || - in->bv_val[in->bv_len-1] != 'B' ) - { - return LDAP_INVALID_SYNTAX; + if( sub->sa_any ) { + for(i=0; sub->sa_any[i].bv_val != NULL; i++) { + inlen += sub->sa_any[i].bv_len; + } + } + if( sub->sa_final.bv_val ) { + inlen += sub->sa_final.bv_len; } - for( i=in->bv_len-3; i>0; i-- ) { - if( in->bv_val[i] != '0' && in->bv_val[i] != '1' ) { - return LDAP_INVALID_SYNTAX; + if( sub->sa_initial.bv_val ) { + if( inlen > left.bv_len ) { + match = 1; + goto done; } - } - return LDAP_SUCCESS; -} + match = memcmp( sub->sa_initial.bv_val, left.bv_val, + sub->sa_initial.bv_len ); -static int -nameUIDValidate( - Syntax *syntax, - struct berval *in ) -{ - int rc; - struct berval dn; + if( match != 0 ) { + goto done; + } - if( in->bv_len == 0 ) return LDAP_SUCCESS; + left.bv_val += sub->sa_initial.bv_len; + left.bv_len -= sub->sa_initial.bv_len; + inlen -= sub->sa_initial.bv_len; + } - ber_dupbv( &dn, in ); - if( !dn.bv_val ) return LDAP_OTHER; + if( sub->sa_final.bv_val ) { + if( inlen > left.bv_len ) { + match = 1; + goto done; + } - if( dn.bv_val[dn.bv_len-1] == 'B' - && dn.bv_val[dn.bv_len-2] == '\'' ) - { - /* assume presence of optional UID */ - ber_len_t i; + match = memcmp( sub->sa_final.bv_val, + &left.bv_val[left.bv_len - sub->sa_final.bv_len], + sub->sa_final.bv_len ); - for(i=dn.bv_len-3; i>1; i--) { - if( dn.bv_val[i] != '0' && dn.bv_val[i] != '1' ) { - break; - } - } - if( dn.bv_val[i] != '\'' || dn.bv_val[i-1] != '#' ) { - ber_memfree( dn.bv_val ); - return LDAP_INVALID_SYNTAX; + if( match != 0 ) { + goto done; } - /* trim the UID to allow use of dnValidate */ - dn.bv_val[i-1] = '\0'; - dn.bv_len = i-1; + left.bv_len -= sub->sa_final.bv_len; + inlen -= sub->sa_final.bv_len; } - rc = dnValidate( NULL, &dn ); - - ber_memfree( dn.bv_val ); - return rc; -} + if( sub->sa_any ) { + for(i=0; sub->sa_any[i].bv_val; i++) { + ber_len_t idx; + char *p; -static int -uniqueMemberNormalize( - slap_mask_t usage, - Syntax *syntax, - MatchingRule *mr, - struct berval *val, - struct berval *normalized ) -{ - struct berval out; - int rc; +retry: + if( inlen > left.bv_len ) { + /* not enough length */ + match = 1; + goto done; + } - ber_dupbv( &out, val ); - if( out.bv_len != 0 ) { - struct berval uid = { 0, NULL }; + if( sub->sa_any[i].bv_len == 0 ) { + continue; + } - if( out.bv_val[out.bv_len-1] == 'B' - && out.bv_val[out.bv_len-2] == '\'' ) - { - /* assume presence of optional UID */ - uid.bv_val = strrchr( out.bv_val, '#' ); + p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len ); - if( uid.bv_val == NULL ) { - free( out.bv_val ); - return LDAP_INVALID_SYNTAX; + if( p == NULL ) { + match = 1; + goto done; } - uid.bv_len = out.bv_len - (uid.bv_val - out.bv_val); - out.bv_len -= uid.bv_len--; - - /* temporarily trim the UID */ - *(uid.bv_val++) = '\0'; - } + idx = p - left.bv_val; - rc = dnNormalize2( NULL, &out, normalized ); + if( idx >= left.bv_len ) { + /* this shouldn't happen */ + return LDAP_OTHER; + } - if( rc != LDAP_SUCCESS ) { - free( out.bv_val ); - return LDAP_INVALID_SYNTAX; - } + left.bv_val = p; + left.bv_len -= idx; - if( uid.bv_len ) { - normalized->bv_val = ch_realloc( normalized->bv_val, - normalized->bv_len + uid.bv_len + sizeof("#") ); + if( sub->sa_any[i].bv_len > left.bv_len ) { + /* not enough left */ + match = 1; + goto done; + } - /* insert the separator */ - normalized->bv_val[normalized->bv_len++] = '#'; + match = memcmp( left.bv_val, + sub->sa_any[i].bv_val, + sub->sa_any[i].bv_len ); - /* append the UID */ - AC_MEMCPY( &normalized->bv_val[normalized->bv_len], - uid.bv_val, uid.bv_len ); - normalized->bv_len += uid.bv_len; + if( match != 0 ) { + left.bv_val++; + left.bv_len--; + goto retry; + } - /* terminate */ - normalized->bv_val[normalized->bv_len] = '\0'; + left.bv_val += sub->sa_any[i].bv_len; + left.bv_len -= sub->sa_any[i].bv_len; + inlen -= sub->sa_any[i].bv_len; } - - free( out.bv_val ); } +done: + *matchp = match; return LDAP_SUCCESS; } -/* - * Handling boolean syntax and matching is quite rigid. - * A more flexible approach would be to allow a variety - * of strings to be normalized and prettied into TRUE - * and FALSE. - */ +/* Substrings Index generation function */ +static int +octetStringSubstringsIndexer ( + slap_mask_t use, + slap_mask_t flags, + Syntax *syntax, + MatchingRule *mr, + struct berval *prefix, + BerVarray values, + BerVarray *keysp ) +{ + ber_len_t i, j, nkeys; + size_t slen, mlen; + BerVarray keys; + + HASH_CONTEXT HASHcontext; + unsigned char HASHdigest[HASH_BYTES]; + struct berval digest; + digest.bv_val = HASHdigest; + digest.bv_len = sizeof(HASHdigest); + + nkeys=0; + + for( i=0; values[i].bv_val != NULL; i++ ) { + /* count number of indices to generate */ + if( values[i].bv_len < SLAP_INDEX_SUBSTR_MINLEN ) { + continue; + } + + if( flags & SLAP_INDEX_SUBSTR_INITIAL ) { + if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) { + nkeys += SLAP_INDEX_SUBSTR_MAXLEN - + ( SLAP_INDEX_SUBSTR_MINLEN - 1); + } else { + nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 ); + } + } + + if( flags & SLAP_INDEX_SUBSTR_ANY ) { + if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) { + nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1 ); + } + } + + if( flags & SLAP_INDEX_SUBSTR_FINAL ) { + if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) { + nkeys += SLAP_INDEX_SUBSTR_MAXLEN - + ( SLAP_INDEX_SUBSTR_MINLEN - 1); + } else { + nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 ); + } + } + } + + if( nkeys == 0 ) { + /* no keys to generate */ + *keysp = NULL; + return LDAP_SUCCESS; + } + + keys = ch_malloc( sizeof( struct berval ) * (nkeys+1) ); + + slen = syntax->ssyn_oidlen; + mlen = mr->smr_oidlen; + + nkeys=0; + for( i=0; values[i].bv_val != NULL; i++ ) { + ber_len_t j,max; + + if( values[i].bv_len < SLAP_INDEX_SUBSTR_MINLEN ) continue; + + if( ( flags & SLAP_INDEX_SUBSTR_ANY ) && + ( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) ) + { + char pre = SLAP_INDEX_SUBSTR_PREFIX; + max = values[i].bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1); + + for( j=0; jbv_len > 0 ) { + HASH_Update( &HASHcontext, + prefix->bv_val, prefix->bv_len ); + } + + HASH_Update( &HASHcontext, + &pre, sizeof( pre ) ); + HASH_Update( &HASHcontext, + syntax->ssyn_oid, slen ); + HASH_Update( &HASHcontext, + mr->smr_oid, mlen ); + HASH_Update( &HASHcontext, + &values[i].bv_val[j], + SLAP_INDEX_SUBSTR_MAXLEN ); + HASH_Final( HASHdigest, &HASHcontext ); + + ber_dupbv( &keys[nkeys++], &digest ); + } + } + + max = SLAP_INDEX_SUBSTR_MAXLEN < values[i].bv_len + ? SLAP_INDEX_SUBSTR_MAXLEN : values[i].bv_len; + + for( j=SLAP_INDEX_SUBSTR_MINLEN; j<=max; j++ ) { + char pre; + + if( flags & SLAP_INDEX_SUBSTR_INITIAL ) { + pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX; + HASH_Init( &HASHcontext ); + if( prefix != NULL && prefix->bv_len > 0 ) { + HASH_Update( &HASHcontext, + prefix->bv_val, prefix->bv_len ); + } + HASH_Update( &HASHcontext, + &pre, sizeof( pre ) ); + HASH_Update( &HASHcontext, + syntax->ssyn_oid, slen ); + HASH_Update( &HASHcontext, + mr->smr_oid, mlen ); + HASH_Update( &HASHcontext, + values[i].bv_val, j ); + HASH_Final( HASHdigest, &HASHcontext ); + + ber_dupbv( &keys[nkeys++], &digest ); + } + + if( flags & SLAP_INDEX_SUBSTR_FINAL ) { + pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX; + HASH_Init( &HASHcontext ); + if( prefix != NULL && prefix->bv_len > 0 ) { + HASH_Update( &HASHcontext, + prefix->bv_val, prefix->bv_len ); + } + HASH_Update( &HASHcontext, + &pre, sizeof( pre ) ); + HASH_Update( &HASHcontext, + syntax->ssyn_oid, slen ); + HASH_Update( &HASHcontext, + mr->smr_oid, mlen ); + HASH_Update( &HASHcontext, + &values[i].bv_val[values[i].bv_len-j], j ); + HASH_Final( HASHdigest, &HASHcontext ); + + ber_dupbv( &keys[nkeys++], &digest ); + } + + } + + } + + if( nkeys > 0 ) { + keys[nkeys].bv_val = NULL; + *keysp = keys; + } else { + ch_free( keys ); + *keysp = NULL; + } + + return LDAP_SUCCESS; +} + +static int +octetStringSubstringsFilter ( + slap_mask_t use, + slap_mask_t flags, + Syntax *syntax, + MatchingRule *mr, + struct berval *prefix, + void * assertedValue, + BerVarray *keysp ) +{ + SubstringsAssertion *sa; + char pre; + unsigned casefold; + ber_len_t nkeys = 0; + size_t slen, mlen, klen; + BerVarray keys; + HASH_CONTEXT HASHcontext; + unsigned char HASHdigest[HASH_BYTES]; + struct berval *value; + struct berval digest; + + sa = (SubstringsAssertion *) assertedValue; + + if( flags & SLAP_INDEX_SUBSTR_INITIAL && sa->sa_initial.bv_val != NULL + && sa->sa_initial.bv_len >= SLAP_INDEX_SUBSTR_MINLEN ) + { + nkeys++; + } + + if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) { + ber_len_t i; + for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) { + if( sa->sa_any[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) { + /* don't bother accounting for stepping */ + nkeys += sa->sa_any[i].bv_len - + ( SLAP_INDEX_SUBSTR_MAXLEN - 1 ); + } + } + } + + if( flags & SLAP_INDEX_SUBSTR_FINAL && sa->sa_final.bv_val != NULL && + sa->sa_final.bv_len >= SLAP_INDEX_SUBSTR_MINLEN ) + { + nkeys++; + } + + if( nkeys == 0 ) { + *keysp = NULL; + return LDAP_SUCCESS; + } + + digest.bv_val = HASHdigest; + digest.bv_len = sizeof(HASHdigest); + + slen = syntax->ssyn_oidlen; + mlen = mr->smr_oidlen; + + keys = ch_malloc( sizeof( struct berval ) * (nkeys+1) ); + nkeys = 0; + + if( flags & SLAP_INDEX_SUBSTR_INITIAL && sa->sa_initial.bv_val != NULL && + sa->sa_initial.bv_len >= SLAP_INDEX_SUBSTR_MINLEN ) + { + pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX; + value = &sa->sa_initial; + + klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len + ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len; + + HASH_Init( &HASHcontext ); + if( prefix != NULL && prefix->bv_len > 0 ) { + HASH_Update( &HASHcontext, + prefix->bv_val, prefix->bv_len ); + } + HASH_Update( &HASHcontext, + &pre, sizeof( pre ) ); + HASH_Update( &HASHcontext, + syntax->ssyn_oid, slen ); + HASH_Update( &HASHcontext, + mr->smr_oid, mlen ); + HASH_Update( &HASHcontext, + value->bv_val, klen ); + HASH_Final( HASHdigest, &HASHcontext ); + + ber_dupbv( &keys[nkeys++], &digest ); + } + + if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) { + ber_len_t i, j; + pre = SLAP_INDEX_SUBSTR_PREFIX; + klen = SLAP_INDEX_SUBSTR_MAXLEN; + + for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) { + if( sa->sa_any[i].bv_len < SLAP_INDEX_SUBSTR_MAXLEN ) { + continue; + } + + value = &sa->sa_any[i]; + + for(j=0; + j <= value->bv_len - SLAP_INDEX_SUBSTR_MAXLEN; + j += SLAP_INDEX_SUBSTR_STEP ) + { + HASH_Init( &HASHcontext ); + if( prefix != NULL && prefix->bv_len > 0 ) { + HASH_Update( &HASHcontext, + prefix->bv_val, prefix->bv_len ); + } + HASH_Update( &HASHcontext, + &pre, sizeof( pre ) ); + HASH_Update( &HASHcontext, + syntax->ssyn_oid, slen ); + HASH_Update( &HASHcontext, + mr->smr_oid, mlen ); + HASH_Update( &HASHcontext, + &value->bv_val[j], klen ); + HASH_Final( HASHdigest, &HASHcontext ); + + ber_dupbv( &keys[nkeys++], &digest ); + } + + } + } + + if( flags & SLAP_INDEX_SUBSTR_FINAL && sa->sa_final.bv_val != NULL && + sa->sa_final.bv_len >= SLAP_INDEX_SUBSTR_MINLEN ) + { + pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX; + value = &sa->sa_final; + + klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len + ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len; + + HASH_Init( &HASHcontext ); + if( prefix != NULL && prefix->bv_len > 0 ) { + HASH_Update( &HASHcontext, + prefix->bv_val, prefix->bv_len ); + } + HASH_Update( &HASHcontext, + &pre, sizeof( pre ) ); + HASH_Update( &HASHcontext, + syntax->ssyn_oid, slen ); + HASH_Update( &HASHcontext, + mr->smr_oid, mlen ); + HASH_Update( &HASHcontext, + &value->bv_val[value->bv_len-klen], klen ); + HASH_Final( HASHdigest, &HASHcontext ); + + ber_dupbv( &keys[nkeys++], &digest ); + } + + if( nkeys > 0 ) { + keys[nkeys].bv_val = NULL; + *keysp = keys; + } else { + ch_free( keys ); + *keysp = NULL; + } + + return LDAP_SUCCESS; +} + +static int +bitStringValidate( + Syntax *syntax, + struct berval *in ) +{ + ber_len_t i; + + /* very unforgiving validation, requires no normalization + * before simplistic matching + */ + if( in->bv_len < 3 ) { + return LDAP_INVALID_SYNTAX; + } + + /* + * rfc 2252 section 6.3 Bit String + * bitstring = "'" *binary-digit "'" + * binary-digit = "0" / "1" + * example: '0101111101'B + */ + + if( in->bv_val[0] != '\'' || + in->bv_val[in->bv_len-2] != '\'' || + in->bv_val[in->bv_len-1] != 'B' ) + { + return LDAP_INVALID_SYNTAX; + } + + for( i=in->bv_len-3; i>0; i-- ) { + if( in->bv_val[i] != '0' && in->bv_val[i] != '1' ) { + return LDAP_INVALID_SYNTAX; + } + } + + return LDAP_SUCCESS; +} + +static int +nameUIDValidate( + Syntax *syntax, + struct berval *in ) +{ + int rc; + struct berval dn; + + if( in->bv_len == 0 ) return LDAP_SUCCESS; + + ber_dupbv( &dn, in ); + if( !dn.bv_val ) return LDAP_OTHER; + + if( dn.bv_val[dn.bv_len-1] == 'B' + && dn.bv_val[dn.bv_len-2] == '\'' ) + { + /* assume presence of optional UID */ + ber_len_t i; + + for(i=dn.bv_len-3; i>1; i--) { + if( dn.bv_val[i] != '0' && dn.bv_val[i] != '1' ) { + break; + } + } + if( dn.bv_val[i] != '\'' || dn.bv_val[i-1] != '#' ) { + ber_memfree( dn.bv_val ); + return LDAP_INVALID_SYNTAX; + } + + /* trim the UID to allow use of dnValidate */ + dn.bv_val[i-1] = '\0'; + dn.bv_len = i-1; + } + + rc = dnValidate( NULL, &dn ); + + ber_memfree( dn.bv_val ); + return rc; +} + +static int +uniqueMemberNormalize( + slap_mask_t usage, + Syntax *syntax, + MatchingRule *mr, + struct berval *val, + struct berval *normalized ) +{ + struct berval out; + int rc; + + ber_dupbv( &out, val ); + if( out.bv_len != 0 ) { + struct berval uid = { 0, NULL }; + + if( out.bv_val[out.bv_len-1] == 'B' + && out.bv_val[out.bv_len-2] == '\'' ) + { + /* assume presence of optional UID */ + uid.bv_val = strrchr( out.bv_val, '#' ); + + if( uid.bv_val == NULL ) { + free( out.bv_val ); + return LDAP_INVALID_SYNTAX; + } + + uid.bv_len = out.bv_len - (uid.bv_val - out.bv_val); + out.bv_len -= uid.bv_len--; + + /* temporarily trim the UID */ + *(uid.bv_val++) = '\0'; + } + + rc = dnNormalize2( NULL, &out, normalized ); + + if( rc != LDAP_SUCCESS ) { + free( out.bv_val ); + return LDAP_INVALID_SYNTAX; + } + + if( uid.bv_len ) { + normalized->bv_val = ch_realloc( normalized->bv_val, + normalized->bv_len + uid.bv_len + sizeof("#") ); + + /* insert the separator */ + normalized->bv_val[normalized->bv_len++] = '#'; + + /* append the UID */ + AC_MEMCPY( &normalized->bv_val[normalized->bv_len], + uid.bv_val, uid.bv_len ); + normalized->bv_len += uid.bv_len; + + /* terminate */ + normalized->bv_val[normalized->bv_len] = '\0'; + } + + free( out.bv_val ); + } + + return LDAP_SUCCESS; +} + +/* + * Handling boolean syntax and matching is quite rigid. + * A more flexible approach would be to allow a variety + * of strings to be normalized and prettied into TRUE + * and FALSE. + */ static int booleanValidate( Syntax *syntax, @@ -685,250 +1029,30 @@ UTF8StringNormalize( if( wasspace ) { /* last character was a space, trim it */ --nvalue.bv_len; - } - nvalue.bv_val[nvalue.bv_len] = '\0'; - - } else { - /* string of all spaces is treated as one space */ - nvalue.bv_val[0] = ' '; - nvalue.bv_val[1] = '\0'; - nvalue.bv_len = 1; - } - - *normalized = nvalue; - return LDAP_SUCCESS; -} - -#ifndef SLAP_NVALUES - -#ifndef SLAPD_APPROX_OLDSINGLESTRING -#if defined(SLAPD_APPROX_INITIALS) -#define SLAPD_APPROX_DELIMITER "._ " -#define SLAPD_APPROX_WORDLEN 2 -#else -#define SLAPD_APPROX_DELIMITER " " -#define SLAPD_APPROX_WORDLEN 1 -#endif - -static int -approxMatch( - int *matchp, - slap_mask_t flags, - Syntax *syntax, - MatchingRule *mr, - struct berval *value, - void *assertedValue ) -{ - struct berval *nval, *assertv; - char *val, **values, **words, *c; - int i, count, len, nextchunk=0, nextavail=0; - - /* Yes, this is necessary */ - nval = UTF8bvnormalize( value, NULL, LDAP_UTF8_APPROX ); - if( nval == NULL ) { - *matchp = 1; - return LDAP_SUCCESS; - } - - /* Yes, this is necessary */ - assertv = UTF8bvnormalize( ((struct berval *)assertedValue), - NULL, LDAP_UTF8_APPROX ); - if( assertv == NULL ) { - ber_bvfree( nval ); - *matchp = 1; - return LDAP_SUCCESS; - } - - /* Isolate how many words there are */ - for ( c = nval->bv_val, count = 1; *c; c++ ) { - c = strpbrk( c, SLAPD_APPROX_DELIMITER ); - if ( c == NULL ) break; - *c = '\0'; - count++; - } - - /* Get a phonetic copy of each word */ - words = (char **)ch_malloc( count * sizeof(char *) ); - values = (char **)ch_malloc( count * sizeof(char *) ); - for ( c = nval->bv_val, i = 0; i < count; i++, c += strlen(c) + 1 ) { - words[i] = c; - values[i] = phonetic(c); - } - - /* Work through the asserted value's words, to see if at least some - of the words are there, in the same order. */ - len = 0; - while ( (ber_len_t) nextchunk < assertv->bv_len ) { - len = strcspn( assertv->bv_val + nextchunk, SLAPD_APPROX_DELIMITER); - if( len == 0 ) { - nextchunk++; - continue; - } -#if defined(SLAPD_APPROX_INITIALS) - else if( len == 1 ) { - /* Single letter words need to at least match one word's initial */ - for( i=nextavail; ibv_val + nextchunk, words[i], 1 )) { - nextavail=i+1; - break; - } - } -#endif - else { - /* Isolate the next word in the asserted value and phonetic it */ - assertv->bv_val[nextchunk+len] = '\0'; - val = phonetic( assertv->bv_val + nextchunk ); - - /* See if this phonetic chunk is in the remaining words of *value */ - for( i=nextavail; i= count ) { - nextavail=-1; - break; - } - - /* Go on to the next word in the asserted value */ - nextchunk += len+1; - } - - /* If some of the words were seen, call it a match */ - if( nextavail > 0 ) { - *matchp = 0; - } - else { - *matchp = 1; - } - - /* Cleanup allocs */ - ber_bvfree( assertv ); - for( i=0; i= SLAPD_APPROX_WORDLEN ) wordcount++; - c+= len; - if (*c == '\0') break; - *c = '\0'; - } - - /* Allocate/increase storage to account for new keys */ - newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1) - * sizeof(struct berval) ); - AC_MEMCPY( newkeys, keys, keycount * sizeof(struct berval) ); - if( keys ) ch_free( keys ); - keys = newkeys; - - /* Get a phonetic copy of each word */ - for( c = val.bv_val, i = 0; i < wordcount; c += len + 1 ) { - len = strlen( c ); - if( len < SLAPD_APPROX_WORDLEN ) continue; - ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] ); - keycount++; - i++; - } - - ber_memfree( val.bv_val ); - } - keys[keycount].bv_val = NULL; - *keysp = keys; - - return LDAP_SUCCESS; -} - -static int -approxFilter( - slap_mask_t use, - slap_mask_t flags, - Syntax *syntax, - MatchingRule *mr, - struct berval *prefix, - void * assertedValue, - BerVarray *keysp ) -{ - char *c; - int i, count, len; - struct berval *val; - BerVarray keys; - - /* Yes, this is necessary */ - val = UTF8bvnormalize( ((struct berval *)assertedValue), - NULL, LDAP_UTF8_APPROX ); - if( val == NULL || val->bv_val == NULL ) { - keys = (struct berval *)ch_malloc( sizeof(struct berval) ); - keys[0].bv_val = NULL; - *keysp = keys; - ber_bvfree( val ); - return LDAP_SUCCESS; - } - - /* Isolate how many words there are. There will be a key for each */ - for( count = 0,c = val->bv_val; *c; c++) { - len = strcspn(c, SLAPD_APPROX_DELIMITER); - if( len >= SLAPD_APPROX_WORDLEN ) count++; - c+= len; - if (*c == '\0') break; - *c = '\0'; - } - - /* Allocate storage for new keys */ - keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) ); - - /* Get a phonetic copy of each word */ - for( c = val->bv_val, i = 0; i < count; c += len + 1 ) { - len = strlen(c); - if( len < SLAPD_APPROX_WORDLEN ) continue; - ber_str2bv( phonetic( c ), 0, 0, &keys[i] ); - i++; - } - - ber_bvfree( val ); + } + nvalue.bv_val[nvalue.bv_len] = '\0'; - keys[count].bv_val = NULL; - *keysp = keys; + } else { + /* string of all spaces is treated as one space */ + nvalue.bv_val[0] = ' '; + nvalue.bv_val[1] = '\0'; + nvalue.bv_len = 1; + } + *normalized = nvalue; return LDAP_SUCCESS; } +#ifndef SLAP_NVALUES + +#ifndef SLAPD_APPROX_OLDSINGLESTRING +#if defined(SLAPD_APPROX_INITIALS) +#define SLAPD_APPROX_DELIMITER "._ " +#define SLAPD_APPROX_WORDLEN 2 #else -/* No other form of Approximate Matching is defined */ +#define SLAPD_APPROX_DELIMITER " " +#define SLAPD_APPROX_WORDLEN 1 +#endif static int approxMatch( @@ -939,272 +1063,162 @@ approxMatch( struct berval *value, void *assertedValue ) { - char *vapprox, *avapprox; - char *s, *t; + struct berval *nval, *assertv; + char *val, **values, **words, *c; + int i, count, len, nextchunk=0, nextavail=0; /* Yes, this is necessary */ - s = UTF8normalize( value, UTF8_NOCASEFOLD ); - if( s == NULL ) { + nval = UTF8bvnormalize( value, NULL, LDAP_UTF8_APPROX ); + if( nval == NULL ) { *matchp = 1; return LDAP_SUCCESS; } /* Yes, this is necessary */ - t = UTF8normalize( ((struct berval *)assertedValue), - UTF8_NOCASEFOLD ); - if( t == NULL ) { - free( s ); - *matchp = -1; + assertv = UTF8bvnormalize( ((struct berval *)assertedValue), + NULL, LDAP_UTF8_APPROX ); + if( assertv == NULL ) { + ber_bvfree( nval ); + *matchp = 1; return LDAP_SUCCESS; } - vapprox = phonetic( strip8bitChars( s ) ); - avapprox = phonetic( strip8bitChars( t ) ); - - free( s ); - free( t ); - - *matchp = strcmp( vapprox, avapprox ); - - ch_free( vapprox ); - ch_free( avapprox ); - - return LDAP_SUCCESS; -} - -static int -approxIndexer( - slap_mask_t use, - slap_mask_t flags, - Syntax *syntax, - MatchingRule *mr, - struct berval *prefix, - BerVarray values, - BerVarray *keysp ) -{ - int i; - BerVarray *keys; - char *s; - - for( i=0; values[i].bv_val != NULL; i++ ) { - /* empty - just count them */ - } - - /* we should have at least one value at this point */ - assert( i > 0 ); - - keys = (struct berval *)ch_malloc( sizeof( struct berval ) * (i+1) ); - - /* Copy each value and run it through phonetic() */ - for( i=0; values[i].bv_val != NULL; i++ ) { - /* Yes, this is necessary */ - s = UTF8normalize( &values[i], UTF8_NOCASEFOLD ); - - /* strip 8-bit chars and run through phonetic() */ - ber_str2bv( phonetic( strip8bitChars( s ) ), 0, 0, &keys[i] ); - free( s ); + /* Isolate how many words there are */ + for ( c = nval->bv_val, count = 1; *c; c++ ) { + c = strpbrk( c, SLAPD_APPROX_DELIMITER ); + if ( c == NULL ) break; + *c = '\0'; + count++; } - keys[i].bv_val = NULL; - - *keysp = keys; - return LDAP_SUCCESS; -} -static int -approxFilter( - slap_mask_t use, - slap_mask_t flags, - Syntax *syntax, - MatchingRule *mr, - struct berval *prefix, - void * assertedValue, - BerVarray *keysp ) -{ - BerVarray keys; - char *s; - - keys = (struct berval *)ch_malloc( sizeof( struct berval * ) * 2 ); - - /* Yes, this is necessary */ - s = UTF8normalize( ((struct berval *)assertedValue), - UTF8_NOCASEFOLD ); - if( s == NULL ) { - keys[0] = NULL; - } else { - /* strip 8-bit chars and run through phonetic() */ - keys[0] = ber_bvstr( phonetic( strip8bitChars( s ) ) ); - free( s ); - keys[1] = NULL; + /* Get a phonetic copy of each word */ + words = (char **)ch_malloc( count * sizeof(char *) ); + values = (char **)ch_malloc( count * sizeof(char *) ); + for ( c = nval->bv_val, i = 0; i < count; i++, c += strlen(c) + 1 ) { + words[i] = c; + values[i] = phonetic(c); } - *keysp = keys; - return LDAP_SUCCESS; -} -#endif -#endif /* !SLAP_NVALUES */ - -/* Substrings Index generation function */ -static int -octetStringSubstringsIndexer ( - slap_mask_t use, - slap_mask_t flags, - Syntax *syntax, - MatchingRule *mr, - struct berval *prefix, - BerVarray values, - BerVarray *keysp ) -{ - ber_len_t i, j, nkeys; - size_t slen, mlen; - BerVarray keys; - - HASH_CONTEXT HASHcontext; - unsigned char HASHdigest[HASH_BYTES]; - struct berval digest; - digest.bv_val = HASHdigest; - digest.bv_len = sizeof(HASHdigest); - - nkeys=0; - - for( i=0; values[i].bv_val != NULL; i++ ) { - /* count number of indices to generate */ - if( values[i].bv_len < SLAP_INDEX_SUBSTR_MINLEN ) { + /* Work through the asserted value's words, to see if at least some + of the words are there, in the same order. */ + len = 0; + while ( (ber_len_t) nextchunk < assertv->bv_len ) { + len = strcspn( assertv->bv_val + nextchunk, SLAPD_APPROX_DELIMITER); + if( len == 0 ) { + nextchunk++; continue; } - - if( flags & SLAP_INDEX_SUBSTR_INITIAL ) { - if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) { - nkeys += SLAP_INDEX_SUBSTR_MAXLEN - - ( SLAP_INDEX_SUBSTR_MINLEN - 1); - } else { - nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 ); - } +#if defined(SLAPD_APPROX_INITIALS) + else if( len == 1 ) { + /* Single letter words need to at least match one word's initial */ + for( i=nextavail; ibv_val + nextchunk, words[i], 1 )) { + nextavail=i+1; + break; + } } +#endif + else { + /* Isolate the next word in the asserted value and phonetic it */ + assertv->bv_val[nextchunk+len] = '\0'; + val = phonetic( assertv->bv_val + nextchunk ); - if( flags & SLAP_INDEX_SUBSTR_ANY ) { - if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) { - nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1 ); + /* See if this phonetic chunk is in the remaining words of *value */ + for( i=nextavail; i= SLAP_INDEX_SUBSTR_MAXLEN ) { - nkeys += SLAP_INDEX_SUBSTR_MAXLEN - - ( SLAP_INDEX_SUBSTR_MINLEN - 1); - } else { - nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 ); - } + /* This chunk in the asserted value was NOT within the *value. */ + if( i >= count ) { + nextavail=-1; + break; } - } - if( nkeys == 0 ) { - /* no keys to generate */ - *keysp = NULL; - return LDAP_SUCCESS; + /* Go on to the next word in the asserted value */ + nextchunk += len+1; } - keys = ch_malloc( sizeof( struct berval ) * (nkeys+1) ); - - slen = syntax->ssyn_oidlen; - mlen = mr->smr_oidlen; - - nkeys=0; - for( i=0; values[i].bv_val != NULL; i++ ) { - ber_len_t j,max; - - if( values[i].bv_len < SLAP_INDEX_SUBSTR_MINLEN ) continue; - - if( ( flags & SLAP_INDEX_SUBSTR_ANY ) && - ( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) ) - { - char pre = SLAP_INDEX_SUBSTR_PREFIX; - max = values[i].bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1); - - for( j=0; jbv_len > 0 ) { - HASH_Update( &HASHcontext, - prefix->bv_val, prefix->bv_len ); - } - - HASH_Update( &HASHcontext, - &pre, sizeof( pre ) ); - HASH_Update( &HASHcontext, - syntax->ssyn_oid, slen ); - HASH_Update( &HASHcontext, - mr->smr_oid, mlen ); - HASH_Update( &HASHcontext, - &values[i].bv_val[j], - SLAP_INDEX_SUBSTR_MAXLEN ); - HASH_Final( HASHdigest, &HASHcontext ); - - ber_dupbv( &keys[nkeys++], &digest ); - } - } + /* If some of the words were seen, call it a match */ + if( nextavail > 0 ) { + *matchp = 0; + } + else { + *matchp = 1; + } - max = SLAP_INDEX_SUBSTR_MAXLEN < values[i].bv_len - ? SLAP_INDEX_SUBSTR_MAXLEN : values[i].bv_len; + /* Cleanup allocs */ + ber_bvfree( assertv ); + for( i=0; ibv_len > 0 ) { - HASH_Update( &HASHcontext, - prefix->bv_val, prefix->bv_len ); - } - HASH_Update( &HASHcontext, - &pre, sizeof( pre ) ); - HASH_Update( &HASHcontext, - syntax->ssyn_oid, slen ); - HASH_Update( &HASHcontext, - mr->smr_oid, mlen ); - HASH_Update( &HASHcontext, - values[i].bv_val, j ); - HASH_Final( HASHdigest, &HASHcontext ); +static int +approxIndexer( + slap_mask_t use, + slap_mask_t flags, + Syntax *syntax, + MatchingRule *mr, + struct berval *prefix, + BerVarray values, + BerVarray *keysp ) +{ + char *c; + int i,j, len, wordcount, keycount=0; + struct berval *newkeys; + BerVarray keys=NULL; - ber_dupbv( &keys[nkeys++], &digest ); - } + for( j=0; values[j].bv_val != NULL; j++ ) { + struct berval val = { 0, NULL }; + /* Yes, this is necessary */ + UTF8bvnormalize( &values[j], &val, LDAP_UTF8_APPROX ); + assert( val.bv_val != NULL ); - if( flags & SLAP_INDEX_SUBSTR_FINAL ) { - pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX; - HASH_Init( &HASHcontext ); - if( prefix != NULL && prefix->bv_len > 0 ) { - HASH_Update( &HASHcontext, - prefix->bv_val, prefix->bv_len ); - } - HASH_Update( &HASHcontext, - &pre, sizeof( pre ) ); - HASH_Update( &HASHcontext, - syntax->ssyn_oid, slen ); - HASH_Update( &HASHcontext, - mr->smr_oid, mlen ); - HASH_Update( &HASHcontext, - &values[i].bv_val[values[i].bv_len-j], j ); - HASH_Final( HASHdigest, &HASHcontext ); + /* Isolate how many words there are. There will be a key for each */ + for( wordcount = 0, c = val.bv_val; *c; c++) { + len = strcspn(c, SLAPD_APPROX_DELIMITER); + if( len >= SLAPD_APPROX_WORDLEN ) wordcount++; + c+= len; + if (*c == '\0') break; + *c = '\0'; + } - ber_dupbv( &keys[nkeys++], &digest ); - } + /* Allocate/increase storage to account for new keys */ + newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1) + * sizeof(struct berval) ); + AC_MEMCPY( newkeys, keys, keycount * sizeof(struct berval) ); + if( keys ) ch_free( keys ); + keys = newkeys; + /* Get a phonetic copy of each word */ + for( c = val.bv_val, i = 0; i < wordcount; c += len + 1 ) { + len = strlen( c ); + if( len < SLAPD_APPROX_WORDLEN ) continue; + ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] ); + keycount++; + i++; } + ber_memfree( val.bv_val ); } - - if( nkeys > 0 ) { - keys[nkeys].bv_val = NULL; - *keysp = keys; - } else { - ch_free( keys ); - *keysp = NULL; - } + keys[keycount].bv_val = NULL; + *keysp = keys; return LDAP_SUCCESS; } -static int -octetStringSubstringsFilter ( +static int +approxFilter( slap_mask_t use, slap_mask_t flags, Syntax *syntax, @@ -1213,157 +1227,165 @@ octetStringSubstringsFilter ( void * assertedValue, BerVarray *keysp ) { - SubstringsAssertion *sa; - char pre; - unsigned casefold; - ber_len_t nkeys = 0; - size_t slen, mlen, klen; + char *c; + int i, count, len; + struct berval *val; BerVarray keys; - HASH_CONTEXT HASHcontext; - unsigned char HASHdigest[HASH_BYTES]; - struct berval *value; - struct berval digest; - - sa = (SubstringsAssertion *) assertedValue; - if( flags & SLAP_INDEX_SUBSTR_INITIAL && sa->sa_initial.bv_val != NULL - && sa->sa_initial.bv_len >= SLAP_INDEX_SUBSTR_MINLEN ) - { - nkeys++; + /* Yes, this is necessary */ + val = UTF8bvnormalize( ((struct berval *)assertedValue), + NULL, LDAP_UTF8_APPROX ); + if( val == NULL || val->bv_val == NULL ) { + keys = (struct berval *)ch_malloc( sizeof(struct berval) ); + keys[0].bv_val = NULL; + *keysp = keys; + ber_bvfree( val ); + return LDAP_SUCCESS; } - if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) { - ber_len_t i; - for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) { - if( sa->sa_any[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) { - /* don't bother accounting for stepping */ - nkeys += sa->sa_any[i].bv_len - - ( SLAP_INDEX_SUBSTR_MAXLEN - 1 ); - } - } + /* Isolate how many words there are. There will be a key for each */ + for( count = 0,c = val->bv_val; *c; c++) { + len = strcspn(c, SLAPD_APPROX_DELIMITER); + if( len >= SLAPD_APPROX_WORDLEN ) count++; + c+= len; + if (*c == '\0') break; + *c = '\0'; } - if( flags & SLAP_INDEX_SUBSTR_FINAL && sa->sa_final.bv_val != NULL && - sa->sa_final.bv_len >= SLAP_INDEX_SUBSTR_MINLEN ) - { - nkeys++; - } + /* Allocate storage for new keys */ + keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) ); - if( nkeys == 0 ) { - *keysp = NULL; - return LDAP_SUCCESS; + /* Get a phonetic copy of each word */ + for( c = val->bv_val, i = 0; i < count; c += len + 1 ) { + len = strlen(c); + if( len < SLAPD_APPROX_WORDLEN ) continue; + ber_str2bv( phonetic( c ), 0, 0, &keys[i] ); + i++; } - digest.bv_val = HASHdigest; - digest.bv_len = sizeof(HASHdigest); + ber_bvfree( val ); - slen = syntax->ssyn_oidlen; - mlen = mr->smr_oidlen; + keys[count].bv_val = NULL; + *keysp = keys; - keys = ch_malloc( sizeof( struct berval ) * (nkeys+1) ); - nkeys = 0; + return LDAP_SUCCESS; +} - if( flags & SLAP_INDEX_SUBSTR_INITIAL && sa->sa_initial.bv_val != NULL && - sa->sa_initial.bv_len >= SLAP_INDEX_SUBSTR_MINLEN ) - { - pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX; - value = &sa->sa_initial; +#else +/* No other form of Approximate Matching is defined */ - klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len - ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len; +static int +approxMatch( + int *matchp, + slap_mask_t flags, + Syntax *syntax, + MatchingRule *mr, + struct berval *value, + void *assertedValue ) +{ + char *vapprox, *avapprox; + char *s, *t; - HASH_Init( &HASHcontext ); - if( prefix != NULL && prefix->bv_len > 0 ) { - HASH_Update( &HASHcontext, - prefix->bv_val, prefix->bv_len ); - } - HASH_Update( &HASHcontext, - &pre, sizeof( pre ) ); - HASH_Update( &HASHcontext, - syntax->ssyn_oid, slen ); - HASH_Update( &HASHcontext, - mr->smr_oid, mlen ); - HASH_Update( &HASHcontext, - value->bv_val, klen ); - HASH_Final( HASHdigest, &HASHcontext ); + /* Yes, this is necessary */ + s = UTF8normalize( value, UTF8_NOCASEFOLD ); + if( s == NULL ) { + *matchp = 1; + return LDAP_SUCCESS; + } - ber_dupbv( &keys[nkeys++], &digest ); + /* Yes, this is necessary */ + t = UTF8normalize( ((struct berval *)assertedValue), + UTF8_NOCASEFOLD ); + if( t == NULL ) { + free( s ); + *matchp = -1; + return LDAP_SUCCESS; } - if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) { - ber_len_t i, j; - pre = SLAP_INDEX_SUBSTR_PREFIX; - klen = SLAP_INDEX_SUBSTR_MAXLEN; + vapprox = phonetic( strip8bitChars( s ) ); + avapprox = phonetic( strip8bitChars( t ) ); + + free( s ); + free( t ); + + *matchp = strcmp( vapprox, avapprox ); + + ch_free( vapprox ); + ch_free( avapprox ); + + return LDAP_SUCCESS; +} + +static int +approxIndexer( + slap_mask_t use, + slap_mask_t flags, + Syntax *syntax, + MatchingRule *mr, + struct berval *prefix, + BerVarray values, + BerVarray *keysp ) +{ + int i; + BerVarray *keys; + char *s; - for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) { - if( sa->sa_any[i].bv_len < SLAP_INDEX_SUBSTR_MAXLEN ) { - continue; - } + for( i=0; values[i].bv_val != NULL; i++ ) { + /* empty - just count them */ + } - value = &sa->sa_any[i]; + /* we should have at least one value at this point */ + assert( i > 0 ); - for(j=0; - j <= value->bv_len - SLAP_INDEX_SUBSTR_MAXLEN; - j += SLAP_INDEX_SUBSTR_STEP ) - { - HASH_Init( &HASHcontext ); - if( prefix != NULL && prefix->bv_len > 0 ) { - HASH_Update( &HASHcontext, - prefix->bv_val, prefix->bv_len ); - } - HASH_Update( &HASHcontext, - &pre, sizeof( pre ) ); - HASH_Update( &HASHcontext, - syntax->ssyn_oid, slen ); - HASH_Update( &HASHcontext, - mr->smr_oid, mlen ); - HASH_Update( &HASHcontext, - &value->bv_val[j], klen ); - HASH_Final( HASHdigest, &HASHcontext ); + keys = (struct berval *)ch_malloc( sizeof( struct berval ) * (i+1) ); - ber_dupbv( &keys[nkeys++], &digest ); - } + /* Copy each value and run it through phonetic() */ + for( i=0; values[i].bv_val != NULL; i++ ) { + /* Yes, this is necessary */ + s = UTF8normalize( &values[i], UTF8_NOCASEFOLD ); - } + /* strip 8-bit chars and run through phonetic() */ + ber_str2bv( phonetic( strip8bitChars( s ) ), 0, 0, &keys[i] ); + free( s ); } + keys[i].bv_val = NULL; - if( flags & SLAP_INDEX_SUBSTR_FINAL && sa->sa_final.bv_val != NULL && - sa->sa_final.bv_len >= SLAP_INDEX_SUBSTR_MINLEN ) - { - pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX; - value = &sa->sa_final; - - klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len - ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len; + *keysp = keys; + return LDAP_SUCCESS; +} - HASH_Init( &HASHcontext ); - if( prefix != NULL && prefix->bv_len > 0 ) { - HASH_Update( &HASHcontext, - prefix->bv_val, prefix->bv_len ); - } - HASH_Update( &HASHcontext, - &pre, sizeof( pre ) ); - HASH_Update( &HASHcontext, - syntax->ssyn_oid, slen ); - HASH_Update( &HASHcontext, - mr->smr_oid, mlen ); - HASH_Update( &HASHcontext, - &value->bv_val[value->bv_len-klen], klen ); - HASH_Final( HASHdigest, &HASHcontext ); +static int +approxFilter( + slap_mask_t use, + slap_mask_t flags, + Syntax *syntax, + MatchingRule *mr, + struct berval *prefix, + void * assertedValue, + BerVarray *keysp ) +{ + BerVarray keys; + char *s; - ber_dupbv( &keys[nkeys++], &digest ); - } + keys = (struct berval *)ch_malloc( sizeof( struct berval * ) * 2 ); - if( nkeys > 0 ) { - keys[nkeys].bv_val = NULL; - *keysp = keys; + /* Yes, this is necessary */ + s = UTF8normalize( ((struct berval *)assertedValue), + UTF8_NOCASEFOLD ); + if( s == NULL ) { + keys[0] = NULL; } else { - ch_free( keys ); - *keysp = NULL; + /* strip 8-bit chars and run through phonetic() */ + keys[0] = ber_bvstr( phonetic( strip8bitChars( s ) ) ); + free( s ); + keys[1] = NULL; } + *keysp = keys; return LDAP_SUCCESS; } +#endif +#endif /* !SLAP_NVALUES */ /* Remove all spaces and '-' characters */ static int @@ -1724,130 +1746,6 @@ IA5StringNormalize( return LDAP_SUCCESS; } -static int -octetStringSubstringsMatch ( - int *matchp, - slap_mask_t flags, - Syntax *syntax, - MatchingRule *mr, - struct berval *value, - void *assertedValue ) -{ - int match = 0; - SubstringsAssertion *sub = assertedValue; - struct berval left = *value; - int i; - ber_len_t inlen=0; - - /* Add up asserted input length */ - if( sub->sa_initial.bv_val ) { - inlen += sub->sa_initial.bv_len; - } - if( sub->sa_any ) { - for(i=0; sub->sa_any[i].bv_val != NULL; i++) { - inlen += sub->sa_any[i].bv_len; - } - } - if( sub->sa_final.bv_val ) { - inlen += sub->sa_final.bv_len; - } - - if( sub->sa_initial.bv_val ) { - if( inlen > left.bv_len ) { - match = 1; - goto done; - } - - match = memcmp( sub->sa_initial.bv_val, left.bv_val, - sub->sa_initial.bv_len ); - - if( match != 0 ) { - goto done; - } - - left.bv_val += sub->sa_initial.bv_len; - left.bv_len -= sub->sa_initial.bv_len; - inlen -= sub->sa_initial.bv_len; - } - - if( sub->sa_final.bv_val ) { - if( inlen > left.bv_len ) { - match = 1; - goto done; - } - - match = memcmp( sub->sa_final.bv_val, - &left.bv_val[left.bv_len - sub->sa_final.bv_len], - sub->sa_final.bv_len ); - - if( match != 0 ) { - goto done; - } - - left.bv_len -= sub->sa_final.bv_len; - inlen -= sub->sa_final.bv_len; - } - - if( sub->sa_any ) { - for(i=0; sub->sa_any[i].bv_val; i++) { - ber_len_t idx; - char *p; - -retry: - if( inlen > left.bv_len ) { - /* not enough length */ - match = 1; - goto done; - } - - if( sub->sa_any[i].bv_len == 0 ) { - continue; - } - - p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len ); - - if( p == NULL ) { - match = 1; - goto done; - } - - idx = p - left.bv_val; - - if( idx >= left.bv_len ) { - /* this shouldn't happen */ - return LDAP_OTHER; - } - - left.bv_val = p; - left.bv_len -= idx; - - if( sub->sa_any[i].bv_len > left.bv_len ) { - /* not enough left */ - match = 1; - goto done; - } - - match = memcmp( left.bv_val, - sub->sa_any[i].bv_val, - sub->sa_any[i].bv_len ); - - if( match != 0 ) { - left.bv_val++; - left.bv_len--; - goto retry; - } - - left.bv_val += sub->sa_any[i].bv_len; - left.bv_len -= sub->sa_any[i].bv_len; - inlen -= sub->sa_any[i].bv_len; - } - } - -done: - *matchp = match; - return LDAP_SUCCESS; -} - static int numericStringValidate( Syntax *syntax, @@ -2770,6 +2668,7 @@ static slap_syntax_defs_rec syntax_defs[] = { SLAP_SYNTAX_BLOB, blobValidate, NULL}, {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' " X_NOT_H_R ")", +#define berValidate blobValidate SLAP_SYNTAX_BER, berValidate, NULL}, {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )", 0, bitStringValidate, NULL }, @@ -2989,16 +2888,16 @@ static slap_mrule_defs_rec mrule_defs[] = { "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )", SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL, NULL, - objectIdentifierNormalize, objectIdentifierMatch, - objectIdentifierIndexer, objectIdentifierFilter, + objectIdentifierNormalize, octetStringMatch, + octetStringIndexer, octetStringFilter, NULL}, {"( 2.5.13.1 NAME 'distinguishedNameMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )", SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL, NULL, - distinguishedNameNormalize, distinguishedNameMatch, - distinguishedNameIndexer, distinguishedNameFilter, + dnNormalize, dnMatch, + octetStringIndexer, octetStringFilter, NULL}, {"( 2.5.13.2 NAME 'caseIgnoreMatch' " @@ -3006,60 +2905,57 @@ static slap_mrule_defs_rec mrule_defs[] = { SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes, NULL, - caseIgnoreNormalize, caseIgnoreMatch, - caseIgnoreIndexer, caseIgnoreFilter, + UTF8StringNormalize, octetStringMatch, + octetStringIndexer, octetStringFilter, directoryStringApproxMatchOID }, {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )", SLAP_MR_ORDERING, directoryStringSyntaxes, - NULL, caseIgnoreNormalize, caseIgnoreOrderingMatch, - NULL, NULL, NULL}, + NULL, UTF8StringNormalize, octetStringOrderingMatch, + NULL, NULL, + NULL}, {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", SLAP_MR_SUBSTR, NULL, - NULL, NULL, - caseIgnoreSubstringsMatch, - caseIgnoreSubstringsIndexer, caseIgnoreSubstringsFilter, + NULL, UTF8StringNormalize, octetStringSubstringsMatch, + octetStringSubstringsIndexer, octetStringSubstringsFilter, NULL}, {"( 2.5.13.5 NAME 'caseExactMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )", SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes, - NULL, - caseExactNormalize, caseExactMatch, - caseExactIndexer, caseExactFilter, + NULL, UTF8StringNormalize, octetStringMatch, + octetStringIndexer, octetStringFilter, directoryStringApproxMatchOID }, {"( 2.5.13.6 NAME 'caseExactOrderingMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )", SLAP_MR_ORDERING, directoryStringSyntaxes, - NULL, caseExactNormalize, caseExactOrderingMatch, - NULL, NULL, NULL}, + NULL, UTF8StringNormalize, octetStringOrderingMatch, + NULL, NULL, + NULL}, {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", SLAP_MR_SUBSTR, directoryStringSyntaxes, - NULL, - NULL, caseExactSubstringsMatch, - caseExactSubstringsIndexer, caseExactSubstringsFilter, + NULL, UTF8StringNormalize, octetStringSubstringsMatch, + octetStringSubstringsIndexer, octetStringSubstringsFilter, NULL}, {"( 2.5.13.8 NAME 'numericStringMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )", SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL, - NULL, - numericStringNormalize, numericStringMatch, - numericStringIndexer, numericStringFilter, + NULL, numericStringNormalize, octetStringSubstringsMatch, + octetStringSubstringsIndexer, octetStringSubstringsFilter, NULL}, {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", SLAP_MR_SUBSTR, NULL, - NULL, - NULL, numericStringSubstringsMatch, - numericStringSubstringsIndexer, numericStringSubstringsFilter, + NULL, numericStringNormalize, octetStringSubstringsMatch, + octetStringSubstringsIndexer, octetStringSubstringsFilter, NULL}, {"( 2.5.13.11 NAME 'caseIgnoreListMatch' " @@ -3075,82 +2971,76 @@ static slap_mrule_defs_rec mrule_defs[] = { {"( 2.5.13.13 NAME 'booleanMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )", SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL, - NULL, - NULL, booleanMatch, - booleanIndexer, booleanFilter, + NULL, NULL, booleanMatch, + octetStringIndexer, octetStringFilter, NULL}, {"( 2.5.13.14 NAME 'integerMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL, - NULL, - integerNormalize, integerMatch, - integerIndexer, integerFilter, + NULL, integerNormalize, integerMatch, + octetStringIndexer, octetStringFilter, NULL}, {"( 2.5.13.15 NAME 'integerOrderingMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", - SLAP_MR_ORDERING, NULL, NULL, - integerNormalize, integerOrderingMatch, - integerIndexer, integerFilter, + SLAP_MR_ORDERING, NULL, + NULL, integerNormalize, integerOrderingMatch, + NULL, NULL, NULL}, {"( 2.5.13.16 NAME 'bitStringMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )", SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL, - NULL, - NULL, bitStringMatch, - bitStringIndexer, bitStringFilter, + NULL, NULL, octetStringMatch, + octetStringIndexer, octetStringFilter, NULL}, {"( 2.5.13.17 NAME 'octetStringMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )", SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL, - NULL, NULL, - octetStringMatch, octetStringIndexer, octetStringFilter, + NULL, NULL, octetStringMatch, + octetStringIndexer, octetStringFilter, NULL}, {"( 2.5.13.18 NAME 'octetStringOrderingMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )", SLAP_MR_ORDERING, NULL, + NULL, NULL, octetStringOrderingMatch, NULL, NULL, - octetStringOrderingMatch, NULL, NULL, NULL}, {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )", SLAP_MR_SUBSTR, NULL, - NULL, NULL, - octetStringSubstringsMatch, NULL, NULL, + NULL, NULL, octetStringSubstringsMatch, + octetStringSubstringsIndexer, octetStringSubstringsFilter, NULL}, {"( 2.5.13.20 NAME 'telephoneNumberMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )", SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL, NULL, - telephoneNumberNormalize, telephoneNumberMatch, - telephoneNumberIndexer, telephoneNumberFilter, + telephoneNumberNormalize, octetStringMatch, + octetStringIndexer, octetStringFilter, NULL}, {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", SLAP_MR_SUBSTR, NULL, - NULL, NULL, telephoneNumberSubstringsMatch, - telephoneNumberSubstringsIndexer, telephoneNumberSubstringsFilter, + NULL, telephoneNumberNormalize, octetStringSubstringsMatch, + octetStringSubstringsIndexer, octetStringSubstringsFilter, NULL}, {"( 2.5.13.22 NAME 'presentationAddressMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )", SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL, - NULL, NULL, - NULL, NULL, NULL, - NULL}, + NULL, NULL, NULL, NULL, NULL, NULL}, {"( 2.5.13.23 NAME 'uniqueMemberMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )", SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL, - NULL, - uniqueMemberNormalize, uniqueMemberMatch, + NULL, uniqueMemberNormalize, uniqueMemberMatch, NULL, NULL, NULL}, @@ -3162,24 +3052,21 @@ static slap_mrule_defs_rec mrule_defs[] = { {"( 2.5.13.27 NAME 'generalizedTimeMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )", SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL, - NULL, - generalizedTimeNormalize, generalizedTimeMatch, + NULL, generalizedTimeNormalize, octetStringMatch, NULL, NULL, NULL}, {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )", SLAP_MR_ORDERING, NULL, - NULL, - generalizedTimeNormalize, generalizedTimeOrderingMatch, + NULL, generalizedTimeNormalize, octetStringOrderingMatch, NULL, NULL, NULL}, {"( 2.5.13.29 NAME 'integerFirstComponentMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", SLAP_MR_EQUALITY | SLAP_MR_EXT, integerFirstComponentMatchSyntaxes, - NULL, - integerFirstComponentNormalize, integerMatch, + NULL, integerFirstComponentNormalize, integerMatch, NULL, NULL, NULL}, @@ -3187,9 +3074,8 @@ static slap_mrule_defs_rec mrule_defs[] = { "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )", SLAP_MR_EQUALITY | SLAP_MR_EXT, objectIdentifierFirstComponentMatchSyntaxes, - NULL, - objectIdentifierFirstComponentNormalize, objectIdentifierMatch, - NULL, NULL, + NULL, objectIdentifierFirstComponentNormalize, octetStringMatch, + octetStringIndexer, octetStringFilter, NULL}, #ifndef SLAP_NVALUES @@ -3197,8 +3083,7 @@ static slap_mrule_defs_rec mrule_defs[] = { {"( 2.5.13.34 NAME 'certificateExactMatch' " "SYNTAX 1.2.826.0.1.3344810.7.1 )", SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes, - certificateExactConvert, NULL, - certificateExactMatch, + certificateExactConvert, NULL, certificateExactMatch, certificateExactIndexer, certificateExactFilter, NULL}, #endif @@ -3207,33 +3092,29 @@ static slap_mrule_defs_rec mrule_defs[] = { {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )", SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL, - NULL, - caseExactIA5Normalize, caseExactIA5Match, - caseExactIA5Indexer, caseExactIA5Filter, + NULL, IA5StringNormalize, octetStringMatch, + octetStringIndexer, octetStringFilter, IA5StringApproxMatchOID }, {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )", SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL, - NULL, - NULL, caseIgnoreIA5Match, - caseIgnoreIA5Indexer, caseIgnoreIA5Filter, + NULL, IA5StringNormalize, octetStringMatch, + octetStringIndexer, octetStringFilter, IA5StringApproxMatchOID }, {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )", SLAP_MR_SUBSTR, NULL, - NULL, - NULL, caseIgnoreIA5SubstringsMatch, - caseIgnoreIA5SubstringsIndexer, caseIgnoreIA5SubstringsFilter, + NULL, IA5StringNormalize, octetStringSubstringsMatch, + octetStringSubstringsIndexer, octetStringSubstringsFilter, NULL}, {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )", SLAP_MR_SUBSTR, NULL, - NULL, - NULL, caseExactIA5SubstringsMatch, - caseExactIA5SubstringsIndexer, caseExactIA5SubstringsFilter, + NULL, IA5StringNormalize, octetStringSubstringsMatch, + octetStringSubstringsIndexer, octetStringSubstringsFilter, NULL}, #ifdef SLAPD_AUTHPASSWD @@ -3241,8 +3122,8 @@ static slap_mrule_defs_rec mrule_defs[] = { {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )", SLAP_MR_EQUALITY, NULL, + NULL, NULL, authPasswordMatch, NULL, NULL, - authPasswordMatch, NULL, NULL, NULL}, #endif @@ -3250,23 +3131,23 @@ static slap_mrule_defs_rec mrule_defs[] = { {"( 1.3.6.1.4.1.4203.666.4.2 NAME 'OpenLDAPaciMatch' " "SYNTAX 1.3.6.1.4.1.4203.666.2.1 )", SLAP_MR_EQUALITY, NULL, + NULL, NULL, OpenLDAPaciMatch, NULL, NULL, - OpenLDAPaciMatch, NULL, NULL, NULL}, #endif {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", SLAP_MR_EXT, NULL, - NULL, - NULL, integerBitAndMatch, NULL, NULL, + NULL, NULL, integerBitAndMatch, + NULL, NULL, NULL}, {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", SLAP_MR_EXT, NULL, - NULL, - NULL, integerBitOrMatch, NULL, NULL, + NULL, NULL, integerBitOrMatch, + NULL, NULL, NULL}, {NULL, SLAP_MR_NONE, NULL,