[389-commits] 5 commits - ldap/schema ldap/servers Makefile.am Makefile.in VERSION.sh

Richard Allen Megginson rmeggins at fedoraproject.org
Wed Feb 17 22:05:17 UTC 2010


 Makefile.am                                    |    1 
 Makefile.in                                    |   15 
 VERSION.sh                                     |    2 
 ldap/schema/05rfc4523.ldif                     |   14 
 ldap/servers/plugins/syntaxes/bin.c            |   90 ++++
 ldap/servers/plugins/syntaxes/bitstring.c      |   36 +
 ldap/servers/plugins/syntaxes/ces.c            |  139 +++++++
 ldap/servers/plugins/syntaxes/cis.c            |  256 +++++++++++++
 ldap/servers/plugins/syntaxes/dn.c             |   42 ++
 ldap/servers/plugins/syntaxes/int.c            |   64 ++-
 ldap/servers/plugins/syntaxes/nameoptuid.c     |   41 ++
 ldap/servers/plugins/syntaxes/numericstring.c  |  116 ++++--
 ldap/servers/plugins/syntaxes/syntax.h         |   56 ++-
 ldap/servers/plugins/syntaxes/syntax_common.c  |  117 ++++++
 ldap/servers/plugins/syntaxes/tel.c            |   62 +++
 ldap/servers/slapd/attr.c                      |   76 ++++
 ldap/servers/slapd/attrsyntax.c                |   55 ++
 ldap/servers/slapd/back-ldbm/back-ldbm.h       |    4 
 ldap/servers/slapd/back-ldbm/filterindex.c     |   76 +---
 ldap/servers/slapd/back-ldbm/index.c           |   20 -
 ldap/servers/slapd/back-ldbm/ldbm_attr.c       |  115 ++++--
 ldap/servers/slapd/back-ldbm/ldif2ldbm.c       |    2 
 ldap/servers/slapd/back-ldbm/matchrule.c       |   26 -
 ldap/servers/slapd/back-ldbm/proto-back-ldbm.h |    3 
 ldap/servers/slapd/back-ldbm/sort.c            |    8 
 ldap/servers/slapd/back-ldbm/vlv.c             |   22 -
 ldap/servers/slapd/back-ldbm/vlv_srch.c        |    4 
 ldap/servers/slapd/back-ldbm/vlv_srch.h        |    3 
 ldap/servers/slapd/entry.c                     |   23 -
 ldap/servers/slapd/filter.h                    |    1 
 ldap/servers/slapd/filtercmp.c                 |   19 -
 ldap/servers/slapd/match.c                     |   57 ++-
 ldap/servers/slapd/pblock.c                    |  110 +++++
 ldap/servers/slapd/plugin_mr.c                 |  461 ++++++++++++++++++++++++-
 ldap/servers/slapd/plugin_syntax.c             |  331 ++++++++++++++---
 ldap/servers/slapd/proto-slap.h                |   26 +
 ldap/servers/slapd/schema.c                    |    4 
 ldap/servers/slapd/slap.h                      |   30 +
 ldap/servers/slapd/slapi-plugin-compat4.h      |    6 
 ldap/servers/slapd/slapi-plugin.h              |   65 +++
 ldap/servers/slapd/valueset.c                  |   31 -
 41 files changed, 2302 insertions(+), 327 deletions(-)

New commits:
commit ecf93e699b04d45fdfa07b12094adaab0233c47a
Author: Rich Megginson <rmeggins at redhat.com>
Date:   Tue Feb 16 15:56:59 2010 -0700

    change syntax plugins to register required matching rule plugins
    
    https://bugzilla.redhat.com/show_bug.cgi?id=559315
    Resolves: 559315
    Description: Searching some attributes are now case sensitive when they were previously case-insensitive
    Reviewed by: nhosoi (Thanks!) - also added some suggested comments
    I added code to allow the syntax plugins to register corresponding
    matching rules.  That is, the functions that the syntax plugins use
    for filter matching and key generation can also be used for matching
    rules with the new wrapper code.  I added some convenience functions
    and structures in the syntax plugin code to make it easier to add
    matching rules in the future.  I also added a new feature to the
    matching rule code - in the LDAP spec definition of matching rule, the
    syntax provided in the matching rule definition is the syntax for
    the _assertion value_ used with the matching rule, which is not
    necessarily the same as the syntax of the _attribute values_ to which
    the matching rule can be applied.  For example, matching rules that apply
    to syntax DirectoryString can also be applied in some cases to
    PrintableString, CountryString, and IA5String.  There are several other
    cases like this as well.  I also introduced the concept of a compat
    syntax that can be used with a matching rule.  The server will now
    check, when reading in the schema, if the syntax and matching rules
    for an attribute are consistent.
    Finally, for 05rfc4523.ldif, I changed the attributes to use
    octetStringMatch instead of one of the unimplemented certificate
    matching rules.

diff --git a/Makefile.am b/Makefile.am
index d2c52ff..1774ccd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1047,6 +1047,7 @@ libsyntax_plugin_la_SOURCES = ldap/servers/plugins/syntaxes/bin.c \
 	ldap/servers/plugins/syntaxes/phonetic.c \
 	ldap/servers/plugins/syntaxes/sicis.c \
 	ldap/servers/plugins/syntaxes/string.c \
+	ldap/servers/plugins/syntaxes/syntax_common.c \
 	ldap/servers/plugins/syntaxes/tel.c \
 	ldap/servers/plugins/syntaxes/telex.c \
 	ldap/servers/plugins/syntaxes/teletex.c \
diff --git a/Makefile.in b/Makefile.in
old mode 100755
new mode 100644
index fc381a0..fe2d14b
--- a/Makefile.in
+++ b/Makefile.in
@@ -626,6 +626,7 @@ am_libsyntax_plugin_la_OBJECTS =  \
 	ldap/servers/plugins/syntaxes/libsyntax_plugin_la-phonetic.lo \
 	ldap/servers/plugins/syntaxes/libsyntax_plugin_la-sicis.lo \
 	ldap/servers/plugins/syntaxes/libsyntax_plugin_la-string.lo \
+	ldap/servers/plugins/syntaxes/libsyntax_plugin_la-syntax_common.lo \
 	ldap/servers/plugins/syntaxes/libsyntax_plugin_la-tel.lo \
 	ldap/servers/plugins/syntaxes/libsyntax_plugin_la-telex.lo \
 	ldap/servers/plugins/syntaxes/libsyntax_plugin_la-teletex.lo \
@@ -2036,6 +2037,7 @@ libsyntax_plugin_la_SOURCES = ldap/servers/plugins/syntaxes/bin.c \
 	ldap/servers/plugins/syntaxes/phonetic.c \
 	ldap/servers/plugins/syntaxes/sicis.c \
 	ldap/servers/plugins/syntaxes/string.c \
+	ldap/servers/plugins/syntaxes/syntax_common.c \
 	ldap/servers/plugins/syntaxes/tel.c \
 	ldap/servers/plugins/syntaxes/telex.c \
 	ldap/servers/plugins/syntaxes/teletex.c \
@@ -3808,6 +3810,9 @@ ldap/servers/plugins/syntaxes/libsyntax_plugin_la-sicis.lo:  \
 ldap/servers/plugins/syntaxes/libsyntax_plugin_la-string.lo:  \
 	ldap/servers/plugins/syntaxes/$(am__dirstamp) \
 	ldap/servers/plugins/syntaxes/$(DEPDIR)/$(am__dirstamp)
+ldap/servers/plugins/syntaxes/libsyntax_plugin_la-syntax_common.lo:  \
+	ldap/servers/plugins/syntaxes/$(am__dirstamp) \
+	ldap/servers/plugins/syntaxes/$(DEPDIR)/$(am__dirstamp)
 ldap/servers/plugins/syntaxes/libsyntax_plugin_la-tel.lo:  \
 	ldap/servers/plugins/syntaxes/$(am__dirstamp) \
 	ldap/servers/plugins/syntaxes/$(DEPDIR)/$(am__dirstamp)
@@ -4585,6 +4590,8 @@ mostlyclean-compile:
 	-rm -f ldap/servers/plugins/syntaxes/libsyntax_plugin_la-sicis.lo
 	-rm -f ldap/servers/plugins/syntaxes/libsyntax_plugin_la-string.$(OBJEXT)
 	-rm -f ldap/servers/plugins/syntaxes/libsyntax_plugin_la-string.lo
+	-rm -f ldap/servers/plugins/syntaxes/libsyntax_plugin_la-syntax_common.$(OBJEXT)
+	-rm -f ldap/servers/plugins/syntaxes/libsyntax_plugin_la-syntax_common.lo
 	-rm -f ldap/servers/plugins/syntaxes/libsyntax_plugin_la-tel.$(OBJEXT)
 	-rm -f ldap/servers/plugins/syntaxes/libsyntax_plugin_la-tel.lo
 	-rm -f ldap/servers/plugins/syntaxes/libsyntax_plugin_la-teletex.$(OBJEXT)
@@ -5263,6 +5270,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ldap/servers/plugins/syntaxes/$(DEPDIR)/libsyntax_plugin_la-phonetic.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ldap/servers/plugins/syntaxes/$(DEPDIR)/libsyntax_plugin_la-sicis.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ldap/servers/plugins/syntaxes/$(DEPDIR)/libsyntax_plugin_la-string.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ldap/servers/plugins/syntaxes/$(DEPDIR)/libsyntax_plugin_la-syntax_common.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ldap/servers/plugins/syntaxes/$(DEPDIR)/libsyntax_plugin_la-tel.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ldap/servers/plugins/syntaxes/$(DEPDIR)/libsyntax_plugin_la-teletex.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ldap/servers/plugins/syntaxes/$(DEPDIR)/libsyntax_plugin_la-telex.Plo at am__quote@
@@ -8012,6 +8020,13 @@ ldap/servers/plugins/syntaxes/libsyntax_plugin_la-string.lo: ldap/servers/plugin
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsyntax_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ldap/servers/plugins/syntaxes/libsyntax_plugin_la-string.lo `test -f 'ldap/servers/plugins/syntaxes/string.c' || echo '$(srcdir)/'`ldap/servers/plugins/syntaxes/string.c
 
+ldap/servers/plugins/syntaxes/libsyntax_plugin_la-syntax_common.lo: ldap/servers/plugins/syntaxes/syntax_common.c
+ at am__fastdepCC_TRUE@	if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsyntax_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ldap/servers/plugins/syntaxes/libsyntax_plugin_la-syntax_common.lo -MD -MP -MF "ldap/servers/plugins/syntaxes/$(DEPDIR)/libsyntax_plugin_la-syntax_common.Tpo" -c -o ldap/servers/plugins/syntaxes/libsyntax_plugin_la-syntax_common.lo `test -f 'ldap/servers/plugins/syntaxes/syntax_common.c' || echo '$(srcdir)/'`ldap/servers/plugins/syntaxes/syntax_common.c; \
+ at am__fastdepCC_TRUE@	then mv -f "ldap/servers/plugins/syntaxes/$(DEPDIR)/libsyntax_plugin_la-syntax_common.Tpo" "ldap/servers/plugins/syntaxes/$(DEPDIR)/libsyntax_plugin_la-syntax_common.Plo"; else rm -f "ldap/servers/plugins/syntaxes/$(DEPDIR)/libsyntax_plugin_la-syntax_common.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='ldap/servers/plugins/syntaxes/syntax_common.c' object='ldap/servers/plugins/syntaxes/libsyntax_plugin_la-syntax_common.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsyntax_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ldap/servers/plugins/syntaxes/libsyntax_plugin_la-syntax_common.lo `test -f 'ldap/servers/plugins/syntaxes/syntax_common.c' || echo '$(srcdir)/'`ldap/servers/plugins/syntaxes/syntax_common.c
+
 ldap/servers/plugins/syntaxes/libsyntax_plugin_la-tel.lo: ldap/servers/plugins/syntaxes/tel.c
 @am__fastdepCC_TRUE@	if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsyntax_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ldap/servers/plugins/syntaxes/libsyntax_plugin_la-tel.lo -MD -MP -MF "ldap/servers/plugins/syntaxes/$(DEPDIR)/libsyntax_plugin_la-tel.Tpo" -c -o ldap/servers/plugins/syntaxes/libsyntax_plugin_la-tel.lo `test -f 'ldap/servers/plugins/syntaxes/tel.c' || echo '$(srcdir)/'`ldap/servers/plugins/syntaxes/tel.c; \
 @am__fastdepCC_TRUE@	then mv -f "ldap/servers/plugins/syntaxes/$(DEPDIR)/libsyntax_plugin_la-tel.Tpo" "ldap/servers/plugins/syntaxes/$(DEPDIR)/libsyntax_plugin_la-tel.Plo"; else rm -f "ldap/servers/plugins/syntaxes/$(DEPDIR)/libsyntax_plugin_la-tel.Tpo"; exit 1; fi
diff --git a/ldap/schema/05rfc4523.ldif b/ldap/schema/05rfc4523.ldif
index ed2d5b2..74334f3 100644
--- a/ldap/schema/05rfc4523.ldif
+++ b/ldap/schema/05rfc4523.ldif
@@ -11,7 +11,7 @@ dn: cn=schema
 #  SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 )
 attributeTypes: ( 2.5.4.36 NAME 'userCertificate'
   DESC 'X.509 user certificate'
-  EQUALITY certificateExactMatch
+  EQUALITY octetStringMatch
   SYNTAX 1.3.6.1.4.1.1466.115.121.1.40
   X-ORIGIN 'RFC 4523' )
 #
@@ -23,7 +23,7 @@ attributeTypes: ( 2.5.4.36 NAME 'userCertificate'
 #  SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 )
 attributeTypes: ( 2.5.4.37 NAME 'cACertificate'
   DESC 'X.509 CA certificate'
-  EQUALITY certificateExactMatch
+  EQUALITY octetStringMatch
   SYNTAX 1.3.6.1.4.1.1466.115.121.1.40
   X-ORIGIN 'RFC 4523' )
 #
@@ -36,7 +36,7 @@ attributeTypes: ( 2.5.4.37 NAME 'cACertificate'
 #  X-ORIGIN 'RFC 4523' )
 attributeTypes: ( 2.5.4.40 NAME 'crossCertificatePair'
   DESC 'X.509 cross certificate pair'
-  EQUALITY certificatePairExactMatch
+  EQUALITY octetStringMatch
   SYNTAX 1.3.6.1.4.1.1466.115.121.1.40
   X-ORIGIN 'RFC 4523' )
 #
@@ -49,7 +49,7 @@ attributeTypes: ( 2.5.4.40 NAME 'crossCertificatePair'
 #  X-ORIGIN 'RFC 4523' )
 attributeTypes: ( 2.5.4.39 NAME 'certificateRevocationList'
   DESC 'X.509 certificate revocation list'
-  EQUALITY certificateListExactMatch
+  EQUALITY octetStringMatch
   SYNTAX 1.3.6.1.4.1.1466.115.121.1.40
   X-ORIGIN 'RFC 4523' )
 #
@@ -62,7 +62,7 @@ attributeTypes: ( 2.5.4.39 NAME 'certificateRevocationList'
 #  X-ORIGIN 'RFC 4523' )
 attributeTypes: ( 2.5.4.38 NAME 'authorityRevocationList'
   DESC 'X.509 authority revocation list'
-  EQUALITY certificateListExactMatch
+  EQUALITY octetStringMatch
   SYNTAX 1.3.6.1.4.1.1466.115.121.1.40
   X-ORIGIN 'RFC 4523' )
 #
@@ -75,7 +75,7 @@ attributeTypes: ( 2.5.4.38 NAME 'authorityRevocationList'
 #  X-ORIGIN 'RFC 4523' )
 attributeTypes: ( 2.5.4.53 NAME 'deltaRevocationList'
   DESC 'X.509 delta revocation list'
-  EQUALITY certificateListExactMatch
+  EQUALITY octetStringMatch
   SYNTAX 1.3.6.1.4.1.1466.115.121.1.40
   X-ORIGIN 'RFC 4523' )
 #
@@ -88,7 +88,7 @@ attributeTypes: ( 2.5.4.53 NAME 'deltaRevocationList'
 #  X-ORIGIN 'RFC 4523' )
 attributeTypes: ( 2.5.4.52 NAME 'supportedAlgorithms'
   DESC 'X.509 supported algorithms'
-  EQUALITY algorithmIdentifierMatch
+  EQUALITY octetStringMatch
   SYNTAX 1.3.6.1.4.1.1466.115.121.1.40
   X-ORIGIN 'RFC 4523' )
 #
diff --git a/ldap/servers/plugins/syntaxes/bin.c b/ldap/servers/plugins/syntaxes/bin.c
index 229e142..b1b4659 100644
--- a/ldap/servers/plugins/syntaxes/bin.c
+++ b/ldap/servers/plugins/syntaxes/bin.c
@@ -52,12 +52,18 @@
 #include <sys/types.h>
 #include "syntax.h"
 
+#define CERTIFICATE_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.8"
+#define CERTIFICATELIST_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.9"
+#define CERTIFICATEPAIR_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.10"
+#define SUPPORTEDALGORITHM_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.49"
+
 static int bin_filter_ava( Slapi_PBlock *pb, struct berval *bvfilter,
 			Slapi_Value **bvals, int ftype, Slapi_Value **retVal );
 static int bin_values2keys( Slapi_PBlock *pb, Slapi_Value **bvals,
 	Slapi_Value ***ivals, int ftype );
 static int bin_assertion2keys_ava( Slapi_PBlock *pb, Slapi_Value *bval,
 	Slapi_Value ***ivals, int ftype );
+static int bin_compare(struct berval *v1, struct berval *v2);
 
 /*
  * Attribute syntaxes. We treat all of these the same since the
@@ -98,6 +104,66 @@ static Slapi_PluginDesc fax_pdesc = {
 	"Fax attribute syntax plugin"
 };
 
+static const char *octetStringMatch_names[] = {"octetStringMatch", "2.5.13.17", NULL};
+static const char *octetStringOrderingMatch_names[] = {"octetStringOrderingMatch", "2.5.13.18", NULL};
+
+static char *octetStringCompat_syntaxes[] = {BINARY_SYNTAX_OID, JPEG_SYNTAX_OID, FAX_SYNTAX_OID, CERTIFICATE_SYNTAX_OID, CERTIFICATELIST_SYNTAX_OID, CERTIFICATEPAIR_SYNTAX_OID, SUPPORTEDALGORITHM_SYNTAX_OID, NULL};
+
+static struct mr_plugin_def mr_plugin_table[] = {
+{{"2.5.13.17", NULL, "octetStringMatch", "The octetStringMatch rule compares an assertion value of the Octet "
+"String syntax to an attribute value of a syntax (e.g., the Octet "
+"String or JPEG syntax) whose corresponding ASN.1 type is the OCTET "
+"STRING ASN.1 type.  "
+"The rule evaluates to TRUE if and only if the attribute value and the "
+"assertion value are the same length and corresponding octets (by "
+"position) are the same.", OCTETSTRING_SYNTAX_OID, 0, octetStringCompat_syntaxes}, /* matching rule desc */
+ {"octetStringMatch-mr", VENDOR, DS_PACKAGE_VERSION, "octetStringMatch matching rule plugin"}, /* plugin desc */
+   octetStringMatch_names, /* matching rule name/oid/aliases */
+   NULL, NULL, bin_filter_ava, NULL, bin_values2keys,
+   bin_assertion2keys_ava, NULL, bin_compare},
+{{"2.5.13.18", NULL, "octetStringOrderingMatch", "The octetStringOrderingMatch rule compares an assertion value of the "
+"Octet String syntax to an attribute value of a syntax (e.g., the "
+"Octet String or JPEG syntax) whose corresponding ASN.1 type is the "
+"OCTET STRING ASN.1 type.  "
+"The rule evaluates to TRUE if and only if the attribute value appears "
+"earlier in the collation order than the assertion value.  The rule "
+"compares octet strings from the first octet to the last octet, and "
+"from the most significant bit to the least significant bit within the "
+"octet.  The first occurrence of a different bit determines the "
+"ordering of the strings.  A zero bit precedes a one bit.  If the "
+"strings contain different numbers of octets but the longer string is "
+"identical to the shorter string up to the length of the shorter "
+"string, then the shorter string precedes the longer string.",
+OCTETSTRING_SYNTAX_OID, 0, octetStringCompat_syntaxes}, /* matching rule desc */
+ {"octetStringOrderingMatch-mr", VENDOR, DS_PACKAGE_VERSION, "octetStringOrderingMatch matching rule plugin"}, /* plugin desc */
+ octetStringOrderingMatch_names, /* matching rule name/oid/aliases */
+ NULL, NULL, bin_filter_ava, NULL, bin_values2keys,
+ bin_assertion2keys_ava, NULL, bin_compare}
+};
+/*
+certificateExactMatch
+certificateListExactMatch
+certificatePairExactMatch
+algorithmIdentifierMatch
+certificateMatch
+certificatePairMatch
+certificateListMatch
+*/
+
+static size_t mr_plugin_table_size = sizeof(mr_plugin_table)/sizeof(mr_plugin_table[0]);
+
+static int
+matching_rule_plugin_init(Slapi_PBlock *pb)
+{
+	return syntax_matching_rule_plugin_init(pb, mr_plugin_table, mr_plugin_table_size);
+}
+
+static int
+register_matching_rule_plugins()
+{
+	return syntax_register_matching_rule_plugins(mr_plugin_table, mr_plugin_table_size, matching_rule_plugin_init);
+}
+
 /*
  * register_bin_like_plugin():  register all items for a bin-like plugin.
  */
@@ -134,6 +200,7 @@ bin_init( Slapi_PBlock *pb )
 	LDAPDebug( LDAP_DEBUG_PLUGIN, "=> bin_init\n", 0, 0, 0 );
 	rc = register_bin_like_plugin( pb, &bin_pdesc, bin_names,
 		 	BINARY_SYNTAX_OID );
+	rc |= register_matching_rule_plugins();
 	LDAPDebug( LDAP_DEBUG_PLUGIN, "<= bin_init %d\n", rc, 0, 0 );
 	return( rc );
 }
@@ -268,3 +335,26 @@ bin_assertion2keys_ava( Slapi_PBlock *pb, Slapi_Value *bval,
     }
 	return( 0 );
 }
+
+#define BV_EMPTY(bv) ((!bv || !bv->bv_len || !bv->bv_val))
+
+static int
+bin_compare(    
+	struct berval	*v1,
+    struct berval	*v2
+)
+{
+    int rc = 0;
+
+    if (BV_EMPTY(v1) && BV_EMPTY(v2)) {
+        rc = 0; /* empty == empty */
+    } else if (BV_EMPTY(v1) && !BV_EMPTY(v2)) {
+        rc = 1; /* something in v2 always greater than empty v1 */
+    } else if (!BV_EMPTY(v1) && BV_EMPTY(v2)) {
+        rc = -1; /* something in v1 always greater than empty v2 */
+    } else { /* both have actual data */
+        rc = slapi_berval_cmp(v1, v2);
+    }
+
+    return rc;
+}
diff --git a/ldap/servers/plugins/syntaxes/bitstring.c b/ldap/servers/plugins/syntaxes/bitstring.c
index 70738f1..eefe8fc 100644
--- a/ldap/servers/plugins/syntaxes/bitstring.c
+++ b/ldap/servers/plugins/syntaxes/bitstring.c
@@ -66,6 +66,41 @@ static char *names[] = { "Bit String", "bitstring", BITSTRING_SYNTAX_OID, 0 };
 static Slapi_PluginDesc pdesc = { "bitstring-syntax", VENDOR, DS_PACKAGE_VERSION,
 	"Bit String attribute syntax plugin" };
 
+static const char *bitStringMatch_names[] = {"bitStringMatch", "2.5.13.16", NULL};
+
+static struct mr_plugin_def mr_plugin_table[] = {
+    {{"2.5.13.16", NULL, "bitStringMatch", "The bitStringMatch rule compares an assertion value of the Bit String "
+      "syntax to an attribute value of a syntax (e.g., the Bit String "
+      "syntax) whose corresponding ASN.1 type is BIT STRING.  "
+      "If the corresponding ASN.1 type of the attribute syntax does not have "
+      "a named bit list [ASN.1] (which is the case for the Bit String "
+      "syntax), then the rule evaluates to TRUE if and only if the attribute "
+      "value has the same number of bits as the assertion value and the bits "
+      "match on a bitwise basis.  "
+      "If the corresponding ASN.1 type does have a named bit list, then "
+      "bitStringMatch operates as above, except that trailing zero bits in "
+      "the attribute and assertion values are treated as absent.",
+      BITSTRING_SYNTAX_OID, 0, NULL /* only the specified syntax is supported */}, /* matching rule desc */
+     {"bitStringMatch-mr", VENDOR, DS_PACKAGE_VERSION, "bitStringMatch matching rule plugin"}, /* plugin desc */
+     bitStringMatch_names, /* matching rule name/oid/aliases */
+     NULL, NULL, bitstring_filter_ava, NULL, bitstring_values2keys,
+     bitstring_assertion2keys_ava, NULL, bitstring_compare}
+};
+
+static size_t mr_plugin_table_size = sizeof(mr_plugin_table)/sizeof(mr_plugin_table[0]);
+
+static int
+matching_rule_plugin_init(Slapi_PBlock *pb)
+{
+	return syntax_matching_rule_plugin_init(pb, mr_plugin_table, mr_plugin_table_size);
+}
+
+static int
+register_matching_rule_plugins()
+{
+	return syntax_register_matching_rule_plugins(mr_plugin_table, mr_plugin_table_size, matching_rule_plugin_init);
+}
+
 int
 bitstring_init( Slapi_PBlock *pb )
 {
@@ -99,6 +134,7 @@ bitstring_init( Slapi_PBlock *pb )
 	rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_VALIDATE,
 	    (void *) bitstring_validate );
 
+	rc |= register_matching_rule_plugins();
 	LDAPDebug( LDAP_DEBUG_PLUGIN, "<= bitstring_init %d\n", rc, 0, 0 );
 	return( rc );
 }
diff --git a/ldap/servers/plugins/syntaxes/ces.c b/ldap/servers/plugins/syntaxes/ces.c
index 077afc1..07abcd5 100644
--- a/ldap/servers/plugins/syntaxes/ces.c
+++ b/ldap/servers/plugins/syntaxes/ces.c
@@ -49,6 +49,10 @@
 #include <sys/types.h>
 #include "syntax.h"
 
+/* this is used in proposed schema, but there is no official
+   OID yet - so for now, use our private MR OID namespace */
+#define CASEEXACTIA5SUBSTRINGSMATCH_OID "2.16.840.1.113730.3.3.1"
+
 static int ces_filter_ava( Slapi_PBlock *pb, struct berval *bvfilter,
 		Slapi_Value **bvals, int ftype, Slapi_Value **retVal );
 static int ces_filter_sub( Slapi_PBlock *pb, char *initial, char **any,
@@ -75,6 +79,140 @@ static Slapi_PluginDesc ia5_pdesc = { "ces-syntax", VENDOR,
 static Slapi_PluginDesc uri_pdesc = { "uri-syntax", VENDOR,
 	DS_PACKAGE_VERSION, "uri attribute syntax plugin" };
 
+static const char *caseExactIA5Match_names[] = {"caseExactIA5Match", "1.3.6.1.4.1.1466.109.114.1", NULL};
+static const char *caseExactMatch_names[] = {"caseExactMatch", "2.5.13.5", NULL};
+static const char *caseExactOrderingMatch_names[] = {"caseExactOrderingMatch", "2.5.13.6", NULL};
+static const char *caseExactSubstringsMatch_names[] = {"caseExactSubstringsMatch", "2.5.13.7", NULL};
+static const char *caseExactIA5SubstringsMatch_names[] = {"caseExactIA5SubstringsMatch", CASEEXACTIA5SUBSTRINGSMATCH_OID, NULL};
+
+static char *dirString_syntaxes[] = {COUNTRYSTRING_SYNTAX_OID,
+                                           DIRSTRING_SYNTAX_OID,
+                                           PRINTABLESTRING_SYNTAX_OID,NULL};
+static char *dirStringCompat_syntaxes[] = {COUNTRYSTRING_SYNTAX_OID,
+                                                 PRINTABLESTRING_SYNTAX_OID,NULL};
+static char *ia5String_syntaxes[] = {IA5STRING_SYNTAX_OID,NULL};
+
+/* for some reason vendorName and vendorVersion are dirstring but want
+   to use EQUALITY caseExactIA5Match ???? RFC 3045
+   also the old definition of automountInformation from 60autofs.ldif
+   does the same thing */
+static char *caseExactIA5Match_syntaxes[] = {DIRSTRING_SYNTAX_OID, NULL};
+
+static struct mr_plugin_def mr_plugin_table[] = {
+{{"1.3.6.1.4.1.1466.109.114.1", NULL, "caseExactIA5Match", "The caseExactIA5Match rule compares an assertion value of the IA5 "
+"String syntax to an attribute value of a syntax (e.g., the IA5 String "
+"syntax) whose corresponding ASN.1 type is IA5String. "
+"The rule evaluates to TRUE if and only if the prepared attribute "
+"value character string and the prepared assertion value character "
+"string have the same number of characters and corresponding "
+"characters have the same code point. "
+"In preparing the attribute value and assertion value for comparison, "
+"characters are not case folded in the Map preparation step, and only "
+"Insignificant Space Handling is applied in the Insignificant "
+"Character Handling step.",
+IA5STRING_SYNTAX_OID, 0, caseExactIA5Match_syntaxes}, /* matching rule desc */
+ {"caseExactIA5Match-mr", VENDOR, DS_PACKAGE_VERSION, "caseExactIA5Match matching rule plugin"}, /* plugin desc */
+   caseExactIA5Match_names, /* matching rule name/oid/aliases */
+   NULL, NULL, ces_filter_ava, NULL, ces_values2keys,
+   ces_assertion2keys_ava, NULL, ces_compare},
+{{"2.5.13.5", NULL, "caseExactMatch", "The caseExactMatch rule compares an assertion value of the Directory "
+"String syntax to an attribute value of a syntax (e.g., the Directory "
+"String, Printable String, Country String, or Telephone Number syntax) "
+"whose corresponding ASN.1 type is DirectoryString or one of the "
+"alternative string types of DirectoryString, such as PrintableString "
+"(the other alternatives do not correspond to any syntax defined in "
+"this document). "
+"The rule evaluates to TRUE if and only if the prepared attribute "
+"value character string and the prepared assertion value character "
+"string have the same number of characters and corresponding "
+"characters have the same code point. "
+"In preparing the attribute value and assertion value for comparison, "
+"characters are not case folded in the Map preparation step, and only "
+"Insignificant Space Handling is applied in the Insignificant "
+"Character Handling step.",
+DIRSTRING_SYNTAX_OID, 0, dirStringCompat_syntaxes}, /* matching rule desc */
+ {"caseExactMatch-mr", VENDOR, DS_PACKAGE_VERSION, "caseExactMatch matching rule plugin"}, /* plugin desc */
+   caseExactMatch_names, /* matching rule name/oid/aliases */
+   NULL, NULL, ces_filter_ava, NULL, ces_values2keys,
+   ces_assertion2keys_ava, NULL, ces_compare},
+{{"2.5.13.6", NULL, "caseExactOrderingMatch", "The caseExactOrderingMatch rule compares an assertion value of the "
+"Directory String syntax to an attribute value of a syntax (e.g., the "
+"Directory String, Printable String, Country String, or Telephone "
+"Number syntax) whose corresponding ASN.1 type is DirectoryString or "
+"one of its alternative string types. "
+"The rule evaluates to TRUE if and only if, in the code point "
+"collation order, the prepared attribute value character string "
+"appears earlier than the prepared assertion value character string; "
+"i.e., the attribute value is \"less than\" the assertion value. "
+"In preparing the attribute value and assertion value for comparison, "
+"characters are not case folded in the Map preparation step, and only "
+"Insignificant Space Handling is applied in the Insignificant "
+"Character Handling step.",
+DIRSTRING_SYNTAX_OID, 0, dirStringCompat_syntaxes}, /* matching rule desc */
+ {"caseExactOrderingMatch-mr", VENDOR, DS_PACKAGE_VERSION, "caseExactOrderingMatch matching rule plugin"}, /* plugin desc */
+   caseExactOrderingMatch_names, /* matching rule name/oid/aliases */
+   NULL, NULL, ces_filter_ava, NULL, ces_values2keys,
+   ces_assertion2keys_ava, NULL, ces_compare},
+{{"2.5.13.7", NULL, "caseExactSubstringsMatch", "The caseExactSubstringsMatch rule compares an assertion value of the "
+"Substring Assertion syntax to an attribute value of a syntax (e.g., "
+"the Directory String, Printable String, Country String, or Telephone "
+"Number syntax) whose corresponding ASN.1 type is DirectoryString or "
+"one of its alternative string types. "
+"The rule evaluates to TRUE if and only if (1) the prepared substrings "
+"of the assertion value match disjoint portions of the prepared "
+"attribute value character string in the order of the substrings in "
+"the assertion value, (2) an <initial> substring, if present, matches "
+"the beginning of the prepared attribute value character string, and "
+"(3) a <final> substring, if present, matches the end of the prepared "
+"attribute value character string.  A prepared substring matches a "
+"portion of the prepared attribute value character string if "
+"corresponding characters have the same code point. "
+"In preparing the attribute value and assertion value substrings for "
+"comparison, characters are not case folded in the Map preparation "
+"step, and only Insignificant Space Handling is applied in the "
+"Insignificant Character Handling step.",
+"1.3.6.1.4.1.1466.115.121.1.58", 0, dirString_syntaxes}, /* matching rule desc */
+ {"caseExactSubstringsMatch-mr", VENDOR, DS_PACKAGE_VERSION, "caseExactSubstringsMatch matching rule plugin"}, /* plugin desc */
+ caseExactSubstringsMatch_names, /* matching rule name/oid/aliases */
+ NULL, NULL, NULL, ces_filter_sub, ces_values2keys,
+ NULL, ces_assertion2keys_sub, ces_compare},
+{{CASEEXACTIA5SUBSTRINGSMATCH_OID, NULL, "caseExactIA5SubstringsMatch", "The caseExactIA5SubstringsMatch rule compares an assertion value of the "
+"Substring Assertion syntax to an attribute value of a syntax (e.g., "
+"the IA5 syntax) whose corresponding ASN.1 type is IA5 String or "
+"one of its alternative string types. "
+"The rule evaluates to TRUE if and only if (1) the prepared substrings "
+"of the assertion value match disjoint portions of the prepared "
+"attribute value character string in the order of the substrings in "
+"the assertion value, (2) an <initial> substring, if present, matches "
+"the beginning of the prepared attribute value character string, and "
+"(3) a <final> substring, if present, matches the end of the prepared "
+"attribute value character string.  A prepared substring matches a "
+"portion of the prepared attribute value character string if "
+"corresponding characters have the same code point. "
+"In preparing the attribute value and assertion value substrings for "
+"comparison, characters are not case folded in the Map preparation "
+"step, and only Insignificant Space Handling is applied in the "
+"Insignificant Character Handling step.",
+"1.3.6.1.4.1.1466.115.121.1.58", 0, ia5String_syntaxes}, /* matching rule desc */
+ {"caseExactIA5SubstringsMatch-mr", VENDOR, DS_PACKAGE_VERSION, "caseExactIA5SubstringsMatch matching rule plugin"}, /* plugin desc */
+   caseExactIA5SubstringsMatch_names, /* matching rule name/oid/aliases */
+   NULL, NULL, NULL, ces_filter_sub, ces_values2keys,
+   NULL, ces_assertion2keys_sub, ces_compare}
+};
+
+static size_t mr_plugin_table_size = sizeof(mr_plugin_table)/sizeof(mr_plugin_table[0]);
+
+static int
+matching_rule_plugin_init(Slapi_PBlock *pb)
+{
+	return syntax_matching_rule_plugin_init(pb, mr_plugin_table, mr_plugin_table_size);
+}
+
+static int
+register_matching_rule_plugins()
+{
+	return syntax_register_matching_rule_plugins(mr_plugin_table, mr_plugin_table_size, matching_rule_plugin_init);
+}
 
 /*
  * register_ces_like_plugin():  register all items for a cis-like plugin.
@@ -124,6 +262,7 @@ ces_init( Slapi_PBlock *pb )
 	LDAPDebug( LDAP_DEBUG_PLUGIN, "=> ces_init\n", 0, 0, 0 );
 
 	rc = register_ces_like_plugin(pb,&ia5_pdesc,ia5_names,IA5STRING_SYNTAX_OID, ia5_validate);
+	rc |= register_matching_rule_plugins();
 
 	LDAPDebug( LDAP_DEBUG_PLUGIN, "<= ces_init %d\n", rc, 0, 0 );
 	return( rc );
diff --git a/ldap/servers/plugins/syntaxes/cis.c b/ldap/servers/plugins/syntaxes/cis.c
index 4a15e5e..77f6d55 100644
--- a/ldap/servers/plugins/syntaxes/cis.c
+++ b/ldap/servers/plugins/syntaxes/cis.c
@@ -95,16 +95,6 @@ static char *time_names[] = { "GeneralizedTime", "time",
 
 #define GENERALIZEDTIMEMATCH_OID "2.5.13.27"
 #define GENERALIZEDTIMEORDERINGMATCH_OID "2.5.13.28"
-static Slapi_MatchingRuleEntry
-generalizedTimeMatch = { GENERALIZEDTIMEMATCH_OID, NULL /* no alias? */,
-                         "generalizedTimeMatch", "The rule evaluates to TRUE if and only if the attribute value represents the same universal coordinated time as the assertion value.",
-                         GENERALIZEDTIME_SYNTAX_OID, 0 /* not obsolete */ };
-
-static Slapi_MatchingRuleEntry
-generalizedTimeOrderingMatch = { GENERALIZEDTIMEORDERINGMATCH_OID, NULL /* no alias? */,
-                                 "generalizedTimeOrderingMatch", "The rule evaluates to TRUE if and only if the attribute value represents a universal coordinated time that is earlier than the universal coordinated time represented by the assertion value.",
-                                 GENERALIZEDTIME_SYNTAX_OID, 0 /* not obsolete */ };
-
 
 static char *country_names[] = { "Country String",
 		COUNTRYSTRING_SYNTAX_OID, 0};
@@ -180,6 +170,248 @@ static Slapi_PluginDesc printable_pdesc = { "printablestring-syntax",
 		VENDOR, DS_PACKAGE_VERSION,
 		"Printable String attribtue syntax plugin" };
 
+static const char *generalizedTimeMatch_names[] = {"generalizedTimeMatch", GENERALIZEDTIMEMATCH_OID, NULL};
+static const char *generalizedTimeOrderingMatch_names[] = {"generalizedTimeOrderingMatch", GENERALIZEDTIMEORDERINGMATCH_OID, NULL};
+static const char *booleanMatch_names[] = {"booleanMatch", "2.5.13.13", NULL};
+static const char *caseIgnoreIA5Match_names[] = {"caseIgnoreIA5Match", "1.3.6.1.4.1.1466.109.114.2", NULL};
+static const char *caseIgnoreIA5SubstringsMatch_names[] = {"caseIgnoreIA5SubstringsMatch", "1.3.6.1.4.1.1466.109.114.3", NULL};
+static const char *caseIgnoreListMatch_names[] = {"caseIgnoreListMatch", "2.5.13.11", NULL};
+static const char *caseIgnoreListSubstringsMatch_names[] = {"caseIgnoreListSubstringsMatch", "2.5.13.12", NULL};
+static const char *caseIgnoreMatch_names[] = {"caseIgnoreMatch", "2.5.13.2", NULL};
+static const char *caseIgnoreOrderingMatch_names[] = {"caseIgnoreOrderingMatch", "2.5.13.3", NULL};
+static const char *caseIgnoreSubstringsMatch_names[] = {"caseIgnoreSubstringsMatch", "2.5.13.4", NULL};
+static const char *directoryStringFirstComponentMatch_names[] = {"directoryStringFirstComponentMatch", "2.5.13.31", NULL};
+static const char *objectIdentifierMatch_names[] = {"objectIdentifierMatch", "2.5.13.0", NULL};
+static const char *objectIdentifierFirstComponentMatch_names[] = {"objectIdentifierFirstComponentMatch", "2.5.13.30", NULL};
+
+static char *dirString_syntaxes[] = {COUNTRYSTRING_SYNTAX_OID,
+                                           DIRSTRING_SYNTAX_OID,
+                                           PRINTABLESTRING_SYNTAX_OID,NULL};
+static char *dirStringCompat_syntaxes[] = {COUNTRYSTRING_SYNTAX_OID,
+                                                 PRINTABLESTRING_SYNTAX_OID,NULL};
+static char *caseIgnoreIA5SubstringsMatch_syntaxes[] = {IA5STRING_SYNTAX_OID,NULL};
+static char *caseIgnoreListSubstringsMatch_syntaxes[] = {POSTALADDRESS_SYNTAX_OID,NULL};
+static char *objectIdentifierFirstComponentMatch_syntaxes[] = {DIRSTRING_SYNTAX_OID, NULL};
+
+static struct mr_plugin_def mr_plugin_table[] = {
+{{GENERALIZEDTIMEMATCH_OID, NULL /* no alias? */,
+  "generalizedTimeMatch", "The rule evaluates to TRUE if and only if the attribute value represents the same universal coordinated time as the assertion value.",
+  GENERALIZEDTIME_SYNTAX_OID, 0 /* not obsolete */, NULL /* no other syntaxes supported */ },
+ {"generalizedTimeMatch-mr", VENDOR, DS_PACKAGE_VERSION, "generalizedTimeMatch matching rule plugin"}, /* plugin desc */
+ generalizedTimeMatch_names, /* matching rule name/oid/aliases */
+ NULL, NULL, cis_filter_ava, NULL, cis_values2keys,
+ cis_assertion2keys_ava, NULL, cis_compare},
+{{GENERALIZEDTIMEORDERINGMATCH_OID, NULL /* no alias? */,
+  "generalizedTimeOrderingMatch", "The rule evaluates to TRUE if and only if the attribute value represents a universal coordinated time that is earlier than the universal coordinated time represented by the assertion value.",
+  GENERALIZEDTIME_SYNTAX_OID, 0 /* not obsolete */, NULL /* no other syntaxes supported */ },
+ {"generalizedTimeOrderingMatch-mr", VENDOR, DS_PACKAGE_VERSION, "generalizedTimeOrderingMatch matching rule plugin"}, /* plugin desc */
+ generalizedTimeOrderingMatch_names, /* matching rule name/oid/aliases */
+ NULL, NULL, cis_filter_ava, NULL, cis_values2keys,
+ cis_assertion2keys_ava, NULL, cis_compare},
+/* strictly speaking, boolean is case sensitive */
+{{"2.5.13.13", NULL, "booleanMatch", "The booleanMatch rule compares an assertion value of the Boolean "
+"syntax to an attribute value of a syntax (e.g., the Boolean syntax) "
+"whose corresponding ASN.1 type is BOOLEAN.  "
+"The rule evaluates to TRUE if and only if the attribute value and the "
+"assertion value are both TRUE or both FALSE.", BOOLEAN_SYNTAX_OID, 0, NULL /* no other syntaxes supported */}, /* matching rule desc */
+ {"booleanMatch-mr", VENDOR, DS_PACKAGE_VERSION, "booleanMatch matching rule plugin"}, /* plugin desc */
+   booleanMatch_names, /* matching rule name/oid/aliases */
+   NULL, NULL, cis_filter_ava, NULL, cis_values2keys,
+   cis_assertion2keys_ava, NULL, cis_compare},
+{{"1.3.6.1.4.1.1466.109.114.2", NULL, "caseIgnoreIA5Match", "The caseIgnoreIA5Match rule compares an assertion value of the IA5 "
+"String syntax to an attribute value of a syntax (e.g., the IA5 String "
+"syntax) whose corresponding ASN.1 type is IA5String.  "
+"The rule evaluates to TRUE if and only if the prepared attribute "
+"value character string and the prepared assertion value character "
+"string have the same number of characters and corresponding "
+"characters have the same code point.  "
+"In preparing the attribute value and assertion value for comparison, "
+"characters are case folded in the Map preparation step, and only "
+"Insignificant Space Handling is applied in the Insignificant "
+"Character Handling step.", IA5STRING_SYNTAX_OID, 0, NULL /* no other syntaxes supported */}, /* matching rule desc */
+ {"caseIgnoreIA5Match-mr", VENDOR, DS_PACKAGE_VERSION, "caseIgnoreIA5Match matching rule plugin"}, /* plugin desc */
+   caseIgnoreIA5Match_names, /* matching rule name/oid/aliases */
+   NULL, NULL, cis_filter_ava, NULL, cis_values2keys,
+   cis_assertion2keys_ava, NULL, cis_compare},
+{{"1.3.6.1.4.1.1466.109.114.3", NULL, "caseIgnoreIA5SubstringsMatch", "The caseIgnoreIA5SubstringsMatch rule compares an assertion value of "
+"the Substring Assertion syntax to an attribute value of a syntax "
+"(e.g., the IA5 String syntax) whose corresponding ASN.1 type is "
+"IA5String.  "
+"The rule evaluates to TRUE if and only if (1) the prepared substrings "
+"of the assertion value match disjoint portions of the prepared "
+"attribute value character string in the order of the substrings in "
+"the assertion value, (2) an <initial> substring, if present, matches "
+"the beginning of the prepared attribute value character string, and "
+"(3) a <final> substring, if present, matches the end of the prepared "
+"attribute value character string.  A prepared substring matches a "
+"portion of the prepared attribute value character string if "
+"corresponding characters have the same code point.  "
+"In preparing the attribute value and assertion value substrings for "
+"comparison, characters are case folded in the Map preparation step, "
+"and only Insignificant Space Handling is applied in the Insignificant "
+"Character Handling step.", "1.3.6.1.4.1.1466.115.121.1.58", 0, caseIgnoreIA5SubstringsMatch_syntaxes}, /* matching rule desc */
+ {"caseIgnoreIA5SubstringsMatch-mr", VENDOR, DS_PACKAGE_VERSION, "caseIgnoreIA5SubstringsMatch matching rule plugin"}, /* plugin desc */
+   caseIgnoreIA5SubstringsMatch_names, /* matching rule name/oid/aliases */
+   NULL, NULL, NULL, cis_filter_sub, cis_values2keys,
+   NULL, cis_assertion2keys_sub, NULL},
+{{"2.5.13.2", NULL, "caseIgnoreMatch", "The caseIgnoreMatch rule compares an assertion value of the Directory "
+"String syntax to an attribute value of a syntax (e.g., the Directory "
+"String, Printable String, Country String, or Telephone Number syntax) "
+"whose corresponding ASN.1 type is DirectoryString or one of its "
+"alternative string types.  "
+"The rule evaluates to TRUE if and only if the prepared attribute "
+"value character string and the prepared assertion value character "
+"string have the same number of characters and corresponding "
+"characters have the same code point. "
+"In preparing the attribute value and assertion value for comparison, "
+"characters are case folded in the Map preparation step, and only "
+"Insignificant Space Handling is applied in the Insignificant "
+"Character Handling step.", DIRSTRING_SYNTAX_OID, 0, dirStringCompat_syntaxes}, /* matching rule desc */
+ {"caseIgnoreMatch-mr", VENDOR, DS_PACKAGE_VERSION, "caseIgnoreMatch matching rule plugin"}, /* plugin desc */
+   caseIgnoreMatch_names, /* matching rule name/oid/aliases */
+   NULL, NULL, cis_filter_ava, NULL, cis_values2keys,
+   cis_assertion2keys_ava, NULL, cis_compare},
+{{"2.5.13.3", NULL, "caseIgnoreOrderingMatch", "The caseIgnoreOrderingMatch rule compares an assertion value of the "
+"Directory String syntax to an attribute value of a syntax (e.g., the "
+"Directory String, Printable String, Country String, or Telephone "
+"Number syntax) whose corresponding ASN.1 type is DirectoryString or "
+"one of its alternative string types. "
+"The rule evaluates to TRUE if and only if, in the code point "
+"collation order, the prepared attribute value character string "
+"appears earlier than the prepared assertion value character string; "
+"i.e., the attribute value is \"less than\" the assertion value. "
+"In preparing the attribute value and assertion value for comparison, "
+"characters are case folded in the Map preparation step, and only "
+"Insignificant Space Handling is applied in the Insignificant "
+"Character Handling step.", DIRSTRING_SYNTAX_OID, 0, dirStringCompat_syntaxes}, /* matching rule desc */
+ {"caseIgnoreOrderingMatch-mr", VENDOR, DS_PACKAGE_VERSION, "caseIgnoreOrderingMatch matching rule plugin"}, /* plugin desc */
+   caseIgnoreOrderingMatch_names, /* matching rule name/oid/aliases */
+   NULL, NULL, cis_filter_ava, NULL, cis_values2keys,
+   cis_assertion2keys_ava, NULL, cis_compare},
+{{"2.5.13.4", NULL, "caseIgnoreSubstringsMatch", "The caseIgnoreSubstringsMatch rule compares an assertion value of the "
+"Substring Assertion syntax to an attribute value of a syntax (e.g., "
+"the Directory String, Printable String, Country String, or Telephone "
+"Number syntax) whose corresponding ASN.1 type is DirectoryString or "
+"one of its alternative string types. "
+"The rule evaluates to TRUE if and only if (1) the prepared substrings "
+"of the assertion value match disjoint portions of the prepared "
+"attribute value character string in the order of the substrings in "
+"the assertion value, (2) an <initial> substring, if present, matches "
+"the beginning of the prepared attribute value character string, and "
+"(3) a <final> substring, if present, matches the end of the prepared "
+"attribute value character string.  A prepared substring matches a "
+"portion of the prepared attribute value character string if "
+"corresponding characters have the same code point. "
+"In preparing the attribute value and assertion value substrings for "
+"comparison, characters are case folded in the Map preparation step, "
+"and only Insignificant Space Handling is applied in the Insignificant "
+"Character Handling step.", "1.3.6.1.4.1.1466.115.121.1.58", 0, dirString_syntaxes}, /* matching rule desc */
+ {"caseIgnoreSubstringsMatch-mr", VENDOR, DS_PACKAGE_VERSION, "caseIgnoreSubstringsMatch matching rule plugin"}, /* plugin desc */
+   caseIgnoreSubstringsMatch_names, /* matching rule name/oid/aliases */
+   NULL, NULL, NULL, cis_filter_sub, cis_values2keys,
+   NULL, cis_assertion2keys_sub, cis_compare},
+{{"2.5.13.11", NULL, "caseIgnoreListMatch", "The caseIgnoreListMatch rule compares an assertion value that is a "
+"sequence of strings to an attribute value of a syntax (e.g., the "
+"Postal Address syntax) whose corresponding ASN.1 type is a SEQUENCE "
+"OF the DirectoryString ASN.1 type. "
+"The rule evaluates to TRUE if and only if the attribute value and the "
+"assertion value have the same number of strings and corresponding "
+"strings (by position) match according to the caseIgnoreMatch matching "
+"rule. "
+"In [X.520], the assertion syntax for this matching rule is defined to "
+"be: "
+"      SEQUENCE OF DirectoryString {ub-match} "
+"That is, it is different from the corresponding type for the Postal "
+"Address syntax.  The choice of the Postal Address syntax for the "
+"assertion syntax of the caseIgnoreListMatch in LDAP should not be "
+"seen as limiting the matching rule to apply only to attributes with "
+"the Postal Address syntax.", POSTALADDRESS_SYNTAX_OID, 0, NULL /* postal syntax only */}, /* matching rule desc */
+ {"caseIgnoreListMatch-mr", VENDOR, DS_PACKAGE_VERSION, "caseIgnoreListMatch matching rule plugin"}, /* plugin desc */
+   caseIgnoreListMatch_names, /* matching rule name/oid/aliases */
+   NULL, NULL, cis_filter_ava, NULL, cis_values2keys,
+   cis_assertion2keys_ava, NULL, cis_compare},
+{{"2.5.13.12", NULL, "caseIgnoreListSubstringsMatch", "The caseIgnoreListSubstringsMatch rule compares an assertion value of "
+"the Substring Assertion syntax to an attribute value of a syntax "
+"(e.g., the Postal Address syntax) whose corresponding ASN.1 type is a "
+"SEQUENCE OF the DirectoryString ASN.1 type. "
+"The rule evaluates to TRUE if and only if the assertion value "
+"matches, per the caseIgnoreSubstringsMatch rule, the character string "
+"formed by concatenating the strings of the attribute value, except "
+"that none of the <initial>, <any>, or <final> substrings of the "
+"assertion value are considered to match a substring of the "
+"concatenated string which spans more than one of the original strings "
+"of the attribute value. "
+"Note that, in terms of the LDAP-specific encoding of the Postal "
+"Address syntax, the concatenated string omits the <DOLLAR> line "
+"separator and the escaping of \"\\\" and \"$\" characters.",
+"1.3.6.1.4.1.1466.115.121.1.58", 0, caseIgnoreListSubstringsMatch_syntaxes}, /* matching rule desc */
+ {"caseIgnoreListSubstringsMatch-mr", VENDOR, DS_PACKAGE_VERSION, "caseIgnoreListSubstringsMatch matching rule plugin"}, /* plugin desc */
+   caseIgnoreListSubstringsMatch_names, /* matching rule name/oid/aliases */
+   NULL, NULL, NULL, cis_filter_sub, cis_values2keys,
+   NULL, cis_assertion2keys_sub, cis_compare},
+{{"2.5.13.0", NULL, "objectIdentifierMatch", "The objectIdentifierMatch rule compares an assertion value of the OID "
+"syntax to an attribute value of a syntax (e.g., the OID syntax) whose "
+"corresponding ASN.1 type is OBJECT IDENTIFIER. "
+"The rule evaluates to TRUE if and only if the assertion value and the "
+"attribute value represent the same object identifier; that is, the "
+"same sequence of integers, whether represented explicitly in the "
+"<numericoid> form of <oid> or implicitly in the <descr> form (see "
+"[RFC4512]). "
+"If an LDAP client supplies an assertion value in the <descr> form and "
+"the chosen descriptor is not recognized by the server, then the "
+"objectIdentifierMatch rule evaluates to Undefined.",
+OID_SYNTAX_OID, 0, NULL /* OID syntax only for now */}, /* matching rule desc */
+ {"objectIdentifierMatch-mr", VENDOR, DS_PACKAGE_VERSION, "objectIdentifierMatch matching rule plugin"}, /* plugin desc */
+ objectIdentifierMatch_names, /* matching rule name/oid/aliases */
+ NULL, NULL, cis_filter_ava, NULL, cis_values2keys,
+ cis_assertion2keys_ava, NULL, cis_compare},
+{{"2.5.13.31", NULL, "directoryStringFirstComponentMatch", "The directoryStringFirstComponentMatch rule compares an assertion "
+"value of the Directory String syntax to an attribute value of a "
+"syntax whose corresponding ASN.1 type is a SEQUENCE with a mandatory "
+"first component of the DirectoryString ASN.1 type. "
+"Note that the assertion syntax of this matching rule differs from the "
+"attribute syntax of attributes for which this is the equality "
+"matching rule. "
+"The rule evaluates to TRUE if and only if the assertion value matches "
+"the first component of the attribute value using the rules of "
+"caseIgnoreMatch.", DIRSTRING_SYNTAX_OID, 0, dirStringCompat_syntaxes}, /* matching rule desc */
+ {"directoryStringFirstComponentMatch-mr", VENDOR, DS_PACKAGE_VERSION, "directoryStringFirstComponentMatch matching rule plugin"}, /* plugin desc */
+   directoryStringFirstComponentMatch_names, /* matching rule name/oid/aliases */
+   NULL, NULL, cis_filter_ava, NULL, cis_values2keys,
+   cis_assertion2keys_ava, NULL, NULL},
+{{"2.5.13.30", NULL, "objectIdentifierFirstComponentMatch",
+"The objectIdentifierFirstComponentMatch rule compares an assertion "
+"value of the OID syntax to an attribute value of a syntax (e.g., the "
+"Attribute Type Description, DIT Content Rule Description, LDAP Syntax "
+"Description, Matching Rule Description, Matching Rule Use "
+"Description, Name Form Description, or Object Class Description "
+"syntax) whose corresponding ASN.1 type is a SEQUENCE with a mandatory "
+"first component of the OBJECT IDENTIFIER ASN.1 type. "
+"Note that the assertion syntax of this matching rule differs from the "
+"attribute syntax of attributes for which this is the equality "
+"matching rule. "
+"The rule evaluates to TRUE if and only if the assertion value matches "
+"the first component of the attribute value using the rules of "
+"objectIdentifierMatch.", OID_SYNTAX_OID, 0, objectIdentifierFirstComponentMatch_syntaxes}, /* matching rule desc */
+ {"objectIdentifierFirstComponentMatch-mr", VENDOR, DS_PACKAGE_VERSION, "objectIdentifierFirstComponentMatch matching rule plugin"}, /* plugin desc */
+   objectIdentifierFirstComponentMatch_names, /* matching rule name/oid/aliases */
+   NULL, NULL, cis_filter_ava, NULL, cis_values2keys,
+   cis_assertion2keys_ava, NULL, NULL}
+};
+
+static size_t mr_plugin_table_size = sizeof(mr_plugin_table)/sizeof(mr_plugin_table[0]);
+
+static int
+matching_rule_plugin_init(Slapi_PBlock *pb)
+{
+	return syntax_matching_rule_plugin_init(pb, mr_plugin_table, mr_plugin_table_size);
+}
+
+static int
+register_matching_rule_plugins()
+{
+	return syntax_register_matching_rule_plugins(mr_plugin_table, mr_plugin_table_size, matching_rule_plugin_init);
+}
 
 /*
  * register_cis_like_plugin():  register all items for a cis-like plugin.
@@ -229,6 +461,7 @@ cis_init( Slapi_PBlock *pb )
 	LDAPDebug( LDAP_DEBUG_PLUGIN, "=> cis_init\n", 0, 0, 0 );
 	rc = register_cis_like_plugin( pb, &dirstring_pdesc, dirstring_names,
 		 	DIRSTRING_SYNTAX_OID, dirstring_validate );
+	rc |= register_matching_rule_plugins();
 	LDAPDebug( LDAP_DEBUG_PLUGIN, "<= cis_init %d\n", rc, 0, 0 );
 	return( rc );
 }
@@ -254,9 +487,6 @@ time_init( Slapi_PBlock *pb )
 	LDAPDebug( LDAP_DEBUG_PLUGIN, "=> time_init\n", 0, 0, 0 );
 	rc = register_cis_like_plugin( pb, &time_pdesc, time_names,
 			GENERALIZEDTIME_SYNTAX_OID, time_validate );
-	/* also register this plugin for matching rules */
-	rc |= slapi_matchingrule_register(&generalizedTimeMatch);
-	rc |= slapi_matchingrule_register(&generalizedTimeOrderingMatch);
 	LDAPDebug( LDAP_DEBUG_PLUGIN, "<= time_init %d\n", rc, 0, 0 );
 	return( rc );
 }
diff --git a/ldap/servers/plugins/syntaxes/dn.c b/ldap/servers/plugins/syntaxes/dn.c
index 9a41a05..092175a 100644
--- a/ldap/servers/plugins/syntaxes/dn.c
+++ b/ldap/servers/plugins/syntaxes/dn.c
@@ -65,6 +65,47 @@ static char *names[] = { "DN", DN_SYNTAX_OID, 0 };
 static Slapi_PluginDesc pdesc = { "dn-syntax", VENDOR,
 	DS_PACKAGE_VERSION, "distinguished name attribute syntax plugin" };
 
+static const char *distinguishedNameMatch_names[] = {"distinguishedNameMatch", "2.5.13.1", NULL};
+
+static struct mr_plugin_def mr_plugin_table[] = {
+{{"2.5.13.1", NULL, "distinguishedNameMatch", "The distinguishedNameMatch rule compares an assertion value of the DN "
+"syntax to an attribute value of a syntax (e.g., the DN syntax) whose "
+"corresponding ASN.1 type is DistinguishedName. "
+"The rule evaluates to TRUE if and only if the attribute value and the "
+"assertion value have the same number of relative distinguished names "
+"and corresponding relative distinguished names (by position) are the "
+"same.  A relative distinguished name (RDN) of the assertion value is "
+"the same as an RDN of the attribute value if and only if they have "
+"the same number of attribute value assertions and each attribute "
+"value assertion (AVA) of the first RDN is the same as the AVA of the "
+"second RDN with the same attribute type.  The order of the AVAs is "
+"not significant.  Also note that a particular attribute type may "
+"appear in at most one AVA in an RDN.  Two AVAs with the same "
+"attribute type are the same if their values are equal according to "
+"the equality matching rule of the attribute type.  If one or more of "
+"the AVA comparisons evaluate to Undefined and the remaining AVA "
+"comparisons return TRUE then the distinguishedNameMatch rule "
+"evaluates to Undefined.", DN_SYNTAX_OID, 0, NULL /* dn only for now */}, /* matching rule desc */
+ {"distinguishedNameMatch-mr", VENDOR, DS_PACKAGE_VERSION, "distinguishedNameMatch matching rule plugin"}, /* plugin desc */
+ distinguishedNameMatch_names, /* matching rule name/oid/aliases */
+ NULL, NULL, dn_filter_ava, NULL, dn_values2keys,
+ dn_assertion2keys_ava, NULL, NULL},
+};
+
+static size_t mr_plugin_table_size = sizeof(mr_plugin_table)/sizeof(mr_plugin_table[0]);
+
+static int
+matching_rule_plugin_init(Slapi_PBlock *pb)
+{
+	return syntax_matching_rule_plugin_init(pb, mr_plugin_table, mr_plugin_table_size);
+}
+
+static int
+register_matching_rule_plugins()
+{
+	return syntax_register_matching_rule_plugins(mr_plugin_table, mr_plugin_table_size, matching_rule_plugin_init);
+}
+
 int
 dn_init( Slapi_PBlock *pb )
 {
@@ -93,6 +134,7 @@ dn_init( Slapi_PBlock *pb )
 	rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_VALIDATE,
 	    (void *) dn_validate );
 
+	rc |= register_matching_rule_plugins();
 	LDAPDebug( LDAP_DEBUG_PLUGIN, "<= dn_init %d\n", rc, 0, 0 );
 	return( rc );
 }
diff --git a/ldap/servers/plugins/syntaxes/int.c b/ldap/servers/plugins/syntaxes/int.c
index ace9365..b3a7de0 100644
--- a/ldap/servers/plugins/syntaxes/int.c
+++ b/ldap/servers/plugins/syntaxes/int.c
@@ -65,16 +65,59 @@ static char *names[] = { "INTEGER", "int", INTEGER_SYNTAX_OID, 0 };
 static Slapi_PluginDesc pdesc = { "int-syntax", VENDOR,
 	DS_PACKAGE_VERSION, "integer attribute syntax plugin" };
 
-static Slapi_MatchingRuleEntry
-integerMatch = { INTEGERMATCH_OID, NULL /* no alias? */,
-                 "integerMatch", "The rule evaluates to TRUE if and only if the attribute value and the assertion value are the same integer value.",
-                 INTEGER_SYNTAX_OID, 0 /* not obsolete */ };
+static const char *integerMatch_names[] = {"integerMatch", INTEGERMATCH_OID, NULL};
+static const char *integerOrderingMatch_names[] = {"integerOrderingMatch", INTEGERORDERINGMATCH_OID, NULL};
+static const char *integerFirstComponentMatch_names[] = {"integerFirstComponentMatch", "2.5.13.29", NULL};
+
+/* hack for now until we can support all of the rfc4517 syntaxes */
+static char *integerFirstComponentMatch_syntaxes[] = {DIRSTRING_SYNTAX_OID, NULL};
+
+static struct mr_plugin_def mr_plugin_table[] = {
+{{INTEGERMATCH_OID, NULL /* no alias? */,
+  "integerMatch", "The rule evaluates to TRUE if and only if the attribute value and the assertion value are the same integer value.",
+  INTEGER_SYNTAX_OID, 0 /* not obsolete */, NULL /* no other compatible syntaxes */ },
+ {"integerMatch-mr", VENDOR, DS_PACKAGE_VERSION, "integerMatch matching rule plugin" },
+ integerMatch_names, /* matching rule name/oid/aliases */
+ NULL, NULL, int_filter_ava, NULL, int_values2keys,
+ int_assertion2keys, NULL, int_compare},
+{{INTEGERORDERINGMATCH_OID, NULL /* no alias? */,
+  "integerOrderingMatch", "The rule evaluates to TRUE if and only if the integer value of the attribute value is less than the integer value of the assertion value.",
+  INTEGER_SYNTAX_OID, 0 /* not obsolete */, NULL /* no other compatible syntaxes */ },
+ {"integerOrderingMatch-mr", VENDOR, DS_PACKAGE_VERSION, "integerOrderingMatch matching rule plugin" },
+ integerOrderingMatch_names, /* matching rule name/oid/aliases */
+ NULL, NULL, int_filter_ava, NULL, int_values2keys,
+ int_assertion2keys, NULL, int_compare},
+/* NOTE: THIS IS BROKEN - WE DON'T SUPPORT THE FIRSTCOMPONENT match */
+{{"2.5.13.29", NULL, "integerFirstComponentMatch", "The integerFirstComponentMatch rule compares an assertion value of "
+"the Integer syntax to an attribute value of a syntax (e.g., the DIT "
+"Structure Rule Description syntax) whose corresponding ASN.1 type is "
+"a SEQUENCE with a mandatory first component of the INTEGER ASN.1 "
+"type.  "
+"Note that the assertion syntax of this matching rule differs from the "
+"attribute syntax of attributes for which this is the equality "
+"matching rule.  "
+"The rule evaluates to TRUE if and only if the assertion value and the "
+"first component of the attribute value are the same integer value.",
+INTEGER_SYNTAX_OID, 0, integerFirstComponentMatch_syntaxes}, /* matching rule desc */
+ {"integerFirstComponentMatch-mr", VENDOR, DS_PACKAGE_VERSION, "integerFirstComponentMatch matching rule plugin"}, /* plugin desc */
+   integerFirstComponentMatch_names, /* matching rule name/oid/aliases */
+   NULL, NULL, int_filter_ava, NULL, int_values2keys,
+   int_assertion2keys, NULL, int_compare},
+};
+
+static size_t mr_plugin_table_size = sizeof(mr_plugin_table)/sizeof(mr_plugin_table[0]);
 
-static Slapi_MatchingRuleEntry
-integerOrderingMatch = { INTEGERORDERINGMATCH_OID, NULL /* no alias? */,
-                         "integerOrderingMatch", "The rule evaluates to TRUE if and only if the integer value of the attribute value is less than the integer value of the assertion value.",
-                         INTEGER_SYNTAX_OID, 0 /* not obsolete */ };
+static int
+matching_rule_plugin_init(Slapi_PBlock *pb)
+{
+	return syntax_matching_rule_plugin_init(pb, mr_plugin_table, mr_plugin_table_size);
+}
 
+static int
+register_matching_rule_plugins()
+{
+	return syntax_register_matching_rule_plugins(mr_plugin_table, mr_plugin_table_size, matching_rule_plugin_init);
+}
 
 int
 int_init( Slapi_PBlock *pb )
@@ -105,10 +148,7 @@ int_init( Slapi_PBlock *pb )
 	rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_VALIDATE,
 	    (void *) int_validate );
 
-	/* also register this plugin for matching rules */
-	rc |= slapi_matchingrule_register(&integerMatch);
-	rc |= slapi_matchingrule_register(&integerOrderingMatch);
-
+	rc |= register_matching_rule_plugins();
 	LDAPDebug( LDAP_DEBUG_PLUGIN, "<= int_init %d\n", rc, 0, 0 );
 	return( rc );
 }
diff --git a/ldap/servers/plugins/syntaxes/nameoptuid.c b/ldap/servers/plugins/syntaxes/nameoptuid.c
index b46ac53..8a76e05 100644
--- a/ldap/servers/plugins/syntaxes/nameoptuid.c
+++ b/ldap/servers/plugins/syntaxes/nameoptuid.c
@@ -66,6 +66,46 @@ static char *names[] = { "Name And Optional UID", "nameoptuid", NAMEANDOPTIONALU
 static Slapi_PluginDesc pdesc = { "nameoptuid-syntax", VENDOR, DS_PACKAGE_VERSION,
 	"Name And Optional UID attribute syntax plugin" };
 
+static const char *uniqueMemberMatch_names[] = {"uniqueMemberMatch", "2.5.13.23", NULL};
+static struct mr_plugin_def mr_plugin_table[] = {
+{{"2.5.13.23", NULL, "uniqueMemberMatch", "The uniqueMemberMatch rule compares an assertion value of the Name "
+"And Optional UID syntax to an attribute value of a syntax (e.g., the "
+"Name And Optional UID syntax) whose corresponding ASN.1 type is "
+"NameAndOptionalUID.  "
+"The rule evaluates to TRUE if and only if the <distinguishedName> "
+"components of the assertion value and attribute value match according "
+"to the distinguishedNameMatch rule and either, (1) the <BitString> "
+"component is absent from both the attribute value and assertion "
+"value, or (2) the <BitString> component is present in both the "
+"attribute value and the assertion value and the <BitString> component "
+"of the assertion value matches the <BitString> component of the "
+"attribute value according to the bitStringMatch rule.  "
+"Note that this matching rule has been altered from its description in "
+"X.520 [X.520] in order to make the matching rule commutative.  Server "
+"implementors should consider using the original X.520 semantics "
+"(where the matching was less exact) for approximate matching of "
+"attributes with uniqueMemberMatch as the equality matching rule.",
+NAMEANDOPTIONALUID_SYNTAX_OID, 0, NULL /* no other syntaxes supported */}, /* matching rule desc */
+ {"uniqueMemberMatch-mr", VENDOR, DS_PACKAGE_VERSION, "uniqueMemberMatch matching rule plugin"}, /* plugin desc */
+ uniqueMemberMatch_names, /* matching rule name/oid/aliases */
+ NULL, NULL, nameoptuid_filter_ava, NULL, nameoptuid_values2keys,
+ nameoptuid_assertion2keys_ava, NULL, nameoptuid_compare},
+};
+
+static size_t mr_plugin_table_size = sizeof(mr_plugin_table)/sizeof(mr_plugin_table[0]);
+
+static int
+matching_rule_plugin_init(Slapi_PBlock *pb)
+{
+	return syntax_matching_rule_plugin_init(pb, mr_plugin_table, mr_plugin_table_size);
+}
+
+static int
+register_matching_rule_plugins()
+{
+	return syntax_register_matching_rule_plugins(mr_plugin_table, mr_plugin_table_size, matching_rule_plugin_init);
+}
+
 int
 nameoptuid_init( Slapi_PBlock *pb )
 {
@@ -99,6 +139,7 @@ nameoptuid_init( Slapi_PBlock *pb )
 	rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_VALIDATE,
 	    (void *) nameoptuid_validate );
 
+	rc |= register_matching_rule_plugins();
 	LDAPDebug( LDAP_DEBUG_PLUGIN, "<= nameoptuid_init %d\n", rc, 0, 0 );
 	return( rc );
 }
diff --git a/ldap/servers/plugins/syntaxes/numericstring.c b/ldap/servers/plugins/syntaxes/numericstring.c
index acda9ac..d1bf475 100644
--- a/ldap/servers/plugins/syntaxes/numericstring.c
+++ b/ldap/servers/plugins/syntaxes/numericstring.c
@@ -49,10 +49,14 @@
 
 static int numstr_filter_ava( Slapi_PBlock *pb, struct berval *bvfilter,
 		Slapi_Value **bvals, int ftype, Slapi_Value **retVal );
+static int numstr_filter_sub( Slapi_PBlock *pb, char *initial, char **any,
+		char *final, Slapi_Value **bvals );
 static int numstr_values2keys( Slapi_PBlock *pb, Slapi_Value **val,
 		Slapi_Value ***ivals, int ftype );
 static int numstr_assertion2keys( Slapi_PBlock *pb, Slapi_Value *val,
 		Slapi_Value ***ivals, int ftype );
+static int numstr_assertion2keys_sub( Slapi_PBlock *pb, char *initial, char **any,
+		char *final, Slapi_Value ***ivals );
 static int numstr_compare(struct berval	*v1, struct berval	*v2);
 static int numstr_validate(struct berval *val);
 
@@ -61,36 +65,65 @@ static char *names[] = { "Numeric String", "numstr", NUMERICSTRING_SYNTAX_OID, 0
 
 #define NUMERICSTRINGMATCH_OID		"2.5.13.8"
 #define NUMERICSTRINGORDERINGMATCH_OID	"2.5.13.9"
-#define NUMERICSTRINGSUBSTRINGMATCH_OID	"2.5.13.10"
+#define NUMERICSTRINGSUBSTRINGSMATCH_OID	"2.5.13.10"
 
 static Slapi_PluginDesc pdesc = { "numstr-syntax", VENDOR,
 	DS_PACKAGE_VERSION, "numeric string attribute syntax plugin" };
 
-static Slapi_MatchingRuleEntry
-numericStringMatch = { NUMERICSTRINGMATCH_OID, NULL /* no alias? */,
-                 "numericStringMatch", "The rule evaluates to TRUE if and only if the prepared "
-                 "attribute value character string and the prepared assertion value character "
-                 "string have the same number of characters and corresponding characters have "
-                 "the same code point.",
-                 NUMERICSTRING_SYNTAX_OID, 0 /* not obsolete */ };
-
-static Slapi_MatchingRuleEntry
-numericStringOrderingMatch = { NUMERICSTRINGORDERINGMATCH_OID, NULL /* no alias? */,
-                 "numericStringOrderingMatch", "The rule evaluates to TRUE if and only if, "
-                 "in the code point collation order, the prepared attribute value character "
-                 "string appears earlier than the prepared assertion value character string; "
-                 "i.e., the attribute value is less than the assertion value.",
-                 NUMERICSTRING_SYNTAX_OID, 0 /* not obsolete */ };
-
-static Slapi_MatchingRuleEntry
-numericStringSubstringMatch = { NUMERICSTRINGSUBSTRINGMATCH_OID, NULL /* no alias? */,
-                 "numericStringSubstringMatch", "The rule evaluates to TRUE if and only if (1) "
-                 "the prepared substrings of the assertion value match disjoint portions of "
-                 "the prepared attribute value, (2) an initial substring, if present, matches "
-                 "the beginning of the prepared attribute value character string, and (3) a "
-                 "final substring, if present, matches the end of the prepared attribute value "
-                 "character string.",
-                 NUMERICSTRING_SYNTAX_OID, 0 /* not obsolete */ };
+static const char *numericStringMatch_names[] = {"numericStringMatch", NUMERICSTRINGMATCH_OID, NULL};
+static const char *numericStringOrderingMatch_names[] = {"numericStringOrderingMatch", NUMERICSTRINGORDERINGMATCH_OID, NULL};
+static const char *numericStringSubstringsMatch_names[] = {"numericStringSubstringsMatch", NUMERICSTRINGSUBSTRINGSMATCH_OID, NULL};
+
+static char *numericStringSubstringsMatch_syntaxes[] = {NUMERICSTRING_SYNTAX_OID,NULL};
+
+static struct mr_plugin_def mr_plugin_table[] = {
+{{NUMERICSTRINGMATCH_OID, NULL /* no alias? */,
+  "numericStringMatch", "The rule evaluates to TRUE if and only if the prepared "
+  "attribute value character string and the prepared assertion value character "
+  "string have the same number of characters and corresponding characters have "
+  "the same code point.",
+  NUMERICSTRING_SYNTAX_OID, 0 /* not obsolete */, NULL /* numstr syntax only for now */ },
+ {"numericStringMatch-mr", VENDOR, DS_PACKAGE_VERSION, "numericStringMatch matching rule plugin"}, /* plugin desc */
+ numericStringMatch_names, /* matching rule name/oid/aliases */
+ NULL, NULL, numstr_filter_ava, NULL, numstr_values2keys,
+ numstr_assertion2keys, NULL, numstr_compare},
+{{NUMERICSTRINGORDERINGMATCH_OID, NULL /* no alias? */,
+  "numericStringOrderingMatch", "The rule evaluates to TRUE if and only if, "
+  "in the code point collation order, the prepared attribute value character "
+  "string appears earlier than the prepared assertion value character string; "
+  "i.e., the attribute value is less than the assertion value.",
+  NUMERICSTRING_SYNTAX_OID, 0 /* not obsolete */, NULL /* numstr syntax only for now */ },
+ {"numericStringOrderingMatch-mr", VENDOR, DS_PACKAGE_VERSION, "numericStringOrderingMatch matching rule plugin"}, /* plugin desc */
+ numericStringOrderingMatch_names, /* matching rule name/oid/aliases */
+ NULL, NULL, numstr_filter_ava, NULL, numstr_values2keys,
+ numstr_assertion2keys, NULL, numstr_compare},
+{{NUMERICSTRINGSUBSTRINGSMATCH_OID, NULL /* no alias? */,
+  "numericStringSubstringsMatch", "The rule evaluates to TRUE if and only if (1) "
+  "the prepared substrings of the assertion value match disjoint portions of "
+  "the prepared attribute value, (2) an initial substring, if present, matches "
+  "the beginning of the prepared attribute value character string, and (3) a "
+  "final substring, if present, matches the end of the prepared attribute value "
+  "character string.",
+  "1.3.6.1.4.1.1466.115.121.1.58", 0 /* not obsolete */, numericStringSubstringsMatch_syntaxes}, /* matching rule desc */
+ {"numericStringSubstringsMatch-mr", VENDOR, DS_PACKAGE_VERSION, "numericStringSubstringsMatch matching rule plugin"}, /* plugin desc */
+ numericStringSubstringsMatch_names, /* matching rule name/oid/aliases */
+ NULL, NULL, NULL, numstr_filter_sub, numstr_values2keys,
+ NULL, numstr_assertion2keys_sub, numstr_compare},
+};
+
+static size_t mr_plugin_table_size = sizeof(mr_plugin_table)/sizeof(mr_plugin_table[0]);
+
+static int
+matching_rule_plugin_init(Slapi_PBlock *pb)
+{
+	return syntax_matching_rule_plugin_init(pb, mr_plugin_table, mr_plugin_table_size);
+}
+
+static int
+register_matching_rule_plugins()
+{
+	return syntax_register_matching_rule_plugins(mr_plugin_table, mr_plugin_table_size, matching_rule_plugin_init);
+}
 
 int
 numstr_init( Slapi_PBlock *pb )
@@ -121,11 +154,7 @@ numstr_init( Slapi_PBlock *pb )
 	rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_VALIDATE,
 	    (void *) numstr_validate );
 
-	/* also register this plugin for matching rules */
-	rc |= slapi_matchingrule_register(&numericStringMatch);
-	rc |= slapi_matchingrule_register(&numericStringOrderingMatch);
-	rc |= slapi_matchingrule_register(&numericStringSubstringMatch);
-
+	rc |= register_matching_rule_plugins();
 	LDAPDebug( LDAP_DEBUG_PLUGIN, "<= numstr_init %d\n", rc, 0, 0 );
 	return( rc );
 }
@@ -139,6 +168,18 @@ numstr_filter_ava( Slapi_PBlock *pb, struct berval *bvfilter,
 }
 
 static int
+numstr_filter_sub(
+    Slapi_PBlock		*pb,
+    char		*initial,
+    char		**any,
+    char		*final,
+    Slapi_Value	**bvals
+)
+{
+	return( string_filter_sub( pb, initial, any, final, bvals, SYNTAX_SI | SYNTAX_CES ) );
+}
+
+static int
 numstr_values2keys( Slapi_PBlock *pb, Slapi_Value **vals, Slapi_Value ***ivals, int ftype )
 {
 	return( string_values2keys( pb, vals, ivals, SYNTAX_SI | SYNTAX_CES,
@@ -152,6 +193,19 @@ numstr_assertion2keys( Slapi_PBlock *pb, Slapi_Value *val, Slapi_Value ***ivals,
                                       SYNTAX_SI | SYNTAX_CES, ftype ));
 }
 
+static int
+numstr_assertion2keys_sub(
+    Slapi_PBlock		*pb,
+    char		*initial,
+    char		**any,
+    char		*final,
+    Slapi_Value	***ivals
+)
+{
+	return( string_assertion2keys_sub( pb, initial, any, final, ivals,
+	    SYNTAX_SI | SYNTAX_CES ) );
+}
+
 static int numstr_compare(    
 	struct berval	*v1,
 	struct berval	*v2
diff --git a/ldap/servers/plugins/syntaxes/syntax.h b/ldap/servers/plugins/syntaxes/syntax.h
index 4007028..ec3d5f0 100644
--- a/ldap/servers/plugins/syntaxes/syntax.h
+++ b/ldap/servers/plugins/syntaxes/syntax.h
@@ -61,10 +61,6 @@
 #define SUBMIDDLE	3
 #define SUBEND		3
 
-#ifndef MIN
-#define MIN( a, b )	(a < b ? a : b )
-#endif
-
 #define SYNTAX_PLUGIN_SUBSYSTEM "syntax-plugin"
 
 /* The following are derived from RFC 4512, section 1.4. */
@@ -131,4 +127,56 @@ int distinguishedname_validate( const char *begin, const char *end );
 int rdn_validate( const char *begin, const char *end, const char **last );
 int bitstring_validate_internal(const char *begin, const char *end);
 
+struct mr_plugin_def {
+    Slapi_MatchingRuleEntry mr_def_entry; /* for slapi_matchingrule_register */
+    Slapi_PluginDesc mr_plg_desc; /* for SLAPI_PLUGIN_DESCRIPTION */
+    const char **mr_names; /* list of oid and names, NULL terminated SLAPI_PLUGIN_MR_NAMES */
+    /* these are optional for new style mr plugins */
+    IFP	mr_filter_create; /* old style factory function SLAPI_PLUGIN_MR_FILTER_CREATE_FN */
+    IFP	mr_indexer_create; /* old style factory function SLAPI_PLUGIN_MR_INDEXER_CREATE_FN */
+    /* new style syntax plugin functions */
+    /* not all functions will apply to all matching rule types */
+    /* e.g. a SUBSTR rule will not have a filter_ava func */
+    IFP	mr_filter_ava; /* SLAPI_PLUGIN_MR_FILTER_AVA */
+    IFP	mr_filter_sub; /* SLAPI_PLUGIN_MR_FILTER_SUB */
+    IFP	mr_values2keys; /* SLAPI_PLUGIN_MR_VALUES2KEYS */
+    IFP	mr_assertion2keys_ava; /* SLAPI_PLUGIN_MR_ASSERTION2KEYS_AVA */
+    IFP	mr_assertion2keys_sub; /* SLAPI_PLUGIN_MR_ASSERTION2KEYS_SUB */
+    IFP	mr_compare; /* SLAPI_PLUGIN_MR_COMPARE - only for ORDERING */
+};
+
+int syntax_register_matching_rule_plugins(struct mr_plugin_def mr_plugin_table[], size_t mr_plugin_table_size, IFP matching_rule_plugin_init);
+int syntax_matching_rule_plugin_init(Slapi_PBlock *pb, struct mr_plugin_def mr_plugin_table[], size_t mr_plugin_table_size);
+
 #endif
+
+#ifdef UNSUPPORTED_MATCHING_RULES
+/* list of names/oids/aliases for each matching rule */
+static const char *keywordMatch_names[] = {"keywordMatch", "2.5.13.33", NULL};
+static const char *wordMatch_names[] = {"wordMatch", "2.5.13.32", NULL};
+/* table of matching rule plugin defs for mr register and plugin register */
+static struct mr_plugin_def mr_plugin_table[] = {
+{{"2.5.13.33", NULL, "keywordMatch", "The keywordMatch rule compares an assertion value of the Directory"
+"String syntax to an attribute value of a syntax (e.g., the Directory"
+"String syntax) whose corresponding ASN.1 type is DirectoryString."
+"The rule evaluates to TRUE if and only if the assertion value"
+"character string matches any keyword in the attribute value.  The"
+"identification of keywords in the attribute value and the exactness"
+"of the match are both implementation specific.", "1.3.6.1.4.1.1466.115.121.1.15", 0}, /* matching rule desc */
+ {"keywordMatch-mr", VENDOR, DS_PACKAGE_VERSION, "keywordMatch matching rule plugin"}, /* plugin desc */
+   keywordMatch_names, /* matching rule name/oid/aliases */
+   NULL, NULL, mr_filter_ava, mr_filter_sub, mr_values2keys,
+   mr_assertion2keys_ava, mr_assertion2keys_sub, mr_compare, keywordMatch_syntaxes},,
+{{"2.5.13.32", NULL, "wordMatch", "The wordMatch rule compares an assertion value of the Directory"
+"String syntax to an attribute value of a syntax (e.g., the Directory"
+"String syntax) whose corresponding ASN.1 type is DirectoryString."
+"The rule evaluates to TRUE if and only if the assertion value word"
+"matches, according to the semantics of caseIgnoreMatch, any word in"
+"the attribute value.  The precise definition of a word is"
+"implementation specific.", "1.3.6.1.4.1.1466.115.121.1.15", 0}, /* matching rule desc */
+ {"wordMatch-mr", VENDOR, DS_PACKAGE_VERSION, "wordMatch matching rule plugin"}, /* plugin desc */
+   wordMatch_names, /* matching rule name/oid/aliases */
+   NULL, NULL, mr_filter_ava, mr_filter_sub, mr_values2keys,
+   mr_assertion2keys_ava, mr_assertion2keys_sub, mr_compare, wordMatch_syntaxes},
+};
+#endif /* UNSUPPORTED_MATCHING_RULES */
diff --git a/ldap/servers/plugins/syntaxes/syntax_common.c b/ldap/servers/plugins/syntaxes/syntax_common.c
new file mode 100644
index 0000000..713d9a0
--- /dev/null
+++ b/ldap/servers/plugins/syntaxes/syntax_common.c
@@ -0,0 +1,117 @@
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ * 
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ * 
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception. 
+ * 
+ * 
+ * Copyright (C) 2010 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "syntax.h"
+
+int
+syntax_register_matching_rule_plugins(
+	struct mr_plugin_def mr_plugin_table[],
+	size_t mr_plugin_table_size,
+	IFP matching_rule_plugin_init
+)
+{
+	int rc = -1;
+	int ii;
+
+	for (ii = 0; ii < mr_plugin_table_size; ++ii) {
+		char *argv[2];
+
+		argv[0] = mr_plugin_table[ii].mr_def_entry.mr_name;
+		argv[1] = NULL;
+		rc = slapi_register_plugin_ext("matchingrule", 1 /* enabled */,
+									   "matching_rule_plugin_init",
+									   matching_rule_plugin_init,
+									   mr_plugin_table[ii].mr_def_entry.mr_name,
+									   argv, NULL, PLUGIN_DEFAULT_PRECEDENCE);
+	}
+
+	return rc;
+}
+
+int
+syntax_matching_rule_plugin_init(
+	Slapi_PBlock *pb,
+	struct mr_plugin_def mr_plugin_table[],
+	size_t mr_plugin_table_size
+)
+{
+	int ii;
+	char **argv = NULL;
+	int rc = -1;
+	struct mr_plugin_def *mrpd = NULL;
+
+	slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv);
+	if (!argv || !argv[0]) {
+		slapi_log_error(SLAPI_LOG_FATAL, "syntax_matching_rule_plugin_init",
+						"Error: matching rule plugin name not specified\n");
+		return rc;
+	}
+	for (ii = 0; ii < mr_plugin_table_size; ++ii) {
+		/* get the arguments - argv[0] is our plugin name */
+		/* find the plugin name in the table */
+		if (!strcmp(mr_plugin_table[ii].mr_def_entry.mr_name, argv[0])) {
+			mrpd = &mr_plugin_table[ii];
+			rc = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01);
+			rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, &mrpd->mr_plg_desc);
+			rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_MR_FILTER_CREATE_FN, mrpd->mr_filter_create);
+			rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_MR_INDEXER_CREATE_FN, mrpd->mr_indexer_create);
+			rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_MR_FILTER_AVA, mrpd->mr_filter_ava);
+			rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_MR_FILTER_SUB, mrpd->mr_filter_sub);
+			rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_MR_VALUES2KEYS, mrpd->mr_values2keys);
+			rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_MR_ASSERTION2KEYS_AVA, mrpd->mr_assertion2keys_ava);
+			rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_MR_ASSERTION2KEYS_SUB, mrpd->mr_assertion2keys_sub);
+			rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_MR_NAMES, mrpd->mr_names);
+			rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_MR_COMPARE, mrpd->mr_compare);
+			break;
+		}
+	}
+
+	if (!mrpd) {
+		slapi_log_error(SLAPI_LOG_FATAL, "syntax_matching_rule_plugin_init",
+						"Error: matching rule plugin name [%s] not found\n",
+						argv[0]);
+	} else {
+		rc = slapi_matchingrule_register(&mrpd->mr_def_entry);
+	}
+
+	return rc;
+}
+
diff --git a/ldap/servers/plugins/syntaxes/tel.c b/ldap/servers/plugins/syntaxes/tel.c
index 8c74908..10c7ced 100644
--- a/ldap/servers/plugins/syntaxes/tel.c
+++ b/ldap/servers/plugins/syntaxes/tel.c
@@ -66,6 +66,67 @@ static char *names[] = { "TelephoneNumber", "tel", TELEPHONE_SYNTAX_OID, 0 };
 static Slapi_PluginDesc pdesc = { "tele-syntax", VENDOR, DS_PACKAGE_VERSION,
 	"telephoneNumber attribute syntax plugin" };
 
+static const char *telephoneNumberMatch_names[] = {"telephoneNumberMatch", "2.5.13.20", NULL};
+static const char *telephoneNumberSubstringsMatch_names[] = {"telephoneNumberSubstringsMatch", "2.5.13.21", NULL};
+
+static char *telephoneNumberSubstringsMatch_syntaxes[] = {TELEPHONE_SYNTAX_OID, NULL};
+
+static struct mr_plugin_def mr_plugin_table[] = {
+{{"2.5.13.20", NULL, "telephoneNumberMatch", "The telephoneNumberMatch rule compares an assertion value of the "
+"Telephone Number syntax to an attribute value of a syntax (e.g., the "
+"Telephone Number syntax) whose corresponding ASN.1 type is a "
+"PrintableString representing a telephone number. "
+"The rule evaluates to TRUE if and only if the prepared attribute "
+"value character string and the prepared assertion value character "
+"string have the same number of characters and corresponding "
+"characters have the same code point. "
+"In preparing the attribute value and assertion value for comparison, "
+"characters are case folded in the Map preparation step, and only "
+"telephoneNumber Insignificant Character Handling is applied in the "
+"Insignificant Character Handling step.",
+TELEPHONE_SYNTAX_OID, 0, NULL /* tel syntax only */}, /* matching rule desc */
+ {"telephoneNumberMatch-mr", VENDOR, DS_PACKAGE_VERSION, "telephoneNumberMatch matching rule plugin"}, /* plugin desc */
+ telephoneNumberMatch_names, /* matching rule name/oid/aliases */
+ NULL, NULL, tel_filter_ava, NULL, tel_values2keys,
+ tel_assertion2keys_ava, NULL, tel_compare},
+{{"2.5.13.21", NULL, "telephoneNumberSubstringsMatch", "The telephoneNumberSubstringsMatch rule compares an assertion value "
+"of the Substring Assertion syntax to an attribute value of a syntax "
+"(e.g., the Telephone Number syntax) whose corresponding ASN.1 type is "
+"a PrintableString representing a telephone number. "
+"The rule evaluates to TRUE if and only if (1) the prepared substrings "
+"of the assertion value match disjoint portions of the prepared "
+"attribute value character string in the order of the substrings in "
+"the assertion value, (2) an <initial> substring, if present, matches "
+"the beginning of the prepared attribute value character string, and "
+"(3) a <final> substring, if present, matches the end of the prepared "
+"attribute value character string.  A prepared substring matches a "
+"portion of the prepared attribute value character string if "
+"corresponding characters have the same code point. "
+"In preparing the attribute value and assertion value substrings for "
+"comparison, characters are case folded in the Map preparation step, "
+"and only telephoneNumber Insignificant Character Handling is applied "
+"in the Insignificant Character Handling step.",
+"1.3.6.1.4.1.1466.115.121.1.58", 0, telephoneNumberSubstringsMatch_syntaxes}, /* matching rule desc */
+ {"telephoneNumberSubstringsMatch-mr", VENDOR, DS_PACKAGE_VERSION, "telephoneNumberSubstringsMatch matching rule plugin"}, /* plugin desc */
+ telephoneNumberSubstringsMatch_names, /* matching rule name/oid/aliases */
+ NULL, NULL, NULL, tel_filter_sub, tel_values2keys,
+ NULL, tel_assertion2keys_sub, tel_compare},
+};
+
+static size_t mr_plugin_table_size = sizeof(mr_plugin_table)/sizeof(mr_plugin_table[0]);
+
+static int
+matching_rule_plugin_init(Slapi_PBlock *pb)
+{
+	return syntax_matching_rule_plugin_init(pb, mr_plugin_table, mr_plugin_table_size);
+}
+
+static int
+register_matching_rule_plugins()
+{
+	return syntax_register_matching_rule_plugins(mr_plugin_table, mr_plugin_table_size, matching_rule_plugin_init);
+}
+
 int
 tel_init( Slapi_PBlock *pb )
 {
@@ -99,6 +160,7 @@ tel_init( Slapi_PBlock *pb )
 	rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_VALIDATE,
 	    (void *) tel_validate );
 
+	rc |= register_matching_rule_plugins();
 	LDAPDebug( LDAP_DEBUG_PLUGIN, "<= tel_init %d\n", rc, 0, 0 );
 	return( rc );
 }
diff --git a/ldap/servers/slapd/attrsyntax.c b/ldap/servers/slapd/attrsyntax.c
index 11b272a..f39c0e9 100644
--- a/ldap/servers/slapd/attrsyntax.c
+++ b/ldap/servers/slapd/attrsyntax.c
@@ -546,6 +546,9 @@ attr_syntax_dup( struct asyntaxinfo *a )
 	newas->asi_flags = a->asi_flags;
 	newas->asi_oid = slapi_ch_strdup( a->asi_oid);
 	newas->asi_syntaxlength = a->asi_syntaxlength;
+	newas->asi_mr_eq_plugin = a->asi_mr_eq_plugin;
+	newas->asi_mr_ord_plugin = a->asi_mr_ord_plugin;
+	newas->asi_mr_sub_plugin = a->asi_mr_sub_plugin;
 
 	return( newas );
 }
@@ -658,9 +661,11 @@ attr_syntax_create(
 {
 	char					*s;
 	struct asyntaxinfo		a;
+	int rc = LDAP_SUCCESS;
 
 	/* XXXmcs: had to cast away const in many places below */
 	memset(&a, 0, sizeof(a));
+	*asip = NULL;
 	a.asi_name = slapi_ch_strdup(attr_names[0]);
 	if ( NULL != attr_names[1] ) {
 		a.asi_aliases = (char **)&attr_names[1]; /* all but the zero'th element */
@@ -674,8 +679,45 @@ attr_syntax_create(
 	a.asi_origin = (char **)attr_origins;
 	a.asi_plugin = plugin_syntax_find( attr_syntax );
 	a.asi_syntaxlength = syntaxlength;
+	/* ideally, we would report an error and fail to start if there was some problem
+	   with the matching rule - but since this functionality is new, and we might
+	   cause havoc if lots of servers failed to start because of bogus schema, we
+	   just report an error here - at some point in the future, we should actually
+	   report an error and exit, or allow the user to control the behavior - for
+	   now, just log an error, and address each case
+	*/
+	if (mr_equality && !slapi_matchingrule_is_compat(mr_equality, attr_syntax)) {
+		slapi_log_error(SLAPI_LOG_FATAL, "attr_syntax_create",
+						"Error: the EQUALITY matching rule [%s] is not compatible "
+						"with the syntax [%s] for the attribute [%s]\n",
+						mr_equality, attr_syntax, attr_names[0]);
+/*
+		rc = LDAP_INAPPROPRIATE_MATCHING;
+		goto done;
+*/
+	}
 	a.asi_mr_eq_plugin = plugin_mr_find( mr_equality );
+	if (mr_ordering && !slapi_matchingrule_is_compat(mr_ordering, attr_syntax)) {
+		slapi_log_error(SLAPI_LOG_FATAL, "attr_syntax_create",
+						"Error: the ORDERING matching rule [%s] is not compatible "
+						"with the syntax [%s] for the attribute [%s]\n",
+						mr_ordering, attr_syntax, attr_names[0]);
+/*
+		rc = LDAP_INAPPROPRIATE_MATCHING;
+		goto done;
+*/
+	}
 	a.asi_mr_ord_plugin = plugin_mr_find( mr_ordering );
+	if (mr_substring && !slapi_matchingrule_is_compat(mr_substring, attr_syntax)) {
+		slapi_log_error(SLAPI_LOG_FATAL, "attr_syntax_create",
+						"Error: the SUBSTR matching rule [%s] is not compatible "
+						"with the syntax [%s] for the attribute [%s]\n",
+						mr_substring, attr_syntax, attr_names[0]);
+/*
+		rc = LDAP_INAPPROPRIATE_MATCHING;
+		goto done;
+*/
+	}
 	a.asi_mr_sub_plugin = plugin_mr_find( mr_substring );
 	a.asi_flags = flags;
 
@@ -694,9 +736,10 @@ attr_syntax_create(
 	}
 
 	*asip = attr_syntax_dup(&a);
+done:
 	slapi_ch_free((void **)&a.asi_name);
 
-	return LDAP_SUCCESS;
+	return rc;
 }
 
 
diff --git a/ldap/servers/slapd/match.c b/ldap/servers/slapd/match.c
index 24d9137..241b182 100644
--- a/ldap/servers/slapd/match.c
+++ b/ldap/servers/slapd/match.c
@@ -182,6 +182,7 @@ slapi_matchingrule_free(Slapi_MatchingRuleEntry **mrEntry,
 	slapi_ch_free((void **)&((*mrEntry)->mr_desc));
 	slapi_ch_free((void **)&((*mrEntry)->mr_syntax));
 	slapi_ch_free((void **)&((*mrEntry)->mr_oidalias));
+	slapi_ch_array_free((*mrEntry)->mr_compat_syntax);
     }
     slapi_ch_free((void **)mrEntry);
     return;
@@ -244,6 +245,7 @@ int slapi_matchingrule_register(Slapi_MatchingRuleEntry *mrule)
 	    slapi_ch_strdup((char *) mrule->mr_syntax);
     }
     newmrl->mr_entry->mr_obsolete = mrule->mr_obsolete;
+    newmrl->mr_entry->mr_compat_syntax = charray_dup(mrule->mr_compat_syntax);
 
     for(mrl = g_get_global_mrl();
         ((NULL != mrl) && (NULL != mrl->mrl_next));
@@ -277,18 +279,57 @@ int slapi_matchingrule_unregister(char *oid)
 int slapi_matchingrule_is_ordering(const char *oid_or_name, const char *syntax_oid)
 {
     struct matchingRuleList *mrl=NULL;
+
+    if (slapi_matchingrule_is_compat(oid_or_name, syntax_oid)) {
+        for (mrl = g_get_global_mrl(); mrl != NULL; mrl = mrl->mrl_next) {
+            if (mrl->mr_entry->mr_name && !strcasecmp(oid_or_name, mrl->mr_entry->mr_name)) {
+                return (mrl->mr_entry->mr_name &&
+                        PL_strcasestr(mrl->mr_entry->mr_name, "ordering"));
+            }
+            if (mrl->mr_entry->mr_oid && !strcmp(oid_or_name, mrl->mr_entry->mr_oid)) {
+                return (mrl->mr_entry->mr_name &&
+                        PL_strcasestr(mrl->mr_entry->mr_name, "ordering"));
+            }
+        }
+    }
+
+    return 0;
+}
+
+/*
+  See if a matching rule for this name or OID
+  is compatible with the given syntax.
+*/
+int slapi_matchingrule_is_compat(const char *mr_oid_or_name, const char *syntax_oid)
+{
+    struct matchingRuleList *mrl=NULL;
+    int found = 0;
+
     for (mrl = g_get_global_mrl(); mrl != NULL; mrl = mrl->mrl_next) {
-        if (mrl->mr_entry->mr_name && !strcasecmp(oid_or_name, mrl->mr_entry->mr_name)) {
-            return (mrl->mr_entry->mr_name &&
-                    PL_strcasestr(mrl->mr_entry->mr_name, "ordering") &&
-                    !strcmp(mrl->mr_entry->mr_syntax, syntax_oid));
+        if (mrl->mr_entry->mr_name && !strcasecmp(mr_oid_or_name, mrl->mr_entry->mr_name)) {
+            found = 1;
+            break;
+        }
+        if (mrl->mr_entry->mr_oid && !strcmp(mr_oid_or_name, mrl->mr_entry->mr_oid)) {
+            found = 1;
+            break;
+        }
+    }
+
+    if (found && mrl) {
+        char **mr_syntax;
+        if (!strcmp(mrl->mr_entry->mr_syntax, syntax_oid)) {
+            return 1;
         }
-        if (mrl->mr_entry->mr_oid && !strcmp(oid_or_name, mrl->mr_entry->mr_oid)) {
-            return (mrl->mr_entry->mr_name &&
-                    PL_strcasestr(mrl->mr_entry->mr_name, "ordering") &&
-                    !strcmp(mrl->mr_entry->mr_syntax, syntax_oid));
+        for (mr_syntax = mrl->mr_entry->mr_compat_syntax;
+             mr_syntax;
+             mr_syntax++) {
+            if (!strcmp(*mr_syntax, syntax_oid)) {
+                return 1;
+            }
         }
     }
+            
 
     return 0;
 }
diff --git a/ldap/servers/slapd/plugin_mr.c b/ldap/servers/slapd/plugin_mr.c
index b8b0499..194f8ae 100644
--- a/ldap/servers/slapd/plugin_mr.c
+++ b/ldap/servers/slapd/plugin_mr.c
@@ -94,21 +94,30 @@ slapi_get_global_mr_plugins()
 struct slapdplugin *
 plugin_mr_find( const char *nameoroid )
 {
-	struct slapdplugin	*pi;
+	struct slapdplugin	*pi = NULL;
 
-	for ( pi = get_plugin_list(PLUGIN_LIST_MATCHINGRULE); pi != NULL; pi = pi->plg_next ) {
+	for ( pi = get_plugin_list(PLUGIN_LIST_MATCHINGRULE); (nameoroid != NULL) && (pi != NULL); pi = pi->plg_next ) {
 		if ( charray_inlist( pi->plg_mr_names, (char *)nameoroid ) ) {
 			break;
 		}
 	}
+
+	if (!nameoroid) {
+		pi = NULL;
+	}
+
+	if (nameoroid && !pi) {
+		slapi_log_error(SLAPI_LOG_CONFIG, "plugin_mr_find",
+						"Error: matching rule plugin for [%s] not found\n", nameoroid);
+	}
+
 	return ( pi );
 }
 
 static int
-plugin_mr_get_type(struct slapdplugin *pi, int *ordering)
+plugin_mr_get_type(struct slapdplugin *pi)
 {
 	int rc = LDAP_FILTER_EQUALITY;
-	*ordering = 0;
 	if (pi) {
 		char **str = pi->plg_mr_names;
 		for (; str && *str; ++str) {
@@ -121,7 +130,7 @@ plugin_mr_get_type(struct slapdplugin *pi, int *ordering)
 				break;
 			}
 			if (PL_strcasestr(*str, "ordering")) {
-				*ordering = 1;
+				rc = LDAP_FILTER_GE;
 				break;
 			}
 		}
@@ -249,7 +258,8 @@ mr_private_indexer_done(struct mr_private *mrpriv)
 {
 	if (mrpriv && mrpriv->sva) {
 		valuearray_free(&mrpriv->sva);
-	} else if (mrpriv && mrpriv->bva) {
+	}
+	if (mrpriv && mrpriv->bva) {
 		ber_bvecfree(mrpriv->bva);
 		mrpriv->bva = NULL;
 	}
@@ -301,9 +311,8 @@ mr_wrap_mr_index_sv_fn(Slapi_PBlock* pb)
 	} else if (!pi->plg_mr_values2keys) {
 		LDAPDebug0Args(LDAP_DEBUG_ANY, "mr_wrap_mr_index_sv_fn: error - plugin has no plg_mr_values2keys function\n");
 	} else {
-		int ordering = 0;
 		struct mr_private *mrpriv = NULL;
-		int ftype = plugin_mr_get_type(pi, &ordering);
+		int ftype = plugin_mr_get_type(pi);
 		slapi_pblock_get(pb, SLAPI_PLUGIN_MR_VALUES, &in_vals);
 		(*pi->plg_mr_values2keys)(pb, in_vals, &out_vals, ftype);
 		slapi_pblock_set(pb, SLAPI_PLUGIN_MR_KEYS, out_vals);
@@ -334,15 +343,22 @@ mr_wrap_mr_index_fn(Slapi_PBlock* pb)
 	valuearray_init_bervalarray(in_vals, &in_vals_sv);
 	slapi_pblock_set(pb, SLAPI_PLUGIN_MR_VALUES, in_vals_sv); /* use sv */
 	rc = mr_wrap_mr_index_sv_fn(pb);
+	/* clean up in_vals_sv */
+	valuearray_free(&in_vals_sv);
+	/* restore old in_vals */
+	slapi_pblock_set(pb, SLAPI_PLUGIN_MR_VALUES, in_vals);
 	/* get result sv keys */
 	slapi_pblock_get(pb, SLAPI_PLUGIN_MR_KEYS, &out_vals_sv);
 	/* convert to bvec */
 	valuearray_get_bervalarray(out_vals_sv, &out_vals);
-	valuearray_free(&out_vals_sv); /* don't need svals */
+	/* NOTE: mrpriv owns out_vals_sv (mpriv->sva) - will
+	   get freed by mr_private_indexer_done() */
 	/* we have to save out_vals to free next time or during destroy */
 	slapi_pblock_get(pb, SLAPI_PLUGIN_OBJECT, &mrpriv);
 	mr_private_indexer_done(mrpriv); /* free old vals, if any */
 	mrpriv->bva = out_vals; /* save pointer for later */
+	/* set return value berval array for caller */
+	slapi_pblock_set(pb, SLAPI_PLUGIN_MR_KEYS, out_vals);
 
 	return rc;
 }
@@ -396,8 +412,8 @@ default_mr_filter_index(Slapi_PBlock *pb)
 
 	slapi_pblock_get(pb, SLAPI_PLUGIN_OBJECT, &mrpriv);
 
-	slapi_pblock_set(pb, SLAPI_PLUGIN, mrpriv->pi);
-	slapi_pblock_set(pb, SLAPI_PLUGIN_MR_TYPE, mrpriv->type);
+	slapi_pblock_set(pb, SLAPI_PLUGIN, (void *)mrpriv->pi);
+	slapi_pblock_set(pb, SLAPI_PLUGIN_MR_TYPE, (void *)mrpriv->type);
 	/* extensible_candidates uses struct berval ** indexer */
 	slapi_pblock_set(pb, SLAPI_PLUGIN_MR_INDEX_FN, mr_wrap_mr_index_fn);
 	slapi_pblock_set(pb, SLAPI_PLUGIN_MR_VALUES, mrpriv->values);
@@ -405,7 +421,7 @@ default_mr_filter_index(Slapi_PBlock *pb)
 	   is the indextype value passed to index_index2prefix - it must be the
 	   same OID as used in the index configuration for the index matching
 	   rule */
-	slapi_pblock_set(pb, SLAPI_PLUGIN_MR_OID, mrpriv->oid);
+	slapi_pblock_set(pb, SLAPI_PLUGIN_MR_OID, (void *)mrpriv->oid);
 	slapi_pblock_set(pb, SLAPI_PLUGIN_MR_QUERY_OPERATOR, &mrpriv->op);
 
 	return rc;
@@ -427,23 +443,27 @@ default_mr_filter_create(Slapi_PBlock *pb)
 		!slapi_pblock_get(pb, SLAPI_PLUGIN_MR_VALUE, &mrVALUE) && mrVALUE != NULL &&
 		!slapi_pblock_get(pb, SLAPI_PLUGIN, &pi) && pi != NULL) {
 		int op = SLAPI_OP_EQUAL;
-		int ordering = 0;
 		struct mr_private *mrpriv = NULL;
+		int ftype = 0;
 
 		LDAPDebug2Args(LDAP_DEBUG_FILTER, "=> default_mr_filter_create(oid %s; type %s)\n",
 					   mrOID, mrTYPE);
 
-		int ftype = plugin_mr_get_type(pi, &ordering);
+		ftype = plugin_mr_get_type(pi);
 		/* map the ftype to the op type */
-		if (ftype == LDAP_FILTER_EQUALITY) {
-			if (ordering) { /* not sure what to do here - default to GE */
-				op = SLAPI_OP_GREATER_OR_EQUAL;
-			}
+		if (ftype == LDAP_FILTER_GE) {
+			/*
+			 * The rule evaluates to TRUE if and only if, in the code point
+			 * collation order, the prepared attribute value character string
+			 * appears earlier than the prepared assertion value character string;
+			 * i.e., the attribute value is "less than" the assertion value.
+			 */
+			op = SLAPI_OP_LESS;
 /*
 		} else if (ftype == LDAP_FILTER_SUBSTRINGS) {
 			op = SLAPI_OP_SUBSTRING;
 */
-		} else { /* unsupported */
+		} else if (ftype != LDAP_FILTER_EQUALITY) { /* unsupported */
 			/* NOTE: we cannot currently support substring matching rules - the
 			   reason is that the API provides no way to pass in the search time limit
 			   required by the syntax filter substring match functions
@@ -498,7 +518,7 @@ default_mr_filter_create(Slapi_PBlock *pb)
 				  mrOID ? "" : " oid",
 				  mrTYPE ? "" : " attribute type",
 				  mrVALUE ? "" : " filter value");
-    }
+	}
 
 done:
 	LDAPDebug1Arg(LDAP_DEBUG_FILTER, "=> default_mr_filter_create: %d\n", rc);
@@ -526,6 +546,10 @@ attempt_mr_filter_create (mr_filter_t* f, struct slapdplugin* mrp, Slapi_PBlock*
 		    rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
 		}
     }
+    if (NULL == mrf_create) {
+	/* no create func - unavailable */
+	rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
+    }
     return rc;
 }
 
@@ -552,22 +576,22 @@ plugin_mr_filter_create (mr_filter_t* f)
 		    }
 		}
     }
-	if (rc)
-	{
+    if (rc)
+    {
 		/* look for a new syntax-style mr plugin */
 		mrp = plugin_mr_find(f->mrf_oid);
 		if (mrp)
 		{
-			/* set the default index create fn */
-			pblock_init(&pb);
-			slapi_pblock_set(&pb, SLAPI_PLUGIN, mrp);
-			slapi_pblock_set(&pb, SLAPI_PLUGIN_MR_FILTER_CREATE_FN, default_mr_filter_create);
+		    /* set the default index create fn */
+		    pblock_init(&pb);
+		    slapi_pblock_set(&pb, SLAPI_PLUGIN, mrp);
+		    slapi_pblock_set(&pb, SLAPI_PLUGIN_MR_FILTER_CREATE_FN, default_mr_filter_create);
 		    if (!(rc = attempt_mr_filter_create (f, mrp, &pb)))
 		    {
 				plugin_mr_bind (f->mrf_oid, mrp); /* for future reference */
-			}
+		    }
 		}
-	}
+    }
     if (!rc)
     {
 		/* This plugin has created the desired filter. */
@@ -586,7 +610,7 @@ slapi_mr_filter_index (Slapi_Filter* f, Slapi_PBlock* pb)
     int rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
     if (f->f_choice == LDAP_FILTER_EXTENDED && f->f_mr.mrf_index != NULL &&
 		!(rc = slapi_pblock_set (pb, SLAPI_PLUGIN_OBJECT, f->f_mr.mrf_object)))
-	{
+    {
 		rc = f->f_mr.mrf_index (pb);
     }
     return rc;
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index 5f0fc47..5f97c05 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -4466,12 +4466,13 @@ int slapi_berval_cmp(const struct berval* L, const struct berval* R);
         ! memcmp ((L)->bv_val, (R)->bv_val, (L)->bv_len))
 
 typedef struct slapi_matchingRuleEntry {
-    char *mr_oid;
-    char *mr_oidalias;
-    char *mr_name;
-    char *mr_desc;
-    char *mr_syntax;
-    int mr_obsolete;
+    char *mr_oid; /* the official oid */
+    char *mr_oidalias; /* not currently used */
+    char *mr_name; /* the official name */
+    char *mr_desc; /* a description */
+    char *mr_syntax; /* the assertion syntax OID */
+    int mr_obsolete; /* is mr obsolete? */
+    char **mr_compat_syntax; /* list of OIDs of other syntaxes that can use this matching rule */
 } slapi_matchingRuleEntry;
 typedef struct slapi_matchingRuleEntry	Slapi_MatchingRuleEntry;
 
@@ -4482,8 +4483,30 @@ int slapi_matchingrule_get(Slapi_MatchingRuleEntry *mr, int arg, void *value);
 int slapi_matchingrule_set(Slapi_MatchingRuleEntry *mr, int arg, void *value);
 int slapi_matchingrule_register(Slapi_MatchingRuleEntry *mrEntry);
 int slapi_matchingrule_unregister(char *oid);
+
+/**
+ * Is the given matching rule an ordering matching rule and is it
+ * compatible with the given syntax?
+ * 
+ * \param name_or_oid Name or OID of a matching rule
+ * \param syntax_oid OID of a syntax
+ * \return \c TRUE if the matching rule is an ordering rule and can be used by the given syntax
+ * \return \c FALSE otherwise 
+ */
 int slapi_matchingrule_is_ordering(const char *oid_or_name, const char *syntax_oid);
 
+/**
+ * Can the given syntax OID use the given matching rule name/OID? A
+ * matching rule can apply to more than one syntax.  Use this function
+ * to determine if the given syntax can use the given matching rule.
+ * 
+ * \param mr_name_or_oid Name or OID of a matching rule
+ * \param syntax_oid OID of a syntax
+ * \return \c TRUE if the syntax can be used with the matching rule
+ * \return \c FALSE otherwise 
+ */
+int slapi_matchingrule_is_compat(const char *mr_oid_or_name, const char *syntax_oid);
+
 /*
  * access control
  */


commit 6adbad044ef95411882ec546281a0df6d0816673
Author: Rich Megginson <rmeggins at redhat.com>
Date:   Wed Feb 10 14:49:03 2010 -0700

    change extensible filter code to use new syntax function style mr funcs
    
    Created wrappers around the new syntax style functions to make them look
    like the old style filter functions.  There are a few caveats:
    1) SUBSTRING extensible filter searches are not supported.  There is no
    way currently to pass in the timelimit required by the syntax substring
    filter functions.
    2) ORDERING only does greater than or equal.  There is no standard way to
    do an extensible match with a standard ordering matching rule and specify
    less than or greater than.

diff --git a/ldap/servers/slapd/filter.h b/ldap/servers/slapd/filter.h
index ad85b5f..a2d4117 100644
--- a/ldap/servers/slapd/filter.h
+++ b/ldap/servers/slapd/filter.h
@@ -58,7 +58,6 @@ typedef struct mr_filter_t {
     char*         mrf_type;
     struct berval mrf_value;
     char          mrf_dnAttrs;
-    struct slapdplugin* mrf_plugin;
     mrFilterMatchFn mrf_match;
     mrf_plugin_fn mrf_index;
     unsigned int  mrf_reusable; /* MRF_ANY_xxx */
diff --git a/ldap/servers/slapd/plugin_mr.c b/ldap/servers/slapd/plugin_mr.c
index 014082b..b8b0499 100644
--- a/ldap/servers/slapd/plugin_mr.c
+++ b/ldap/servers/slapd/plugin_mr.c
@@ -47,9 +47,28 @@
 
 #include "slap.h"
 
-struct mr_indexer_private {
+/* because extensible_candidates can call an indexing
+   operation in the middle of a filtering operation,
+   we have to use a structure that can be used by both
+   since we can only have 1 SLAPI_PLUGIN_OBJECT in
+   that case */
+struct mr_private {
 	Slapi_Value **sva; /* if using index_sv_fn */
 	struct berval **bva; /* if using index_fn */
+	/* if doing a purely indexing operation, the fields
+	   below are not used */
+	const struct slapdplugin *pi; /* our plugin */
+	const char *oid; /* orig oid */
+	const char *type; /* orig type from filter */
+	const struct berval *value; /* orig value from filter */
+	int ftype; /* filter type */
+	int op; /* query op type */
+	IFP match_fn; /* match func to use */
+	/* note - substring matching rules not currently supported */
+	char *initial; /* these are for substring matches */
+	char *any[2]; /* at most one value for extensible filter */
+	char *final; /* these are for substring matches */
+	const struct berval *values[2]; /* for indexing */
 };
 
 static oid_item_t* global_mr_oids = NULL;
@@ -86,9 +105,10 @@ plugin_mr_find( const char *nameoroid )
 }
 
 static int
-plugin_mr_get_type(struct slapdplugin *pi)
+plugin_mr_get_type(struct slapdplugin *pi, int *ordering)
 {
 	int rc = LDAP_FILTER_EQUALITY;
+	*ordering = 0;
 	if (pi) {
 		char **str = pi->plg_mr_names;
 		for (; str && *str; ++str) {
@@ -100,6 +120,10 @@ plugin_mr_get_type(struct slapdplugin *pi)
 				rc = LDAP_FILTER_APPROX;
 				break;
 			}
+			if (PL_strcasestr(*str, "ordering")) {
+				*ordering = 1;
+				break;
+			}
 		}
 	}
 
@@ -203,100 +227,59 @@ slapi_mr_indexer_create (Slapi_PBlock* opb)
     return rc;
 }
 
-static int
-attempt_mr_filter_create (mr_filter_t* f, struct slapdplugin* mrp, Slapi_PBlock* pb)
+static struct mr_private *
+mr_private_new(const struct slapdplugin *pi, const char *oid, const char *type, const struct berval *value, int ftype, int op)
 {
-    int rc;
-    IFP mrf_create = NULL;
-    f->mrf_match = NULL;
-    pblock_init (pb);
-    if (!(rc = slapi_pblock_set (pb, SLAPI_PLUGIN, mrp)) &&
-		!(rc = slapi_pblock_get (pb, SLAPI_PLUGIN_MR_FILTER_CREATE_FN, &mrf_create)) &&
-		mrf_create != NULL &&
-		!(rc = slapi_pblock_set (pb, SLAPI_PLUGIN_MR_OID, f->mrf_oid)) &&
-		!(rc = slapi_pblock_set (pb, SLAPI_PLUGIN_MR_TYPE, f->mrf_type)) &&
-		!(rc = slapi_pblock_set (pb, SLAPI_PLUGIN_MR_VALUE, &(f->mrf_value))) &&
-		!(rc = mrf_create (pb)) &&
-		!(rc = slapi_pblock_get (pb, SLAPI_PLUGIN_MR_FILTER_MATCH_FN, &(f->mrf_match)))) {
-		if (f->mrf_match == NULL)
-		{
-		    rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
-		}
-    }
-    return rc;
+	struct mr_private *mrpriv;
+
+	mrpriv = (struct mr_private *)slapi_ch_calloc(1, sizeof(struct mr_private));
+	mrpriv->pi = pi;
+	mrpriv->oid = oid; /* should be consistent for lifetime of usage - no copy necessary */
+	mrpriv->type = type; /* should be consistent for lifetime of usage - no copy necessary */
+	mrpriv->value = value; /* should be consistent for lifetime of usage - no copy necessary */
+	mrpriv->ftype = ftype;
+	mrpriv->op = op;
+	mrpriv->values[0] = mrpriv->value; /* for filter_index */
+
+	return mrpriv;
 }
 
-int /* an LDAP error code, hopefully LDAP_SUCCESS */
-plugin_mr_filter_create (mr_filter_t* f)
-{
-    int rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
-    struct slapdplugin* mrp = plugin_mr_find_registered (f->mrf_oid);
-    Slapi_PBlock pb;
-
-    if (mrp != NULL)
-    {
-		rc = attempt_mr_filter_create (f, mrp, &pb);
-    }
-    else
-    {
-		/* call each plugin, until one is able to handle this request. */
-		for (mrp = get_plugin_list(PLUGIN_LIST_MATCHINGRULE); mrp != NULL; mrp = mrp->plg_next)
-		{
-		    if (!(rc = attempt_mr_filter_create (f, mrp, &pb)))
-		    {
-				plugin_mr_bind (f->mrf_oid, mrp); /* for future reference */
-				break;
-		    }
-		}
-    }
-    if (!rc)
-    {
-		/* This plugin has created the desired filter. */
-		f->mrf_plugin = mrp;
-		slapi_pblock_get (&pb, SLAPI_PLUGIN_MR_FILTER_INDEX_FN, &(f->mrf_index));
-		slapi_pblock_get (&pb, SLAPI_PLUGIN_MR_FILTER_REUSABLE, &(f->mrf_reusable));
-		slapi_pblock_get (&pb, SLAPI_PLUGIN_MR_FILTER_RESET_FN, &(f->mrf_reset));
-		slapi_pblock_get (&pb, SLAPI_PLUGIN_OBJECT, &(f->mrf_object));
-		slapi_pblock_get (&pb, SLAPI_PLUGIN_DESTROY_FN, &(f->mrf_destroy));
-    }
-    return rc;
-}
-
-int /* an LDAP error code, hopefully LDAP_SUCCESS */
-slapi_mr_filter_index (Slapi_Filter* f, Slapi_PBlock* pb)
-{
-    int rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
-    if (f->f_choice == LDAP_FILTER_EXTENDED && f->f_mr.mrf_index != NULL &&
-		!(rc = slapi_pblock_set (pb, SLAPI_PLUGIN_OBJECT, f->f_mr.mrf_object)))
-	{
-		rc = f->f_mr.mrf_index (pb);
-    }
-    return rc;
-}
-
-static struct mr_indexer_private *
-mr_indexer_private_new()
+static void
+mr_private_indexer_done(struct mr_private *mrpriv)
 {
-	return (struct mr_indexer_private *)slapi_ch_calloc(1, sizeof(struct mr_indexer_private));
+	if (mrpriv && mrpriv->sva) {
+		valuearray_free(&mrpriv->sva);
+	} else if (mrpriv && mrpriv->bva) {
+		ber_bvecfree(mrpriv->bva);
+		mrpriv->bva = NULL;
+	}
 }
 
 static void
-mr_indexer_private_done(struct mr_indexer_private *mrip)
+mr_private_done(struct mr_private *mrpriv)
 {
-	if (mrip && mrip->sva) {
-		valuearray_free(&mrip->sva);
-	} else if (mrip && mrip->bva) {
-		ber_bvecfree(mrip->bva);
-		mrip->bva = NULL;
+	if (mrpriv) {
+		mrpriv->pi = NULL;
+		mrpriv->oid = NULL;
+		mrpriv->type = NULL;
+		mrpriv->value = NULL;
+		mrpriv->ftype = 0;
+		mrpriv->op = 0;
+		slapi_ch_free_string(&mrpriv->initial);
+		slapi_ch_free_string(&mrpriv->any[0]);
+		slapi_ch_free_string(&mrpriv->final);
+		mrpriv->match_fn = NULL;
+		mrpriv->values[0] = NULL;
 	}
+	mr_private_indexer_done(mrpriv);
 }
 
 static void
-mr_indexer_private_free(struct mr_indexer_private **mrip)
+mr_private_free(struct mr_private **mrpriv)
 {
-	if (mrip) {
-		mr_indexer_private_done(*mrip);
-		slapi_ch_free((void **)mrip);
+	if (mrpriv) {
+		mr_private_done(*mrpriv);
+		slapi_ch_free((void **)mrpriv);
 	}
 }
 
@@ -318,15 +301,16 @@ mr_wrap_mr_index_sv_fn(Slapi_PBlock* pb)
 	} else if (!pi->plg_mr_values2keys) {
 		LDAPDebug0Args(LDAP_DEBUG_ANY, "mr_wrap_mr_index_sv_fn: error - plugin has no plg_mr_values2keys function\n");
 	} else {
-		struct mr_indexer_private *mrip = NULL;
-		int ftype = plugin_mr_get_type(pi);
+		int ordering = 0;
+		struct mr_private *mrpriv = NULL;
+		int ftype = plugin_mr_get_type(pi, &ordering);
 		slapi_pblock_get(pb, SLAPI_PLUGIN_MR_VALUES, &in_vals);
 		(*pi->plg_mr_values2keys)(pb, in_vals, &out_vals, ftype);
 		slapi_pblock_set(pb, SLAPI_PLUGIN_MR_KEYS, out_vals);
 		/* we have to save out_vals to free next time or during destroy */
-		slapi_pblock_get(pb, SLAPI_PLUGIN_OBJECT, &mrip);
-		mr_indexer_private_done(mrip); /* free old vals, if any */
-		mrip->sva = out_vals; /* save pointer for later */
+		slapi_pblock_get(pb, SLAPI_PLUGIN_OBJECT, &mrpriv);
+		mr_private_indexer_done(mrpriv); /* free old vals, if any */
+		mrpriv->sva = out_vals; /* save pointer for later */
 		rc = 0;
 	}
 	return rc;
@@ -341,7 +325,7 @@ mr_wrap_mr_index_fn(Slapi_PBlock* pb)
 	int rc = -1;
 	struct berval **in_vals = NULL;
 	struct berval **out_vals = NULL;
-	struct mr_indexer_private *mrip = NULL;
+	struct mr_private *mrpriv = NULL;
 	Slapi_Value **in_vals_sv = NULL;
 	Slapi_Value **out_vals_sv = NULL;
 
@@ -356,22 +340,267 @@ mr_wrap_mr_index_fn(Slapi_PBlock* pb)
 	valuearray_get_bervalarray(out_vals_sv, &out_vals);
 	valuearray_free(&out_vals_sv); /* don't need svals */
 	/* we have to save out_vals to free next time or during destroy */
-	slapi_pblock_get(pb, SLAPI_PLUGIN_OBJECT, &mrip);
-	mr_indexer_private_done(mrip); /* free old vals, if any */
-	mrip->bva = out_vals; /* save pointer for later */
+	slapi_pblock_get(pb, SLAPI_PLUGIN_OBJECT, &mrpriv);
+	mr_private_indexer_done(mrpriv); /* free old vals, if any */
+	mrpriv->bva = out_vals; /* save pointer for later */
+
+	return rc;
+}
+
+static int
+default_mr_filter_destroy(Slapi_PBlock* pb)
+{
+	struct mr_private *mrpriv = NULL;
+
+	slapi_pblock_get(pb, SLAPI_PLUGIN_OBJECT, &mrpriv);
+	mr_private_free(&mrpriv);
+	mrpriv = NULL;
+	slapi_pblock_set(pb, SLAPI_PLUGIN_OBJECT, mrpriv);
+
+	return 0;
+}
+
+static int
+default_mr_filter_match(void *obj, Slapi_Entry *e, Slapi_Attr *attr)
+{
+/* returns:  0  filter matched
+ *	    -1  filter did not match
+ *	    >0  an LDAP error code
+ */
+	int rc = -1;
+	struct mr_private* mrpriv = (struct mr_private*)obj;
+    for (; (rc == -1) && (attr != NULL); slapi_entry_next_attr(e, attr, &attr)) {
+		char* type = NULL;
+		if (!slapi_attr_get_type (attr, &type) && type != NULL &&
+			!slapi_attr_type_cmp (mrpriv->type, type, 2/*match subtypes*/)) {
+			Slapi_Value **vals = attr_get_present_values(attr);
+#ifdef SUPPORT_MR_SUBSTRING_MATCHING
+			if (mrpriv->ftype == LDAP_FILTER_SUBSTRINGS) {
+				rc = (*mrpriv->match_fn)(pb, mrpriv->initial, mrpriv->any, mrpriv->final, vals);
+			}
+#endif
+			rc = (*mrpriv->match_fn)(NULL, mrpriv->value, vals, mrpriv->ftype, NULL);
+		}
+    }
+
+	return rc;
+}
+
+/* convert the filter value into an array of values for use
+   in index key generation */
+static int
+default_mr_filter_index(Slapi_PBlock *pb)
+{
+	int rc = 0;
+	struct mr_private* mrpriv = NULL;
+
+	slapi_pblock_get(pb, SLAPI_PLUGIN_OBJECT, &mrpriv);
+
+	slapi_pblock_set(pb, SLAPI_PLUGIN, mrpriv->pi);
+	slapi_pblock_set(pb, SLAPI_PLUGIN_MR_TYPE, mrpriv->type);
+	/* extensible_candidates uses struct berval ** indexer */
+	slapi_pblock_set(pb, SLAPI_PLUGIN_MR_INDEX_FN, mr_wrap_mr_index_fn);
+	slapi_pblock_set(pb, SLAPI_PLUGIN_MR_VALUES, mrpriv->values);
+	/* the OID is magic - this is used to calculate the index prefix - it
+	   is the indextype value passed to index_index2prefix - it must be the
+	   same OID as used in the index configuration for the index matching
+	   rule */
+	slapi_pblock_set(pb, SLAPI_PLUGIN_MR_OID, mrpriv->oid);
+	slapi_pblock_set(pb, SLAPI_PLUGIN_MR_QUERY_OPERATOR, &mrpriv->op);
 
 	return rc;
 }
 
 static int
+default_mr_filter_create(Slapi_PBlock *pb)
+{
+	int rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION; /* failed to initialize */
+	char* mrOID = NULL;
+	char* mrTYPE = NULL;
+	struct berval* mrVALUE = NULL;
+	struct slapdplugin* pi = NULL;
+
+	LDAPDebug0Args(LDAP_DEBUG_FILTER, "=> default_mr_filter_create\n");
+
+	if (!slapi_pblock_get(pb, SLAPI_PLUGIN_MR_OID, &mrOID) && mrOID != NULL &&
+		!slapi_pblock_get(pb, SLAPI_PLUGIN_MR_TYPE, &mrTYPE) && mrTYPE != NULL &&
+		!slapi_pblock_get(pb, SLAPI_PLUGIN_MR_VALUE, &mrVALUE) && mrVALUE != NULL &&
+		!slapi_pblock_get(pb, SLAPI_PLUGIN, &pi) && pi != NULL) {
+		int op = SLAPI_OP_EQUAL;
+		int ordering = 0;
+		struct mr_private *mrpriv = NULL;
+
+		LDAPDebug2Args(LDAP_DEBUG_FILTER, "=> default_mr_filter_create(oid %s; type %s)\n",
+					   mrOID, mrTYPE);
+
+		int ftype = plugin_mr_get_type(pi, &ordering);
+		/* map the ftype to the op type */
+		if (ftype == LDAP_FILTER_EQUALITY) {
+			if (ordering) { /* not sure what to do here - default to GE */
+				op = SLAPI_OP_GREATER_OR_EQUAL;
+			}
+/*
+		} else if (ftype == LDAP_FILTER_SUBSTRINGS) {
+			op = SLAPI_OP_SUBSTRING;
+*/
+		} else { /* unsupported */
+			/* NOTE: we cannot currently support substring matching rules - the
+			   reason is that the API provides no way to pass in the search time limit
+			   required by the syntax filter substring match functions
+			*/
+			LDAPDebug1Arg(LDAP_DEBUG_FILTER, "<= default_mr_filter_create - unsupported filter type %d\n",
+						  ftype);
+			goto done;
+		}
+		slapi_pblock_set(pb, SLAPI_PLUGIN_MR_QUERY_OPERATOR, &op);
+		mrpriv = mr_private_new(pi, mrOID, mrTYPE, mrVALUE, ftype, op);
+#ifdef SUPPORT_MR_SUBSTRING_MATCHING
+		if ((ftype == LDAP_FILTER_SUBSTRINGS) && (mrVALUE->bv_len > 0) && (mrVALUE->bv_val)) {
+			char *first, *last;
+			int have_initial = 0, have_final = 0;
+
+			if ((mrVALUE->bv_len > 1) && (mrVALUE->bv_val[0] == '*')) {
+				first = &mrVALUE->bv_val[1]; /* point at first "real" char */
+				have_final = 1; /* substring final match */
+			} else {
+				first = mrVALUE->bv_val; /* point at beginning */
+			}
+			if ((mrVALUE->bv_len > 1) && (mrVALUE->bv_val[mrVALUE->bv_len-1] == '*')) {
+				last = &mrVALUE->bv_val[mrVALUE->bv_len-2]; /* point at last "real" char */
+				have_initial = 1; /* substring initial match */
+			} else {
+				last = &mrVALUE->bv_val[mrVALUE->bv_len-1]; /* point at end */
+			}
+			if (have_initial == have_final) { /* both or none specified - assume any */
+				mrpriv->any[0] = PL_strndup(first, last-first);
+			} else if (have_initial) {
+				mrpriv->initial = PL_strndup(first, last-first);
+			} else if (have_final) {
+				mrpriv->final = PL_strndup(first, last-first);
+			}
+		}
+		if (ftype == LDAP_FILTER_SUBSTRINGS) {
+			mrpriv->match_fn = pi->plg_mr_filter_sub;
+		} else {
+			mrpriv->match_fn = pi->plg_mr_filter_ava;
+		}
+#else
+		mrpriv->match_fn = pi->plg_mr_filter_ava;
+#endif
+		slapi_pblock_set(pb, SLAPI_PLUGIN_OBJECT, mrpriv);
+		slapi_pblock_set(pb, SLAPI_PLUGIN_MR_FILTER_MATCH_FN, default_mr_filter_match);
+		slapi_pblock_set(pb, SLAPI_PLUGIN_MR_FILTER_INDEX_FN, default_mr_filter_index);
+		slapi_pblock_set(pb, SLAPI_PLUGIN_DESTROY_FN, default_mr_filter_destroy);
+		rc = 0; /* success */
+	} else {
+		LDAPDebug(LDAP_DEBUG_FILTER,
+				  "default_mr_filter_create: missing parameter: %s%s%s\n",
+				  mrOID ? "" : " oid",
+				  mrTYPE ? "" : " attribute type",
+				  mrVALUE ? "" : " filter value");
+    }
+
+done:
+	LDAPDebug1Arg(LDAP_DEBUG_FILTER, "=> default_mr_filter_create: %d\n", rc);
+
+	return rc;
+}
+
+static int
+attempt_mr_filter_create (mr_filter_t* f, struct slapdplugin* mrp, Slapi_PBlock* pb)
+{
+    int rc;
+    IFP mrf_create = NULL;
+    f->mrf_match = NULL;
+    pblock_init (pb);
+    if (!(rc = slapi_pblock_set (pb, SLAPI_PLUGIN, mrp)) &&
+		!(rc = slapi_pblock_get (pb, SLAPI_PLUGIN_MR_FILTER_CREATE_FN, &mrf_create)) &&
+		mrf_create != NULL &&
+		!(rc = slapi_pblock_set (pb, SLAPI_PLUGIN_MR_OID, f->mrf_oid)) &&
+		!(rc = slapi_pblock_set (pb, SLAPI_PLUGIN_MR_TYPE, f->mrf_type)) &&
+		!(rc = slapi_pblock_set (pb, SLAPI_PLUGIN_MR_VALUE, &(f->mrf_value))) &&
+		!(rc = mrf_create (pb)) &&
+		!(rc = slapi_pblock_get (pb, SLAPI_PLUGIN_MR_FILTER_MATCH_FN, &(f->mrf_match)))) {
+		if (f->mrf_match == NULL)
+		{
+		    rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
+		}
+    }
+    return rc;
+}
+
+int /* an LDAP error code, hopefully LDAP_SUCCESS */
+plugin_mr_filter_create (mr_filter_t* f)
+{
+    int rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
+    struct slapdplugin* mrp = plugin_mr_find_registered (f->mrf_oid);
+    Slapi_PBlock pb;
+
+    if (mrp != NULL)
+    {
+		rc = attempt_mr_filter_create (f, mrp, &pb);
+    }
+    else
+    {
+		/* call each plugin, until one is able to handle this request. */
+		for (mrp = get_plugin_list(PLUGIN_LIST_MATCHINGRULE); mrp != NULL; mrp = mrp->plg_next)
+		{
+		    if (!(rc = attempt_mr_filter_create (f, mrp, &pb)))
+		    {
+				plugin_mr_bind (f->mrf_oid, mrp); /* for future reference */
+				break;
+		    }
+		}
+    }
+	if (rc)
+	{
+		/* look for a new syntax-style mr plugin */
+		mrp = plugin_mr_find(f->mrf_oid);
+		if (mrp)
+		{
+			/* set the default index create fn */
+			pblock_init(&pb);
+			slapi_pblock_set(&pb, SLAPI_PLUGIN, mrp);
+			slapi_pblock_set(&pb, SLAPI_PLUGIN_MR_FILTER_CREATE_FN, default_mr_filter_create);
+		    if (!(rc = attempt_mr_filter_create (f, mrp, &pb)))
+		    {
+				plugin_mr_bind (f->mrf_oid, mrp); /* for future reference */
+			}
+		}
+	}
+    if (!rc)
+    {
+		/* This plugin has created the desired filter. */
+		slapi_pblock_get (&pb, SLAPI_PLUGIN_MR_FILTER_INDEX_FN, &(f->mrf_index));
+		slapi_pblock_get (&pb, SLAPI_PLUGIN_MR_FILTER_REUSABLE, &(f->mrf_reusable));
+		slapi_pblock_get (&pb, SLAPI_PLUGIN_MR_FILTER_RESET_FN, &(f->mrf_reset));
+		slapi_pblock_get (&pb, SLAPI_PLUGIN_OBJECT, &(f->mrf_object));
+		slapi_pblock_get (&pb, SLAPI_PLUGIN_DESTROY_FN, &(f->mrf_destroy));
+    }
+    return rc;
+}
+
+int /* an LDAP error code, hopefully LDAP_SUCCESS */
+slapi_mr_filter_index (Slapi_Filter* f, Slapi_PBlock* pb)
+{
+    int rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
+    if (f->f_choice == LDAP_FILTER_EXTENDED && f->f_mr.mrf_index != NULL &&
+		!(rc = slapi_pblock_set (pb, SLAPI_PLUGIN_OBJECT, f->f_mr.mrf_object)))
+	{
+		rc = f->f_mr.mrf_index (pb);
+    }
+    return rc;
+}
+
+static int
 default_mr_indexer_destroy(Slapi_PBlock* pb)
 {
-	struct mr_indexer_private *mrip = NULL;
+	struct mr_private *mrpriv = NULL;
 
-	slapi_pblock_get(pb, SLAPI_PLUGIN_OBJECT, &mrip);
-	mr_indexer_private_free(&mrip);
-	mrip = NULL;
-	slapi_pblock_set(pb, SLAPI_PLUGIN_OBJECT, mrip);
+	slapi_pblock_get(pb, SLAPI_PLUGIN_OBJECT, &mrpriv);
+	mr_private_free(&mrpriv);
+	mrpriv = NULL;
+	slapi_pblock_set(pb, SLAPI_PLUGIN_OBJECT, mrpriv);
 
 	return 0;
 }
@@ -396,7 +625,7 @@ default_mr_indexer_create(Slapi_PBlock* pb)
 		goto done;
 	}
 
-	slapi_pblock_set(pb, SLAPI_PLUGIN_OBJECT, mr_indexer_private_new());
+	slapi_pblock_set(pb, SLAPI_PLUGIN_OBJECT, mr_private_new(pi, NULL, NULL, NULL, 0, 0));
 	slapi_pblock_set(pb, SLAPI_PLUGIN_MR_INDEX_FN, mr_wrap_mr_index_fn);
 	slapi_pblock_set(pb, SLAPI_PLUGIN_MR_INDEX_SV_FN, mr_wrap_mr_index_sv_fn);
 	slapi_pblock_set(pb, SLAPI_PLUGIN_DESTROY_FN, default_mr_indexer_destroy);
@@ -406,4 +635,3 @@ default_mr_indexer_create(Slapi_PBlock* pb)
 done:
 	return rc;
 }
-


commit ca6e6538a65bc03f7b8e1c521b5d0ba6d7b82a9e
Author: Rich Megginson <rmeggins at redhat.com>
Date:   Wed Feb 10 09:16:28 2010 -0700

    wrap new style matching rule plugins for use in old style indexing code
    
    Create wrappers for the new syntax plugin style matching rule code so that
    we can use the old matching rule indexing functions.  Introduced a new type
    of indexer for Slapi_Value values.  The old style used struct berval * values,
    but the syntax plugins and a lot of newer code work with Slapi_Value* instead.

diff --git a/ldap/servers/slapd/back-ldbm/ldbm_attr.c b/ldap/servers/slapd/back-ldbm/ldbm_attr.c
index 3866e12..a73a532 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_attr.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_attr.c
@@ -240,6 +240,25 @@ attr_index_config(
 			}
 
 			/* compute a->ai_index_rules: */
+			/* for index rules there are two uses:
+			 * 1) a simple way to define an ordered index to support <= and >= searches
+			 * for those attributes which do not have an ORDERING matching rule defined
+			 * for them in their schema definition.  The index generated is not a :RULE:
+			 * index, it is a normal = EQUALITY index, with the keys ordered using the
+			 * comparison function provided by the syntax plugin for the attribute.  For
+			 * example - the uidNumber attribute has INTEGER syntax, but the standard
+			 * definition of the attribute does not specify an ORDERING matching rule.
+			 * By default, this means that you cannot perform searches like
+			 * (uidNumber>=501) - but many users expect to be able to perform this type of
+			 * search.  By specifying that you want an ordered index, using an integer
+			 * matching rule, you can support indexed seaches of this type.
+			 * 2) a RULE index - the index key prefix is :NAMEOROID: - this is used
+			 * to support extensible match searches like (cn:fr-CA.3:=gilles), which would
+			 * find the index key :fr-CA.3:gilles in the cn index.
+			 * We check first to see if this is a simple ordered index - user specified an
+			 * ordering matching rule compatible with the attribute syntax, and there is
+			 * a compare function.  If not, we assume it is a RULE index definition.
+			 */
 			j = 0;
 			if (index_rules != NULL) for (; index_rules[j] != NULL; ++j);
 			if (j > 0) { /* there are some candidates */
@@ -250,47 +269,66 @@ attr_index_config(
 					/* Check that index_rules[j] is an official OID */
 					char* officialOID = NULL;
 					IFP mrINDEX = NULL;
-					Slapi_PBlock* pb = slapi_pblock_new();
+					Slapi_PBlock* pb = NULL;
+					int do_continue = 0; /* can we skip the RULE parsing stuff? */
+
+					if ((p = strstr(index_rules[j], INDEX_ATTR_SUBSTRBEGIN))) {
+						_set_attr_substrlen(INDEX_SUBSTRBEGIN, index_rules[j],
+											&substrlens);
+						do_continue = 1; /* done with j - next j */
+					} else if ((p = strstr(index_rules[j], INDEX_ATTR_SUBSTRMIDDLE))) {
+						_set_attr_substrlen(INDEX_SUBSTRMIDDLE, index_rules[j],
+											&substrlens);
+						do_continue = 1; /* done with j - next j */
+					} else if ((p = strstr(index_rules[j], INDEX_ATTR_SUBSTREND))) {
+						_set_attr_substrlen(INDEX_SUBSTREND, index_rules[j],
+											&substrlens);
+						do_continue = 1; /* done with j - next j */
+					/* check if this is a simple ordering specification
+					   for an attribute that has no ordering matching rule */
+					} else if (slapi_matchingrule_is_ordering(index_rules[j], attrsyntax_oid) &&
+							   !a->ai_sattr.a_mr_ord_plugin) { /* no ordering for this attribute */
+						need_compare_fn = 1; /* get compare func for this attr */
+						do_continue = 1; /* done with j - next j */
+					}
+
+					if (do_continue) {
+						continue; /* done with index_rules[j] */
+					}
+
+					/* must be a RULE specification */
+					pb = slapi_pblock_new();
+					/* next check if this is a RULE type index
+					   try to actually create an indexer and see if the indexer
+					   actually has a regular INDEX_FN or an INDEX_SV_FN */
 					if (!slapi_pblock_set (pb, SLAPI_PLUGIN_MR_OID, index_rules[j]) &&
 						!slapi_pblock_set (pb, SLAPI_PLUGIN_MR_TYPE, a->ai_type) &&
 						!slapi_mr_indexer_create (pb) &&
-						!slapi_pblock_get (pb, SLAPI_PLUGIN_MR_INDEX_FN, &mrINDEX) &&
-						mrINDEX != NULL &&
+						((!slapi_pblock_get (pb, SLAPI_PLUGIN_MR_INDEX_FN, &mrINDEX) &&
+						  mrINDEX != NULL) ||
+						 (!slapi_pblock_get (pb, SLAPI_PLUGIN_MR_INDEX_SV_FN, &mrINDEX) &&
+						  mrINDEX != NULL)) &&
 						!slapi_pblock_get (pb, SLAPI_PLUGIN_MR_OID, &officialOID) &&
 						officialOID != NULL) {
 						if (!strcasecmp (index_rules[j], officialOID)) {
-						official_rules[k++] = slapi_ch_strdup (officialOID);
+							official_rules[k++] = slapi_ch_strdup (officialOID);
 						} else {
-						char* preamble = slapi_ch_smprintf("%s: line %d", fname, lineno);
-						LDAPDebug (LDAP_DEBUG_ANY, "%s: use \"%s\" instead of \"%s\" (ignored)\n",
-							   preamble, officialOID, index_rules[j] );
-						slapi_ch_free((void**)&preamble);
+							char* preamble = slapi_ch_smprintf("%s: line %d", fname, lineno);
+							LDAPDebug (LDAP_DEBUG_ANY, "%s: use \"%s\" instead of \"%s\" (ignored)\n",
+									   preamble, officialOID, index_rules[j] );
+							slapi_ch_free((void**)&preamble);
 						}
-					} else if ((p =
-                                strstr(index_rules[j], INDEX_ATTR_SUBSTRBEGIN))) {
-						_set_attr_substrlen(INDEX_SUBSTRBEGIN, index_rules[j],
-											&substrlens);
-					} else if ((p =
-                                strstr(index_rules[j], INDEX_ATTR_SUBSTRMIDDLE))) {
-						_set_attr_substrlen(INDEX_SUBSTRMIDDLE, index_rules[j],
-											&substrlens);
-					} else if ((p =
-                                strstr(index_rules[j], INDEX_ATTR_SUBSTREND))) {
-						_set_attr_substrlen(INDEX_SUBSTREND, index_rules[j],
-											&substrlens);
-					} else if (!slapi_matchingrule_is_ordering(index_rules[j], attrsyntax_oid)) {
+					} else { /* we don't know what this is */
 						LDAPDebug (LDAP_DEBUG_ANY, "%s: line %d: "
 							   "unknown or invalid matching rule \"%s\" in index configuration (ignored)\n",
 							   fname, lineno, index_rules[j] );
-					} else { /* assume builtin and use compare fn provided by syntax plugin */
-						need_compare_fn = 1;
 					}
 					{/* It would improve speed to save the indexer, for future use.
 						But, for simplicity, we destroy it now: */
 						IFP mrDESTROY = NULL;
 						if (!slapi_pblock_get (pb, SLAPI_PLUGIN_DESTROY_FN, &mrDESTROY) &&
-						mrDESTROY != NULL) {
-						mrDESTROY (pb);
+							mrDESTROY != NULL) {
+							mrDESTROY (pb);
 						}
 					}
 					slapi_pblock_destroy (pb);
@@ -317,12 +355,8 @@ attr_index_config(
 
 		/* if user didn't specify an ordering rule in the index config,
 		   see if the schema def for the attr defines one */
-		if (!need_compare_fn) {
-			asyntaxinfo *asi = attr_syntax_get_by_name( a->ai_type );
-			if (asi && asi->asi_mr_ordering) {
-			 	need_compare_fn = 1;
-			}
-			attr_syntax_return( asi );
+		if (!need_compare_fn && a->ai_sattr.a_mr_ord_plugin) {
+			need_compare_fn = 1;
 		}
 
 		if (need_compare_fn) {
diff --git a/ldap/servers/slapd/back-ldbm/matchrule.c b/ldap/servers/slapd/back-ldbm/matchrule.c
index 0734935..043c968 100644
--- a/ldap/servers/slapd/back-ldbm/matchrule.c
+++ b/ldap/servers/slapd/back-ldbm/matchrule.c
@@ -96,7 +96,17 @@ create_matchrule_indexer(Slapi_PBlock **pb,char* matchrule,char* type)
 
 	if ( (0 != return_value) || (mrINDEX == NULL) )
 	{
-		return LDAP_OPERATIONS_ERROR;
+		/* doesn't have an old MR_INDEX_FN - look for MR_INDEX_SV_FN */
+		return_value = slapi_pblock_get (*pb, SLAPI_PLUGIN_MR_INDEX_SV_FN, &mrINDEX);
+		
+		if ( (0 != return_value) || (mrINDEX == NULL) )
+		{
+			return LDAP_OPERATIONS_ERROR;
+		}
+		else
+		{
+			return LDAP_SUCCESS;
+		}
 	}
 	else
 	{
@@ -146,18 +156,10 @@ int
 matchrule_values_to_keys_sv(Slapi_PBlock *pb,Slapi_Value **input_values,Slapi_Value ***output_values)
 {
 	IFP mrINDEX = NULL;
-        struct berval **bvi, **bvo;
-
-        valuearray_get_bervalarray(input_values, &bvi);
 
-	slapi_pblock_get (pb, SLAPI_PLUGIN_MR_INDEX_FN, &mrINDEX);
-	slapi_pblock_set (pb, SLAPI_PLUGIN_MR_VALUES, bvi);
+	slapi_pblock_get (pb, SLAPI_PLUGIN_MR_INDEX_SV_FN, &mrINDEX);
+	slapi_pblock_set (pb, SLAPI_PLUGIN_MR_VALUES, input_values);
 	mrINDEX (pb);
-	slapi_pblock_get (pb, SLAPI_PLUGIN_MR_KEYS, &bvo);
-
-        slapi_pblock_set (pb, SLAPI_PLUGIN_MR_VALUES, NULL);
-        ber_bvecfree(bvi);
-
-        valuearray_init_bervalarray(bvo, output_values);
+	slapi_pblock_get (pb, SLAPI_PLUGIN_MR_KEYS, output_values);
 	return 0;
 }
diff --git a/ldap/servers/slapd/pblock.c b/ldap/servers/slapd/pblock.c
index b5d994a..7d88574 100644
--- a/ldap/servers/slapd/pblock.c
+++ b/ldap/servers/slapd/pblock.c
@@ -1349,6 +1349,9 @@ slapi_pblock_get( Slapi_PBlock *pblock, int arg, void *value )
 	case SLAPI_PLUGIN_MR_INDEX_FN:
 		(*(IFP *)value) = pblock->pb_mr_index_fn;
 		break;
+	case SLAPI_PLUGIN_MR_INDEX_SV_FN:
+		(*(IFP *)value) = pblock->pb_mr_index_sv_fn;
+		break;
 
 	/* matching rule plugin arguments */
 	case SLAPI_PLUGIN_MR_OID:
@@ -2722,6 +2725,9 @@ slapi_pblock_set( Slapi_PBlock *pblock, int arg, void *value )
 	case SLAPI_PLUGIN_MR_INDEX_FN:
 		pblock->pb_mr_index_fn = (IFP) value;
 		break;
+	case SLAPI_PLUGIN_MR_INDEX_SV_FN:
+		pblock->pb_mr_index_sv_fn = (IFP) value;
+		break;
 
 	/* matching rule plugin arguments */
 	case SLAPI_PLUGIN_MR_OID:
diff --git a/ldap/servers/slapd/plugin_mr.c b/ldap/servers/slapd/plugin_mr.c
index 8f62a7a..014082b 100644
--- a/ldap/servers/slapd/plugin_mr.c
+++ b/ldap/servers/slapd/plugin_mr.c
@@ -47,9 +47,16 @@
 
 #include "slap.h"
 
+struct mr_indexer_private {
+	Slapi_Value **sva; /* if using index_sv_fn */
+	struct berval **bva; /* if using index_fn */
+};
+
 static oid_item_t* global_mr_oids = NULL;
 static PRLock* global_mr_oids_lock = NULL;
 
+static int default_mr_indexer_create(Slapi_PBlock* pb);
+
 static void
 init_global_mr_lock()
 {
@@ -78,6 +85,27 @@ plugin_mr_find( const char *nameoroid )
 	return ( pi );
 }
 
+static int
+plugin_mr_get_type(struct slapdplugin *pi)
+{
+	int rc = LDAP_FILTER_EQUALITY;
+	if (pi) {
+		char **str = pi->plg_mr_names;
+		for (; str && *str; ++str) {
+			if (PL_strcasestr(*str, "substr")) {
+				rc = LDAP_FILTER_SUBSTRINGS;
+				break;
+			}
+			if (PL_strcasestr(*str, "approx")) {
+				rc = LDAP_FILTER_APPROX;
+				break;
+			}
+		}
+	}
+
+	return rc;
+}
+
 static struct slapdplugin*
 plugin_mr_find_registered (char* oid)
 {
@@ -144,15 +172,32 @@ slapi_mr_indexer_create (Slapi_PBlock* opb)
 				    !(rc = slapi_pblock_get (&pb, SLAPI_PLUGIN_MR_INDEXER_CREATE_FN, &createFn)) &&
 				    createFn != NULL &&
 				    !(rc = createFn (&pb)) &&
-				    !(rc = slapi_pblock_get (&pb, SLAPI_PLUGIN_MR_INDEX_FN, &indexFn)) &&
-				    indexFn != NULL)
+					((!(rc = slapi_pblock_get (&pb, SLAPI_PLUGIN_MR_INDEX_FN, &indexFn)) &&
+					 indexFn != NULL) ||
+					 (!(rc = slapi_pblock_get (&pb, SLAPI_PLUGIN_MR_INDEX_SV_FN, &indexFn)) &&
+					  indexFn != NULL)))
 				{
 				    /* Success: this plugin can handle it. */
 				    memcpy (opb, &pb, sizeof(Slapi_PBlock));
 				    plugin_mr_bind (oid, mrp); /* for future reference */
+					rc = 0; /* success */
 				    break;
 				}
 		    }
+			if (rc != 0) {
+				/* look for a new syntax-style mr plugin */
+				struct slapdplugin *pi = plugin_mr_find(oid);
+				if (pi) {
+					Slapi_PBlock pb;
+					memcpy (&pb, opb, sizeof(Slapi_PBlock));
+					slapi_pblock_set(&pb, SLAPI_PLUGIN, pi);
+					rc = default_mr_indexer_create(&pb);
+					if (!rc) {
+						memcpy (opb, &pb, sizeof(Slapi_PBlock));
+						plugin_mr_bind (oid, pi); /* for future reference */
+					}
+				}
+			}
 		}
     }
     return rc;
@@ -229,3 +274,136 @@ slapi_mr_filter_index (Slapi_Filter* f, Slapi_PBlock* pb)
     return rc;
 }
 
+static struct mr_indexer_private *
+mr_indexer_private_new()
+{
+	return (struct mr_indexer_private *)slapi_ch_calloc(1, sizeof(struct mr_indexer_private));
+}
+
+static void
+mr_indexer_private_done(struct mr_indexer_private *mrip)
+{
+	if (mrip && mrip->sva) {
+		valuearray_free(&mrip->sva);
+	} else if (mrip && mrip->bva) {
+		ber_bvecfree(mrip->bva);
+		mrip->bva = NULL;
+	}
+}
+
+static void
+mr_indexer_private_free(struct mr_indexer_private **mrip)
+{
+	if (mrip) {
+		mr_indexer_private_done(*mrip);
+		slapi_ch_free((void **)mrip);
+	}
+}
+
+/* this function takes SLAPI_PLUGIN_MR_VALUES as Slapi_Value ** and
+   returns SLAPI_PLUGIN_MR_KEYS as Slapi_Value **
+*/
+static int
+mr_wrap_mr_index_sv_fn(Slapi_PBlock* pb)
+{
+	int rc = -1;
+	Slapi_Value **in_vals = NULL;
+	Slapi_Value **out_vals = NULL;
+	struct slapdplugin *pi = NULL;
+	
+	slapi_pblock_set(pb, SLAPI_PLUGIN_MR_KEYS, out_vals); /* make sure output is cleared */
+	slapi_pblock_get(pb, SLAPI_PLUGIN, &pi);
+	if (!pi) {
+		LDAPDebug0Args(LDAP_DEBUG_ANY, "mr_wrap_mr_index_sv_fn: error - no plugin specified\n");
+	} else if (!pi->plg_mr_values2keys) {
+		LDAPDebug0Args(LDAP_DEBUG_ANY, "mr_wrap_mr_index_sv_fn: error - plugin has no plg_mr_values2keys function\n");
+	} else {
+		struct mr_indexer_private *mrip = NULL;
+		int ftype = plugin_mr_get_type(pi);
+		slapi_pblock_get(pb, SLAPI_PLUGIN_MR_VALUES, &in_vals);
+		(*pi->plg_mr_values2keys)(pb, in_vals, &out_vals, ftype);
+		slapi_pblock_set(pb, SLAPI_PLUGIN_MR_KEYS, out_vals);
+		/* we have to save out_vals to free next time or during destroy */
+		slapi_pblock_get(pb, SLAPI_PLUGIN_OBJECT, &mrip);
+		mr_indexer_private_done(mrip); /* free old vals, if any */
+		mrip->sva = out_vals; /* save pointer for later */
+		rc = 0;
+	}
+	return rc;
+}
+
+/* this function takes SLAPI_PLUGIN_MR_VALUES as struct berval ** and
+   returns SLAPI_PLUGIN_MR_KEYS as struct berval **
+*/
+static int
+mr_wrap_mr_index_fn(Slapi_PBlock* pb)
+{
+	int rc = -1;
+	struct berval **in_vals = NULL;
+	struct berval **out_vals = NULL;
+	struct mr_indexer_private *mrip = NULL;
+	Slapi_Value **in_vals_sv = NULL;
+	Slapi_Value **out_vals_sv = NULL;
+
+	slapi_pblock_get(pb, SLAPI_PLUGIN_MR_VALUES, &in_vals); /* get bervals */
+	/* convert bervals to sv ary */
+	valuearray_init_bervalarray(in_vals, &in_vals_sv);
+	slapi_pblock_set(pb, SLAPI_PLUGIN_MR_VALUES, in_vals_sv); /* use sv */
+	rc = mr_wrap_mr_index_sv_fn(pb);
+	/* get result sv keys */
+	slapi_pblock_get(pb, SLAPI_PLUGIN_MR_KEYS, &out_vals_sv);
+	/* convert to bvec */
+	valuearray_get_bervalarray(out_vals_sv, &out_vals);
+	valuearray_free(&out_vals_sv); /* don't need svals */
+	/* we have to save out_vals to free next time or during destroy */
+	slapi_pblock_get(pb, SLAPI_PLUGIN_OBJECT, &mrip);
+	mr_indexer_private_done(mrip); /* free old vals, if any */
+	mrip->bva = out_vals; /* save pointer for later */
+
+	return rc;
+}
+
+static int
+default_mr_indexer_destroy(Slapi_PBlock* pb)
+{
+	struct mr_indexer_private *mrip = NULL;
+
+	slapi_pblock_get(pb, SLAPI_PLUGIN_OBJECT, &mrip);
+	mr_indexer_private_free(&mrip);
+	mrip = NULL;
+	slapi_pblock_set(pb, SLAPI_PLUGIN_OBJECT, mrip);
+
+	return 0;
+}
+
+/* this is the default mr indexer create func
+   for new syntax-style mr plugins */
+static int
+default_mr_indexer_create(Slapi_PBlock* pb)
+{
+	int rc = -1;
+	struct slapdplugin *pi = NULL;
+	
+	slapi_pblock_get(pb, SLAPI_PLUGIN, &pi);
+	if (NULL == pi) {
+		LDAPDebug0Args(LDAP_DEBUG_ANY, "default_mr_indexer_create: error - no plugin specified\n");
+		goto done;
+	}
+
+	if (NULL == pi->plg_mr_values2keys) {
+		LDAPDebug1Arg(LDAP_DEBUG_ANY, "default_mr_indexer_create: error - plugin [%s] has no plg_mr_values2keys function\n",
+					  pi->plg_name);
+		goto done;
+	}
+
+	slapi_pblock_set(pb, SLAPI_PLUGIN_OBJECT, mr_indexer_private_new());
+	slapi_pblock_set(pb, SLAPI_PLUGIN_MR_INDEX_FN, mr_wrap_mr_index_fn);
+	slapi_pblock_set(pb, SLAPI_PLUGIN_MR_INDEX_SV_FN, mr_wrap_mr_index_sv_fn);
+	slapi_pblock_set(pb, SLAPI_PLUGIN_DESTROY_FN, default_mr_indexer_destroy);
+	slapi_pblock_set(pb, SLAPI_PLUGIN_MR_INDEXER_CREATE_FN, default_mr_indexer_create);
+	rc = 0;
+
+done:
+	return rc;
+}
+
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
index 9dea452..adef7a8 100644
--- a/ldap/servers/slapd/slap.h
+++ b/ldap/servers/slapd/slap.h
@@ -1440,7 +1440,7 @@ typedef struct slapi_pblock {
 	mrFilterMatchFn	pb_mr_filter_match_fn;
 	IFP		pb_mr_filter_index_fn;
 	IFP		pb_mr_filter_reset_fn;
-	IFP		pb_mr_index_fn;
+	IFP		pb_mr_index_fn; /* values and keys are struct berval ** */
 	char*		pb_mr_oid;
 	char*		pb_mr_type;
 	struct berval*	pb_mr_value;
@@ -1540,6 +1540,7 @@ typedef struct slapi_pblock {
 							   /* used in plugin init; pb_plugin is not ready, then */
 	LDAPControl	**pb_search_ctrls; /* for search operations, allows plugins to provide
 									  controls to pass for each entry or referral returned */
+	IFP		pb_mr_index_sv_fn; /* values and keys are Slapi_Value ** */
 } slapi_pblock;
 
 /* index if substrlens */
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index 6ced381..5f0fc47 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -5456,6 +5456,7 @@ typedef struct slapi_plugindesc {
 #define SLAPI_PLUGIN_MR_FILTER_INDEX_FN		603
 #define SLAPI_PLUGIN_MR_FILTER_RESET_FN		604
 #define SLAPI_PLUGIN_MR_INDEX_FN		605
+#define SLAPI_PLUGIN_MR_INDEX_SV_FN		606
 
 /* matching rule plugin arguments */
 #define SLAPI_PLUGIN_MR_OID			610


commit 834c706f04e53bb3ca95caa31c6e1166ad79210e
Author: Rich Megginson <rmeggins at redhat.com>
Date:   Mon Feb 8 08:57:52 2010 -0700

    Do not use syntax plugins directly for filters, indexing
    
    There were many places in the server code that directly used the syntax
    plugin for the attribute.  If the attribute schema definition specified
    a matching rule, we must use that matching rule for matching values of
    that attribute, filtering that attribute, and generating index keys for
    values of that attribute.  New internal and plugin APIs have been added
    that use the Slapi_Attr* instead of using the syntax plugin directly.
    The new API will determine which matching rule to apply based on the
    schema definition.

diff --git a/ldap/servers/slapd/attr.c b/ldap/servers/slapd/attr.c
index 89aa9f5..97a9c92 100644
--- a/ldap/servers/slapd/attr.c
+++ b/ldap/servers/slapd/attr.c
@@ -290,11 +290,17 @@ slapi_attr_init_locking_optional(Slapi_Attr *a, const char *type, PRBool use_loc
 		{
 			a->a_plugin = asi->asi_plugin;
 			a->a_flags = asi->asi_flags;
+			a->a_mr_eq_plugin = asi->asi_mr_eq_plugin;
+			a->a_mr_ord_plugin = asi->asi_mr_ord_plugin;
+			a->a_mr_sub_plugin = asi->asi_mr_sub_plugin;
 		}
 		else
 		{
 			a->a_plugin = NULL;    /* XXX - should be rare */
 			a->a_flags = 0;        /* XXX - should be rare */
+			a->a_mr_eq_plugin = NULL;
+			a->a_mr_ord_plugin = NULL;
+			a->a_mr_sub_plugin = NULL;
 		}
 
 		attr_syntax_return_locking_optional( asi, use_lock );
@@ -779,7 +785,7 @@ attr_add_valuearray(Slapi_Attr *a, Slapi_Value **vals, const char *dn)
              * input vals array for duplicates
              */
             Avlnode *vtree = NULL;
-            rc= valuetree_add_valuearray(a->a_type, a->a_plugin, vals, &vtree, &duplicate_index);
+            rc= valuetree_add_valuearray(a, vals, &vtree, &duplicate_index);
             valuetree_free(&vtree);
             was_present_null = 1;
         } else {
@@ -892,3 +898,71 @@ attr_check_minmax ( const char *attr_name, char *value, long minval, long maxval
 
 	return retVal;
 }
+
+/**
+   Returns the function which can be used to compare (like memcmp/strcmp)
+   two values of this type of attribute.  The comparison function will use
+   the ORDERING matching rule if available, or the default comparison
+   function from the syntax plugin.
+   Note: if there is no ORDERING matching rule, and the syntax does not
+   provide an ordered compare function, this function will return
+   LDAP_PROTOCOL_ERROR and compare_fn will be NULL.
+   Returns LDAP_SUCCESS if successful and sets *compare_fn to the function.
+ */
+int
+attr_get_value_cmp_fn(const Slapi_Attr *attr, value_compare_fn_type *compare_fn)
+{
+	int rc = LDAP_PROTOCOL_ERROR;
+
+	LDAPDebug0Args(LDAP_DEBUG_TRACE,
+					"=> slapi_attr_get_value_cmp_fn\n");
+
+	*compare_fn = NULL;
+
+	if (attr == NULL) {
+		LDAPDebug0Args(LDAP_DEBUG_TRACE,
+						"<= slapi_attr_get_value_cmp_fn no attribute given\n");
+		rc = LDAP_PARAM_ERROR; /* unkonwn */
+		goto done;
+	}
+
+	if (attr->a_mr_ord_plugin && attr->a_mr_ord_plugin->plg_mr_compare) {
+		*compare_fn = (value_compare_fn_type) attr->a_mr_ord_plugin->plg_mr_compare;
+		rc = LDAP_SUCCESS;
+		goto done;
+	}
+
+	if ((attr->a_plugin->plg_syntax_flags & SLAPI_PLUGIN_SYNTAX_FLAG_ORDERING) == 0) {
+		LDAPDebug2Args(LDAP_DEBUG_TRACE,
+					   "<= slapi_attr_get_value_cmp_fn syntax [%s] for attribute [%s] does not support ordering\n",
+					   attr->a_plugin->plg_syntax_oid, attr->a_type);
+		goto done;
+	}
+
+	if (attr->a_plugin->plg_syntax_filter_ava == NULL) {
+		LDAPDebug2Args(LDAP_DEBUG_TRACE,
+					   "<= slapi_attr_get_value_cmp_fn syntax [%s] for attribute [%s] does not support equality matching\n",
+					   attr->a_plugin->plg_syntax_oid, attr->a_type);
+		goto done;
+	}
+
+	if (attr->a_plugin->plg_syntax_compare == NULL) {
+		LDAPDebug2Args(LDAP_DEBUG_TRACE,
+					   "<= slapi_attr_get_value_cmp_fn syntax [%s] for attribute [%s] does not have a compare function\n",
+					   attr->a_plugin->plg_syntax_oid, attr->a_type);
+		goto done;
+	}
+
+	*compare_fn = (value_compare_fn_type)attr->a_plugin->plg_syntax_compare;
+	rc = LDAP_SUCCESS;
+
+done:
+	LDAPDebug0Args(LDAP_DEBUG_TRACE, "<= slapi_attr_get_value_cmp_fn \n");
+	return rc;
+}
+
+const char *
+attr_get_syntax_oid(const Slapi_Attr *attr)
+{
+	return attr->a_plugin->plg_syntax_oid;
+}
diff --git a/ldap/servers/slapd/attrsyntax.c b/ldap/servers/slapd/attrsyntax.c
index e88f4ba..11b272a 100644
--- a/ldap/servers/slapd/attrsyntax.c
+++ b/ldap/servers/slapd/attrsyntax.c
@@ -674,6 +674,9 @@ attr_syntax_create(
 	a.asi_origin = (char **)attr_origins;
 	a.asi_plugin = plugin_syntax_find( attr_syntax );
 	a.asi_syntaxlength = syntaxlength;
+	a.asi_mr_eq_plugin = plugin_mr_find( mr_equality );
+	a.asi_mr_ord_plugin = plugin_mr_find( mr_ordering );
+	a.asi_mr_sub_plugin = plugin_mr_find( mr_substring );
 	a.asi_flags = flags;
 
 	/*
@@ -760,10 +763,9 @@ slapi_attr_get_oid_copy( const Slapi_Attr *a, char **oidp )
 int
 slapi_attr_get_syntax_oid_copy( const Slapi_Attr *a, char **oidp )
 {
-	void *pi = NULL;
-
-	if (a && (slapi_attr_type2plugin(a->a_type, &pi) == 0)) {
-		*oidp = slapi_ch_strdup(plugin_syntax2oid(pi));
+	const char *oid;
+	if (a && ((oid = attr_get_syntax_oid(a)))) {
+		*oidp = slapi_ch_strdup(oid);
 		return( 0 );
 	} else {
 		*oidp = NULL;
diff --git a/ldap/servers/slapd/back-ldbm/back-ldbm.h b/ldap/servers/slapd/back-ldbm/back-ldbm.h
index 06cabf2..1153ff3 100644
--- a/ldap/servers/slapd/back-ldbm/back-ldbm.h
+++ b/ldap/servers/slapd/back-ldbm/back-ldbm.h
@@ -467,7 +467,6 @@ struct attrinfo {
                                          * yet. */
 
 #define	IS_INDEXED( a )	( a & INDEX_ANY )
-	void	*ai_plugin; /* the syntax plugin for this attribute */
 	char	**ai_index_rules; /* matching rule OIDs */
 	void	*ai_dblayer;	  /* private data used by the dblayer code */
 	PRInt32 ai_dblayer_count; /* used by the dblayer code */
@@ -475,7 +474,7 @@ struct attrinfo {
 	attrcrypt_private	*ai_attrcrypt;  /* private data used by the attribute encryption code (eg is it enabled or not) */
 	value_compare_fn_type ai_key_cmp_fn; /* function used to compare two index keys -
 											The function is the compare function provided by
-											ai_plugin - this function is used to order
+											attr_get_value_cmp_fn - this function is used to order
 											the keys in the index so that we can use ORDERING
 											searches.  In order for this function to be used,
 											the syntax plugin must define a compare function,
@@ -495,6 +494,7 @@ struct attrinfo {
 							 * len value(s) are stored here.  If not specified, 
 							 * the default length triplet is 2, 3, 2.
                              */
+	Slapi_Attr ai_sattr;	/* interface to syntax and matching rule plugins */
 };
 
 #define MAXDBCACHE	20
diff --git a/ldap/servers/slapd/back-ldbm/filterindex.c b/ldap/servers/slapd/back-ldbm/filterindex.c
index d41829f..b77103b 100644
--- a/ldap/servers/slapd/back-ldbm/filterindex.c
+++ b/ldap/servers/slapd/back-ldbm/filterindex.c
@@ -61,7 +61,8 @@ static IDList * range_candidates(
     char *type,
     struct berval *low_val,
     struct berval *high_val,
-    int *err
+    int *err,
+    const Slapi_Attr *sattr
 );
 static IDList *
 keys2idl(
@@ -194,8 +195,8 @@ ava_candidates(
     struct berval *bval;
     Slapi_Value   **ivals;
     IDList        *idl;
-    void          *pi;
     int           unindexed = 0;
+    Slapi_Attr    sattr;
 
     LDAPDebug( LDAP_DEBUG_TRACE, "=> ava_candidates\n", 0, 0, 0 );
 
@@ -205,6 +206,8 @@ ava_candidates(
         return( NULL );
     }
 
+    slapi_attr_init(&sattr, type);
+
 #ifdef LDAP_DEBUG
     if ( LDAPDebugLevelIsSet( LDAP_DEBUG_TRACE )) {
         char    *op = NULL;
@@ -231,15 +234,17 @@ ava_candidates(
 
     switch ( ftype ) {
         case LDAP_FILTER_GE:
-            idl = range_candidates(pb, be, type, bval, NULL, err);
+            idl = range_candidates(pb, be, type, bval, NULL, err, &sattr);
             LDAPDebug( LDAP_DEBUG_TRACE, "<= ava_candidates %lu\n",
                        (u_long)IDL_NIDS(idl), 0, 0 );
-            return( idl );
+            goto done;
+            break;
         case LDAP_FILTER_LE:
-            idl = range_candidates(pb, be, type, NULL, bval, err);
+            idl = range_candidates(pb, be, type, NULL, bval, err, &sattr);
             LDAPDebug( LDAP_DEBUG_TRACE, "<= ava_candidates %lu\n",
                        (u_long)IDL_NIDS(idl), 0, 0 );
-            return( idl );
+            goto done;
+            break;
         case LDAP_FILTER_EQUALITY:
             indextype = (char*)indextype_EQUALITY;
             break;
@@ -248,15 +253,6 @@ ava_candidates(
             break;
     }
 
-    /*
-     * get the keys corresponding to this assertion value
-     */
-    if ( slapi_attr_type2plugin( type, &pi ) != 0 ) {
-        LDAPDebug( LDAP_DEBUG_TRACE, "  slapi_filter_get_ava no plugin\n",
-            0, 0, 0 );
-        return( NULL );
-    }
-
     /* This code is result of performance anlysis; we are trying to
      * optimize our equality filter processing -- mainly by limiting
      * malloc/free calls.
@@ -282,7 +278,7 @@ ava_candidates(
         ptr[1]=NULL;
         ivals=ptr;
 
-        slapi_call_syntax_assertion2keys_ava_sv( pi, &tmp, (Slapi_Value ***)&ivals, LDAP_FILTER_EQUALITY_FAST);
+        slapi_attr_assertion2keys_ava_sv( &sattr, &tmp, (Slapi_Value ***)&ivals, LDAP_FILTER_EQUALITY_FAST);
         idl = keys2idl( be, type, indextype, ivals, err, &unindexed );
         if ( unindexed ) {
             unsigned int opnote = SLAPI_OP_NOTE_UNINDEXED;
@@ -306,12 +302,13 @@ ava_candidates(
     } else {
         slapi_value_init_berval(&sv, bval);
         ivals=NULL;
-        slapi_call_syntax_assertion2keys_ava_sv( pi, &sv, &ivals, ftype );
+        slapi_attr_assertion2keys_ava_sv( &sattr, &sv, &ivals, ftype );
         value_done(&sv);
         if ( ivals == NULL || *ivals == NULL ) {
             LDAPDebug( LDAP_DEBUG_TRACE,
                 "<= ava_candidates ALLIDS (no keys)\n", 0, 0, 0 );
-            return( idl_allids( be ) );
+            idl = idl_allids( be );
+            goto done;
         }
         idl = keys2idl( be, type, indextype, ivals, err, &unindexed );
         if ( unindexed ) {
@@ -322,6 +319,8 @@ ava_candidates(
          LDAPDebug( LDAP_DEBUG_TRACE, "<= ava_candidates %lu\n",
                    (u_long)IDL_NIDS(idl), 0, 0 );
     }
+done:
+    attr_done(&sattr);
     return( idl );
 }
 
@@ -520,28 +519,18 @@ range_candidates(
     char *type,
     struct berval *low_val,
     struct berval *high_val,
-    int *err
+    int *err,
+    const Slapi_Attr *sattr
 )
 {
     IDList *idl;
     struct berval *low = NULL, *high = NULL;
     struct berval **lows = NULL, **highs = NULL;
-    void *pi;
 
     LDAPDebug(LDAP_DEBUG_TRACE, "=> range_candidates attr=%s\n", type, 0, 0);
 
-    /*
-     * get the keys corresponding to the assertion values
-     */
-
-    if ( slapi_attr_type2plugin( type, &pi ) != 0 ) {
-        LDAPDebug( LDAP_DEBUG_TRACE, "  slapi_filter_get_ava no plugin\n",
-                   0, 0, 0 );
-        return( NULL );
-    }
-
     if (low_val != NULL) {
-        slapi_call_syntax_assertion2keys_ava(pi, low_val, &lows, LDAP_FILTER_EQUALITY);
+        slapi_attr_assertion2keys_ava(sattr, low_val, &lows, LDAP_FILTER_EQUALITY);
         if (lows == NULL || *lows == NULL) {
             LDAPDebug( LDAP_DEBUG_TRACE,
                        "<= range_candidates ALLIDS (no keys)\n", 0, 0, 0 );
@@ -551,7 +540,7 @@ range_candidates(
     }
 
     if (high_val != NULL) {
-        slapi_call_syntax_assertion2keys_ava(pi, high_val, &highs, LDAP_FILTER_EQUALITY);
+        slapi_attr_assertion2keys_ava(sattr, high_val, &highs, LDAP_FILTER_EQUALITY);
         if (highs == NULL || *highs == NULL) {
             LDAPDebug( LDAP_DEBUG_TRACE,
                        "<= range_candidates ALLIDS (no keys)\n", 0, 0, 0 );
@@ -698,7 +687,11 @@ list_candidates(
         is_bounded_range = 0;
     }
     if (is_bounded_range) {
-        idl = range_candidates(pb, be, tpairs[0], vpairs[0], vpairs[1], err);
+        Slapi_Attr sattr;
+
+        slapi_attr_init(&sattr, tpairs[0]);
+        idl = range_candidates(pb, be, tpairs[0], vpairs[0], vpairs[1], err, &sattr);
+        attr_done(&sattr);
         LDAPDebug( LDAP_DEBUG_TRACE, "<= list_candidates %lu\n",
                    (u_long)IDL_NIDS(idl), 0, 0 );
         goto out;
@@ -734,8 +727,12 @@ list_candidates(
             }
             else if (fpairs[1] == f)
             {
+                Slapi_Attr sattr;
+
+                slapi_attr_init(&sattr, tpairs[0]);
                 tmp = range_candidates(pb, be, tpairs[0],
-                                       vpairs[0], vpairs[1], err);
+                                       vpairs[0], vpairs[1], err, &sattr);
+                attr_done(&sattr);
                 if (tmp == NULL && ftype == LDAP_FILTER_AND)
                 {
                     LDAPDebug( LDAP_DEBUG_TRACE,
@@ -839,10 +836,10 @@ substring_candidates(
     char         *type, *initial, *final;
     char         **any;
     IDList       *idl;
-    void         *pi;
     Slapi_Value  **ivals;
     int          unindexed = 0;
     unsigned int opnote = SLAPI_OP_NOTE_UNINDEXED;
+    Slapi_Attr   sattr;
 
     LDAPDebug( LDAP_DEBUG_TRACE, "=> sub_candidates\n", 0, 0, 0 );
 
@@ -856,12 +853,9 @@ substring_candidates(
      * get the index keys corresponding to the substring
      * assertion values
      */
-    if ( slapi_attr_type2plugin( type, &pi ) != 0 ) {
-        LDAPDebug( LDAP_DEBUG_TRACE, "  sub_candidates no plugin\n",
-            0, 0, 0 );
-        return( NULL );
-    }
-    slapi_call_syntax_assertion2keys_sub_sv( pi, initial, any, final, &ivals );
+    slapi_attr_init(&sattr, type);
+    slapi_attr_assertion2keys_sub_sv( &sattr, initial, any, final, &ivals );
+    attr_done(&sattr);
     if ( ivals == NULL || *ivals == NULL ) {
         slapi_pblock_set( pb, SLAPI_OPERATION_NOTES, &opnote );
         LDAPDebug( LDAP_DEBUG_TRACE,
diff --git a/ldap/servers/slapd/back-ldbm/index.c b/ldap/servers/slapd/back-ldbm/index.c
index d7afb47..f26e3d3 100644
--- a/ldap/servers/slapd/back-ldbm/index.c
+++ b/ldap/servers/slapd/back-ldbm/index.c
@@ -54,7 +54,7 @@ static const char *errmsg = "database index operation failed";
 static int   is_indexed (const char* indextype, int indexmask, char** index_rules);
 static Slapi_Value **
 valuearray_minus_valuearray(
-    void *plugin, 
+    const Slapi_Attr *sattr, 
     Slapi_Value **a, 
     Slapi_Value **b
 );
@@ -1848,8 +1848,7 @@ index_addordel_values_ext_sv(
         /* on delete, only remove the equality index if the
          * BE_INDEX_EQUALITY flag is set.
          */
-        slapi_call_syntax_values2keys_sv( ai->ai_plugin, vals, &ivals, 
-                                          LDAP_FILTER_EQUALITY );
+        slapi_attr_values2keys_sv( &ai->ai_sattr, vals, &ivals, LDAP_FILTER_EQUALITY );
 
         err = addordel_values_sv( be, db, basetype, indextype_EQUALITY,
                                   ivals != NULL ? ivals : vals, id, flags, txn, ai, idl_disposition, NULL );
@@ -1866,8 +1865,7 @@ index_addordel_values_ext_sv(
      * approximate index entry
      */
     if ( ai->ai_indexmask & INDEX_APPROX ) {
-        slapi_call_syntax_values2keys_sv( ai->ai_plugin, vals, &ivals, 
-                                          LDAP_FILTER_APPROX );
+        slapi_attr_values2keys_sv( &ai->ai_sattr, vals, &ivals, LDAP_FILTER_APPROX );
 
         if ( ivals != NULL ) {
             err = addordel_values_sv( be, db, basetype,
@@ -1892,19 +1890,19 @@ index_addordel_values_ext_sv(
 		/* prepare pblock to pass ai_substr_lens */
 		pblock_init( &pipb );
 		slapi_pblock_set( &pipb, SLAPI_SYNTAX_SUBSTRLENS, ai->ai_substr_lens );
-        slapi_call_syntax_values2keys_sv_pb( ai->ai_plugin, vals, &ivals, 
+        slapi_attr_values2keys_sv_pb( &ai->ai_sattr, vals, &ivals, 
                                           LDAP_FILTER_SUBSTRINGS, &pipb );
 
         origvals = ivals;
         /* delete only: if the attribute has multiple values,
          * figure out the substrings that should remain
-         * by slapi_call_syntax_values2keys,
+         * by slapi_attr_values2keys,
          * then get rid of them from the being deleted values
          */
         if ( evals != NULL ) {
-            slapi_call_syntax_values2keys_sv_pb( ai->ai_plugin, evals,
+            slapi_attr_values2keys_sv_pb( &ai->ai_sattr, evals,
 							&esubvals, LDAP_FILTER_SUBSTRINGS, &pipb );
-            substresult = valuearray_minus_valuearray( ai->ai_plugin, ivals, esubvals );
+            substresult = valuearray_minus_valuearray( &ai->ai_sattr, ivals, esubvals );
             ivals = substresult;
             valuearray_free( &esubvals );
         }
@@ -2070,7 +2068,7 @@ bvals_strcasecmp(const struct berval *a, const struct berval *b)
 /* the returned array of Slapi_Value needs to be freed. */
 static Slapi_Value **
 valuearray_minus_valuearray(
-    void *plugin, 
+    const Slapi_Attr *sattr, 
     Slapi_Value **a, 
     Slapi_Value **b
 )
@@ -2081,7 +2079,7 @@ valuearray_minus_valuearray(
     value_compare_fn_type cmp_fn;
 
     /* get berval comparison function */
-    plugin_call_syntax_get_compare_fn(plugin, &cmp_fn);
+    attr_get_value_cmp_fn(sattr, &cmp_fn);
     if (cmp_fn == NULL) {
         cmp_fn = (value_compare_fn_type)bvals_strcasecmp;
     }
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_attr.c b/ldap/servers/slapd/back-ldbm/ldbm_attr.c
index 1042cf7..3866e12 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_attr.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_attr.c
@@ -61,6 +61,7 @@ attrinfo_delete(struct attrinfo **pp)
         slapi_ch_free((void**)&((*pp)->ai_type));
         slapi_ch_free((void**)(*pp)->ai_index_rules);
         slapi_ch_free((void**)&((*pp)->ai_attrcrypt));
+        attr_done(&((*pp)->ai_sattr));
         slapi_ch_free((void**)pp);
         *pp= NULL;
     }
@@ -194,11 +195,15 @@ attr_index_config(
 	}
 	for ( i = 0; attrs[i] != NULL; i++ ) {
 		int need_compare_fn = 0;
-		char *attrsyntax_oid = NULL;
+		const char *attrsyntax_oid = NULL;
 		a = attrinfo_new();
+		slapi_attr_init(&a->ai_sattr, attrs[i]);
+		/* we can't just set a->ai_type to the type from a->ai_sattr
+		   if the type has attroptions or subtypes, ai_sattr.a_type will
+		   contain them - but for the purposes of indexing, we don't want
+		   them */
 		a->ai_type = slapi_attr_basetype( attrs[i], NULL, 0 );
-		slapi_attr_type2plugin( a->ai_type, &a->ai_plugin );
-		attrsyntax_oid = slapi_ch_strdup(plugin_syntax2oid(a->ai_plugin));
+		attrsyntax_oid = attr_get_syntax_oid(&a->ai_sattr);
 		if ( argc == 1 ) {
 			a->ai_indexmask = (INDEX_PRESENCE | INDEX_EQUALITY |
 				INDEX_APPROX | INDEX_SUB);
@@ -301,7 +306,6 @@ attr_index_config(
 			}
 		}
 
-		slapi_ch_free_string(&attrsyntax_oid);
 		/* initialize the IDL code's private data */
 		return_value = idl_init_private(be, a);
 		if (0 != return_value) {
@@ -322,11 +326,11 @@ attr_index_config(
 		}
 
 		if (need_compare_fn) {
-			int rc = plugin_call_syntax_get_compare_fn( a->ai_plugin, &a->ai_key_cmp_fn );
+			int rc = attr_get_value_cmp_fn( &a->ai_sattr, &a->ai_key_cmp_fn );
 			if (rc != LDAP_SUCCESS) {
 				LDAPDebug(LDAP_DEBUG_ANY,
-					  "The attribute [%s] does not have a valid ORDERING matching rule\n",
-					  a->ai_type, 0, 0);
+						  "The attribute [%s] does not have a valid ORDERING matching rule - error %d:s\n",
+						  a->ai_type, rc, ldap_err2string(rc));
 				a->ai_key_cmp_fn = NULL;
 			}
 		}
@@ -358,6 +362,7 @@ attr_create_empty(backend *be,char *type,struct attrinfo **ai)
 {
 	ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
 	struct attrinfo	*a = attrinfo_new();
+	slapi_attr_init(&a->ai_sattr, type);
 	a->ai_type = slapi_ch_strdup(type);
 	if ( avl_insert( &inst->inst_attrs, a, ainfo_cmp, ainfo_dup ) != 0 ) {
 		/* duplicate - existing version updated */
diff --git a/ldap/servers/slapd/back-ldbm/ldif2ldbm.c b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c
index 70a2b1f..ce79c6f 100644
--- a/ldap/servers/slapd/back-ldbm/ldif2ldbm.c
+++ b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c
@@ -1408,7 +1408,7 @@ ldbm_back_ldbm2ldif( Slapi_PBlock *pb )
                                                       &psrdn, NULL, 0,
                                                       run_from_cmdline, NULL);
                                 if (rc) {
-                                    LDAPDebugArg(LDAP_DEBUG_ANY,
+                                    LDAPDebug1Arg(LDAP_DEBUG_ANY,
                                           "ldbm2ldif: Failed to get dn of ID "
                                           "%d\n", pid);
                                     slapi_ch_free_string(&rdn);
diff --git a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
index a64919c..f12d41d 100644
--- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
+++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
@@ -418,12 +418,13 @@ int ldbm_back_rmdb( Slapi_PBlock *pb );
  */
 struct sort_spec_thing
 {
-    char *type;
+    char *type; /* attribute type */
     char *matchrule; /* Matching rule string */
     int order; /* 0 == ascending, 1 == decending */
     struct sort_spec_thing *next;    /* Link to the next one */
     Slapi_PBlock *mr_pb; /* For matchrule indexing */
     value_compare_fn_type compare_fn; /* For non-matchrule indexing */
+    Slapi_Attr sattr;
 };
 typedef struct sort_spec_thing sort_spec_thing;
 typedef struct sort_spec_thing sort_spec;
diff --git a/ldap/servers/slapd/back-ldbm/sort.c b/ldap/servers/slapd/back-ldbm/sort.c
index b7114f5..10d4417 100644
--- a/ldap/servers/slapd/back-ldbm/sort.c
+++ b/ldap/servers/slapd/back-ldbm/sort.c
@@ -71,6 +71,7 @@ static void sort_spec_thing_free(sort_spec_thing *s)
 		destroy_matchrule_indexer(s->mr_pb);
 	    slapi_pblock_destroy (s->mr_pb);
 	}
+	attr_done(&s->sattr);
 	slapi_ch_free( (void**)&s);
 }
 
@@ -100,6 +101,7 @@ static sort_spec_thing * sort_spec_thing_new(char *type, char* matchrule, int re
 	s->type = type;
 	s->matchrule = matchrule;
 	s->order = reverse;
+    slapi_attr_init(&s->sattr, type);
 	return s;
 }
 
@@ -188,12 +190,8 @@ int sort_candidates(backend *be,int lookthrough_limit,time_t time_up, Slapi_PBlo
 	/* Iterate over the sort types */
 	for (this_s = s; this_s; this_s=this_s->next) {
 		if (NULL == this_s->matchrule) {
-			void		*pi;
 			int return_value = 0;
-			return_value = slapi_attr_type2plugin( this_s->type, &pi );
-			if (0 == return_value) {
-				return_value = plugin_call_syntax_get_compare_fn( pi, &(this_s->compare_fn) );
-			}
+			return_value = attr_get_value_cmp_fn( &this_s->sattr, &(this_s->compare_fn) );
 			if (return_value  != 0 ) {
 				LDAPDebug( LDAP_DEBUG_TRACE, "Attempting to sort a non-ordered attribute (%s)\n",this_s->type, 0, 0 );
 				/* DBDB we should set the error type here */
diff --git a/ldap/servers/slapd/back-ldbm/vlv.c b/ldap/servers/slapd/back-ldbm/vlv.c
index db809c4..2402017 100644
--- a/ldap/servers/slapd/back-ldbm/vlv.c
+++ b/ldap/servers/slapd/back-ldbm/vlv.c
@@ -564,9 +564,9 @@ vlv_create_key(struct vlvIndex* p, struct backentry* e)
                     int totalattrs;
             		if (p->vlv_sortkey[sortattr]->sk_matchruleoid==NULL)
             		{
-            			/* No matching rule. Syntax Plugin mangles value. */
+            			/* No matching rule. mangle values according to matching rule or syntax */
 						Slapi_Value **va= valueset_get_valuearray(&attr->a_present_values);
-                		slapi_call_syntax_values2keys_sv( p->vlv_syntax_plugin[sortattr], va, &cvalue, LDAP_FILTER_EQUALITY );
+                		slapi_attr_values2keys_sv( attr, va, &cvalue, LDAP_FILTER_EQUALITY );
 						valuearray_get_bervalarray(cvalue,&value);
 
 				/* XXXSD need to free some more stuff */
@@ -933,7 +933,10 @@ vlv_build_candidate_list_byvalue( struct vlvIndex* p, DBC *dbc, PRUint32 length,
     invalue[1]= NULL;
 	if (p->vlv_sortkey[0]->sk_matchruleoid==NULL)
 	{
-		slapi_call_syntax_values2keys(p->vlv_syntax_plugin[0],invalue,&typedown_value,LDAP_FILTER_EQUALITY); /* JCM SLOW FUNCTION */
+		Slapi_Attr sattr;
+		slapi_attr_init(&sattr, p->vlv_sortkey[0]->sk_attrtype);
+		slapi_attr_values2keys(&sattr,invalue,&typedown_value,LDAP_FILTER_EQUALITY); /* JCM SLOW FUNCTION */
+		attr_done(&sattr);
     }
     else
     {
@@ -1484,14 +1487,19 @@ vlv_trim_candidates_byvalue(backend *be, const IDList *candidates, const sort_sp
      */
     if (sort_control->matchrule==NULL)
     {
-        void *pi= NULL;
-        if(slapi_attr_type2plugin(sort_control->type, &pi)==0)
+        attr_get_value_cmp_fn(&sort_control->sattr, &compare_fn);
+        if (compare_fn == NULL) {
+            LDAPDebug1Arg(LDAP_DEBUG_ANY, "vlv_trim_candidates_byvalue: "
+                          "attempt to compare an unordered attribute [%s]\n",
+                          sort_control->type);
+            compare_fn = slapi_berval_cmp;
+        }
+
         {
             struct berval *invalue[2];
             invalue[0]= (struct berval *)&vlv_request_control->value; /* jcm: cast away const */
             invalue[1]= NULL;
-            slapi_call_syntax_values2keys(pi,invalue,&typedown_value,LDAP_FILTER_EQUALITY); /* JCM SLOW FUNCTION */
-            plugin_call_syntax_get_compare_fn( pi, &compare_fn );
+            slapi_attr_values2keys(&sort_control->sattr,invalue,&typedown_value,LDAP_FILTER_EQUALITY); /* JCM SLOW FUNCTION */
             if (compare_fn == NULL) {
                 LDAPDebug(LDAP_DEBUG_ANY, "vlv_trim_candidates_byvalue: "
                           "attempt to compare an unordered attribute",
diff --git a/ldap/servers/slapd/back-ldbm/vlv_srch.c b/ldap/servers/slapd/back-ldbm/vlv_srch.c
index d9a14a4..da59ba3 100644
--- a/ldap/servers/slapd/back-ldbm/vlv_srch.c
+++ b/ldap/servers/slapd/back-ldbm/vlv_srch.c
@@ -534,7 +534,6 @@ vlvIndex_new()
         p->vlv_sortkey= NULL;
         p->vlv_filename= NULL;
 	    p->vlv_mrpb= NULL;
-        p->vlv_syntax_plugin= NULL;
         p->vlv_indexlength_lock= PR_NewLock();
         p->vlv_indexlength_cached= 0;
         p->vlv_indexlength= 0;
@@ -572,7 +571,6 @@ vlvIndex_delete(struct vlvIndex** ppvs)
         slapi_ch_free((void**)&((*ppvs)->vlv_name));
         slapi_ch_free((void**)&((*ppvs)->vlv_filename));
         slapi_ch_free((void**)&((*ppvs)->vlv_mrpb));
-        slapi_ch_free((void**)&((*ppvs)->vlv_syntax_plugin));
         PR_DestroyLock((*ppvs)->vlv_indexlength_lock);
         slapi_ch_free((void**)ppvs);
         *ppvs= NULL;
@@ -611,10 +609,8 @@ vlvIndex_init(struct vlvIndex* p, backend *be, struct vlvSearch* pSearch, const
         int n;
         for(n=0;p->vlv_sortkey[n]!=NULL;n++);
         p->vlv_mrpb= (Slapi_PBlock**)slapi_ch_calloc(n+1,sizeof(Slapi_PBlock*));
-        p->vlv_syntax_plugin= (void **)(Slapi_PBlock**)slapi_ch_calloc(n+1,sizeof(Slapi_PBlock*));
         for(n=0;p->vlv_sortkey[n]!=NULL;n++)
         {
-       		slapi_attr_type2plugin( p->vlv_sortkey[n]->sk_attrtype, &p->vlv_syntax_plugin[n] );
             if(p->vlv_sortkey[n]->sk_matchruleoid!=NULL)
             {
 				create_matchrule_indexer(&p->vlv_mrpb[n],p->vlv_sortkey[n]->sk_matchruleoid,p->vlv_sortkey[n]->sk_attrtype);
diff --git a/ldap/servers/slapd/back-ldbm/vlv_srch.h b/ldap/servers/slapd/back-ldbm/vlv_srch.h
index e32cf88..331dbf7 100644
--- a/ldap/servers/slapd/back-ldbm/vlv_srch.h
+++ b/ldap/servers/slapd/back-ldbm/vlv_srch.h
@@ -106,9 +106,6 @@ struct vlvIndex
     /* Attribute Structure maps filename onto index */
     struct attrinfo *vlv_attrinfo;
 
-    /* Syntax Plugin.  One for each LDAPsortkey */
-    void **vlv_syntax_plugin;
-
     /* Matching Rule PBlock. One for each LDAPsortkey */
 	Slapi_PBlock **vlv_mrpb;
 
diff --git a/ldap/servers/slapd/entry.c b/ldap/servers/slapd/entry.c
index 75b1497..00558f7 100644
--- a/ldap/servers/slapd/entry.c
+++ b/ldap/servers/slapd/entry.c
@@ -465,10 +465,10 @@ typedef struct _str2entry_attr {
  	struct valuearrayfast sa_present_values;
  	struct valuearrayfast sa_deleted_values;
 	int sa_numdups;
-	struct slapdplugin *sa_pi;
 	value_compare_fn_type sa_comparefn;
 	Avlnode *sa_vtree;
 	CSN *sa_attributedeletioncsn;
+	Slapi_Attr sa_attr;
 } str2entry_attr;
 
 static void
@@ -479,10 +479,10 @@ entry_attr_init(str2entry_attr *sa, const char *type, int state)
 	valuearrayfast_init(&sa->sa_present_values,NULL);
 	valuearrayfast_init(&sa->sa_deleted_values,NULL);
     sa->sa_numdups= 0;
-	sa->sa_pi= NULL;
 	sa->sa_comparefn = NULL;
     sa->sa_vtree= NULL;
 	sa->sa_attributedeletioncsn= NULL;
+	slapi_attr_init(&sa->sa_attr, type);
 }
 
 /*
@@ -829,18 +829,8 @@ str2entry_dupcheck( const char *dn, char *s, int flags, int read_stateinfo )
 
 			if ( check_for_duplicate_values )
 			{
-				if ( slapi_attr_type2plugin( type,(void **)&(attrs[nattrs].sa_pi) ) != 0 )
-				{
-					LDAPDebug( LDAP_DEBUG_ANY,
-						"<= str2entry_dupcheck NULL (slapi_attr_type2plugin)\n",
-						0, 0, 0 );
-					slapi_entry_free( e ); e = NULL;
-					if (retmalloc) slapi_ch_free_string(&valuecharptr);
-					if (freetype) slapi_ch_free_string(&type);
-					goto free_and_return;
-				}
 				/* Get the comparison function for later use */
-				plugin_call_syntax_get_compare_fn( attrs[nattrs].sa_pi, &(attrs[nattrs].sa_comparefn));
+				attr_get_value_cmp_fn( &attrs[nattrs].sa_attr, &(attrs[nattrs].sa_comparefn));
 				/*
 				 * If the compare function wasn't available,
 				 * we have to revert to AVL-tree-based dup checking,
@@ -904,9 +894,9 @@ str2entry_dupcheck( const char *dn, char *s, int flags, int read_stateinfo )
 				if (sa->sa_present_values.num > STR2ENTRY_VALUE_DUPCHECK_THRESHOLD)
 				{
 					/* Make the tree from the existing attr values */
-					rc= valuetree_add_valuearray( sa->sa_type, sa->sa_pi, sa->sa_present_values.va, &sa->sa_vtree, NULL);
+					rc= valuetree_add_valuearray( &sa->sa_attr, sa->sa_present_values.va, &sa->sa_vtree, NULL);
 					/* Check if the value already exists, in the tree. */
-					rc= valuetree_add_value( sa->sa_type, sa->sa_pi, value, &sa->sa_vtree);
+					rc= valuetree_add_value( &sa->sa_attr, value, &sa->sa_vtree);
 					fast_dup_check = 0;
 				}
 				else
@@ -927,7 +917,7 @@ str2entry_dupcheck( const char *dn, char *s, int flags, int read_stateinfo )
 			else
 			{
 				/* Check if the value already exists, in the tree. */
-				rc = valuetree_add_value( sa->sa_type, sa->sa_pi, value, &sa->sa_vtree);
+				rc = valuetree_add_value( &sa->sa_attr, value, &sa->sa_vtree);
 			}
 		}
 
@@ -1078,6 +1068,7 @@ free_and_return:
 		valuearrayfast_done(&attrs[ i ].sa_present_values);
 		valuearrayfast_done(&attrs[ i ].sa_deleted_values);
 		valuetree_free( &attrs[ i ].sa_vtree );
+		attr_done( &attrs[ i ].sa_attr );
     }
 	if (tree_attr_checking)
 	{
diff --git a/ldap/servers/slapd/filtercmp.c b/ldap/servers/slapd/filtercmp.c
index 0591681..20a42a2 100644
--- a/ldap/servers/slapd/filtercmp.c
+++ b/ldap/servers/slapd/filtercmp.c
@@ -85,17 +85,15 @@ static PRUint32 stir(PRUint32 hash, PRUint32 x)
 }
 #define STIR(h) (h) = stir((h), 0x2EC6DEAD);
 
-static Slapi_Value **get_normalized_value(struct ava *ava)
+static Slapi_Value **get_normalized_value(const Slapi_Attr *sattr, struct ava *ava)
 {
-    void *plugin;
     Slapi_Value *svlist[2], **keylist, sv;
 
-    slapi_attr_type2plugin(ava->ava_type, &plugin);
     sv.bv = ava->ava_value;
     sv.v_csnset = NULL;
     svlist[0] = &sv;
     svlist[1] = NULL;
-    if ((slapi_call_syntax_values2keys_sv(plugin, svlist, &keylist,
+    if ((slapi_attr_values2keys_sv(sattr, svlist, &keylist,
 					  LDAP_FILTER_EQUALITY) != 0) ||
 	!keylist || !keylist[0])
 	return NULL;
@@ -168,6 +166,7 @@ void filter_compute_hash(struct slapi_filter *f)
     Slapi_Value **keylist;
     Slapi_PBlock *pb;
     struct berval *inval[2], **outval;
+    Slapi_Attr sattr;
 
     if (! hash_filters)
 	return;
@@ -178,7 +177,9 @@ void filter_compute_hash(struct slapi_filter *f)
     case LDAP_FILTER_GE:
     case LDAP_FILTER_LE:
     case LDAP_FILTER_APPROX:
-	keylist = get_normalized_value(&f->f_ava);
+	slapi_attr_init(&sattr, f->f_ava.ava_type);
+	keylist = get_normalized_value(&sattr, &f->f_ava);
+	attr_done(&sattr);
 	if (keylist) {
 	    h = addhash_str(h, f->f_avtype);
 	    STIR(h);
@@ -349,6 +350,7 @@ int slapi_filter_compare(struct slapi_filter *f1, struct slapi_filter *f2)
     Slapi_PBlock *pb1, *pb2;
     struct berval *inval1[2], *inval2[2], **outval1, **outval2;
     int ret;
+    Slapi_Attr sattr;
 
     LDAPDebug(LDAP_DEBUG_TRACE, "=> filter compare\n", 0, 0, 0);
 
@@ -376,19 +378,22 @@ int slapi_filter_compare(struct slapi_filter *f1, struct slapi_filter *f2)
 	    ret = 1;
 	    break;
 	}
-	key1 = get_normalized_value(&f1->f_ava);
+	slapi_attr_init(&sattr, f1->f_ava.ava_type);
+	key1 = get_normalized_value(&sattr, &f1->f_ava);
 	if (key1) {
-	    key2 = get_normalized_value(&f2->f_ava);
+	    key2 = get_normalized_value(&sattr, &f2->f_ava);
 	    if (key2) {
 		ret = memcmp(slapi_value_get_string(key1[0]), 
                              slapi_value_get_string(key2[0]),
 			     slapi_value_get_length(key1[0]));
 		valuearray_free(&key1);
 		valuearray_free(&key2);
+		attr_done(&sattr);
 		break;
 	    }
 	    valuearray_free(&key1);
 	}
+	attr_done(&sattr);
 	ret = 1;
 	break;
     case LDAP_FILTER_PRESENT:
diff --git a/ldap/servers/slapd/pblock.c b/ldap/servers/slapd/pblock.c
index 20ead29..b5d994a 100644
--- a/ldap/servers/slapd/pblock.c
+++ b/ldap/servers/slapd/pblock.c
@@ -1094,7 +1094,7 @@ slapi_pblock_get( Slapi_PBlock *pblock, int arg, void *value )
 		}
 		(*(IFP *)value) = pblock->pb_plugin->plg_syntax_compare;
 		break;
-	case SLAPI_SYNTAX_SUBSTRLENS:
+	case SLAPI_SYNTAX_SUBSTRLENS: /* aka SLAPI_MR_SUBSTRLENS */
 		(*(int **)value) = pblock->pb_substrlens;
 		break;
 	case SLAPI_PLUGIN_SYNTAX_VALIDATE:
@@ -1376,6 +1376,56 @@ slapi_pblock_get( Slapi_PBlock *pblock, int arg, void *value )
 		(*(unsigned int *) value) = pblock->pb_mr_usage;
 		break;
 
+	/* new style matching rule syntax plugin functions */
+	case SLAPI_PLUGIN_MR_FILTER_AVA:
+		if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE ) {
+			return( -1 );
+		}
+		(*(IFP *)value) = pblock->pb_plugin->plg_mr_filter_ava;
+		break;
+	case SLAPI_PLUGIN_MR_FILTER_SUB:
+		if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE ) {
+			return( -1 );
+		}
+		(*(IFP *)value) = pblock->pb_plugin->plg_mr_filter_sub;
+		break;
+	case SLAPI_PLUGIN_MR_VALUES2KEYS:
+		if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE ) {
+			return( -1 );
+		}
+		(*(IFP *)value) = pblock->pb_plugin->plg_mr_values2keys;
+		break;
+	case SLAPI_PLUGIN_MR_ASSERTION2KEYS_AVA:
+		if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE ) {
+			return( -1 );
+		}
+		(*(IFP *)value) = pblock->pb_plugin->plg_mr_assertion2keys_ava;
+		break;
+	case SLAPI_PLUGIN_MR_ASSERTION2KEYS_SUB:
+		if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE ) {
+			return( -1 );
+		}
+		(*(IFP *)value) = pblock->pb_plugin->plg_mr_assertion2keys_sub;
+		break;
+	case SLAPI_PLUGIN_MR_FLAGS:
+		if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE ) {
+			return( -1 );
+		}
+		(*(int *)value) = pblock->pb_plugin->plg_mr_flags;
+		break;
+	case SLAPI_PLUGIN_MR_NAMES:
+		if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE ) {
+			return( -1 );
+		}
+		(*(char ***)value) = pblock->pb_plugin->plg_mr_names;
+		break;
+	case SLAPI_PLUGIN_MR_COMPARE:
+		if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE ) {
+			return( -1 );
+		}
+		(*(IFP *)value) = pblock->pb_plugin->plg_mr_compare;
+		break;
+
 	/* seq arguments */
 	case SLAPI_SEQ_TYPE:
 		(*(int *)value) = pblock->pb_seq_type;
@@ -2371,7 +2421,7 @@ slapi_pblock_set( Slapi_PBlock *pblock, int arg, void *value )
 		}
 		pblock->pb_plugin->plg_syntax_compare = (IFP) value;
 		break;
-	case SLAPI_SYNTAX_SUBSTRLENS:
+	case SLAPI_SYNTAX_SUBSTRLENS: /* aka SLAPI_MR_SUBSTRLENS */
 		pblock->pb_substrlens = (int *) value;
 		break;
 	case SLAPI_PLUGIN_SYNTAX_VALIDATE:
@@ -2699,6 +2749,56 @@ slapi_pblock_set( Slapi_PBlock *pblock, int arg, void *value )
 		pblock->pb_mr_usage = *(unsigned int *) value;
 		break;
 
+	/* new style matching rule syntax plugin functions */
+	case SLAPI_PLUGIN_MR_FILTER_AVA:
+		if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE ) {
+			return( -1 );
+		}
+		pblock->pb_plugin->plg_mr_filter_ava = (IFP) value;
+		break;
+	case SLAPI_PLUGIN_MR_FILTER_SUB:
+		if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE ) {
+			return( -1 );
+		}
+		pblock->pb_plugin->plg_mr_filter_sub = (IFP) value;
+		break;
+	case SLAPI_PLUGIN_MR_VALUES2KEYS:
+		if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE ) {
+			return( -1 );
+		}
+		pblock->pb_plugin->plg_mr_values2keys = (IFP) value;
+		break;
+	case SLAPI_PLUGIN_MR_ASSERTION2KEYS_AVA:
+		if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE ) {
+			return( -1 );
+		}
+		pblock->pb_plugin->plg_mr_assertion2keys_ava = (IFP) value;
+		break;
+	case SLAPI_PLUGIN_MR_ASSERTION2KEYS_SUB:
+		if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE ) {
+			return( -1 );
+		}
+		pblock->pb_plugin->plg_mr_assertion2keys_sub = (IFP) value;
+		break;
+	case SLAPI_PLUGIN_MR_FLAGS:
+		if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE ) {
+			return( -1 );
+		}
+		pblock->pb_plugin->plg_mr_flags = *((int *) value);
+		break;
+	case SLAPI_PLUGIN_MR_NAMES:
+		if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE ) {
+			return( -1 );
+		}
+		pblock->pb_plugin->plg_mr_names = (char **) value;
+		break;
+	case SLAPI_PLUGIN_MR_COMPARE:
+		if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE ) {
+			return( -1 );
+		}
+		pblock->pb_plugin->plg_mr_compare = (IFP) value;
+		break;
+
 	/* seq arguments */
 	case SLAPI_SEQ_TYPE:
 		pblock->pb_seq_type = *((int *)value);
diff --git a/ldap/servers/slapd/plugin_mr.c b/ldap/servers/slapd/plugin_mr.c
index fc07733..8f62a7a 100644
--- a/ldap/servers/slapd/plugin_mr.c
+++ b/ldap/servers/slapd/plugin_mr.c
@@ -65,8 +65,21 @@ slapi_get_global_mr_plugins()
 	return get_plugin_list(PLUGIN_LIST_MATCHINGRULE);
 }
 
+struct slapdplugin *
+plugin_mr_find( const char *nameoroid )
+{
+	struct slapdplugin	*pi;
+
+	for ( pi = get_plugin_list(PLUGIN_LIST_MATCHINGRULE); pi != NULL; pi = pi->plg_next ) {
+		if ( charray_inlist( pi->plg_mr_names, (char *)nameoroid ) ) {
+			break;
+		}
+	}
+	return ( pi );
+}
+
 static struct slapdplugin*
-plugin_mr_find (char* oid)
+plugin_mr_find_registered (char* oid)
 {
 	oid_item_t* i;
 	init_global_mr_lock();
@@ -77,11 +90,11 @@ plugin_mr_find (char* oid)
 	{
 	    if (!strcasecmp (oid, i->oi_oid))
 	    {
-			LDAPDebug (LDAP_DEBUG_FILTER, "plugin_mr_find(%s) != NULL\n", oid, 0, 0);
+			LDAPDebug (LDAP_DEBUG_FILTER, "plugin_mr_find_registered(%s) != NULL\n", oid, 0, 0);
 			return i->oi_plugin;
 	    }
 	}
-    LDAPDebug (LDAP_DEBUG_FILTER, "plugin_mr_find(%s) == NULL\n", oid, 0, 0);
+    LDAPDebug (LDAP_DEBUG_FILTER, "plugin_mr_find_registered(%s) == NULL\n", oid, 0, 0);
     return NULL;
 }
 
@@ -108,7 +121,7 @@ slapi_mr_indexer_create (Slapi_PBlock* opb)
     if (!(rc = slapi_pblock_get (opb, SLAPI_PLUGIN_MR_OID, &oid)))
     {
 		IFP createFn = NULL;
-		struct slapdplugin* mrp = plugin_mr_find (oid);
+		struct slapdplugin* mrp = plugin_mr_find_registered (oid);
 		if (mrp != NULL)
 		{
 		    if (!(rc = slapi_pblock_set (opb, SLAPI_PLUGIN, mrp)) &&
@@ -172,7 +185,7 @@ int /* an LDAP error code, hopefully LDAP_SUCCESS */
 plugin_mr_filter_create (mr_filter_t* f)
 {
     int rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
-    struct slapdplugin* mrp = plugin_mr_find (f->mrf_oid);
+    struct slapdplugin* mrp = plugin_mr_find_registered (f->mrf_oid);
     Slapi_PBlock pb;
 
     if (mrp != NULL)
diff --git a/ldap/servers/slapd/plugin_syntax.c b/ldap/servers/slapd/plugin_syntax.c
index e2cc7fb..80ce12a 100644
--- a/ldap/servers/slapd/plugin_syntax.c
+++ b/ldap/servers/slapd/plugin_syntax.c
@@ -89,7 +89,10 @@ slapi_get_global_syntax_plugins()
 char *
 plugin_syntax2oid( struct slapdplugin *pi )
 {
-	return( pi->plg_syntax_oid );
+	LDAPDebug(LDAP_DEBUG_ANY,
+              "the function plugin_syntax2oid is deprecated - please use attr_get_syntax_oid instead\n", 0, 0, 0);
+    PR_ASSERT(0);
+	return( NULL );
 }
 
 int
@@ -98,37 +101,9 @@ plugin_call_syntax_get_compare_fn(
 	value_compare_fn_type *compare_fn
 )
 {
-	struct slapdplugin	*pi = vpi;
-	*compare_fn = NULL;
-
-	LDAPDebug( LDAP_DEBUG_TRACE,
-	    "=> plugin_call_syntax_get_compare_fn\n",0,0, 0 );
-
-	if ( pi == NULL ) {
-		LDAPDebug( LDAP_DEBUG_TRACE,
-		    "<= plugin_syntax no plugin for attribute type\n",
-		    0, 0, 0 );
-		return( LDAP_PROTOCOL_ERROR );	/* syntax unkonwn */
-	}
-
-	if ( (pi->plg_syntax_flags & SLAPI_PLUGIN_SYNTAX_FLAG_ORDERING) == 0 ) {
-		return( LDAP_PROTOCOL_ERROR );
-	}
-
-	if (pi->plg_syntax_filter_ava == NULL) {
-		LDAPDebug( LDAP_DEBUG_ANY, "<= plugin_call_syntax_get_compare_fn: "
-		    "no filter_ava found for attribute type\n", 0, 0, 0 );
-		return( LDAP_PROTOCOL_ERROR );
-	}
-
-	if (pi->plg_syntax_compare == NULL) {
-		return( LDAP_PROTOCOL_ERROR );
-	}
-
-	*compare_fn = (value_compare_fn_type) pi->plg_syntax_compare;
-
-	LDAPDebug( LDAP_DEBUG_TRACE,
-	    "<= plugin_call_syntax_get_compare_fn \n", 0, 0, 0 );
+	LDAPDebug(LDAP_DEBUG_ANY,
+              "the function plugin_call_syntax_get_compare_fn is deprecated - please use attr_get_value_cmp_fn instead\n", 0, 0, 0);
+    PR_ASSERT(0);
 	return( 0 );
 }
 
@@ -153,14 +128,15 @@ plugin_call_syntax_filter_ava_sv(
 {
 	int		rc;
 	Slapi_PBlock	pipb;
+	IFP ava_fn = NULL;
 
 	LDAPDebug( LDAP_DEBUG_FILTER,
 	    "=> plugin_call_syntax_filter_ava %s=%s\n", ava->ava_type,
 	    ava->ava_value.bv_val, 0 );
 
-	if ( a->a_plugin == NULL ) {
+	if ( ( a->a_mr_eq_plugin == NULL ) && ( a->a_mr_ord_plugin == NULL ) && ( a->a_plugin == NULL ) ) {
 		LDAPDebug( LDAP_DEBUG_FILTER,
-		    "<= plugin_syntax no plugin for attr (%s)\n",
+		    "<= plugin_call_syntax_filter_ava no plugin for attr (%s)\n",
 		    a->a_type, 0, 0 );
 		return( LDAP_PROTOCOL_ERROR );	/* syntax unkonwn */
 	}
@@ -172,33 +148,58 @@ plugin_call_syntax_filter_ava_sv(
 	switch ( ftype ) {
 	case LDAP_FILTER_GE:
 	case LDAP_FILTER_LE:
-		if ( (a->a_plugin->plg_syntax_flags &
-		    SLAPI_PLUGIN_SYNTAX_FLAG_ORDERING) == 0 ) {
+		if ((a->a_mr_ord_plugin == NULL) &&
+			((a->a_plugin->plg_syntax_flags &
+			  SLAPI_PLUGIN_SYNTAX_FLAG_ORDERING) == 0)) {
+			LDAPDebug( LDAP_DEBUG_FILTER,
+					   "<= plugin_call_syntax_filter_ava: attr (%s) has no ordering matching rule, and syntax does not define a compare function\n",
+					   a->a_type, 0, 0 );
 			rc = LDAP_PROTOCOL_ERROR;
 			break;
 		}
+		/* if the attribute has an ordering matching rule plugin, use that,
+		   otherwise, just use the syntax plugin */
+		if (a->a_mr_ord_plugin != NULL) {
+			slapi_pblock_set( &pipb, SLAPI_PLUGIN, (void *) a->a_mr_ord_plugin );
+			ava_fn = a->a_mr_ord_plugin->plg_mr_filter_ava;
+		} else {
+			slapi_pblock_set( &pipb, SLAPI_PLUGIN, (void *) a->a_plugin );
+			ava_fn = a->a_plugin->plg_syntax_filter_ava;
+		}
 		/* FALL */
 	case LDAP_FILTER_EQUALITY:
 	case LDAP_FILTER_APPROX:
-		if ( a->a_plugin->plg_syntax_filter_ava != NULL )
-		{
+		if (NULL == ava_fn) {
+			/* if we have an equality matching rule plugin, use that,
+			   otherwise, just use the syntax plugin */
+			if (a->a_mr_eq_plugin) {
+				slapi_pblock_set( &pipb, SLAPI_PLUGIN, (void *) a->a_mr_eq_plugin );
+				ava_fn = a->a_mr_eq_plugin->plg_mr_filter_ava;
+			} else {
+				slapi_pblock_set( &pipb, SLAPI_PLUGIN, (void *) a->a_plugin );
+				ava_fn = a->a_plugin->plg_syntax_filter_ava;
+			}
+		}
+
+		if ( ava_fn != NULL ) {
 			/* JCM - Maybe the plugin should use the attr value iterator too... */
 			Slapi_Value **va;
-			if(useDeletedValues)
+			if(useDeletedValues) {
 				va= valueset_get_valuearray(&a->a_deleted_values);
-			else
+			} else {
 				va= valueset_get_valuearray(&a->a_present_values);
-			if(va!=NULL)
-			{
-				rc = a->a_plugin->plg_syntax_filter_ava( &pipb,
-				    &ava->ava_value,
-					va,
-	                ftype, retVal );
 			}
+			if(va!=NULL) {
+				rc = (*ava_fn)( &pipb, &ava->ava_value, va, ftype, retVal );
+			}
+		} else {
+			LDAPDebug( LDAP_DEBUG_FILTER,
+					   "<= plugin_call_syntax_filter_ava: attr (%s) has no ava filter function\n",
+					   a->a_type, 0, 0 );
 		}
 		break;
 	default:
-		LDAPDebug( LDAP_DEBUG_ANY, "plugin_call_syntax_filter: "
+		LDAPDebug( LDAP_DEBUG_ANY, "plugin_call_syntax_filter_ava: "
 		    "unknown filter type %d\n", ftype, 0, 0 );
 		rc = LDAP_PROTOCOL_ERROR;
 		break;
@@ -228,20 +229,32 @@ plugin_call_syntax_filter_sub_sv(
 {
 	Slapi_PBlock	pipb;
 	int		rc;
+	IFP sub_fn = NULL;
 
 	LDAPDebug( LDAP_DEBUG_FILTER,
-	    "=> plugin_call_syntax_filter_sub\n", 0, 0, 0 );
+	    "=> plugin_call_syntax_filter_sub_sv\n", 0, 0, 0 );
 
-	if ( a->a_plugin == NULL ) {
+	if ( ( a->a_mr_sub_plugin == NULL ) && ( a->a_plugin == NULL ) ) {
 		LDAPDebug( LDAP_DEBUG_FILTER,
-		    "<= plugin_call_syntax_filter no plugin\n", 0, 0, 0 );
+				   "<= plugin_call_syntax_filter_sub_sv attribute (%s) has no substring matching rule or syntax plugin\n",
+				   a->a_type, 0, 0 );
 		return( -1 );	/* syntax unkonwn - does not match */
 	}
 
-	if ( a->a_plugin->plg_syntax_filter_sub != NULL )
+	pblock_init( &pipb );
+	/* use the substr matching rule plugin if available, otherwise, use
+	   the syntax plugin */
+	if (a->a_mr_sub_plugin) {
+		slapi_pblock_set( &pipb, SLAPI_PLUGIN, (void *) a->a_mr_sub_plugin );
+		sub_fn = a->a_mr_sub_plugin->plg_mr_filter_sub;
+	} else {
+		slapi_pblock_set( &pipb, SLAPI_PLUGIN, (void *) a->a_plugin );
+		sub_fn = a->a_plugin->plg_syntax_filter_sub;
+	}
+
+	if ( sub_fn != NULL )
 	{
 		Slapi_Value **va= valueset_get_valuearray(&a->a_present_values);
-		pblock_init( &pipb );
 		if (pb)
 		{
 			Operation *op = NULL;
@@ -249,9 +262,7 @@ plugin_call_syntax_filter_sub_sv(
 			slapi_pblock_get( pb, SLAPI_OPERATION, &op );
 			slapi_pblock_set( &pipb, SLAPI_OPERATION, op );
 		}
-		slapi_pblock_set( &pipb, SLAPI_PLUGIN, (void *) a->a_plugin );
-		rc = a->a_plugin->plg_syntax_filter_sub( &pipb,
-		    fsub->sf_initial, fsub->sf_any, fsub->sf_final, va);
+		rc = (*sub_fn)( &pipb, fsub->sf_initial, fsub->sf_any, fsub->sf_final, va);
 	} else {
 		rc = -1;
 	}
@@ -554,6 +565,95 @@ slapi_call_syntax_values2keys_sv(
 	return( rc );
 }
 
+int
+slapi_attr_values2keys_sv_pb(
+    const Slapi_Attr	*sattr,
+    Slapi_Value	**vals,
+    Slapi_Value	***ivals,
+    int			ftype,
+	Slapi_PBlock	*pb
+)
+{
+	int			rc;
+	struct slapdplugin	*pi = NULL;
+	IFP v2k_fn = NULL;
+
+	LDAPDebug( LDAP_DEBUG_FILTER, "=> slapi_attr_values2keys_sv\n",
+	    0, 0, 0 );
+
+	switch (ftype) {
+	case LDAP_FILTER_EQUALITY:
+	case LDAP_FILTER_APPROX:
+		if (sattr->a_mr_eq_plugin) {
+			pi = sattr->a_mr_eq_plugin;
+			v2k_fn = sattr->a_mr_eq_plugin->plg_mr_values2keys;
+		} else if (sattr->a_plugin) {
+			pi = sattr->a_plugin;
+			v2k_fn = sattr->a_plugin->plg_syntax_values2keys;
+		}
+		break;
+	case LDAP_FILTER_SUBSTRINGS:
+		if (sattr->a_mr_sub_plugin) {
+			pi = sattr->a_mr_sub_plugin;
+			v2k_fn = sattr->a_mr_sub_plugin->plg_mr_values2keys;
+		} else if (sattr->a_plugin) {
+			pi = sattr->a_plugin;
+			v2k_fn = sattr->a_plugin->plg_syntax_values2keys;
+		}
+		break;
+	default:
+		LDAPDebug( LDAP_DEBUG_ANY, "<= slapi_attr_values2keys_sv: ERROR: unsupported filter type %d\n",
+				   ftype, 0, 0 );
+		rc = LDAP_PROTOCOL_ERROR;
+		goto done;
+	}
+
+	slapi_pblock_set( pb, SLAPI_PLUGIN, pi );
+
+	*ivals = NULL;
+	rc = -1;	/* means no values2keys function */
+	if ( ( pi != NULL ) && ( v2k_fn != NULL ) ) {
+		rc = (*v2k_fn)( pb, vals, ivals, ftype );
+	}
+
+done:
+	LDAPDebug( LDAP_DEBUG_FILTER,
+	    "<= slapi_call_syntax_values2keys %d\n", rc, 0, 0 );
+	return( rc );
+}
+
+int
+slapi_attr_values2keys_sv(
+    const Slapi_Attr	*sattr,
+    Slapi_Value	**vals,
+    Slapi_Value	***ivals,
+    int			ftype
+)
+{
+	Slapi_PBlock pb;
+	pblock_init(&pb);
+	return slapi_attr_values2keys_sv_pb(sattr, vals, ivals, ftype, &pb);
+}
+
+SLAPI_DEPRECATED int
+slapi_attr_values2keys( /* JCM SLOW FUNCTION */
+    const Slapi_Attr	*sattr,
+    struct berval	**vals,
+    struct berval	***ivals,
+    int			ftype
+)
+{
+	int rc;
+	Slapi_Value **svin= NULL;
+	Slapi_Value **svout= NULL;
+	valuearray_init_bervalarray(vals,&svin); /* JCM SLOW FUNCTION */
+	rc= slapi_attr_values2keys_sv(sattr,svin,&svout,ftype);
+	valuearray_get_bervalarray(svout,ivals); /* JCM SLOW FUNCTION */
+	valuearray_free(&svout);
+	valuearray_free(&svin);
+	return rc;
+}
+
 /*
  * almost identical to slapi_call_syntax_values2keys_sv except accepting 
  * pblock to pass some info such as substrlen.
@@ -633,6 +733,73 @@ slapi_call_syntax_assertion2keys_ava_sv(
 	return( rc );
 }
 
+int
+slapi_attr_assertion2keys_ava_sv(
+    const Slapi_Attr *sattr,
+    Slapi_Value	*val,
+    Slapi_Value	***ivals,
+    int			ftype
+)
+{
+	int			rc;
+	Slapi_PBlock		pipb;
+	struct slapdplugin	*pi = NULL;
+	IFP a2k_fn = NULL;
+
+	LDAPDebug( LDAP_DEBUG_FILTER,
+	    "=> slapi_attr_assertion2keys_ava_sv\n", 0, 0, 0 );
+
+	switch (ftype) {
+	case LDAP_FILTER_EQUALITY:
+	case LDAP_FILTER_APPROX:
+	case LDAP_FILTER_EQUALITY_FAST: 
+		if (sattr->a_mr_eq_plugin) {
+			pi = sattr->a_mr_eq_plugin;
+			a2k_fn = sattr->a_mr_eq_plugin->plg_mr_assertion2keys_ava;
+		} else if (sattr->a_plugin) {
+			pi = sattr->a_plugin;
+			a2k_fn = sattr->a_plugin->plg_syntax_assertion2keys_ava;
+		}
+		break;
+	default:
+		LDAPDebug( LDAP_DEBUG_ANY, "<= slapi_attr_assertion2keys_ava_sv: ERROR: unsupported filter type %d\n",
+				   ftype, 0, 0 );
+		rc = LDAP_PROTOCOL_ERROR;
+		goto done;
+	}
+
+	pblock_init( &pipb );
+	slapi_pblock_set( &pipb, SLAPI_PLUGIN, pi );
+
+	rc = -1;	/* means no assertion2keys function */
+	if ( a2k_fn != NULL ) {
+		rc = (*a2k_fn)( &pipb, val, ivals, ftype );
+	}
+done:
+	LDAPDebug( LDAP_DEBUG_FILTER,
+	    "<= slapi_attr_assertion2keys_ava_sv %d\n", rc, 0, 0 );
+	return( rc );
+}
+
+SLAPI_DEPRECATED int
+slapi_attr_assertion2keys_ava( /* JCM SLOW FUNCTION */
+    const Slapi_Attr *sattr,
+    struct berval	*val,
+    struct berval	***ivals,
+    int			ftype
+)
+{
+	int rc;
+	Slapi_Value svin;
+	Slapi_Value **svout= NULL;
+	slapi_value_init_berval(&svin, val);
+	rc= slapi_attr_assertion2keys_ava_sv(sattr,&svin,&svout,ftype);
+	valuearray_get_bervalarray(svout,ivals); /* JCM SLOW FUNCTION */
+	valuearray_free(&svout);
+	value_done(&svin);
+	return rc;
+}
+
 SLAPI_DEPRECATED int
 slapi_call_syntax_assertion2keys_sub( /* JCM SLOW FUNCTION */
     void		*vpi,
@@ -681,3 +848,57 @@ slapi_call_syntax_assertion2keys_sub_sv(
 	return( rc );
 }
 
+int
+slapi_attr_assertion2keys_sub_sv(
+    const Slapi_Attr *sattr,
+    char		*initial,
+    char		**any,
+    char		*final,
+    Slapi_Value	***ivals
+)
+{
+	int			rc;
+	Slapi_PBlock		pipb;
+	struct slapdplugin	*pi = NULL;
+	IFP a2k_fn = NULL;
+
+	LDAPDebug( LDAP_DEBUG_FILTER,
+	    "=> slapi_attr_assertion2keys_sub_sv\n", 0, 0, 0 );
+
+	if (sattr->a_mr_sub_plugin) {
+		pi = sattr->a_mr_sub_plugin;
+		a2k_fn = sattr->a_mr_sub_plugin->plg_mr_assertion2keys_sub;
+	} else if (sattr->a_plugin) {
+		pi = sattr->a_plugin;
+		a2k_fn = sattr->a_plugin->plg_syntax_assertion2keys_sub;
+	}
+	pblock_init( &pipb );
+	slapi_pblock_set( &pipb, SLAPI_PLUGIN, pi );
+
+	rc = -1;	/* means no assertion2keys function */
+	*ivals = NULL;
+	if ( a2k_fn != NULL ) {
+		rc = (*a2k_fn)( &pipb, initial, any, final, ivals );
+	}
+
+	LDAPDebug( LDAP_DEBUG_FILTER,
+	    "<= slapi_attr_assertion2keys_sub_sv %d\n", rc, 0, 0 );
+	return( rc );
+}
+
+SLAPI_DEPRECATED int
+slapi_attr_assertion2keys_sub( /* JCM SLOW FUNCTION */
+    const Slapi_Attr *sattr,
+    char		*initial,
+    char		**any,
+    char		*final,
+    struct berval	***ivals
+)
+{
+	int rc;
+	Slapi_Value **svout= NULL;
+	rc= slapi_attr_assertion2keys_sub_sv(sattr,initial,any,final,&svout);
+	valuearray_get_bervalarray(svout,ivals); /* JCM SLOW FUNCTION */
+	valuearray_free(&svout);
+	return rc;
+}
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
index feca39a..9133958 100644
--- a/ldap/servers/slapd/proto-slap.h
+++ b/ldap/servers/slapd/proto-slap.h
@@ -69,6 +69,27 @@ int attr_add_valuearray(Slapi_Attr *a, Slapi_Value **vals, const char *dn);
 int attr_replace(Slapi_Attr *a, Slapi_Value **vals);
 int attr_check_onoff ( const char *attr_name, char *value, long minval, long maxval, char *errorbuf );
 int attr_check_minmax ( const char *attr_name, char *value, long minval, long maxval, char *errorbuf );
+/**
+ * Returns the function which can be used to compare (like memcmp/strcmp)
+ * two values of this type of attribute.  The comparison function will use
+ * the ORDERING matching rule if available, or the default comparison
+ * function from the syntax plugin.
+ * Note: if there is no ORDERING matching rule, and the syntax does not
+ * provide an ordered compare function, this function will return
+ * LDAP_PROTOCOL_ERROR and compare_fn will be NULL.
+ * Returns LDAP_SUCCESS if successful and sets *compare_fn to the function.
+ *
+ * \param attr The attribute to use
+ * \param compare_fn address of function pointer to set to the function to use
+ * \return LDAP_SUCCESS - success
+ *         LDAP_PARAM_ERROR - attr is NULL
+ *         LDAP_PROTOCOL_ERROR - attr does not support an ordering compare function
+ * \see value_compare_fn_type
+ */
+int attr_get_value_cmp_fn(const Slapi_Attr *attr, value_compare_fn_type *compare_fn);
+/* return the OID of the syntax for this attribute */
+const char *attr_get_syntax_oid(const Slapi_Attr *attr);
+
 
 /*
  * attrlist.c
@@ -145,8 +166,8 @@ void valuearrayfast_add_value(struct valuearrayfast *vaf,const Slapi_Value *v);
 void valuearrayfast_add_value_passin(struct valuearrayfast *vaf,Slapi_Value *v);
 void valuearrayfast_add_valuearrayfast(struct valuearrayfast *vaf,const struct valuearrayfast *vaf_add);
 
-int valuetree_add_value( const char *type, struct slapdplugin *pi, const Slapi_Value *va, Avlnode **valuetreep);
-int valuetree_add_valuearray( const char *type, struct slapdplugin *pi, Slapi_Value **va, Avlnode **valuetreep, int *duplicate_index);
+int valuetree_add_value( const Slapi_Attr *sattr, const Slapi_Value *va, Avlnode **valuetreep);
+int valuetree_add_valuearray( const Slapi_Attr *sattr, Slapi_Value **va, Avlnode **valuetreep, int *duplicate_index);
 void valuetree_free( Avlnode **valuetreep );
 
 /* Valueset functions */
@@ -779,6 +800,7 @@ void plugin_print_lists(void);
  */
 struct slapdplugin *slapi_get_global_mr_plugins();
 int plugin_mr_filter_create (mr_filter_t* f);
+struct slapdplugin *plugin_mr_find( const char *nameoroid );
 
 /*
  * plugin_syntax.c
diff --git a/ldap/servers/slapd/schema.c b/ldap/servers/slapd/schema.c
index 98224df..dadc307 100644
--- a/ldap/servers/slapd/schema.c
+++ b/ldap/servers/slapd/schema.c
@@ -1180,7 +1180,7 @@ schema_attr_enum_callback(struct asyntaxinfo *asip, void *arg)
 		}
 	}
 
-	syntaxoid = plugin_syntax2oid(asip->asi_plugin);
+	syntaxoid = asip->asi_plugin->plg_syntax_oid;
 
 	if ( !aew->schema_ds4x_compat &&
 				asip->asi_syntaxlength != SLAPI_SYNTAXLENGTH_NONE ) {
@@ -3410,7 +3410,7 @@ read_at_ldif(const char *input, struct asyntaxinfo **asipp, char *errorbuf,
         /* We only want to use the parent syntax if a SYNTAX
          * wasn't explicitly specified for this attribute. */
         } else if (NULL == pSyntax) {
-            char *pso = plugin_syntax2oid(asi_parent->asi_plugin);
+            char *pso = asi_parent->asi_plugin->plg_syntax_oid;
             
             if (pso) {
                 slapi_ch_free ((void **)&pSyntax);
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
index 08de2c1..9dea452 100644
--- a/ldap/servers/slapd/slap.h
+++ b/ldap/servers/slapd/slap.h
@@ -453,11 +453,14 @@ struct slapi_attr {
 	char					*a_type;
 	struct slapi_value_set  a_present_values;
 	unsigned long		    a_flags;		/* SLAPI_ATTR_FLAG_... */
-	struct slapdplugin	    *a_plugin;
+	struct slapdplugin	    *a_plugin; /* for the attribute syntax */
 	struct slapi_value_set  a_deleted_values;
 	struct bervals2free     *a_listtofree; /* JCM: EVIL... For DS4 Slapi compatibility. */
 	struct slapi_attr		*a_next;
 	CSN                     *a_deletioncsn; /* The point in time at which this attribute was last deleted */
+	struct slapdplugin	    *a_mr_eq_plugin; /* for the attribute EQUALITY matching rule, if any */
+	struct slapdplugin	    *a_mr_ord_plugin; /* for the attribute ORDERING matching rule, if any */
+	struct slapdplugin	    *a_mr_sub_plugin; /* for the attribute SUBSTRING matching rule, if any */
 };
 
 typedef struct oid_item {
@@ -482,6 +485,9 @@ typedef struct asyntaxinfo {
 	int					asi_syntaxlength;	/* length associated w/syntax */
 	int					asi_refcnt;			/* outstanding references */
 	PRBool				asi_marked_for_delete;	/* delete at next opportunity */
+	struct slapdplugin	*asi_mr_eq_plugin;	/* EQUALITY matching rule plugin */
+	struct slapdplugin	*asi_mr_sub_plugin;	/* SUBSTR matching rule plugin */
+	struct slapdplugin	*asi_mr_ord_plugin;	/* ORDERING matching rule plugin */
 } asyntaxinfo;
 
 /*
@@ -982,9 +988,28 @@ struct slapdplugin {
 		struct plg_un_matching_rule {
 			IFP	plg_un_mr_filter_create; /* factory function */
 			IFP	plg_un_mr_indexer_create; /* factory function */
+			/* new style syntax plugin functions */
+			/* not all functions will apply to all matching rule types */
+			/* e.g. a SUBSTR rule will not have a filter_ava func */
+			IFP	plg_un_mr_filter_ava;
+			IFP	plg_un_mr_filter_sub;
+			IFP	plg_un_mr_values2keys;
+			IFP	plg_un_mr_assertion2keys_ava;
+			IFP	plg_un_mr_assertion2keys_sub;
+			int	plg_un_mr_flags;
+			char	**plg_un_mr_names;
+			IFP	plg_un_mr_compare; /* only for ORDERING */
 		} plg_un_mr;
 #define plg_mr_filter_create	plg_un.plg_un_mr.plg_un_mr_filter_create
 #define plg_mr_indexer_create	plg_un.plg_un_mr.plg_un_mr_indexer_create
+#define plg_mr_filter_ava		plg_un.plg_un_mr.plg_un_mr_filter_ava
+#define plg_mr_filter_sub		plg_un.plg_un_mr.plg_un_mr_filter_sub
+#define plg_mr_values2keys		plg_un.plg_un_mr.plg_un_mr_values2keys
+#define plg_mr_assertion2keys_ava	plg_un.plg_un_mr.plg_un_mr_assertion2keys_ava
+#define plg_mr_assertion2keys_sub	plg_un.plg_un_mr.plg_un_mr_assertion2keys_sub
+#define plg_mr_flags		plg_un.plg_un_mr.plg_un_mr_flags
+#define plg_mr_names		plg_un.plg_un_mr.plg_un_mr_names
+#define plg_mr_compare		plg_un.plg_un_mr.plg_un_mr_compare
 
 		/* syntax plugin structure */
 		struct plg_un_syntax_struct {
diff --git a/ldap/servers/slapd/slapi-plugin-compat4.h b/ldap/servers/slapd/slapi-plugin-compat4.h
index d54cc7d..17f3526 100644
--- a/ldap/servers/slapd/slapi-plugin-compat4.h
+++ b/ldap/servers/slapd/slapi-plugin-compat4.h
@@ -106,6 +106,12 @@ SLAPI_DEPRECATED int slapi_call_syntax_assertion2keys_ava( void *vpi,
 		struct berval *val, struct berval ***ivals, int ftype );
 SLAPI_DEPRECATED int slapi_call_syntax_assertion2keys_sub( void *vpi,
 		char *initial, char **any, char *final, struct berval ***ivals );
+SLAPI_DEPRECATED int slapi_attr_values2keys( const Slapi_Attr *sattr,
+		struct berval **vals, struct berval ***ivals, int ftype );
+SLAPI_DEPRECATED int slapi_attr_assertion2keys_ava( const Slapi_Attr *sattr,
+		struct berval *val, struct berval ***ivals, int ftype );
+SLAPI_DEPRECATED int slapi_attr_assertion2keys_sub( const Slapi_Attr *sattr,
+		char *initial, char **any, char *final, struct berval ***ivals );
 
 /*
  * slapi_entry_attr_hasvalue() has been deprecated in favor of
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index 09cc9d4..6ced381 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -3263,6 +3263,11 @@ int slapi_attr_add_value(Slapi_Attr *a, const Slapi_Value *v);
  * \param pi Address to receive a pointer to the plugin structure.
  * \return \c 0 if successful.
  * \return \c -1 if the plugin is not found.
+ * \deprecated This function was necessary in order to call syntax plugin
+ *             filter and indexing functions - there are new functions
+ *             to use instead, such as slapi_attr_values2keys, etc.
+ *             This function is still used by internal APIs, but new
+ *             code should not use this function
  * \see slapi_attr_get_type()
  * \see slapi_attr_type_cmp()
  * \see slapi_attr_types_equivalent()
@@ -3586,7 +3591,6 @@ int slapi_attr_get_bervals_copy( Slapi_Attr *a, struct berval ***vals );
  */
 char * slapi_attr_syntax_normalize( const char *s );
 
-
 /*
  * value routines
  */
@@ -4726,6 +4730,9 @@ char * slapi_ch_smprintf(const char *fmt, ...)
 
 /*
  * syntax plugin routines
+ * THESE ARE DEPRECATED - the first argument is the syntax plugin
+ * we do not support that style of call anymore - use the slapi_attr_
+ * versions below instead
  */
 int slapi_call_syntax_values2keys_sv( void *vpi, Slapi_Value **vals,
 	Slapi_Value ***ivals, int ftype );
@@ -4736,6 +4743,15 @@ int slapi_call_syntax_assertion2keys_ava_sv( void *vpi, Slapi_Value *val,
 int slapi_call_syntax_assertion2keys_sub_sv( void *vpi, char *initial,
 	char **any, char *final, Slapi_Value ***ivals );
 
+int slapi_attr_values2keys_sv( const Slapi_Attr *sattr, Slapi_Value **vals,
+	Slapi_Value ***ivals, int ftype );
+int slapi_attr_values2keys_sv_pb( const Slapi_Attr *sattr, Slapi_Value **vals,
+	Slapi_Value ***ivals, int ftype, Slapi_PBlock *pb );
+int slapi_attr_assertion2keys_ava_sv( const Slapi_Attr *sattr, Slapi_Value *val,
+	Slapi_Value ***ivals, int ftype );
+int slapi_attr_assertion2keys_sub_sv( const Slapi_Attr *sattr, char *initial,
+	char **any, char *final, Slapi_Value ***ivals );
+
 
 /*
  * internal operation and plugin callback routines
@@ -5450,7 +5466,15 @@ typedef struct slapi_plugindesc {
 #define SLAPI_PLUGIN_MR_FILTER_REUSABLE		615
 #define SLAPI_PLUGIN_MR_QUERY_OPERATOR		616
 #define SLAPI_PLUGIN_MR_USAGE			617
-
+/* new style matching rule syntax plugin functions */
+#define SLAPI_PLUGIN_MR_FILTER_AVA		618
+#define SLAPI_PLUGIN_MR_FILTER_SUB		619
+#define SLAPI_PLUGIN_MR_VALUES2KEYS		620
+#define SLAPI_PLUGIN_MR_ASSERTION2KEYS_AVA	621
+#define SLAPI_PLUGIN_MR_ASSERTION2KEYS_SUB	622
+#define SLAPI_PLUGIN_MR_FLAGS		623
+#define SLAPI_PLUGIN_MR_NAMES		624
+#define SLAPI_PLUGIN_MR_COMPARE		625
 
 /* Defined values of SLAPI_PLUGIN_MR_QUERY_OPERATOR: */
 #define SLAPI_OP_LESS					1
@@ -5484,6 +5508,7 @@ typedef struct slapi_plugindesc {
 
 /* user defined substrlen; not stored in slapdplugin, but pblock itself */
 #define SLAPI_SYNTAX_SUBSTRLENS			709
+#define SLAPI_MR_SUBSTRLENS			SLAPI_SYNTAX_SUBSTRLENS /* alias */
 #define SLAPI_PLUGIN_SYNTAX_VALIDATE		710
 
 /* ACL plugin functions and arguments */
diff --git a/ldap/servers/slapd/valueset.c b/ldap/servers/slapd/valueset.c
index 7334a7a..a9cd37e 100644
--- a/ldap/servers/slapd/valueset.c
+++ b/ldap/servers/slapd/valueset.c
@@ -616,12 +616,11 @@ typedef struct valuetree_node
  *  and *valuetreep is set to NULL.
  */
 int
-valuetree_add_valuearray( const char *type, struct slapdplugin *pi, Slapi_Value **va, Avlnode **valuetreep, int *duplicate_index )
+valuetree_add_valuearray( const Slapi_Attr *sattr, Slapi_Value **va, Avlnode **valuetreep, int *duplicate_index )
 {
 	int rc= LDAP_SUCCESS;
 
-	PR_ASSERT(type!=NULL);
-	PR_ASSERT(pi!=NULL);
+	PR_ASSERT(sattr!=NULL);
 	PR_ASSERT(valuetreep!=NULL);
 
 	if ( duplicate_index ) {
@@ -632,9 +631,9 @@ valuetree_add_valuearray( const char *type, struct slapdplugin *pi, Slapi_Value
 	{
 		Slapi_Value	**keyvals;
 		/* Convert the value array into key values */
-		if ( slapi_call_syntax_values2keys_sv( pi, (Slapi_Value**)va, &keyvals, LDAP_FILTER_EQUALITY ) != 0 ) /* jcm cast */
+		if ( slapi_attr_values2keys_sv( sattr, (Slapi_Value**)va, &keyvals, LDAP_FILTER_EQUALITY ) != 0 ) /* jcm cast */
 		{
-			LDAPDebug( LDAP_DEBUG_ANY,"slapi_call_syntax_values2keys for attribute %s failed\n", type, 0, 0 );
+			LDAPDebug( LDAP_DEBUG_ANY,"slapi_attr_values2keys_sv for attribute %s failed\n", sattr->a_type, 0, 0 );
 			rc= LDAP_OPERATIONS_ERROR;
 		}
 		else
@@ -645,7 +644,7 @@ valuetree_add_valuearray( const char *type, struct slapdplugin *pi, Slapi_Value
 			{
 				if ( keyvals[i] == NULL )
 				{
-					LDAPDebug( LDAP_DEBUG_ANY,"slapi_call_syntax_values2keys for attribute %s did not return enough key values\n", type, 0, 0 );
+					LDAPDebug( LDAP_DEBUG_ANY,"slapi_attr_values2keys_sv for attribute %s did not return enough key values\n", sattr->a_type, 0, 0 );
 					rc= LDAP_OPERATIONS_ERROR;
 				}
 				else
@@ -685,12 +684,12 @@ valuetree_add_valuearray( const char *type, struct slapdplugin *pi, Slapi_Value
 }
 
 int
-valuetree_add_value( const char *type, struct slapdplugin *pi, const Slapi_Value *v, Avlnode **valuetreep)
+valuetree_add_value( const Slapi_Attr *sattr, const Slapi_Value *v, Avlnode **valuetreep)
 {
     Slapi_Value *va[2];
     va[0]= (Slapi_Value*)v;
     va[1]= NULL;
-	return valuetree_add_valuearray( type, pi, va, valuetreep, NULL);
+	return valuetree_add_valuearray( sattr, va, valuetreep, NULL);
 }
 
 
@@ -714,7 +713,7 @@ valuetree_find( const struct slapi_attr *a, const Slapi_Value *v, Avlnode *value
 	PR_ASSERT(valuetree!=NULL);
 	PR_ASSERT(index!=NULL);
 
-	if ( a == NULL || a->a_plugin == NULL || v == NULL || valuetree == NULL )
+	if ( a == NULL || v == NULL || valuetree == NULL )
 	{
 		return( LDAP_OPERATIONS_ERROR );
 	}
@@ -722,12 +721,12 @@ valuetree_find( const struct slapi_attr *a, const Slapi_Value *v, Avlnode *value
 	keyvals = NULL;
 	oneval[0] = v;
 	oneval[1] = NULL;
-	if ( slapi_call_syntax_values2keys_sv( a->a_plugin, (Slapi_Value**)oneval, &keyvals, LDAP_FILTER_EQUALITY ) != 0 /* jcm cast */
+	if ( slapi_attr_values2keys_sv( a, (Slapi_Value**)oneval, &keyvals, LDAP_FILTER_EQUALITY ) != 0 /* jcm cast */
 	    || keyvals == NULL
 	    || keyvals[0] == NULL )
 	{
 		LDAPDebug( LDAP_DEBUG_ANY, "valuetree_find_and_replace: "
-		    "slapi_call_syntax_values2keys failed for type %s\n",
+		    "slapi_attr_values2keys_sv failed for type %s\n",
 		    a->a_type, 0, 0 );
 		return( LDAP_OPERATIONS_ERROR );
 	}
@@ -1104,7 +1103,7 @@ valueset_remove_valuearray(Slapi_ValueSet *vs, const Slapi_Attr *a, Slapi_Value
 			 */
 			Avlnode	*vtree = NULL;
 			int numberofexistingvalues= slapi_valueset_count(vs);
-			rc= valuetree_add_valuearray( a->a_type, a->a_plugin, vs->va, &vtree, NULL );
+			rc= valuetree_add_valuearray( a, vs->va, &vtree, NULL );
 			if ( rc!=LDAP_SUCCESS )
 			{
 				/*
@@ -1286,14 +1285,14 @@ valueset_intersectswith_valuearray(Slapi_ValueSet *vs, const Slapi_Attr *a, Slap
 			 * Several values to add: use an AVL tree to detect duplicates.
 			 */
 			Avlnode	*vtree = NULL;
-			rc= valuetree_add_valuearray( a->a_type, a->a_plugin, vs->va, &vtree, duplicate_index );
+			rc= valuetree_add_valuearray( a, vs->va, &vtree, duplicate_index );
 			if(rc==LDAP_OPERATIONS_ERROR)
 			{
 				/* There were already duplicate values in the value set */
 			}
 			else
 			{
-				rc= valuetree_add_valuearray( a->a_type, a->a_plugin, values, &vtree, duplicate_index );
+				rc= valuetree_add_valuearray( a, values, &vtree, duplicate_index );
 				/*
 				 * Returns LDAP_OPERATIONS_ERROR if something very bad happens.
 				 * Or LDAP_TYPE_OR_VALUE_EXISTS if a value already exists.
@@ -1356,7 +1355,7 @@ valueset_replace(Slapi_Attr *a, Slapi_ValueSet *vs, Slapi_Value **valstoreplace)
     if (numberofvalstoreplace > 1)
     {
         Avlnode *vtree = NULL;
-        rc = valuetree_add_valuearray( a->a_type, a->a_plugin, valstoreplace, &vtree, NULL );
+        rc = valuetree_add_valuearray( a, valstoreplace, &vtree, NULL );
         valuetree_free(&vtree);
         if ( LDAP_SUCCESS != rc &&
              /* bz 247413: don't override LDAP_TYPE_OR_VALUE_EXISTS */
@@ -1396,7 +1395,7 @@ valueset_update_csn_for_valuearray(Slapi_ValueSet *vs, const Slapi_Attr *a, Slap
 		{
 			int i;
 			Avlnode	*vtree = NULL;
-			int rc= valuetree_add_valuearray( a->a_type, a->a_plugin, vs->va, &vtree, NULL );
+			int rc= valuetree_add_valuearray( a, vs->va, &vtree, NULL );
 			PR_ASSERT(rc==LDAP_SUCCESS);
 			for (i=0;valuestoupdate[i]!=NULL;++i)
 			{


commit 3e5e21c68afc5ff38d0d843fafaddd145e4d38f5
Author: Rich Megginson <rmeggins at redhat.com>
Date:   Mon Feb 8 08:53:44 2010 -0700

    bump version to 1.2.6.a2

diff --git a/VERSION.sh b/VERSION.sh
index 051b14b..00cdcdf 100644
--- a/VERSION.sh
+++ b/VERSION.sh
@@ -14,7 +14,7 @@ VERSION_MAINT=6
 # if this is a PRERELEASE, set VERSION_PREREL
 # otherwise, comment it out
 # be sure to include the dot prefix in the prerel
-VERSION_PREREL=.a1
+VERSION_PREREL=.a2
 # NOTES on VERSION_PREREL
 # use aN for an alpha release e.g. a1, a2, etc.
 # use rcN for a release candidate e.g. rc1, rc2, etc.




More information about the 389-commits mailing list