]> git.sur5r.net Git - openldap/commitdiff
SLAP_NVALUES code cleanup
authorKurt Zeilenga <kurt@openldap.org>
Mon, 7 Apr 2003 01:06:46 +0000 (01:06 +0000)
committerKurt Zeilenga <kurt@openldap.org>
Mon, 7 Apr 2003 01:06:46 +0000 (01:06 +0000)
servers/slapd/schema_init.c

index 5ef9efa58206bb36c2da51003a6bf4d5600798bf..e7c8107ddabbd235e5f28b7435b60e1912f3181b 100644 (file)
 #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
 #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; j<max; j++ ) {
+                               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],
+                                       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; i<count; i++ )
-                               if( !strncasecmp( assertv->bv_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; i++ ){
-                               if( !strcmp( val, values[i] ) ){
-                                       nextavail = i+1;
-                                       break;
-                               }
-                       }
-                       ch_free( val );
-               }
-
-               /* This chunk in the asserted value was NOT within the *value. */
-               if( 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<count; i++ ) {
-               ch_free( values[i] );
-       }
-       ch_free( values );
-       ch_free( words );
-       ber_bvfree( nval );
-
-       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 )
-{
-       char *c;
-       int i,j, len, wordcount, keycount=0;
-       struct berval *newkeys;
-       BerVarray keys=NULL;
-
-       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 );
-
-               /* 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';
-               }
-
-               /* 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; i<count; i++ )
+                               if( !strncasecmp( assertv->bv_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<count; i++ ){
+                               if( !strcmp( val, values[i] ) ){
+                                       nextavail = i+1;
+                                       break;
+                               }
                        }
+                       ch_free( val );
                }
 
-               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 );
-                       }
+               /* 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; j<max; j++ ) {
-                               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],
-                                       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; i<count; i++ ) {
+               ch_free( values[i] );
+       }
+       ch_free( values );
+       ch_free( words );
+       ber_bvfree( nval );
 
-               for( j=SLAP_INDEX_SUBSTR_MINLEN; j<=max; j++ ) {
-                       char pre;
+       return LDAP_SUCCESS;
+}
 
-                       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 );
+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,