]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/schema_init.c
liberally accept many LDAPv2/LDAPv3 stuff in DN (quoted parts, ';' as rdn separator...
[openldap] / servers / slapd / schema_init.c
index a676409265a0a85eb3360e09bc132c5dc70c417f..8437777e12722ed44d77784a3079b37862fca325 100644 (file)
@@ -8,8 +8,10 @@
 #include "portable.h"
 
 #include <stdio.h>
+#include <limits.h>
 
 #include <ac/ctype.h>
+#include <ac/errno.h>
 #include <ac/string.h>
 #include <ac/socket.h>
 
 #define berValidate                                            blobValidate
 
 /* unimplemented pretters */
-#define dnPretty                                               NULL
 #define integerPretty                                  NULL
+#ifndef USE_LDAP_DN_PARSING
+#      define dnPretty                                         NULL
+#else
+#      define SLAP_LDAPDN_PRETTY 0x1
+#endif /* !USE_LDAP_DN_PARSING */
 
 /* recycled matching routines */
 #define bitStringMatch                                 octetStringMatch
-#define integerMatch                                   caseIgnoreIA5Match
 #define numericStringMatch                             caseIgnoreIA5Match
 #define objectIdentifierMatch                  caseIgnoreIA5Match
 #define telephoneNumberMatch                   caseIgnoreIA5Match
@@ -70,8 +75,8 @@
 /* recycled indexing/filtering routines */
 #define dnIndexer                              caseExactIgnoreIndexer
 #define dnFilter                               caseExactIgnoreFilter
-#define integerIndexer                                 caseIgnoreIA5Indexer
-#define integerFilter                                  caseIgnoreIA5Filter
+#define bitStringFilter                        octetStringFilter
+#define bitStringIndexer               octetStringIndexer
 
 #define telephoneNumberIndexer                 caseIgnoreIA5Indexer
 #define telephoneNumberFilter                  caseIgnoreIA5Filter
@@ -217,6 +222,310 @@ int octetStringFilter(
        return LDAP_SUCCESS;
 }
 
+#ifdef USE_LDAP_DN_PARSING
+static int
+dnValidate(
+       Syntax *syntax,
+       struct berval *in )
+{
+       int             rc;
+       LDAPDN          *dn = NULL;
+
+       if ( in->bv_len == 0 ) {
+               return( LDAP_SUCCESS );
+       }
+
+       rc = ldap_str2dn( in->bv_val, &dn, LDAP_DN_FORMAT_LDAP );
+
+       /*
+        * Fixme: should we also validate each DN component?
+        */
+       ldapava_free_dn( dn );
+       
+       if ( rc != LDAP_SUCCESS ) {
+               return( LDAP_INVALID_SYNTAX );
+       }
+
+       return( LDAP_SUCCESS );
+}
+
+static void
+AVA_Sort( LDAPRDN *rdn, int iAVA )
+{
+       int             i;
+       LDAPAVA         *ava_in = rdn[ iAVA ][ 0 ];
+       
+       for ( i = 0; i < iAVA; i++ ) {
+               LDAPAVA         *ava = rdn[ i ][ 0 ];
+               int             a, j;
+
+               a = strcmp( ava_in->la_attr->bv_val, ava->la_attr->bv_val );
+
+               if ( a > 0 ) {
+                       break;
+               }
+
+               while ( a == 0 ) {
+                       int             v, d;
+
+                       d = ava_in->la_value->bv_len - ava->la_value->bv_len;
+
+                       v = memcmp( ava_in->la_value->bv_val, 
+                                       ava->la_value->bv_val,
+                                       d <= 0 ? ava_in->la_value->bv_len 
+                                               : ava->la_value->bv_len );
+
+                       if ( v == 0 && d != 0 ) {
+                               v = d;
+                       }
+
+                       if ( v <= 0 ) {
+                               /* 
+                                * got it!
+                                */
+                               break;
+                       }
+
+                       if ( ++i == iAVA ) {
+                               /*
+                                * already sorted
+                                */
+                               return;
+                       }
+
+                       ava = rdn[ i ][ 0 ];
+                       a = strcmp( ava_in->la_value->bv_val, 
+                                       ava->la_value->bv_val );
+               }
+
+               /*
+                * move ahead
+                */
+               for ( j = iAVA; j > i; j-- ) {
+                       rdn[ j ][ 0 ] = rdn[ j - 1 ][ 0 ];
+               }
+               rdn[ i ][ 0 ] = ava_in;
+
+               return;
+       }
+}
+
+/*
+ * In-place, schema-aware normalization / "pretty"ing of the
+ * structural representation of a distinguished name.
+ */
+static int
+LDAPDN_rewrite( LDAPDN *dn, unsigned flags )
+{
+       int             iRDN;
+       int             rc;
+
+       assert( dn );
+
+       for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
+               LDAPRDN         *rdn = dn[ iRDN ][ 0 ];
+               int             iAVA;
+
+               for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
+                       LDAPAVA                 *ava = rdn[ iAVA ][ 0 ];
+                       AttributeDescription    *ad = NULL;
+                       const char              *text = NULL;
+                       slap_syntax_transform_func *transf = NULL;
+                       MatchingRule *mr;
+                       struct berval           *bv = NULL;
+
+                       rc = slap_bv2ad( ava->la_attr, &ad, &text );
+                       if ( rc != LDAP_SUCCESS ) {
+                               return LDAP_INVALID_SYNTAX;
+                       }
+
+                       /* 
+                        * Replace attr oid/name with the canonical name
+                        */
+                       ber_bvfree( ava->la_attr );
+                       ava->la_attr = ber_bvdup( &ad->ad_cname );
+
+                       if( flags & SLAP_LDAPDN_PRETTY ) {
+                               transf = ad->ad_type->sat_syntax->ssyn_pretty;
+                               mr = NULL;
+                       } else {
+                               transf = ad->ad_type->sat_syntax->ssyn_normalize;
+                               mr = ad->ad_type->sat_equality;
+                       }
+
+                       if ( transf ) {
+                               /*
+                                * transform value by normalize/pretty function
+                                */
+                               rc = ( *transf )( ad->ad_type->sat_syntax,
+                                       ava->la_value, &bv );
+                       
+                               if ( rc != LDAP_SUCCESS ) {
+                                       return LDAP_INVALID_SYNTAX;
+                               }
+                       }
+
+                       if( mr && ( mr->smr_usage & SLAP_MR_DN_FOLD ) ) {
+                               struct berval *s = bv;
+
+                               bv = ber_bvstr( UTF8normalize( bv ? bv : ava->la_value, 
+                                       UTF8_CASEFOLD ) );
+
+                               ber_bvfree( s );
+                       }
+
+                       if( bv ) {
+                               ber_bvfree( ava->la_value );
+                               ava->la_value = bv;
+                       }
+
+                       AVA_Sort( rdn, iAVA );
+               }
+       }
+
+       return LDAP_SUCCESS;
+}
+
+int
+dnNormalize(
+       Syntax *syntax,
+       struct berval *val,
+       struct berval **normalized )
+{
+       struct berval *out = NULL;
+
+       Debug( LDAP_DEBUG_TRACE, ">>> dnNormalize: <%s>\n", val->bv_val, 0, 0 );
+
+       if ( val->bv_len != 0 ) {
+               LDAPDN          *dn = NULL;
+               char            *dn_out = NULL;
+               int             rc;
+
+               /*
+                * Go to structural representation
+                */
+               rc = ldap_str2dn( val->bv_val, &dn, LDAP_DN_FORMAT_LDAP );
+               if ( rc != LDAP_SUCCESS ) {
+                       return LDAP_INVALID_SYNTAX;
+               }
+
+               /*
+                * Schema-aware rewrite
+                */
+               if ( LDAPDN_rewrite( dn, 0 ) != LDAP_SUCCESS ) {
+                       ldapava_free_dn( dn );
+                       return LDAP_INVALID_SYNTAX;
+               }
+
+               /*
+                * Back to string representation
+                */
+               rc = ldap_dn2str( dn, &dn_out, LDAP_DN_FORMAT_LDAPV3 );
+
+               ldapava_free_dn( dn );
+
+               if ( rc != LDAP_SUCCESS ) {
+                       return LDAP_INVALID_SYNTAX;
+               }
+
+               out = ber_bvstr( dn_out );
+
+       } else {
+               out = ber_bvdup( val );
+       }
+
+       Debug( LDAP_DEBUG_TRACE, "<<< dnNormalize: <%s>\n", out->bv_val, 0, 0 );
+
+       *normalized = out;
+
+       return LDAP_SUCCESS;
+}
+
+int
+dnPretty(
+       Syntax *syntax,
+       struct berval *val,
+       struct berval **pretty)
+{
+       struct berval *out = NULL;
+
+       Debug( LDAP_DEBUG_TRACE, ">>> dnPretty: <%s>\n", val->bv_val, 0, 0 );
+
+       if ( val->bv_len != 0 ) {
+               LDAPDN          *dn = NULL;
+               char            *dn_out = NULL;
+               int             rc;
+
+               /* FIXME: should be liberal in what we accept */
+               rc = ldap_str2dn( val->bv_val, &dn, LDAP_DN_FORMAT_LDAP );
+               if ( rc != LDAP_SUCCESS ) {
+                       return LDAP_INVALID_SYNTAX;
+               }
+
+               /*
+                * Schema-aware rewrite
+                */
+               if ( LDAPDN_rewrite( dn, SLAP_LDAPDN_PRETTY ) != LDAP_SUCCESS ) {
+                       ldapava_free_dn( dn );
+                       return LDAP_INVALID_SYNTAX;
+               }
+
+               /* FIXME: not sure why the default isn't pretty */
+               rc = ldap_dn2str( dn, &dn_out,
+                       LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY );
+
+               ldapava_free_dn( dn );
+
+               if ( rc != LDAP_SUCCESS ) {
+                       return LDAP_INVALID_SYNTAX;
+               }
+
+               out = ber_bvstr( dn_out );
+
+       } else {
+               out = ber_bvdup( val );
+       }
+
+       Debug( LDAP_DEBUG_TRACE, "<<< dnPretty: <%s>\n", out->bv_val, 0, 0 );
+
+       *pretty = out;
+
+       return LDAP_SUCCESS;
+}
+
+int
+dnMatch(
+       int *matchp,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *value,
+       void *assertedValue )
+{
+       int match;
+       struct berval *asserted = (struct berval *) assertedValue;
+       
+       match = value->bv_len - asserted->bv_len;
+
+       if ( match == 0 ) {
+               match = strcmp( value->bv_val, asserted->bv_val );
+       }
+
+#ifdef NEW_LOGGING
+       LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY,
+               "dnMatch: %d\n    %s\n    %s\n", match,
+               value->bv_val, asserted->bv_val ));
+#else
+       Debug( LDAP_DEBUG_ARGS, "dnMatch %d\n\t\"%s\"\n\t\"%s\"\n",
+               match, value->bv_val, asserted->bv_val );
+#endif
+
+       *matchp = match;
+       return( LDAP_SUCCESS );
+}
+
+#else /* !USE_LDAP_DN_PARSING */
+
 static int
 dnValidate(
        Syntax *syntax,
@@ -256,7 +565,7 @@ dnNormalize(
 
        if ( val->bv_len != 0 ) {
                char *dn;
-               out = ber_bvstr( UTF8normalize( val->bv_val, UTF8_CASEFOLD ) );
+               out = ber_bvstr( UTF8normalize( val, UTF8_CASEFOLD ) );
 
                dn = dn_validate( out->bv_val );
 
@@ -275,7 +584,7 @@ dnNormalize(
        return LDAP_SUCCESS;
 }
 
-static int
+int
 dnMatch(
        int *matchp,
        slap_mask_t flags,
@@ -311,6 +620,8 @@ dnMatch(
        return LDAP_SUCCESS;
 }
 
+#endif /* !USE_LDAP_DN_PARSING */
+
 static int
 nameUIDValidate(
        Syntax *syntax,
@@ -332,13 +643,10 @@ nameUIDValidate(
                                break;
                        }
                }
-               if( dn->bv_val[i] != '\'' ) {
-                       return LDAP_INVALID_SYNTAX;
-               }
-               if( dn->bv_val[i-1] != 'B' ) {
-                       return LDAP_INVALID_SYNTAX;
-               }
-               if( dn->bv_val[i-2] != '#' ) {
+               if( dn->bv_val[i] != '\'' ||
+                   dn->bv_val[i-1] != 'B' ||
+                   dn->bv_val[i-2] != '#' ) {
+                       ber_bvfree( dn );
                        return LDAP_INVALID_SYNTAX;
                }
 
@@ -441,14 +749,21 @@ bitStringValidate(
                return LDAP_INVALID_SYNTAX;
        }
 
-       if( in->bv_val[0] != 'B' ||
-               in->bv_val[1] != '\'' ||
-               in->bv_val[in->bv_len-1] != '\'' )
+       /*
+        * 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-2; i>1; i-- ) {
+       for( i=in->bv_len-3; i>0; i-- ) {
                if( in->bv_val[i] != '0' && in->bv_val[i] != '1' ) {
                        return LDAP_INVALID_SYNTAX;
                }
@@ -457,6 +772,51 @@ bitStringValidate(
        return LDAP_SUCCESS;
 }
 
+static int
+bitStringNormalize(
+       Syntax *syntax,
+       struct berval *val,
+       struct berval **normalized )
+{
+       /*
+     * A normalized bitString is has no extaneous (leading) zero bits.
+        * That is, '00010'B is normalized to '10'B
+        * However, as a special case, '0'B requires no normalization.
+     */
+       struct berval *newval;
+       char *p;
+
+       /* start at the first bit */
+       p = &val->bv_val[1];
+
+       /* Find the first non-zero bit */
+       while ( *p == '0' ) p++;
+
+       newval = (struct berval *) ch_malloc( sizeof(struct berval) );
+
+       if( *p == '\'' ) {
+               /* no non-zero bits */
+               newval->bv_val = ch_strdup("\'0\'B");
+               newval->bv_len = sizeof("\'0\'B") - 1;
+               goto done;
+       }
+
+       newval->bv_val = ch_malloc( val->bv_len + 1 );
+
+       newval->bv_val[0] = '\'';
+       newval->bv_len = 1;
+
+       for( ; *p != '\0'; p++ ) {
+               newval->bv_val[newval->bv_len++] = *p;
+       }
+
+       newval->bv_val[newval->bv_len] = '\0';
+
+done:
+       *normalized = newval;
+       return LDAP_SUCCESS;
+}
+
 /*
  * Handling boolean syntax and matching is quite rigid.
  * A more flexible approach would be to allow a variety
@@ -621,7 +981,7 @@ UTF8SubstringsassertionNormalize(
        }
 
        if( sa->sa_initial != NULL ) {
-               nsa->sa_initial = ber_bvstr( UTF8normalize( sa->sa_initial->bv_val, casefold ) );
+               nsa->sa_initial = ber_bvstr( UTF8normalize( sa->sa_initial, casefold ) );
                if( nsa->sa_initial == NULL ) {
                        goto err;
                }
@@ -633,7 +993,7 @@ UTF8SubstringsassertionNormalize(
                }
                nsa->sa_any = (struct berval **)ch_malloc( (i + 1) * sizeof(struct berval *) );
                for( i=0; sa->sa_any[i] != NULL; i++ ) {
-                       nsa->sa_any[i] = ber_bvstr( UTF8normalize( sa->sa_any[i]->bv_val, casefold ) );
+                       nsa->sa_any[i] = ber_bvstr( UTF8normalize( sa->sa_any[i], casefold ) );
                        if( nsa->sa_any[i] == NULL ) {
                                goto err;
                        }
@@ -642,7 +1002,7 @@ UTF8SubstringsassertionNormalize(
        }
 
        if( sa->sa_final != NULL ) {
-               nsa->sa_final = ber_bvstr( UTF8normalize( sa->sa_final->bv_val, casefold ) );
+               nsa->sa_final = ber_bvstr( UTF8normalize( sa->sa_final, casefold ) );
                if( nsa->sa_final == NULL ) {
                        goto err;
                }
@@ -651,9 +1011,9 @@ UTF8SubstringsassertionNormalize(
        return nsa;
 
 err:
-       ch_free( nsa->sa_final );
+       ber_bvfree( nsa->sa_final );
        ber_bvecfree( nsa->sa_any );
-       ch_free( nsa->sa_initial );
+       ber_bvfree( nsa->sa_initial );
        ch_free( nsa );
        return NULL;
 }
@@ -701,23 +1061,23 @@ approxMatch(
        struct berval *value,
        void *assertedValue )
 {
-       char *val, *assertv, **values, **words, *c;
+       char *val, *nval, *assertv, **values, **words, *c;
        int i, count, len, nextchunk=0, nextavail=0;
        size_t avlen;
 
        /* Yes, this is necessary */
-       val = UTF8normalize( value->bv_val, UTF8_NOCASEFOLD );
-       if( val == NULL ) {
+       nval = UTF8normalize( value, UTF8_NOCASEFOLD );
+       if( nval == NULL ) {
                *matchp = 1;
                return LDAP_SUCCESS;
        }
-       strip8bitChars( val );
+       strip8bitChars( nval );
 
        /* Yes, this is necessary */
-       assertv = UTF8normalize( ((struct berval *)assertedValue)->bv_val,
+       assertv = UTF8normalize( ((struct berval *)assertedValue),
                                 UTF8_NOCASEFOLD );
        if( assertv == NULL ) {
-               free( val );
+               ch_free( nval );
                *matchp = 1;
                return LDAP_SUCCESS;
        }
@@ -725,7 +1085,7 @@ approxMatch(
        avlen = strlen( assertv );
 
        /* Isolate how many words there are */
-       for( c=val,count=1; *c; c++ ) {
+       for( c=nval,count=1; *c; c++ ) {
                c = strpbrk( c, SLAPD_APPROX_DELIMITER );
                if ( c == NULL ) break;
                *c = '\0';
@@ -735,7 +1095,7 @@ approxMatch(
        /* Get a phonetic copy of each word */
        words = (char **)ch_malloc( count * sizeof(char *) );
        values = (char **)ch_malloc( count * sizeof(char *) );
-       for( c=val,i=0;  i<count;  i++,c+=strlen(c)+1 ) {
+       for( c=nval,i=0;  i<count;  i++,c+=strlen(c)+1 ) {
                words[i] = c;
                values[i] = phonetic(c);
        }
@@ -771,6 +1131,7 @@ approxMatch(
                                        break;
                                }
                        }
+                       ch_free( val );
                }
 
                /* This chunk in the asserted value was NOT within the *value. */
@@ -798,7 +1159,7 @@ approxMatch(
        }
        ch_free( values );
        ch_free( words );
-       free( val );
+       ch_free( nval );
 
        return LDAP_SUCCESS;
 }
@@ -819,7 +1180,7 @@ approxIndexer(
 
        for( j=0; values[j] != NULL; j++ ) {
                /* Yes, this is necessary */
-               val = UTF8normalize( values[j]->bv_val, UTF8_NOCASEFOLD );
+               val = UTF8normalize( values[j], UTF8_NOCASEFOLD );
                strip8bitChars( val );
 
                /* Isolate how many words there are. There will be a key for each */
@@ -872,7 +1233,7 @@ approxFilter(
        struct berval **keys;
 
        /* Yes, this is necessary */
-       val = UTF8normalize( ((struct berval *)assertValue)->bv_val,
+       val = UTF8normalize( ((struct berval *)assertValue),
                             UTF8_NOCASEFOLD );
        if( val == NULL ) {
                keys = (struct berval **)ch_malloc( sizeof(struct berval *) );
@@ -927,14 +1288,14 @@ approxMatch(
        char *s, *t;
 
        /* Yes, this is necessary */
-       s = UTF8normalize( value->bv_val, UTF8_NOCASEFOLD );
+       s = UTF8normalize( value, UTF8_NOCASEFOLD );
        if( s == NULL ) {
                *matchp = 1;
                return LDAP_SUCCESS;
        }
 
        /* Yes, this is necessary */
-       t = UTF8normalize( ((struct berval *)assertedValue)->bv_val,
+       t = UTF8normalize( ((struct berval *)assertedValue),
                           UTF8_NOCASEFOLD );
        if( t == NULL ) {
                free( s );
@@ -982,7 +1343,7 @@ approxIndexer(
        /* Copy each value and run it through phonetic() */
        for( i=0; values[i] != NULL; i++ ) {
                /* Yes, this is necessary */
-               s = UTF8normalize( values[i]->bv_val, UTF8_NOCASEFOLD );
+               s = UTF8normalize( values[i], UTF8_NOCASEFOLD );
 
                /* strip 8-bit chars and run through phonetic() */
                keys[i] = ber_bvstr( phonetic( strip8bitChars( s ) ) );
@@ -1011,7 +1372,7 @@ approxFilter(
        keys = (struct berval **)ch_malloc( sizeof( struct berval * ) * 2 );
 
        /* Yes, this is necessary */
-       s = UTF8normalize( ((struct berval *)assertValue)->bv_val,
+       s = UTF8normalize( ((struct berval *)assertValue),
                             UTF8_NOCASEFOLD );
        if( s == NULL ) {
                keys[0] = NULL;
@@ -1053,7 +1414,7 @@ caseExactIgnoreSubstringsMatch(
        void *assertedValue )
 {
        int match = 0;
-       SubstringsAssertion *sub;
+       SubstringsAssertion *sub = NULL;
        struct berval left;
        int i;
        ber_len_t inlen=0;
@@ -1062,7 +1423,7 @@ caseExactIgnoreSubstringsMatch(
        casefold = strcmp( mr->smr_oid, caseExactSubstringsMatchOID )
                ? UTF8_CASEFOLD : UTF8_NOCASEFOLD;
 
-       nav = UTF8normalize( value->bv_val, casefold );
+       nav = UTF8normalize( value, casefold );
        if( nav == NULL ) {
                match = 1;
                goto done;
@@ -1153,6 +1514,11 @@ retry:
 
                        if( idx >= left.bv_len ) {
                                /* this shouldn't happen */
+                               free( nav );
+                               ch_free( sub->sa_final );
+                               ber_bvecfree( sub->sa_any );
+                               ch_free( sub->sa_initial );
+                               ch_free( sub );
                                return LDAP_OTHER;
                        }
 
@@ -1184,9 +1550,9 @@ retry:
 done:
        free( nav );
        if( sub != NULL ) {
-               ch_free( sub->sa_final );
+               ber_bvfree( sub->sa_final );
                ber_bvecfree( sub->sa_any );
-               ch_free( sub->sa_initial );
+               ber_bvfree( sub->sa_initial );
                ch_free( sub );
        }
        *matchp = match;
@@ -1230,7 +1596,7 @@ int caseExactIgnoreIndexer(
 
        for( i=0; values[i] != NULL; i++ ) {
                struct berval *value;
-               value = ber_bvstr( UTF8normalize( values[i]->bv_val,
+               value = ber_bvstr( UTF8normalize( values[i],
                        casefold ) );
 
                HASH_Init( &HASHcontext );
@@ -1282,7 +1648,7 @@ int caseExactIgnoreFilter(
        casefold = strcmp( mr->smr_oid, caseExactMatchOID )
                ? UTF8_CASEFOLD : UTF8_NOCASEFOLD;
 
-       value = ber_bvstr( UTF8normalize( ((struct berval *) assertValue)->bv_val,
+       value = ber_bvstr( UTF8normalize( ((struct berval *) assertValue),
                casefold ) );
        /* This usually happens if filter contains bad UTF8 */
        if( value == NULL ) {
@@ -1351,7 +1717,7 @@ int caseExactIgnoreSubstringsIndexer(
 
        nvalues = ch_malloc( sizeof( struct berval * ) * (i+1) );
        for( i=0; values[i] != NULL; i++ ) {
-               nvalues[i] = ber_bvstr( UTF8normalize( values[i]->bv_val,
+               nvalues[i] = ber_bvstr( UTF8normalize( values[i],
                        casefold ) );
        }
        nvalues[i] = NULL;
@@ -1391,6 +1757,7 @@ int caseExactIgnoreSubstringsIndexer(
        if( nkeys == 0 ) {
                /* no keys to generate */
                *keysp = NULL;
+               ber_bvecfree( nvalues );
                return LDAP_SUCCESS;
        }
 
@@ -1551,6 +1918,10 @@ int caseExactIgnoreSubstringsFilter(
        }
 
        if( nkeys == 0 ) {
+               ber_bvfree( sa->sa_final );
+               ber_bvecfree( sa->sa_any );
+               ber_bvfree( sa->sa_initial );
+               ch_free( sa );
                *keysp = NULL;
                return LDAP_SUCCESS;
        }
@@ -1662,9 +2033,9 @@ int caseExactIgnoreSubstringsFilter(
                ch_free( keys );
                *keysp = NULL;
        }
-       ch_free( sa->sa_final );
+       ber_bvfree( sa->sa_final );
        ber_bvecfree( sa->sa_any );
-       ch_free( sa->sa_initial );
+       ber_bvfree( sa->sa_initial );
        ch_free( sa );
 
        return LDAP_SUCCESS;
@@ -1724,6 +2095,98 @@ oidValidate(
        return LDAP_INVALID_SYNTAX;
 }
 
+static int
+integerMatch(
+       int *matchp,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *value,
+       void *assertedValue )
+{
+       char *v, *av;
+       int vsign=0, avsign=0;
+       struct berval *asserted;
+       ber_len_t vlen, avlen;
+
+
+       /* Start off pessimistic */
+       *matchp = 1;
+
+       /* Skip past leading spaces/zeros, and get the sign of the *value number */
+       v = value->bv_val;
+       vlen = value->bv_len;
+       while( vlen ) {
+               if( ASCII_SPACE(*v) || ( *v == '0' )) {
+                       /* empty -- skip spaces */
+               }
+               else if ( *v == '+' ) {
+                       vsign = 1;
+               }
+               else if ( *v == '-' ) {
+                       vsign = -1;
+               }
+               else if ( ASCII_DIGIT(*v) ) {
+                       if ( vsign == 0 ) vsign = 1;
+                       vsign *= 2;
+                       break;
+               }
+               v++;
+               vlen--;
+       }
+
+       /* Skip past leading spaces/zeros, and get the sign of the *assertedValue
+          number */
+       asserted = (struct berval *) assertedValue;
+       av = asserted->bv_val;
+       avlen = asserted->bv_len;
+       while( avlen ) {
+               if( ASCII_SPACE(*av) || ( *av == '0' )) {
+                       /* empty -- skip spaces */
+               }
+               else if ( *av == '+' ) {
+                       avsign = 1;
+               }
+               else if ( *av == '-' ) {
+                       avsign = -1;
+               }
+               else if ( ASCII_DIGIT(*av) ) {
+                       if ( avsign == 0 ) avsign = 1;
+                       avsign *= 2;
+                       break;
+               }
+               av++;
+               avlen--;
+       }
+
+       /* The two ?sign vars are now one of :
+          -2  negative non-zero number
+          -1  -0   \
+           0   0   collapse these three to 0
+          +1  +0   /
+          +2  positive non-zero number
+       */
+       if ( abs( vsign ) == 1 ) vsign = 0;
+       if ( abs( avsign ) == 1 ) avsign = 0;
+
+       if( vsign != avsign ) return LDAP_SUCCESS;
+
+       /* Check the significant digits */
+       while( vlen && avlen ) {
+               if( *v != *av ) break;
+               v++;
+               vlen--;
+               av++;
+               avlen--;
+       }
+
+       /* If all digits compared equal, the numbers are equal */
+       if(( vlen == 0 ) && ( avlen == 0 )) {
+               *matchp = 0;
+       }
+       return LDAP_SUCCESS;
+}
+       
 static int
 integerValidate(
        Syntax *syntax,
@@ -1733,13 +2196,13 @@ integerValidate(
 
        if( !val->bv_len ) return LDAP_INVALID_SYNTAX;
 
-       if( val->bv_val[0] == '+' || val->bv_val[0] == '-' ) {
+       if(( val->bv_val[0] == '+' ) || ( val->bv_val[0] == '-' )) {
                if( val->bv_len < 2 ) return LDAP_INVALID_SYNTAX;
        } else if( !ASCII_DIGIT(val->bv_val[0]) ) {
                return LDAP_INVALID_SYNTAX;
        }
 
-       for(i=1; i < val->bv_len; i++) {
+       for( i=1; i < val->bv_len; i++ ) {
                if( !ASCII_DIGIT(val->bv_val[i]) ) return LDAP_INVALID_SYNTAX;
        }
 
@@ -1752,43 +2215,109 @@ integerNormalize(
        struct berval *val,
        struct berval **normalized )
 {
-       int negative;
-       struct berval *newval;
        char *p;
+       int negative=0;
+       struct berval *newval;
+       ber_len_t len;
+
 
        p = val->bv_val;
+       len = val->bv_len;
+
+       /* Ignore leading spaces */
+       while ( len && ( *p == ' ' )) {
+               p++;
+               len--;
+       }
 
        /* save sign */
-       negative = ( *p == '-' );
-       if( *p == '-' || *p == '+' ) p++;
+       if( len ) {
+               negative = ( *p == '-' );
+               if(( *p == '-' ) || ( *p == '+' )) {
+                       p++;
+                       len--;
+               }
+       }
 
        /* Ignore leading zeros */
-       while ( *p == '0' ) p++;
+       while ( len && ( *p == '0' )) {
+               p++;
+               len--;
+       }
 
        newval = (struct berval *) ch_malloc( sizeof(struct berval) );
 
-       if( *p == '\0' ) {
+       /* If there are no non-zero digits left, the number is zero, otherwise
+          allocate space for the number and copy it into the buffer */
+       if( len == 0 ) {
                newval->bv_val = ch_strdup("0");
                newval->bv_len = 1;
-               goto done;
+       }
+       else {
+               newval->bv_len = len+negative;
+               newval->bv_val = ch_malloc( newval->bv_len );
+               if( negative ) {
+                       newval->bv_val[0] = '-';
+               }
+               memcpy( newval->bv_val + negative, p, len );
        }
 
-       newval->bv_val = ch_malloc( val->bv_len + 1 );
-       newval->bv_len = 0;
+       *normalized = newval;
+       return LDAP_SUCCESS;
+}
+
+/* Index generation function */
+int integerIndexer(
+       slap_mask_t use,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *prefix,
+       struct berval **values,
+       struct berval ***keysp )
+{
+       int i;
+       struct berval **keys;
 
-       if( negative ) {
-               newval->bv_val[newval->bv_len++] = '-';
+       /* we should have at least one value at this point */
+       assert( values != NULL && values[0] != NULL );
+
+       for( i=0; values[i] != NULL; i++ ) {
+               /* empty -- just count them */
        }
 
-       for( ; *p != '\0'; p++ ) {
-               newval->bv_val[newval->bv_len++] = *p;
+       keys = ch_malloc( sizeof( struct berval * ) * (i+1) );
+
+       for( i=0; values[i] != NULL; i++ ) {
+               integerNormalize( syntax, values[i], &keys[i] );
        }
 
-done:
-       *normalized = newval;
+       keys[i] = NULL;
+       *keysp = keys;
+       return LDAP_SUCCESS;
+}
+
+/* Index generation function */
+int integerFilter(
+       slap_mask_t use,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *prefix,
+       void * assertValue,
+       struct berval ***keysp )
+{
+       struct berval **keys;
+
+       keys = ch_malloc( sizeof( struct berval * ) * 2 );
+       integerNormalize( syntax, assertValue, &keys[0] );
+       keys[1] = NULL;
+       *keysp = keys;
+
        return LDAP_SUCCESS;
 }
 
+
 static int
 countryStringValidate(
        Syntax *syntax,
@@ -3222,6 +3751,462 @@ objectIdentifierFirstComponentMatch(
        return rc;
 }
 
+static int
+integerBitAndMatch(
+       int *matchp,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *value,
+       void *assertedValue )
+{
+       long lValue, lAssertedValue;
+
+       /* safe to assume integers are NUL terminated? */
+       lValue = strtoul(value->bv_val, NULL, 10);
+       if(( lValue == LONG_MIN || lValue == LONG_MAX) && errno == ERANGE )
+               return LDAP_CONSTRAINT_VIOLATION;
+
+       lAssertedValue = strtol(((struct berval *)assertedValue)->bv_val, NULL, 10);
+       if(( lAssertedValue == LONG_MIN || lAssertedValue == LONG_MAX) && errno == ERANGE )
+               return LDAP_CONSTRAINT_VIOLATION;
+
+       *matchp = (lValue & lAssertedValue);
+       return LDAP_SUCCESS;
+}
+
+static int
+integerBitOrMatch(
+       int *matchp,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *value,
+       void *assertedValue )
+{
+       long lValue, lAssertedValue;
+
+       /* safe to assume integers are NUL terminated? */
+       lValue = strtoul(value->bv_val, NULL, 10);
+       if(( lValue == LONG_MIN || lValue == LONG_MAX) && errno == ERANGE )
+               return LDAP_CONSTRAINT_VIOLATION;
+
+       lAssertedValue = strtol(((struct berval *)assertedValue)->bv_val, NULL, 10);
+       if(( lAssertedValue == LONG_MIN || lAssertedValue == LONG_MAX) && errno == ERANGE )
+               return LDAP_CONSTRAINT_VIOLATION;
+
+       *matchp = (lValue | lAssertedValue);
+       return LDAP_SUCCESS;
+}
+
+#ifdef HAVE_TLS
+#include <openssl/x509.h>
+#include <openssl/err.h>
+char digit[] = "0123456789";
+
+/*
+ * Next function returns a string representation of a ASN1_INTEGER.
+ * It works for unlimited lengths.
+ */
+
+static struct berval *
+asn1_integer2str(ASN1_INTEGER *a)
+{
+       char buf[256];
+       char *p;
+  
+       /* We work backwards, make it fill from the end of buf */
+       p = buf + sizeof(buf) - 1;
+       *p = '\0';
+
+       if ( a == NULL || a->length == 0 ) {
+               *--p = '0';
+       } else {
+               int i;
+               int n = a->length;
+               int base = 0;
+               unsigned int *copy;
+
+               /* We want to preserve the original */
+               copy = ch_malloc(n*sizeof(unsigned int));
+               for (i = 0; i<n; i++) {
+                       copy[i] = a->data[i];
+               }
+
+               /* 
+                * base indicates the index of the most significant
+                * byte that might be nonzero.  When it goes off the
+                * end, we now there is nothing left to do.
+                */
+               while (base < n) {
+                       unsigned int carry;
+
+                       carry = 0;
+                       for (i = base; i<n; i++ ) {
+                               copy[i] += carry*256;
+                               carry = copy[i] % 10;
+                               copy[i] /= 10;
+                       }
+                       if (p <= buf+1) {
+                               /*
+                                * Way too large, we need to leave
+                                * room for sign if negative
+                                */
+                               free(copy);
+                               return NULL;
+                       }
+                       *--p = digit[carry];
+                       if (copy[base] == 0)
+                               base++;
+               }
+               free(copy);
+       }
+
+       if ( a->type == V_ASN1_NEG_INTEGER ) {
+               *--p = '-';
+       }
+
+       return ber_bvstrdup(p);
+}
+
+/* Get a DN in RFC2253 format from a X509_NAME internal struct */
+static struct berval *
+dn_openssl2ldap(X509_NAME *name)
+{
+       char issuer_dn[1024];
+       BIO *bio;
+
+       bio = BIO_new(BIO_s_mem());
+       if ( !bio ) {
+#ifdef NEW_LOGGING
+               LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY,
+                          "dn_openssl2ldap: error creating BIO_s_mem: %s\n",
+                          ERR_error_string(ERR_get_error(),NULL)));
+#else
+               Debug( LDAP_DEBUG_ARGS, "dn_openssl2ldap: "
+                      "error creating BIO: %s\n",
+                      ERR_error_string(ERR_get_error(),NULL), NULL, NULL );
+#endif
+               return NULL;
+       }
+       X509_NAME_print_ex(bio, name, 0, XN_FLAG_RFC2253);
+
+       BIO_gets(bio, issuer_dn, 1024);
+
+       BIO_free(bio);
+       return ber_bvstrdup(issuer_dn);
+}
+
+/*
+ * Given a certificate in DER format, extract the corresponding
+ * assertion value for certificateExactMatch
+ */
+static int
+certificateExactConvert(
+       struct berval * in,
+       struct berval ** out )
+{
+       X509 *xcert;
+       unsigned char *p = in->bv_val;
+       struct berval *serial;
+       struct berval *issuer_dn;
+       struct berval *bv_tmp;
+
+       xcert = d2i_X509(NULL, &p, in->bv_len);
+       if ( !xcert ) {
+#ifdef NEW_LOGGING
+               LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY,
+                          "certificateExactConvert: error parsing cert: %s\n",
+                          ERR_error_string(ERR_get_error(),NULL)));
+#else
+               Debug( LDAP_DEBUG_ARGS, "certificateExactConvert: "
+                      "error parsing cert: %s\n",
+                      ERR_error_string(ERR_get_error(),NULL), NULL, NULL );
+#endif
+               return LDAP_INVALID_SYNTAX;
+       }
+
+       serial = asn1_integer2str(xcert->cert_info->serialNumber);
+       if ( !serial ) {
+               X509_free(xcert);
+               return LDAP_INVALID_SYNTAX;
+       }
+       issuer_dn = dn_openssl2ldap(X509_get_issuer_name(xcert));
+       if ( !issuer_dn ) {
+               X509_free(xcert);
+               ber_bvfree(serial);
+               return LDAP_INVALID_SYNTAX;
+       }
+       /* Actually, dn_openssl2ldap returns in a normalized format, but
+          it is different from our normalized format */
+       bv_tmp = issuer_dn;
+       if ( dnNormalize(NULL, bv_tmp, &issuer_dn) != LDAP_SUCCESS ) {
+               X509_free(xcert);
+               ber_bvfree(serial);
+               ber_bvfree(bv_tmp);
+               return LDAP_INVALID_SYNTAX;
+       }
+       ber_bvfree(bv_tmp);
+
+       X509_free(xcert);
+
+       *out = ch_malloc(sizeof(struct berval));
+       (*out)->bv_len = serial->bv_len + 3 + issuer_dn->bv_len + 1;
+       (*out)->bv_val = ch_malloc((*out)->bv_len);
+       p = (*out)->bv_val;
+       AC_MEMCPY(p, serial->bv_val, serial->bv_len);
+       p += serial->bv_len;
+       AC_MEMCPY(p, " $ ", 3);
+       p += 3;
+       AC_MEMCPY(p, issuer_dn->bv_val, issuer_dn->bv_len);
+       p += issuer_dn->bv_len;
+       *p++ = '\0';
+
+#ifdef NEW_LOGGING
+       LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY,
+                  "certificateExactConvert: \n %s\n",
+                  (*out)->bv_val));
+#else
+       Debug( LDAP_DEBUG_ARGS, "certificateExactConvert "
+               "\n\t\"%s\"\n",
+               (*out)->bv_val, NULL, NULL );
+#endif
+
+       ber_bvfree(serial);
+       ber_bvfree(issuer_dn);
+
+       return LDAP_SUCCESS;
+}
+
+static int
+serial_and_issuer_parse(
+       struct berval *assertion,
+       struct berval **serial,
+       struct berval **issuer_dn
+)
+{
+       char *begin;
+       char *end;
+       char *p;
+       char *q;
+
+       begin = assertion->bv_val;
+       end = assertion->bv_val+assertion->bv_len-1;
+       for (p=begin; p<=end && *p != '$'; p++)
+               ;
+       if ( p > end )
+               return LDAP_INVALID_SYNTAX;
+
+       /* p now points at the $ sign, now use begin and end to delimit the
+          serial number */
+       while (ASCII_SPACE(*begin))
+               begin++;
+       end = p-1;
+       while (ASCII_SPACE(*end))
+               end--;
+
+       q = ch_malloc( (end-begin+1)+1 );
+       AC_MEMCPY( q, begin, end-begin+1 );
+       q[end-begin+1] = '\0';
+       *serial = ber_bvstr(q);
+
+       /* now extract the issuer, remember p was at the dollar sign */
+       begin = p+1;
+       end = assertion->bv_val+assertion->bv_len-1;
+       while (ASCII_SPACE(*begin))
+               begin++;
+       /* should we trim spaces at the end too? is it safe always? */
+
+       q = ch_malloc( (end-begin+1)+1 );
+       AC_MEMCPY( q, begin, end-begin+1 );
+       q[end-begin+1] = '\0';
+       *issuer_dn = ber_bvstr(dn_normalize(q));
+
+       return LDAP_SUCCESS;
+}
+
+static int
+certificateExactMatch(
+       int *matchp,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *value,
+       void *assertedValue )
+{
+       X509 *xcert;
+       unsigned char *p = value->bv_val;
+       struct berval *serial;
+       struct berval *issuer_dn;
+       struct berval *asserted_serial;
+       struct berval *asserted_issuer_dn;
+       int ret;
+
+       xcert = d2i_X509(NULL, &p, value->bv_len);
+       if ( !xcert ) {
+#ifdef NEW_LOGGING
+               LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY,
+                          "certificateExactMatch: error parsing cert: %s\n",
+                          ERR_error_string(ERR_get_error(),NULL)));
+#else
+               Debug( LDAP_DEBUG_ARGS, "certificateExactMatch: "
+                      "error parsing cert: %s\n",
+                      ERR_error_string(ERR_get_error(),NULL), NULL, NULL );
+#endif
+               return LDAP_INVALID_SYNTAX;
+       }
+
+       serial = asn1_integer2str(xcert->cert_info->serialNumber);
+       issuer_dn = dn_openssl2ldap(X509_get_issuer_name(xcert));
+
+       X509_free(xcert);
+
+       serial_and_issuer_parse(assertedValue,
+                               &asserted_serial,
+                               &asserted_issuer_dn);
+
+       ret = integerMatch(
+               matchp,
+               flags,
+               slap_schema.si_syn_integer,
+               slap_schema.si_mr_integerMatch,
+               serial,
+               asserted_serial);
+       if ( ret == LDAP_SUCCESS ) {
+               if ( *matchp == 0 ) {
+                       /* We need to normalize everything for dnMatch */
+                       ret = dnMatch(
+                               matchp,
+                               flags,
+                               slap_schema.si_syn_distinguishedName,
+                               slap_schema.si_mr_distinguishedNameMatch,
+                               issuer_dn,
+                               asserted_issuer_dn);
+               }
+       }
+
+#ifdef NEW_LOGGING
+       LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY,
+                  "certificateExactMatch: %d\n  %s $ %s\n       %s $   %s\n",
+                  *matchp, serial->bv_val, issuer_dn->bv_val,
+                  asserted->serial->bv_val, asserted_issuer_dn->bv_val));
+#else
+       Debug( LDAP_DEBUG_ARGS, "certificateExactMatch "
+               "%d\n\t\"%s $ %s\"\n",
+               *matchp, serial->bv_val, issuer_dn->bv_val );
+       Debug( LDAP_DEBUG_ARGS, "\t\"%s $ %s\"\n",
+               asserted_serial->bv_val, asserted_issuer_dn->bv_val,
+               NULL );
+#endif
+
+       ber_bvfree(serial);
+       ber_bvfree(issuer_dn);
+       ber_bvfree(asserted_serial);
+       ber_bvfree(asserted_issuer_dn);
+
+       return ret;
+}
+
+/* 
+ * Index generation function
+ * We just index the serials, in most scenarios the issuer DN is one of
+ * a very small set of values.
+ */
+int certificateExactIndexer(
+       slap_mask_t use,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *prefix,
+       struct berval **values,
+       struct berval ***keysp )
+{
+       int i;
+       struct berval **keys;
+       X509 *xcert;
+       unsigned char *p;
+       struct berval * serial;
+
+       /* we should have at least one value at this point */
+       assert( values != NULL && values[0] != NULL );
+
+       for( i=0; values[i] != NULL; i++ ) {
+               /* empty -- just count them */
+       }
+
+       keys = ch_malloc( sizeof( struct berval * ) * (i+1) );
+
+       for( i=0; values[i] != NULL; i++ ) {
+               p = values[i]->bv_val;
+               xcert = d2i_X509(NULL, &p, values[i]->bv_len);
+               if ( !xcert ) {
+#ifdef NEW_LOGGING
+                       LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY,
+                           "certificateExactIndexer: error parsing cert: %s\n",
+                               ERR_error_string(ERR_get_error(),NULL)));
+#else
+                       Debug( LDAP_DEBUG_ARGS, "certificateExactIndexer: "
+                              "error parsing cert: %s\n",
+                              ERR_error_string(ERR_get_error(),NULL),
+                              NULL, NULL );
+#endif
+                       /* Do we leak keys on error? */
+                       return LDAP_INVALID_SYNTAX;
+               }
+
+               serial = asn1_integer2str(xcert->cert_info->serialNumber);
+               X509_free(xcert);
+               integerNormalize( slap_schema.si_syn_integer,
+                                 serial,
+                                 &keys[i] );
+               ber_bvfree(serial);
+#ifdef NEW_LOGGING
+               LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY,
+                          "certificateExactIndexer: returning: %s\n",
+                          keys[i]->bv_val));
+#else
+               Debug( LDAP_DEBUG_ARGS, "certificateExactIndexer: "
+                      "returning: %s\n",
+                      keys[i]->bv_val,
+                      NULL, NULL );
+#endif
+       }
+
+       keys[i] = NULL;
+       *keysp = keys;
+       return LDAP_SUCCESS;
+}
+
+/* Index generation function */
+/* We think this is always called with a value in matching rule syntax */
+int certificateExactFilter(
+       slap_mask_t use,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *prefix,
+       void * assertValue,
+       struct berval ***keysp )
+{
+       struct berval **keys;
+       struct berval *asserted_serial;
+       struct berval *asserted_issuer_dn;
+
+       serial_and_issuer_parse(assertValue,
+                               &asserted_serial,
+                               &asserted_issuer_dn);
+
+       keys = ch_malloc( sizeof( struct berval * ) * 2 );
+       integerNormalize( syntax, asserted_serial, &keys[0] );
+       keys[1] = NULL;
+       *keysp = keys;
+
+       ber_bvfree(asserted_serial);
+       ber_bvfree(asserted_issuer_dn);
+       return LDAP_SUCCESS;
+}
+#endif
+
 static int
 check_time_syntax (struct berval *val,
        int start,
@@ -3413,7 +4398,7 @@ utcTimeNormalize(
                return LBER_ERROR_MEMORY;
        }
 
-       sprintf( out->bv_val, "%02ld%02ld%02ld%02ld%02ld%02ldZ",
+       sprintf( out->bv_val, "%02d%02d%02d%02d%02d%02dZ",
                parts[1], parts[2] + 1, parts[3] + 1,
                parts[4], parts[5], parts[6] );
        out->bv_len = 13;
@@ -3468,7 +4453,7 @@ generalizedTimeNormalize(
                return LBER_ERROR_MEMORY;
        }
 
-       sprintf( out->bv_val, "%02ld%02ld%02ld%02ld%02ld%02ld%02ldZ",
+       sprintf( out->bv_val, "%02d%02d%02d%02d%02d%02d%02dZ",
                parts[0], parts[1], parts[2] + 1, parts[3] + 1,
                parts[4], parts[5], parts[6] );
        out->bv_len = 15;
@@ -3594,7 +4579,7 @@ struct syntax_defs_rec syntax_defs[] = {
        {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' " X_NOT_H_R ")",
                SLAP_SYNTAX_BER, berValidate, NULL, NULL},
        {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
-               0, bitStringValidate, NULL, NULL },
+               0, bitStringValidate, bitStringNormalize, NULL },
        {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
                0, booleanValidate, NULL, NULL},
        {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
@@ -3637,7 +4622,7 @@ struct syntax_defs_rec syntax_defs[] = {
        {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
                0, IA5StringValidate, IA5StringNormalize, NULL},
        {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
-               0, integerValidate, integerNormalize, integerPretty},
+               0, integerValidate, integerNormalize, NULL},
        {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
                SLAP_SYNTAX_BLOB, blobValidate, NULL, NULL},
        {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
@@ -3680,7 +4665,7 @@ struct syntax_defs_rec syntax_defs[] = {
        {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
                0, NULL, NULL, NULL},
        {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
-               0, printableStringValidate, IA5StringNormalize, NULL},
+               0, printablesStringValidate, IA5StringNormalize, NULL},
        {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
                0, utcTimeValidate, utcTimeNormalize, NULL},
        {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
@@ -3700,12 +4685,25 @@ struct syntax_defs_rec syntax_defs[] = {
        {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
                0, bootParameterValidate, NULL, NULL},
 
+#ifdef HAVE_TLS
+       /* From PKIX */
+       /* These OIDs are not published yet, but will be in the next
+        * I-D for PKIX LDAPv3 schema as have been advanced by David
+        * Chadwick in private mail.
+        */
+       {"( 1.2.826.0.1.3344810.7.1 DESC 'Serial Number and Issuer' )",
+               0, NULL, NULL, NULL},
+#endif
+
        /* OpenLDAP Experimental Syntaxes */
        {"( 1.3.6.1.4.1.4203.666.2.1 DESC 'OpenLDAP Experimental ACI' )",
-               0, UTF8StringValidate /* THIS WILL CHANGE FOR NEW ACI SYNTAX */,
+               SLAP_SYNTAX_HIDE,
+               UTF8StringValidate /* THIS WILL CHANGE FOR NEW ACI SYNTAX */,
                NULL, NULL},
+
+       /* needs updating */
        {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
-               0, NULL, NULL, NULL},
+               SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
 
        /* OpenLDAP Void Syntax */
        {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
@@ -3737,7 +4735,6 @@ struct mrule_defs_rec {
  * 2.5.13.31   directoryStringFirstComponentMatch
  * 2.5.13.32   wordMatch
  * 2.5.13.33   keywordMatch
- * 2.5.13.34   certificateExactMatch
  * 2.5.13.35   certificateMatch
  * 2.5.13.36   certificatePairExactMatch
  * 2.5.13.37   certificatePairMatch
@@ -3793,7 +4790,7 @@ struct mrule_defs_rec mrule_defs[] = {
 
        {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
                "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
-               SLAP_MR_EQUALITY | SLAP_MR_EXT,
+               SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_DN_FOLD,
                NULL, NULL,
                caseIgnoreMatch, caseExactIgnoreIndexer, caseExactIgnoreFilter,
                directoryStringApproxMatchOID },
@@ -3839,7 +4836,7 @@ struct mrule_defs_rec mrule_defs[] = {
 
        {"( 2.5.13.8 NAME 'numericStringMatch' "
                "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
-               SLAP_MR_EQUALITY | SLAP_MR_EXT,
+               SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_DN_FOLD,
                NULL, NULL,
                caseIgnoreIA5Match,
                caseIgnoreIA5Indexer,
@@ -3857,7 +4854,7 @@ struct mrule_defs_rec mrule_defs[] = {
 
        {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
                "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
-               SLAP_MR_EQUALITY | SLAP_MR_EXT,
+               SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_DN_FOLD,
                NULL, NULL,
                caseIgnoreListMatch, NULL, NULL,
                NULL},
@@ -3887,7 +4884,7 @@ struct mrule_defs_rec mrule_defs[] = {
                "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
                SLAP_MR_EQUALITY | SLAP_MR_EXT,
                NULL, NULL,
-               bitStringMatch, NULL, NULL,
+               bitStringMatch, bitStringIndexer, bitStringFilter,
                NULL},
 
        {"( 2.5.13.17 NAME 'octetStringMatch' "
@@ -3899,7 +4896,7 @@ struct mrule_defs_rec mrule_defs[] = {
 
        {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
                "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
-               SLAP_MR_EQUALITY | SLAP_MR_EXT,
+               SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_DN_FOLD,
                NULL, NULL,
                telephoneNumberMatch,
                telephoneNumberIndexer,
@@ -3964,6 +4961,16 @@ struct mrule_defs_rec mrule_defs[] = {
                objectIdentifierFirstComponentMatch, NULL, NULL,
                NULL},
 
+#ifdef HAVE_TLS
+       {"( 2.5.13.34 NAME 'certificateExactMatch' "
+               "SYNTAX 1.2.826.0.1.3344810.7.1 )",
+               SLAP_MR_EQUALITY | SLAP_MR_EXT,
+               certificateExactConvert, NULL,
+               certificateExactMatch,
+               certificateExactIndexer, certificateExactFilter,
+               NULL},
+#endif
+
        {"( 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,
@@ -3973,7 +4980,7 @@ struct mrule_defs_rec mrule_defs[] = {
 
        {"( 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,
+               SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_DN_FOLD,
                NULL, NULL,
                caseIgnoreIA5Match, caseIgnoreIA5Indexer, caseIgnoreIA5Filter,
                IA5StringApproxMatchOID },
@@ -3996,6 +5003,7 @@ struct mrule_defs_rec mrule_defs[] = {
                caseExactIA5SubstringsFilter,
                NULL},
 
+       /* needs updating */
        {"( 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,
@@ -4010,6 +5018,20 @@ struct mrule_defs_rec mrule_defs[] = {
                OpenLDAPaciMatch, NULL, NULL,
                NULL},
 
+       {"( 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,
+               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,
+               integerBitOrMatch, NULL, NULL,
+               NULL},
+
        {NULL, SLAP_MR_NONE, NULL, NULL, NULL, NULL}
 };
 
@@ -4070,3 +5092,12 @@ schema_init( void )
        schema_init_done = 1;
        return LDAP_SUCCESS;
 }
+
+void
+schema_destroy( void )
+{
+       oc_destroy();
+       at_destroy();
+       mr_destroy();
+       syn_destroy();
+}