]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/schema_init.c
Fix prev commit
[openldap] / servers / slapd / schema_init.c
index 056e085d0dd16f34d82317e3d89f97ac1a7f66ee..0d64d5cbbc0e689c09f2b44f037d78a957b6be6b 100644 (file)
 
 #include "ldap_utf8.h"
 
+#ifdef HAVE_TLS
+#include <openssl/x509.h>
+#include <openssl/err.h>
+#include <openssl/rsa.h>
+#include <openssl/crypto.h>
+#include <openssl/pem.h>
+#include <openssl/bio.h>
+#include <openssl/asn1.h>
+#include <openssl/x509v3.h>
+#include <openssl/ssl.h>
+#endif
+
 #include "lutil_hash.h"
 #define HASH_BYTES                             LUTIL_HASH_BYTES
 #define HASH_CONTEXT                   lutil_HASH_CTX
@@ -60,6 +72,33 @@ blobValidate(
 
 #define berValidate blobValidate
 
+static int
+sequenceValidate(
+       Syntax *syntax,
+       struct berval *in )
+{
+       if ( in->bv_len < 2 ) return LDAP_INVALID_SYNTAX;
+       if ( in->bv_val[0] != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
+
+       return LDAP_SUCCESS;
+}
+
+
+#ifdef HAVE_TLS
+static int certificateValidate( Syntax *syntax, struct berval *in )
+{
+       X509 *xcert=NULL;
+       unsigned char *p = in->bv_val;
+       xcert = d2i_X509(NULL, &p, in->bv_len);
+       if ( !xcert ) return LDAP_INVALID_SYNTAX;
+       X509_free(xcert);
+       return LDAP_SUCCESS;
+}
+#else
+#define certificateValidate sequenceValidate
+#endif
+
 static int
 octetStringMatch(
        int *matchp,
@@ -729,6 +768,87 @@ nameUIDValidate(
        return rc;
 }
 
+int
+nameUIDPretty(
+       Syntax *syntax,
+       struct berval *val,
+       struct berval *out,
+       void *ctx )
+{
+       assert( val );
+       assert( out );
+
+
+#ifdef NEW_LOGGING
+       LDAP_LOG( OPERATION, ARGS, ">>> nameUIDPretty: <%s>\n", val->bv_val, 0, 0 );
+#else
+       Debug( LDAP_DEBUG_TRACE, ">>> nameUIDPretty: <%s>\n", val->bv_val, 0, 0 );
+#endif
+
+       if( val->bv_len == 0 ) {
+               ber_dupbv_x( out, val, ctx );
+
+       } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
+               return LDAP_INVALID_SYNTAX;
+
+       } else {
+               int rc;
+               struct berval dnval = *val;
+               struct berval uidval = { 0, NULL };
+
+               if( val->bv_val[val->bv_len-1] == 'B'
+                       && val->bv_val[val->bv_len-2] == '\'' )
+               {
+                       uidval.bv_val=strrchr( val->bv_val, '#' );
+                       if( uidval.bv_val ) {
+                               dnval.bv_len = uidval.bv_val - dnval.bv_val;
+                               uidval.bv_len = val->bv_len - dnval.bv_len;
+
+                               uidval.bv_len--;
+                               uidval.bv_val++;
+                       }
+               }
+
+               rc = dnPretty( syntax, &dnval, out, ctx );
+               if( rc != LDAP_SUCCESS ) return rc;
+
+               if( uidval.bv_val ) {
+                       char *tmp = sl_realloc( out->bv_val, out->bv_len + uidval.bv_len + 2, ctx );
+                       int i, c, got1;
+                       if( tmp == NULL ) {
+                               ber_memfree_x( out->bv_val, ctx );
+                               return LDAP_OTHER;
+                       }
+                       out->bv_val = tmp;
+                       out->bv_val[out->bv_len++] = '#';
+
+                       got1 = uidval.bv_len < sizeof("'0'B"); 
+                       for(i=0; i<uidval.bv_len; i++) {
+                               c = uidval.bv_val[i];
+                               switch(c) {
+                                       case '0':
+                                               if( got1 ) out->bv_val[out->bv_len++] = c;
+                                               break;
+                                       case '1':
+                                               got1 = 1;
+                                       default:
+                                               out->bv_val[out->bv_len++] = c;
+                               }
+                       }
+
+                       out->bv_val[out->bv_len] = '\0';
+               }
+       }
+
+#ifdef NEW_LOGGING
+       LDAP_LOG( OPERATION, ARGS, "<<< nameUIDPretty: <%s>\n", out->bv_val, 0, 0 );
+#else
+       Debug( LDAP_DEBUG_TRACE, "<<< nameUIDPretty: <%s>\n", out->bv_val, 0, 0 );
+#endif
+
+       return LDAP_SUCCESS;
+}
+
 static int
 uniqueMemberNormalize(
        slap_mask_t usage,
@@ -741,6 +861,8 @@ uniqueMemberNormalize(
        struct berval out;
        int rc;
 
+       assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ));
+
        ber_dupbv( &out, val );
        if( out.bv_len != 0 ) {
                struct berval uid = { 0, NULL };
@@ -1050,6 +1172,8 @@ UTF8StringNormalize(
        int flags;
        int i, wasspace;
 
+       assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ));
+
        if( val->bv_val == NULL ) {
                /* assume we're dealing with a syntax (e.g., UTF8String)
                 * which allows empty strings
@@ -1343,6 +1467,8 @@ telephoneNumberNormalize(
 {
        char *p, *q;
 
+       assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ));
+
        /* validator should have refused an empty string */
        assert( val->bv_len );
 
@@ -1588,10 +1714,12 @@ IA5StringNormalize(
        void *ctx )
 {
        char *p, *q;
-       int casefold = SLAP_MR_ASSOCIATED(mr, slap_schema.si_mr_caseExactIA5Match);
+       int casefold = !SLAP_MR_ASSOCIATED(mr, slap_schema.si_mr_caseExactIA5Match);
 
        assert( val->bv_len );
 
+       assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ));
+
        p = val->bv_val;
 
        /* Ignore initial whitespace */
@@ -1706,6 +1834,22 @@ numericStringNormalize(
        return LDAP_SUCCESS;
 }
 
+/*
+ * Integer conversion macros that will use the largest available
+ * type.
+ */
+#if defined(HAVE_STRTOLL) && defined(LLONG_MAX) && defined(LLONG_MIN) && defined(HAVE_LONG_LONG)
+# define SLAP_STRTOL(n,e,b)  strtoll(n,e,b) 
+# define SLAP_LONG_MAX       LLONG_MAX
+# define SLAP_LONG_MIN       LLONG_MIN
+# define SLAP_LONG           long long
+#else
+# define SLAP_STRTOL(n,e,b)  strtol(n,e,b)
+# define SLAP_LONG_MAX       LONG_MAX
+# define SLAP_LONG_MIN       LONG_MIN
+# define SLAP_LONG           long
+#endif /* HAVE_STRTOLL ... */
+
 static int
 integerBitAndMatch(
        int *matchp,
@@ -1715,16 +1859,16 @@ integerBitAndMatch(
        struct berval *value,
        void *assertedValue )
 {
-       long lValue, lAssertedValue;
+       SLAP_LONG lValue, lAssertedValue;
 
        /* safe to assume integers are NUL terminated? */
-       lValue = strtol(value->bv_val, NULL, 10);
-       if(( lValue == LONG_MIN || lValue == LONG_MAX) && errno == ERANGE ) {
+       lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
+       if(( lValue == SLAP_LONG_MIN || lValue == SLAP_LONG_MAX) && errno == ERANGE ) {
                return LDAP_CONSTRAINT_VIOLATION;
        }
 
-       lAssertedValue = strtol(((struct berval *)assertedValue)->bv_val, NULL, 10);
-       if(( lAssertedValue == LONG_MIN || lAssertedValue == LONG_MAX)
+       lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val, NULL, 10);
+       if(( lAssertedValue == SLAP_LONG_MIN || lAssertedValue == SLAP_LONG_MAX )
                && errno == ERANGE )
        {
                return LDAP_CONSTRAINT_VIOLATION;
@@ -1743,16 +1887,16 @@ integerBitOrMatch(
        struct berval *value,
        void *assertedValue )
 {
-       long lValue, lAssertedValue;
+       SLAP_LONG lValue, lAssertedValue;
 
        /* safe to assume integers are NUL terminated? */
-       lValue = strtol(value->bv_val, NULL, 10);
-       if(( lValue == LONG_MIN || lValue == LONG_MAX) && errno == ERANGE ) {
+       lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
+       if(( lValue == SLAP_LONG_MIN || lValue == SLAP_LONG_MAX ) && errno == ERANGE ) {
                return LDAP_CONSTRAINT_VIOLATION;
        }
 
-       lAssertedValue = strtol(((struct berval *)assertedValue)->bv_val, NULL, 10);
-       if(( lAssertedValue == LONG_MIN || lAssertedValue == LONG_MAX)
+       lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val, NULL, 10);
+       if(( lAssertedValue == SLAP_LONG_MIN || lAssertedValue == SLAP_LONG_MAX )
                && errno == ERANGE )
        {
                return LDAP_CONSTRAINT_VIOLATION;
@@ -1767,211 +1911,202 @@ serialNumberAndIssuerValidate(
        Syntax *syntax,
        struct berval *in )
 {
-       int rc = LDAP_INVALID_SYNTAX;
-       struct berval serialNumber, issuer;
+       int rc;
+       int state;
+       ber_len_t n;
+       struct berval sn, i;
+       if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
 
-       serialNumber.bv_val = in->bv_val;
-       for( serialNumber.bv_len = 0;
-               serialNumber.bv_len < in->bv_len;
-               serialNumber.bv_len++ )
-       {
-               if ( serialNumber.bv_val[serialNumber.bv_len] == '$' ) {
-                       issuer.bv_val = &serialNumber.bv_val[serialNumber.bv_len+1];
-                       issuer.bv_len = in->bv_len - (serialNumber.bv_len+1);
+       i.bv_val = strchr( in->bv_val, '$' );
+       if( i.bv_val == NULL ) return LDAP_INVALID_SYNTAX;
 
-                       if( serialNumber.bv_len == 0 || issuer.bv_len == 0 ) break;
+       sn.bv_val = in->bv_val;
+       sn.bv_len = i.bv_val - in->bv_val;
 
-                       rc = integerValidate( NULL, &serialNumber );
-                       if( rc ) break;
+       i.bv_val++;
+       i.bv_len = in->bv_len - (sn.bv_len + 1);
 
-                       rc = dnValidate( NULL, &issuer );
-                       break;
+       /* validate serial number (strict for now) */
+       for( n=0; n < sn.bv_len; n++ ) {
+               if( !ASCII_DIGIT(sn.bv_val[n]) ) {
+                       return LDAP_INVALID_SYNTAX;
                }
        }
 
-       return rc;
+       /* validate DN */
+       rc = dnValidate( NULL, &i );
+       if( rc ) return LDAP_INVALID_SYNTAX;
+
+       return LDAP_SUCCESS;
 }
 
-static int
-serialNumberAndIssuerNormalize(
-       slap_mask_t usage,
+int
+serialNumberAndIssuerPretty(
        Syntax *syntax,
-       MatchingRule *mr,
        struct berval *val,
-       struct berval *normalized,
+       struct berval *out,
        void *ctx )
 {
-       int rc = LDAP_INVALID_SYNTAX;
-       struct berval serialNumber, issuer, nissuer;
-
-       serialNumber.bv_val = val->bv_val;
-       for( serialNumber.bv_len = 0;
-               serialNumber.bv_len < val->bv_len;
-               serialNumber.bv_len++ )
-       {
-               if ( serialNumber.bv_val[serialNumber.bv_len] == '$' ) {
-                       issuer.bv_val = &serialNumber.bv_val[serialNumber.bv_len+1];
-                       issuer.bv_len = val->bv_len - (serialNumber.bv_len+1);
-
-                       if( serialNumber.bv_len == 0 || issuer.bv_len == 0 ) break;
-
-                       rc = dnNormalize( usage, syntax, mr, &issuer, &nissuer, ctx );
-                       if( rc ) break;
+       int rc;
+       int state;
+       ber_len_t n;
+       struct berval sn, i, newi;
 
-                       normalized->bv_len = serialNumber.bv_len + 1 + nissuer.bv_len;
-                       normalized->bv_val = ch_malloc( normalized->bv_len + 1);
+       assert( val );
+       assert( out );
 
-                       AC_MEMCPY( normalized->bv_val,
-                               serialNumber.bv_val, serialNumber.bv_len );
-                       normalized->bv_val[serialNumber.bv_len] = '$';
-                       AC_MEMCPY( &normalized->bv_val[serialNumber.bv_len+1],
-                               nissuer.bv_val, nissuer.bv_len );
-                       normalized->bv_val[normalized->bv_len] = '\0';
-                       break;
-               }
-       }
+#ifdef NEW_LOGGING
+       LDAP_LOG( OPERATION, ARGS, ">>> serialNumberAndIssuerPretty: <%s>\n",
+               val->bv_val, 0, 0 );
+#else
+       Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
+               val->bv_val, 0, 0 );
+#endif
 
-       return rc;
-}
+       if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
 
-#ifdef HAVE_TLS
-#include <openssl/x509.h>
-#include <openssl/err.h>
+       i.bv_val = strchr( val->bv_val, '$' );
+       if( i.bv_val == NULL ) return LDAP_INVALID_SYNTAX;
 
-/*
- * Next function returns a string representation of a ASN1_INTEGER.
- * It works for unlimited lengths.
- */
+       sn.bv_val = val->bv_val;
+       sn.bv_len = i.bv_val - val->bv_val;
 
-static struct berval *
-asn1_integer2str(ASN1_INTEGER *a, struct berval *bv)
-{
-       char buf[256];
-       char *p;
-       static char digit[] = "0123456789";
-  
-       /* We work backwards, make it fill from the end of buf */
-       p = buf + sizeof(buf) - 1;
-       *p = '\0';
+       i.bv_val++;
+       i.bv_len = val->bv_len - (sn.bv_len + 1);
 
-       if ( a == NULL || a->length == 0 ) {
-               *--p = '0';
-       } else {
-               int i;
-               int n = a->length;
-               int base = 0;
-               unsigned int *copy;
+       /* eat leading zeros */
+       for( n=0; n < (sn.bv_len-1); n++ ) {
+               if( sn.bv_val[n] != '0' ) break;
+       }
+       sn.bv_val += n;
+       sn.bv_len -= n;
 
-               /* We want to preserve the original */
-               copy = ch_malloc(n*sizeof(unsigned int));
-               for (i = 0; i<n; i++) {
-                       copy[i] = a->data[i];
+       for( n=0; n < sn.bv_len; n++ ) {
+               if( !ASCII_DIGIT(sn.bv_val[n]) ) {
+                       return LDAP_INVALID_SYNTAX;
                }
+       }
 
-               /* 
-                * 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];
+       /* pretty DN */
+       rc = dnPretty( syntax, &i, &newi, ctx );
+       if( rc ) return LDAP_INVALID_SYNTAX;
 
-                       if (copy[base] == 0) base++;
-               }
-               free(copy);
-       }
+       /* make room from sn + "$" */
+       out->bv_len = sn.bv_len + newi.bv_len + 1;
+       out->bv_val = sl_realloc( newi.bv_val, out->bv_len + 1, ctx );
 
-       if ( a->type == V_ASN1_NEG_INTEGER ) {
-               *--p = '-';
+       if( out->bv_val == NULL ) {
+               sl_free( newi.bv_val, ctx );
+               return LDAP_OTHER;
        }
 
-       return ber_str2bv( p, 0, 1, bv );
+       /* push issuer over */
+       AC_MEMCPY( &out->bv_val[sn.bv_len+1], newi.bv_val, newi.bv_len );
+       /* insert sn and "$" */
+       AC_MEMCPY( out->bv_val, sn.bv_val, sn.bv_len );
+       out->bv_val[sn.bv_len] = '$';
+       /* terminate */
+       out->bv_val[out->bv_len] = '\0';
+
+#ifdef NEW_LOGGING
+       LDAP_LOG( OPERATION, ARGS, "<<< serialNumberAndIssuerPretty: <%s>\n",
+               out->bv_val, 0, 0 );
+#else
+       Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s>\n",
+               out->bv_val, 0, 0 );
+#endif
+
+       return LDAP_SUCCESS;
 }
 
 /*
- * Given a certificate in DER format, extract the corresponding
- * assertion value for certificateExactMatch
+ * This routine is called by certificateExactNormalize when
+ * certificateExactNormalize receives a search string instead of
+ * a certificate. This routine checks if the search value is valid
+ * and then returns the normalized value
  */
 static int
-certificateExactConvert(
-       struct berval * in,
-       struct berval * out )
+serialNumberAndIssuerNormalize(
+       slap_mask_t usage,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *val,
+       struct berval *out,
+       void *ctx )
 {
        int rc;
-       X509 *xcert;
-       unsigned char *p = in->bv_val;
-       struct berval serial;
-       struct berval issuer_dn;
+       int state;
+       ber_len_t n;
+       struct berval sn, i, newi;
+
+       assert( val );
+       assert( out );
 
-       xcert = d2i_X509(NULL, &p, in->bv_len);
-       if ( !xcert ) {
 #ifdef NEW_LOGGING
-               LDAP_LOG( CONFIG, ENTRY, 
-                       "certificateExactConvert: error parsing cert: %s\n",
-                       ERR_error_string(ERR_get_error(),NULL), 0, 0 );
+       LDAP_LOG( OPERATION, ARGS, ">>> serialNumberAndIssuerNormalize: <%s>\n",
+               val->bv_val, 0, 0 );
 #else
-               Debug( LDAP_DEBUG_ARGS, "certificateExactConvert: "
-                       "error parsing cert: %s\n",
-                       ERR_error_string(ERR_get_error(),NULL), NULL, NULL );
+       Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
+               val->bv_val, 0, 0 );
 #endif
-               return LDAP_INVALID_SYNTAX;
-       }
 
-       if ( !asn1_integer2str(xcert->cert_info->serialNumber, &serial) ) {
-               X509_free(xcert);
-               return LDAP_INVALID_SYNTAX;
+       if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
+
+       i.bv_val = strchr( val->bv_val, '$' );
+       if( i.bv_val == NULL ) return LDAP_INVALID_SYNTAX;
+
+       sn.bv_val = val->bv_val;
+       sn.bv_len = i.bv_val - val->bv_val;
+
+       i.bv_val++;
+       i.bv_len = val->bv_len - (sn.bv_len + 1);
+
+       /* eat leading zeros */
+       for( n=0; n < (sn.bv_len-1); n++ ) {
+               if( sn.bv_val[n] != '0' ) break;
        }
+       sn.bv_val += n;
+       sn.bv_len -= n;
 
-       rc = dnX509normalize( X509_get_issuer_name(xcert), &issuer_dn );
-       if( rc != LDAP_SUCCESS ) {
-               X509_free(xcert);
-               ber_memfree(serial.bv_val);
-               return LDAP_INVALID_SYNTAX;
+       for( n=0; n < sn.bv_len; n++ ) {
+               if( !ASCII_DIGIT(sn.bv_val[n]) ) {
+                       return LDAP_INVALID_SYNTAX;
+               }
        }
 
-       X509_free(xcert);
+       /* pretty DN */
+       rc = dnNormalize( usage, syntax, mr, &i, &newi, ctx );
+       if( rc ) return LDAP_INVALID_SYNTAX;
 
-       out->bv_len = serial.bv_len + issuer_dn.bv_len + sizeof(" $ ");
-       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, " $ ", sizeof(" $ ")-1);
-       p += 3;
-       AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
-       p += issuer_dn.bv_len;
-       *p++ = '\0';
+       /* make room from sn + "$" */
+       out->bv_len = sn.bv_len + newi.bv_len + 1;
+       out->bv_val = sl_realloc( newi.bv_val, out->bv_len + 1, ctx );
+
+       if( out->bv_val == NULL ) {
+               sl_free( newi.bv_val, ctx );
+               return LDAP_OTHER;
+       }
+
+       /* push issuer over */
+       AC_MEMCPY( &out->bv_val[sn.bv_len+1], newi.bv_val, newi.bv_len );
+       /* insert sn and "$" */
+       AC_MEMCPY( out->bv_val, sn.bv_val, sn.bv_len );
+       out->bv_val[sn.bv_len] = '$';
+       /* terminate */
+       out->bv_val[out->bv_len] = '\0';
 
 #ifdef NEW_LOGGING
-       LDAP_LOG( CONFIG, ARGS, "certificateExactConvert: %s\n",
+       LDAP_LOG( OPERATION, ARGS, "<<< serialNumberAndIssuerNormalize: <%s>\n",
                out->bv_val, 0, 0 );
 #else
-       Debug( LDAP_DEBUG_ARGS, "certificateExactConvert: %s\n",
-               out->bv_val, NULL, NULL );
+       Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s>\n",
+               out->bv_val, 0, 0 );
 #endif
 
-       ber_memfree(serial.bv_val);
-       ber_memfree(issuer_dn.bv_val);
-
-       return LDAP_SUCCESS;
+       return rc;
 }
 
+#ifdef HAVE_TLS
 static int
 certificateExactNormalize(
        slap_mask_t usage,
@@ -1981,16 +2116,60 @@ certificateExactNormalize(
        struct berval *normalized,
        void *ctx )
 {
-       int rc;
+       int rc = LDAP_INVALID_SYNTAX;
+       unsigned char *p;
+       char *serial = NULL;
+       ber_len_t seriallen;
+       struct berval issuer_dn = { 0, NULL };
+       X509_NAME *name = NULL;
+       ASN1_INTEGER *sn = NULL;
+       X509 *xcert = NULL;
 
-       if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage ) ) {
-               rc = serialNumberAndIssuerNormalize( usage, syntax, mr,
-                       val, normalized, ctx );
+       if( val->bv_len == 0 ) goto done;
 
-       } else {
-               rc = certificateExactConvert( val, normalized );
+       if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
+               return serialNumberAndIssuerNormalize(0,NULL,NULL,val,normalized,ctx);
        }
 
+       assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) );
+
+       p = val->bv_val;
+       xcert = d2i_X509( NULL, &p, val->bv_len);
+       if( xcert == NULL ) goto done;
+
+       sn=X509_get_serialNumber(xcert);
+       if ( sn == NULL ) goto done;
+       serial=i2s_ASN1_INTEGER(0, sn );
+       if( serial == NULL ) goto done;
+       seriallen=strlen(serial);
+
+       name=X509_get_issuer_name(xcert);
+       if( name == NULL ) goto done;
+       rc = dnX509normalize( name, &issuer_dn );
+       if( rc != LDAP_SUCCESS ) goto done;
+
+       normalized->bv_len = seriallen + issuer_dn.bv_len + 1;
+       p = normalized->bv_val = ch_malloc(normalized->bv_len+1);
+       AC_MEMCPY(p, serial, seriallen);
+       p += seriallen;
+       *p++ = '$';
+       AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
+       p += issuer_dn.bv_len;
+       *p = '\0';
+
+#ifdef NEW_LOGGING
+       LDAP_LOG( CONFIG, ARGS, "certificateExactNormalize: %s\n",
+               normalized->bv_val, 0, 0 );
+#else
+       Debug( LDAP_DEBUG_TRACE, "certificateExactNormalize: %s\n",
+               normalized->bv_val, NULL, NULL );
+#endif
+
+done:
+       if (xcert) X509_free(xcert);
+       if (serial) ch_free(serial);
+       if (issuer_dn.bv_val) ber_memfree(issuer_dn.bv_val);
+
        return rc;
 }
 #endif /* HAVE_TLS */
@@ -2456,13 +2635,13 @@ static slap_syntax_defs_rec syntax_defs[] = {
                0, booleanValidate, NULL},
        {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
                X_BINARY X_NOT_H_R ")",
-               SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL},
+               SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, certificateValidate, NULL},
        {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
                X_BINARY X_NOT_H_R ")",
-               SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL},
+               SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, sequenceValidate, NULL},
        {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
                X_BINARY X_NOT_H_R ")",
-               SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL},
+               SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, sequenceValidate, NULL},
        {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
                0, countryStringValidate, NULL},
        {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
@@ -2508,7 +2687,7 @@ static slap_syntax_defs_rec syntax_defs[] = {
        {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
                0, NULL, NULL},
        {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
-               0, nameUIDValidate, NULL},
+               0, nameUIDValidate, nameUIDPretty },
        {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
                0, NULL, NULL},
        {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
@@ -2562,16 +2741,14 @@ static slap_syntax_defs_rec syntax_defs[] = {
        {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
                0, bootParameterValidate, NULL},
 
-       /* 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, serialNumberAndIssuerValidate, NULL},
+       /* From PKIX *//* This OID is not published yet. */
+       {"( 1.2.826.0.1.3344810.7.1 DESC 'Certificate Serial Number and Issuer' )",
+               SLAP_SYNTAX_HIDE,
+               serialNumberAndIssuerValidate,
+               serialNumberAndIssuerPretty},
 
-       /* OpenLDAP Experimental Syntaxes */
 #ifdef SLAPD_ACI_ENABLED
+       /* OpenLDAP Experimental Syntaxes */
        {"( 1.3.6.1.4.1.4203.666.2.1 DESC 'OpenLDAP Experimental ACI' )",
                SLAP_SYNTAX_HIDE,
                UTF8StringValidate /* THIS WILL CHANGE FOR NEW ACI SYNTAX */,
@@ -2590,12 +2767,10 @@ static slap_syntax_defs_rec syntax_defs[] = {
        {NULL, 0, NULL, NULL}
 };
 
-#ifdef HAVE_TLS
 char *certificateExactMatchSyntaxes[] = {
        "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
        NULL
 };
-#endif
 char *directoryStringSyntaxes[] = {
        "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
        NULL
@@ -2626,7 +2801,6 @@ char *objectIdentifierFirstComponentMatchSyntaxes[] = {
  * 2.5.13.31   directoryStringFirstComponentMatch
  * 2.5.13.32   wordMatch
  * 2.5.13.33   keywordMatch
- * 2.5.13.35   certificateMatch
  * 2.5.13.36   certificatePairExactMatch
  * 2.5.13.37   certificatePairMatch
  * 2.5.13.38   certificateListExactMatch
@@ -2852,14 +3026,27 @@ static slap_mrule_defs_rec mrule_defs[] = {
                octetStringIndexer, octetStringFilter,
                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, certificateExactMatchSyntaxes,
+#ifdef HAVE_TLS
                NULL, certificateExactNormalize, octetStringMatch,
                octetStringIndexer, octetStringFilter,
+#else
+               NULL, NULL, NULL, NULL, NULL,
+#endif
                NULL },
+
+       {"( 2.5.13.35 NAME 'certificateMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 )",
+               SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
+#ifdef HAVE_TLS
+               NULL, NULL, octetStringMatch,
+               octetStringIndexer, octetStringFilter,
+#else
+               NULL, NULL, NULL, NULL, NULL,
 #endif
+               NULL },
 
        {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
                "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",