From f9195f9b6f9fc995fe120a9ff0fcd01d51fd0cc8 Mon Sep 17 00:00:00 2001
From: Kurt Zeilenga <kurt@openldap.org>
Date: Sat, 5 Feb 2000 05:01:41 +0000
Subject: [PATCH] Another round of SLAPD_SCHEMA_NOT_COMPAT changes including
 basic structures for handing language tags and binary option (but less actual
 code to actually support them).  Provided for reference only.  Will not even
 compile.

---
 servers/slapd/Makefile.in        |    6 +-
 servers/slapd/add.c              |    7 +-
 servers/slapd/at.c               |  563 ++++++++++++++++
 servers/slapd/attr.c             |  606 ++---------------
 servers/slapd/back-bdb2/add.c    |    2 +-
 servers/slapd/back-bdb2/modify.c |    2 +-
 servers/slapd/back-ldbm/add.c    |    2 +-
 servers/slapd/back-ldbm/index.c  |    9 +
 servers/slapd/back-ldbm/modify.c |    2 +-
 servers/slapd/backend.c          |   37 +-
 servers/slapd/entry.c            |   11 +-
 servers/slapd/libslapd.dsp       |   20 +
 servers/slapd/mr.c               |  206 ++++++
 servers/slapd/oc.c               |  456 +++++++++++++
 servers/slapd/proto-slap.h       |   28 +-
 servers/slapd/result.c           |   69 +-
 servers/slapd/schema.c           | 1036 +-----------------------------
 servers/slapd/schema_check.c     |  271 ++++++++
 servers/slapd/slap.h             |   48 +-
 servers/slapd/syntax.c           |  182 ++++++
 servers/slapd/tools/Makefile.in  |    3 +-
 servers/slapd/tools/slapadd.c    |    2 +-
 22 files changed, 1913 insertions(+), 1655 deletions(-)
 create mode 100644 servers/slapd/at.c
 create mode 100644 servers/slapd/mr.c
 create mode 100644 servers/slapd/oc.c
 create mode 100644 servers/slapd/schema_check.c
 create mode 100644 servers/slapd/syntax.c

diff --git a/servers/slapd/Makefile.in b/servers/slapd/Makefile.in
index bf0cca393f..b25e48efa0 100644
--- a/servers/slapd/Makefile.in
+++ b/servers/slapd/Makefile.in
@@ -15,7 +15,8 @@ SRCS	= main.c daemon.c connection.c search.c filter.c add.c charray.c \
 		value.c ava.c bind.c unbind.c abandon.c filterentry.c \
 		phonetic.c acl.c str2filter.c aclparse.c init.c user.c \
 		repl.c lock.c controls.c extended.c kerberos.c passwd.c \
-		schema.c schema_init.c schemaparse.c \
+		schema.c schema_check.c schema_init.c schemaparse.c \
+		at.c mr.c syntax.c oc.c \
 		monitor.c configinfo.c starttls.c \
 		root_dse.c sasl.c module.c suffixalias.c $(@PLAT@_SRCS)
 
@@ -25,7 +26,8 @@ OBJS	= main.o daemon.o connection.o search.o filter.o add.o charray.o \
 		value.o ava.o bind.o unbind.o abandon.o filterentry.o \
 		phonetic.o acl.o str2filter.o aclparse.o init.o user.o \
 		repl.o lock.o controls.o extended.o kerberos.o passwd.o \
-		schema.o schema_init.o schemaparse.o \
+		schema.o schema_check.o schema_init.o schemaparse.o \
+		at.o mr.o syntax.o oc.o \
 		monitor.o configinfo.o starttls.o \
 		root_dse.o sasl.o module.o suffixalias.o $(@PLAT@_OBJS)
 
diff --git a/servers/slapd/add.c b/servers/slapd/add.c
index 8fef1b17b3..11069badee 100644
--- a/servers/slapd/add.c
+++ b/servers/slapd/add.c
@@ -244,7 +244,12 @@ add_created_attrs( Operation *op, Entry *e )
 
 	/* return error on any attempts by the user to add these attrs */
 	for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
-		if ( oc_check_op_no_usermod_attr( a->a_type ) ) {
+#ifdef SLAPD_SCHEMA_NOT_COMPAT
+		if ( is_at_no_user_mod( a->a_desc.ad_type ))
+#else
+		if ( oc_check_op_no_usermod_attr( a->a_type ) )
+#endif
+		{
 			return LDAP_CONSTRAINT_VIOLATION;
 		}
 	}
diff --git a/servers/slapd/at.c b/servers/slapd/at.c
new file mode 100644
index 0000000000..2538e143ee
--- /dev/null
+++ b/servers/slapd/at.c
@@ -0,0 +1,563 @@
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+/* at.c - routines for dealing with attributes */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/ctype.h>
+#include <ac/errno.h>
+#include <ac/socket.h>
+#include <ac/string.h>
+#include <ac/time.h>
+
+#include "ldap_pvt.h"
+#include "slap.h"
+
+#ifndef SLAPD_SCHEMA_NOT_COMPAT
+char *
+at_canonical_name( const char * a_type )
+{
+	AttributeType	*atp;
+
+	atp=at_find(a_type);
+
+	if ( atp == NULL ) {
+		return (char *) a_type;
+
+	} else if ( atp->sat_names
+		&& atp->sat_names[0] && (*(atp->sat_names[0]) != '\0') )
+	{
+		return atp->sat_names[0];
+
+	} else if (atp->sat_oid && (*atp->sat_oid != '\0')) {
+		return atp->sat_oid;
+	}
+
+	return (char *) a_type;
+}
+
+#define DEFAULT_SYNTAX	SYNTAX_CIS
+
+/*
+ * attr_syntax - return the syntax of attribute type
+ */
+
+int
+attr_syntax( const char *type )
+{
+	AttributeType	*sat;
+
+	sat = at_find(type);
+	if ( sat ) {
+		return( sat->sat_syntax_compat );
+	}
+
+	return( DEFAULT_SYNTAX );
+}
+
+/*
+ * attr_syntax_config - process an attribute syntax config line
+ */
+
+void
+attr_syntax_config(
+    const char	*fname,
+    int		lineno,
+    int		argc,
+    char	**argv
+)
+{
+	char			*save;
+	LDAP_ATTRIBUTE_TYPE	*at;
+	int			lasti;
+	int			code;
+	const char		*err;
+
+	if ( argc < 2 ) {
+		Debug( LDAP_DEBUG_ANY,
+"%s: line %d: missing name in \"attribute <name>+ <syntax>\" (ignored)\n",
+		    fname, lineno, 0 );
+		return;
+	}
+
+	at = (LDAP_ATTRIBUTE_TYPE *)
+		ch_calloc( 1, sizeof(LDAP_ATTRIBUTE_TYPE) );
+
+#define SYNTAX_DS_OID	"1.3.6.1.4.1.1466.115.121.1.15"
+#define SYNTAX_DSCE_OID	"2.5.13.5"
+#define SYNTAX_IA5_OID	"1.3.6.1.4.1.1466.115.121.1.26"
+#define SYNTAX_IA5CE_OID	"1.3.6.1.4.1.1466.109.114.1"
+#define SYNTAX_DN_OID	SLAPD_OID_DN_SYNTAX
+#define SYNTAX_TEL_OID	"1.3.6.1.4.1.1466.115.121.1.50"
+#define SYNTAX_BIN_OID	"1.3.6.1.4.1.1466.115.121.1.40" /* octetString */
+
+	lasti = argc - 1;
+	if ( strcasecmp( argv[lasti], "caseignorestring" ) == 0 ||
+	    strcasecmp( argv[lasti], "cis" ) == 0 ) {
+		at->at_syntax_oid = SYNTAX_DS_OID;
+		at->at_equality_oid = "2.5.13.2";
+		at->at_ordering_oid = "2.5.13.3";
+		at->at_substr_oid = "2.5.13.4";
+
+	} else if ( strcasecmp( argv[lasti], "telephone" ) == 0 ||
+	    strcasecmp( argv[lasti], "tel" ) == 0 ) {
+		at->at_syntax_oid = SYNTAX_TEL_OID;
+		at->at_equality_oid = "2.5.13.20";
+		at->at_substr_oid = "2.5.13.21";
+
+	} else if ( strcasecmp( argv[lasti], "dn" ) == 0 ) {
+		at->at_syntax_oid = SYNTAX_DN_OID;
+		at->at_equality_oid = "2.5.13.1";
+
+	} else if ( strcasecmp( argv[lasti], "caseexactstring" ) == 0 ||
+	    strcasecmp( argv[lasti], "ces" ) == 0 ) {
+		at->at_syntax_oid = SYNTAX_DS_OID;
+		at->at_equality_oid = SYNTAX_DSCE_OID;
+		at->at_ordering_oid = "2.5.13.6";
+		at->at_substr_oid = "2.5.13.7";
+
+	} else if ( strcasecmp( argv[lasti], "binary" ) == 0 ||
+	    strcasecmp( argv[lasti], "bin" ) == 0 ) {
+		/* bin -> octetString, not binary! */
+		at->at_syntax_oid = SYNTAX_BIN_OID;
+		at->at_equality_oid = "2.5.13.17";
+
+	} else {
+		Debug( LDAP_DEBUG_ANY,
+	    "%s: line %d: unknown syntax \"%s\" in attribute line (ignored)\n",
+		    fname, lineno, argv[lasti] );
+		Debug( LDAP_DEBUG_ANY,
+    "possible syntaxes are \"cis\", \"ces\", \"tel\", \"dn\", or \"bin\"\n",
+		    0, 0, 0 );
+		free( (AttributeType *) at );
+		return;
+	}
+
+	save = argv[lasti];
+	argv[lasti] = NULL;
+	at->at_names = charray_dup( argv );
+	argv[lasti] = save;
+
+	code = at_add( at, &err );
+	if ( code ) {
+		fprintf( stderr, "%s: line %d: %s %s\n",
+			 fname, lineno, scherr2str(code), err);
+		exit( EXIT_FAILURE );
+	}
+
+	ldap_memfree(at);
+}
+
+int
+at_fake_if_needed(
+    const char	*name
+)
+{
+	char *argv[3];
+
+	if ( at_find( name ) ) {
+		return 0;
+	} else {
+		argv[0] = (char*) name;
+		argv[1] = "cis";
+		argv[2] = NULL;
+		attr_syntax_config( "implicit", 0, 2, argv );
+		return 0;
+	}
+}
+
+#endif
+
+
+
+struct aindexrec {
+	char		*air_name;
+	AttributeType	*air_at;
+};
+
+static Avlnode	*attr_index = NULL;
+static AttributeType *attr_list = NULL;
+
+static int
+attr_index_cmp(
+    struct aindexrec	*air1,
+    struct aindexrec	*air2
+)
+{
+	return (strcasecmp( air1->air_name, air2->air_name ));
+}
+
+static int
+attr_index_name_cmp(
+    char 		*type,
+    struct aindexrec	*air
+)
+{
+	return (strcasecmp( type, air->air_name ));
+}
+
+AttributeType *
+at_find(
+    const char		*name
+)
+{
+	struct aindexrec	*air;
+	char			*tmpname;
+
+#ifndef SLAPD_SCHEMA_NOT_COMPAT
+	/*
+	 * The name may actually be an AttributeDescription, i.e. it may
+	 * contain options.
+	 */
+	/* Treat any attribute type with option as an unknown attribute type */
+	char *p = strchr( name, ';' );
+	if ( p ) {
+		tmpname = ch_malloc( p-name+1 );
+		strncpy( tmpname, name, p-name );
+		tmpname[p-name] = '\0';
+	} else
+#endif
+	{
+		tmpname = (char *)name;
+	}
+
+	if ( (air = (struct aindexrec *) avl_find( attr_index, tmpname,
+            (AVL_CMP) attr_index_name_cmp )) != NULL ) {
+		if ( tmpname != name )
+			ldap_memfree( tmpname );
+		return( air->air_at );
+	}
+
+	if ( tmpname != name )
+		ldap_memfree( tmpname );
+	return( NULL );
+}
+
+int
+at_append_to_list(
+    AttributeType	*sat,
+    AttributeType	***listp
+)
+{
+	AttributeType	**list;
+	AttributeType	**list1;
+	int		size;
+
+	list = *listp;
+	if ( !list ) {
+		size = 2;
+		list = calloc(size, sizeof(AttributeType *));
+		if ( !list ) {
+			return -1;
+		}
+	} else {
+		size = 0;
+		list1 = *listp;
+		while ( *list1 ) {
+			size++;
+			list1++;
+		}
+		size += 2;
+		list1 = realloc(list, size*sizeof(AttributeType *));
+		if ( !list1 ) {
+			return -1;
+		}
+		list = list1;
+	}
+	list[size-2] = sat;
+	list[size-1] = NULL;
+	*listp = list;
+	return 0;
+}
+
+int
+at_delete_from_list(
+    int			pos,
+    AttributeType	***listp
+)
+{
+	AttributeType	**list;
+	AttributeType	**list1;
+	int		i;
+	int		j;
+
+	if ( pos < 0 ) {
+		return -2;
+	}
+	list = *listp;
+	for ( i=0; list[i]; i++ )
+		;
+	if ( pos >= i ) {
+		return -2;
+	}
+	for ( i=pos, j=pos+1; list[j]; i++, j++ ) {
+		list[i] = list[j];
+	}
+	list[i] = NULL;
+	/* Tell the runtime this can be shrinked */
+	list1 = realloc(list, (i+1)*sizeof(AttributeType **));
+	if ( !list1 ) {
+		return -1;
+	}
+	*listp = list1;
+	return 0;
+}
+
+int
+at_find_in_list(
+    AttributeType	*sat,
+    AttributeType	**list
+)
+{
+	int	i;
+
+	if ( !list ) {
+		return -1;
+	}
+	for ( i=0; list[i]; i++ ) {
+		if ( sat == list[i] ) {
+			return i;
+		}
+	}
+	return -1;
+}
+
+static int
+at_insert(
+    AttributeType	*sat,
+    const char		**err
+)
+{
+	AttributeType		**atp;
+	struct aindexrec	*air;
+	char			**names;
+
+	atp = &attr_list;
+	while ( *atp != NULL ) {
+		atp = &(*atp)->sat_next;
+	}
+	*atp = sat;
+
+	if ( sat->sat_oid ) {
+		air = (struct aindexrec *)
+			ch_calloc( 1, sizeof(struct aindexrec) );
+		air->air_name = sat->sat_oid;
+		air->air_at = sat;
+		if ( avl_insert( &attr_index, (caddr_t) air,
+				 (AVL_CMP) attr_index_cmp,
+				 (AVL_DUP) avl_dup_error ) ) {
+			*err = sat->sat_oid;
+			ldap_memfree(air);
+			return SLAP_SCHERR_DUP_ATTR;
+		}
+		/* FIX: temporal consistency check */
+		at_find(air->air_name);
+	}
+
+	if ( (names = sat->sat_names) ) {
+		while ( *names ) {
+			air = (struct aindexrec *)
+				ch_calloc( 1, sizeof(struct aindexrec) );
+			air->air_name = ch_strdup(*names);
+			air->air_at = sat;
+			if ( avl_insert( &attr_index, (caddr_t) air,
+					 (AVL_CMP) attr_index_cmp,
+					 (AVL_DUP) avl_dup_error ) ) {
+				*err = *names;
+				ldap_memfree(air->air_name);
+				ldap_memfree(air);
+				return SLAP_SCHERR_DUP_ATTR;
+			}
+			/* FIX: temporal consistency check */
+			at_find(air->air_name);
+			names++;
+		}
+	}
+
+	return 0;
+}
+
+int
+at_add(
+    LDAP_ATTRIBUTE_TYPE	*at,
+    const char		**err
+)
+{
+	AttributeType	*sat;
+	MatchingRule	*mr;
+	Syntax		*syn;
+	int		code;
+	char			*cname;
+
+	if ( at->at_names && at->at_names[0] ) {
+		cname = at->at_names[0];
+	} else if ( at->at_oid ) {
+		cname = at->at_oid;
+	} else {
+		cname = "";
+		return SLAP_SCHERR_ATTR_INCOMPLETE;
+	}
+	sat = (AttributeType *) ch_calloc( 1, sizeof(AttributeType) );
+	memcpy( &sat->sat_atype, at, sizeof(LDAP_ATTRIBUTE_TYPE));
+
+#ifdef SLAPD_SCHEMA_NOT_COMPAT
+	sat->sat_cname = cname;
+#endif
+
+	if ( at->at_sup_oid ) {
+		AttributeType *supsat = at_find(at->at_sup_oid);
+
+		if ( (supsat == NULL ) ) {
+			*err = at->at_sup_oid;
+			return SLAP_SCHERR_ATTR_NOT_FOUND;
+		}
+
+		sat->sat_sup = supsat;
+
+		if ( at_append_to_list(sat, &supsat->sat_subtypes) ) {
+			*err = cname;
+			return SLAP_SCHERR_OUTOFMEM;
+		}
+	}
+
+	/*
+	 * Inherit definitions from superiors.  We only check the
+	 * direct superior since that one has already inherited from
+	 * its own superiorss
+	 */
+	if ( sat->sat_sup ) {
+		sat->sat_syntax = sat->sat_sup->sat_syntax;
+
+		sat->sat_equality = sat->sat_sup->sat_equality;
+		sat->sat_ordering = sat->sat_sup->sat_ordering;
+		sat->sat_substr = sat->sat_sup->sat_substr;
+	}
+
+	if ( at->at_syntax_oid ) {
+		if ( (syn = syn_find(sat->sat_syntax_oid)) ) {
+			sat->sat_syntax = syn;
+		} else {
+			*err = sat->sat_syntax_oid;
+			return SLAP_SCHERR_SYN_NOT_FOUND;
+		}
+
+#ifndef SLAPD_SCHEMA_NOT_COMPAT
+		if ( !strcmp(at->at_syntax_oid, SYNTAX_DS_OID) ) {
+			if ( at->at_equality_oid && (
+				!strcmp(at->at_equality_oid, SYNTAX_DSCE_OID) ) )
+			{
+				sat->sat_syntax_compat = SYNTAX_CES;
+			} else {
+				sat->sat_syntax_compat = SYNTAX_CIS;
+			}
+
+		} else if ( !strcmp(at->at_syntax_oid, SYNTAX_IA5_OID) ) {
+			if ( at->at_equality_oid && (
+				!strcmp(at->at_equality_oid, SYNTAX_IA5CE_OID) ) )
+			{
+				sat->sat_syntax_compat = SYNTAX_CES;
+			} else {
+				sat->sat_syntax_compat = SYNTAX_CIS;
+			}
+
+		} else if ( !strcmp(at->at_syntax_oid, SYNTAX_DN_OID ) ) {
+			sat->sat_syntax_compat = SYNTAX_CIS | SYNTAX_DN;
+
+		} else if ( !strcmp(at->at_syntax_oid, SYNTAX_TEL_OID ) ) {
+			sat->sat_syntax_compat = SYNTAX_CIS | SYNTAX_TEL;
+
+		} else if ( !strcmp(at->at_syntax_oid, SYNTAX_BIN_OID ) ) {
+			sat->sat_syntax_compat = SYNTAX_BIN;
+
+		} else {
+			sat->sat_syntax_compat = DEFAULT_SYNTAX;
+		}
+#endif
+
+	} else if ( sat->sat_syntax == NULL ) {
+		return SLAP_SCHERR_ATTR_INCOMPLETE;
+	}
+
+	if ( sat->sat_equality_oid ) {
+		if ( (mr = mr_find(sat->sat_equality_oid)) ) {
+			sat->sat_equality = mr;
+		} else {
+			*err = sat->sat_equality_oid;
+			return SLAP_SCHERR_MR_NOT_FOUND;
+		}
+
+	}
+
+	if ( sat->sat_ordering_oid ) {
+		if ( (mr = mr_find(sat->sat_ordering_oid)) ) {
+			sat->sat_ordering = mr;
+		} else {
+			*err = sat->sat_ordering_oid;
+			return SLAP_SCHERR_MR_NOT_FOUND;
+		}
+	}
+
+	if ( sat->sat_substr_oid ) {
+		if ( (mr = mr_find(sat->sat_substr_oid)) ) {
+			sat->sat_substr = mr;
+		} else {
+			*err = sat->sat_substr_oid;
+			return SLAP_SCHERR_MR_NOT_FOUND;
+		}
+	}
+
+	code = at_insert(sat,err);
+	return code;
+}
+
+#ifdef LDAP_DEBUG
+static int
+at_index_printnode( struct aindexrec *air )
+{
+
+	printf("%s = %s\n",
+		air->air_name,
+		ldap_attributetype2str(&air->air_at->sat_atype) );
+	return( 0 );
+}
+
+static void
+at_index_print( void )
+{
+	printf("Printing attribute type index:\n");
+	(void) avl_apply( attr_index, (AVL_APPLY) at_index_printnode,
+		0, -1, AVL_INORDER );
+}
+#endif
+
+#if defined( SLAPD_SCHEMA_DN )
+int
+at_schema_info( Entry *e )
+{
+	struct berval	val;
+	struct berval	*vals[2];
+	AttributeType	*at;
+
+	vals[0] = &val;
+	vals[1] = NULL;
+
+	for ( at = attr_list; at; at = at->sat_next ) {
+		val.bv_val = ldap_attributetype2str( &at->sat_atype );
+		if ( val.bv_val ) {
+			val.bv_len = strlen( val.bv_val );
+			Debug( LDAP_DEBUG_TRACE, "Merging at [%ld] %s\n",
+			       (long) val.bv_len, val.bv_val, 0 );
+			attr_merge( e, "attributeTypes", vals );
+			ldap_memfree( val.bv_val );
+		} else {
+			return -1;
+		}
+	}
+	return 0;
+}
+#endif
diff --git a/servers/slapd/attr.c b/servers/slapd/attr.c
index 0d95e2887f..0621645f03 100644
--- a/servers/slapd/attr.c
+++ b/servers/slapd/attr.c
@@ -26,10 +26,28 @@
 static void at_index_print( void );
 #endif
 
+#ifdef SLAPD_SCHEMA_NOT_COMPAT
+void
+ad_free( AttributeDescription *ad, int freeit )
+{
+	if( ad == NULL ) return;
+
+	ber_bvfree( ad->ad_cname );
+	free( ad->ad_lang );
+
+	if( freeit ) free( ad );
+}
+#endif
+
 void
 attr_free( Attribute *a )
 {
+#ifdef SLAPD_SCHEMA_NOT_COMPAT
+	/* not yet implemented */
+	ad_free( &a->a_desc, 0 );
+#else
 	free( a->a_type );
+#endif
 	ber_bvecfree( a->a_vals );
 	free( a );
 }
@@ -74,8 +92,13 @@ Attribute *attr_dup( Attribute *a )
 		tmp->a_vals = NULL;
 	}
 
+#ifdef SLAPD_SCHEMA_NOT_COMPAT
+	/* not yet implemented */
+	tmp->a_desc = a->a_desc;
+	tmp->a_desc.ad_cname = ber_bvdup( a->a_desc.ad_cname );
+	tmp->a_desc.ad_lang = ch_strdup( a->a_desc.ad_lang );
+#else
 	tmp->a_type = ch_strdup( a->a_type );
-#ifndef SLAPD_SCHEMA_NOT_COMPAT
 	tmp->a_syntax = a->a_syntax;
 #endif
 	tmp->a_next = NULL;
@@ -101,6 +124,7 @@ Attribute *attrs_dup( Attribute *a )
 	return tmp;
 }
 
+#ifndef SLAPD_SCHEMA_NOT_COMPAT
 /*
  * attr_normalize - normalize an attribute name (make it all lowercase)
  */
@@ -112,7 +136,9 @@ attr_normalize( char *s )
 
 	return( ldap_pvt_str2lower( s ) );
 }
+#endif
 
+#ifndef SLAPD_SCHEMA_NOT_COMPAT
 /*
  * attr_merge_fast - merge the given type and value with the list of
  * attributes in attrs. called from str2entry(), where we can make some
@@ -134,17 +160,21 @@ attr_merge_fast(
 {
 	if ( *a == NULL ) {
 		for ( *a = &e->e_attrs; **a != NULL; *a = &(**a)->a_next ) {
+#ifdef SLAPD_SCHEMA_NOT_COMPAT
+			/* not yet implemented */
+#else
 			if ( strcasecmp( (**a)->a_type, type ) == 0 ) {
 				break;
 			}
+#endif
 		}
 	}
 
 	if ( **a == NULL ) {
 		**a = (Attribute *) ch_malloc( sizeof(Attribute) );
-		(**a)->a_type = attr_normalize( ch_strdup( type ) );
 		(**a)->a_vals = NULL;
 #ifndef SLAPD_SCHEMA_NOT_COMPAT
+		(**a)->a_type = attr_normalize( ch_strdup( type ) );
 		(**a)->a_syntax = attr_syntax( type );
 #endif
 		(**a)->a_next = NULL;
@@ -153,6 +183,7 @@ attr_merge_fast(
 	return( value_add_fast( &(**a)->a_vals, vals, nvals, naddvals,
 	    maxvals ) );
 }
+#endif
 
 /*
  * attr_merge - merge the given type and value with the list of
@@ -171,18 +202,24 @@ attr_merge(
 	Attribute	**a;
 
 	for ( a = &e->e_attrs; *a != NULL; a = &(*a)->a_next ) {
+#ifdef SLAPD_SCHEMA_NOT_COMPAT
+		/* not yet implemented */
+#else
 		if ( strcasecmp( (*a)->a_type, type ) == 0 ) {
 			break;
 		}
+#endif
 	}
 
 	if ( *a == NULL ) {
 		*a = (Attribute *) ch_malloc( sizeof(Attribute) );
+#ifdef SLAPD_SCHEMA_NOT_COMPAT
+		/* not yet implemented */
+#else
 		(*a)->a_type = attr_normalize( ch_strdup( type ) );
-		(*a)->a_vals = NULL;
-#ifndef SLAPD_SCHEMA_NOT_COMPAT
 		(*a)->a_syntax = attr_syntax( type );
 #endif
+		(*a)->a_vals = NULL;
 		(*a)->a_next = NULL;
 	}
 
@@ -190,19 +227,23 @@ attr_merge(
 }
 
 /*
- * attr_find - find and return attribute type in list a
+ * attr_find - find attribute by type
  */
 
 Attribute *
 attr_find(
     Attribute	*a,
-    const char	*type
+	const char	*type
 )
 {
 	for ( ; a != NULL; a = a->a_next ) {
+#ifdef SLAPD_SCHEMA_NOT_COMPAT
+		/* not yet implemented */
+#else
 		if ( strcasecmp( a->a_type, type ) == 0 ) {
 			return( a );
 		}
+#endif
 	}
 
 	return( NULL );
@@ -225,9 +266,13 @@ attr_delete(
 	Attribute	*save;
 
 	for ( a = attrs; *a != NULL; a = &(*a)->a_next ) {
+#ifdef SLAPD_SCHEMA_NOT_COMPAT
+		/* not yet implemented */
+#else
 		if ( strcasecmp( (*a)->a_type, type ) == 0 ) {
 			break;
 		}
+#endif
 	}
 
 	if ( *a == NULL ) {
@@ -241,552 +286,3 @@ attr_delete(
 	return( 0 );
 }
 
-#ifndef SLAPD_SCHEMA_NOT_COMPAT
-
-#define DEFAULT_SYNTAX	SYNTAX_CIS
-
-/*
- * attr_syntax - return the syntax of attribute type
- */
-
-int
-attr_syntax( const char *type )
-{
-	AttributeType	*sat;
-
-	sat = at_find(type);
-	if ( sat ) {
-		return( sat->sat_syntax_compat );
-	}
-
-	return( DEFAULT_SYNTAX );
-}
-
-/*
- * attr_syntax_config - process an attribute syntax config line
- */
-
-void
-attr_syntax_config(
-    const char	*fname,
-    int		lineno,
-    int		argc,
-    char	**argv
-)
-{
-	char			*save;
-	LDAP_ATTRIBUTE_TYPE	*at;
-	int			lasti;
-	int			code;
-	const char		*err;
-
-	if ( argc < 2 ) {
-		Debug( LDAP_DEBUG_ANY,
-"%s: line %d: missing name in \"attribute <name>+ <syntax>\" (ignored)\n",
-		    fname, lineno, 0 );
-		return;
-	}
-
-	at = (LDAP_ATTRIBUTE_TYPE *)
-		ch_calloc( 1, sizeof(LDAP_ATTRIBUTE_TYPE) );
-
-#define SYNTAX_DS_OID	"1.3.6.1.4.1.1466.115.121.1.15"
-#define SYNTAX_DSCE_OID	"2.5.13.5"
-#define SYNTAX_IA5_OID	"1.3.6.1.4.1.1466.115.121.1.26"
-#define SYNTAX_IA5CE_OID	"1.3.6.1.4.1.1466.109.114.1"
-#define SYNTAX_DN_OID	SLAPD_OID_DN_SYNTAX
-#define SYNTAX_TEL_OID	"1.3.6.1.4.1.1466.115.121.1.50"
-#define SYNTAX_BIN_OID	"1.3.6.1.4.1.1466.115.121.1.40" /* octetString */
-
-	lasti = argc - 1;
-	if ( strcasecmp( argv[lasti], "caseignorestring" ) == 0 ||
-	    strcasecmp( argv[lasti], "cis" ) == 0 ) {
-		at->at_syntax_oid = SYNTAX_DS_OID;
-		at->at_equality_oid = "2.5.13.2";
-		at->at_ordering_oid = "2.5.13.3";
-		at->at_substr_oid = "2.5.13.4";
-
-	} else if ( strcasecmp( argv[lasti], "telephone" ) == 0 ||
-	    strcasecmp( argv[lasti], "tel" ) == 0 ) {
-		at->at_syntax_oid = SYNTAX_TEL_OID;
-		at->at_equality_oid = "2.5.13.20";
-		at->at_substr_oid = "2.5.13.21";
-
-	} else if ( strcasecmp( argv[lasti], "dn" ) == 0 ) {
-		at->at_syntax_oid = SYNTAX_DN_OID;
-		at->at_equality_oid = "2.5.13.1";
-
-	} else if ( strcasecmp( argv[lasti], "caseexactstring" ) == 0 ||
-	    strcasecmp( argv[lasti], "ces" ) == 0 ) {
-		at->at_syntax_oid = SYNTAX_DS_OID;
-		at->at_equality_oid = SYNTAX_DSCE_OID;
-		at->at_ordering_oid = "2.5.13.6";
-		at->at_substr_oid = "2.5.13.7";
-
-	} else if ( strcasecmp( argv[lasti], "binary" ) == 0 ||
-	    strcasecmp( argv[lasti], "bin" ) == 0 ) {
-		/* bin -> octetString, not binary! */
-		at->at_syntax_oid = SYNTAX_BIN_OID;
-		at->at_equality_oid = "2.5.13.17";
-
-	} else {
-		Debug( LDAP_DEBUG_ANY,
-	    "%s: line %d: unknown syntax \"%s\" in attribute line (ignored)\n",
-		    fname, lineno, argv[lasti] );
-		Debug( LDAP_DEBUG_ANY,
-    "possible syntaxes are \"cis\", \"ces\", \"tel\", \"dn\", or \"bin\"\n",
-		    0, 0, 0 );
-		free( (AttributeType *) at );
-		return;
-	}
-
-	save = argv[lasti];
-	argv[lasti] = NULL;
-	at->at_names = charray_dup( argv );
-	argv[lasti] = save;
-
-	code = at_add( at, &err );
-	if ( code ) {
-		fprintf( stderr, "%s: line %d: %s %s\n",
-			 fname, lineno, scherr2str(code), err);
-		exit( EXIT_FAILURE );
-	}
-
-	ldap_memfree(at);
-}
-
-int
-at_fake_if_needed(
-    const char	*name
-)
-{
-	char *argv[3];
-
-	if ( at_find( name ) ) {
-		return 0;
-	} else {
-		argv[0] = (char*) name;
-		argv[1] = "cis";
-		argv[2] = NULL;
-		attr_syntax_config( "implicit", 0, 2, argv );
-		return 0;
-	}
-}
-#endif
-
-struct aindexrec {
-	char		*air_name;
-	AttributeType	*air_at;
-};
-
-static Avlnode	*attr_index = NULL;
-static AttributeType *attr_list = NULL;
-
-static int
-attr_index_cmp(
-    struct aindexrec	*air1,
-    struct aindexrec	*air2
-)
-{
-	return (strcasecmp( air1->air_name, air2->air_name ));
-}
-
-static int
-attr_index_name_cmp(
-    char 		*type,
-    struct aindexrec	*air
-)
-{
-	return (strcasecmp( type, air->air_name ));
-}
-
-AttributeType *
-at_find(
-    const char		*name
-)
-{
-	struct aindexrec	*air;
-	char			*tmpname;
-
-#ifndef SLAPD_SCHEMA_NOT_COMPAT
-	/*
-	 * The name may actually be an AttributeDescription, i.e. it may
-	 * contain options.
-	 */
-	/* Treat any attribute type with option as an unknown attribute type */
-	char *p = strchr( name, ';' );
-	if ( p ) {
-		tmpname = ch_malloc( p-name+1 );
-		strncpy( tmpname, name, p-name );
-		tmpname[p-name] = '\0';
-	} else
-#endif
-	{
-		tmpname = (char *)name;
-	}
-
-	if ( (air = (struct aindexrec *) avl_find( attr_index, tmpname,
-            (AVL_CMP) attr_index_name_cmp )) != NULL ) {
-		if ( tmpname != name )
-			ldap_memfree( tmpname );
-		return( air->air_at );
-	}
-
-	if ( tmpname != name )
-		ldap_memfree( tmpname );
-	return( NULL );
-}
-
-int
-at_append_to_list(
-    AttributeType	*sat,
-    AttributeType	***listp
-)
-{
-	AttributeType	**list;
-	AttributeType	**list1;
-	int		size;
-
-	list = *listp;
-	if ( !list ) {
-		size = 2;
-		list = calloc(size, sizeof(AttributeType *));
-		if ( !list ) {
-			return -1;
-		}
-	} else {
-		size = 0;
-		list1 = *listp;
-		while ( *list1 ) {
-			size++;
-			list1++;
-		}
-		size += 2;
-		list1 = realloc(list, size*sizeof(AttributeType *));
-		if ( !list1 ) {
-			return -1;
-		}
-		list = list1;
-	}
-	list[size-2] = sat;
-	list[size-1] = NULL;
-	*listp = list;
-	return 0;
-}
-
-int
-at_delete_from_list(
-    int			pos,
-    AttributeType	***listp
-)
-{
-	AttributeType	**list;
-	AttributeType	**list1;
-	int		i;
-	int		j;
-
-	if ( pos < 0 ) {
-		return -2;
-	}
-	list = *listp;
-	for ( i=0; list[i]; i++ )
-		;
-	if ( pos >= i ) {
-		return -2;
-	}
-	for ( i=pos, j=pos+1; list[j]; i++, j++ ) {
-		list[i] = list[j];
-	}
-	list[i] = NULL;
-	/* Tell the runtime this can be shrinked */
-	list1 = realloc(list, (i+1)*sizeof(AttributeType **));
-	if ( !list1 ) {
-		return -1;
-	}
-	*listp = list1;
-	return 0;
-}
-
-int
-at_find_in_list(
-    AttributeType	*sat,
-    AttributeType	**list
-)
-{
-	int	i;
-
-	if ( !list ) {
-		return -1;
-	}
-	for ( i=0; list[i]; i++ ) {
-		if ( sat == list[i] ) {
-			return i;
-		}
-	}
-	return -1;
-}
-
-static int
-at_insert(
-    AttributeType	*sat,
-    const char		**err
-)
-{
-	AttributeType		**atp;
-	struct aindexrec	*air;
-	char			**names;
-
-	atp = &attr_list;
-	while ( *atp != NULL ) {
-		atp = &(*atp)->sat_next;
-	}
-	*atp = sat;
-
-	if ( sat->sat_oid ) {
-		air = (struct aindexrec *)
-			ch_calloc( 1, sizeof(struct aindexrec) );
-		air->air_name = sat->sat_oid;
-		air->air_at = sat;
-		if ( avl_insert( &attr_index, (caddr_t) air,
-				 (AVL_CMP) attr_index_cmp,
-				 (AVL_DUP) avl_dup_error ) ) {
-			*err = sat->sat_oid;
-			ldap_memfree(air);
-			return SLAP_SCHERR_DUP_ATTR;
-		}
-		/* FIX: temporal consistency check */
-		at_find(air->air_name);
-	}
-	if ( (names = sat->sat_names) ) {
-		while ( *names ) {
-			air = (struct aindexrec *)
-				ch_calloc( 1, sizeof(struct aindexrec) );
-			air->air_name = ch_strdup(*names);
-			air->air_at = sat;
-			if ( avl_insert( &attr_index, (caddr_t) air,
-					 (AVL_CMP) attr_index_cmp,
-					 (AVL_DUP) avl_dup_error ) ) {
-				*err = *names;
-				ldap_memfree(air->air_name);
-				ldap_memfree(air);
-				return SLAP_SCHERR_DUP_ATTR;
-			}
-			/* FIX: temporal consistency check */
-			at_find(air->air_name);
-			names++;
-		}
-	}
-
-	return 0;
-}
-
-int
-at_add(
-    LDAP_ATTRIBUTE_TYPE	*at,
-    const char		**err
-)
-{
-	AttributeType	*sat;
-	AttributeType	*sat1;
-	MatchingRule	*mr;
-	Syntax		*syn;
-	int		code;
-	char		*errattr;
-
-	if ( at->at_names && at->at_names[0] ) {
-		errattr = at->at_names[0];
-	} else if ( at->at_oid ) {
-		errattr = at->at_oid;
-	} else {
-		errattr = "";
-		return SLAP_SCHERR_ATTR_INCOMPLETE;
-	}
-	sat = (AttributeType *) ch_calloc( 1, sizeof(AttributeType) );
-	memcpy( &sat->sat_atype, at, sizeof(LDAP_ATTRIBUTE_TYPE));
-
-	if ( at->at_sup_oid ) {
-		if ( (sat1 = at_find(at->at_sup_oid)) ) {
-			sat->sat_sup = sat1;
-			if ( at_append_to_list(sat, &sat1->sat_subtypes) ) {
-				*err = errattr;
-				return SLAP_SCHERR_OUTOFMEM;
-			}
-		} else {
-			*err = at->at_sup_oid;
-			return SLAP_SCHERR_ATTR_NOT_FOUND;
-		}
-	}
-
-	/*
-	 * Inherit definitions from superiors.  We only check the
-	 * direct superior since that one has already inherited from
-	 * its own superiorss
-	 */
-	if ( sat->sat_sup ) {
-		sat->sat_syntax = sat->sat_sup->sat_syntax;
-
-		sat->sat_equality = sat->sat_sup->sat_equality;
-		sat->sat_ordering = sat->sat_sup->sat_ordering;
-		sat->sat_substr = sat->sat_sup->sat_substr;
-	}
-
-	if ( at->at_syntax_oid ) {
-		if ( (syn = syn_find(sat->sat_syntax_oid)) ) {
-			sat->sat_syntax = syn;
-		} else {
-			*err = sat->sat_syntax_oid;
-			return SLAP_SCHERR_SYN_NOT_FOUND;
-		}
-
-#ifndef SLAPD_SCHEMA_NOT_COMPAT
-		if ( !strcmp(at->at_syntax_oid, SYNTAX_DS_OID) ) {
-			if ( at->at_equality_oid && (
-				!strcmp(at->at_equality_oid, SYNTAX_DSCE_OID) ) )
-			{
-				sat->sat_syntax_compat = SYNTAX_CES;
-			} else {
-				sat->sat_syntax_compat = SYNTAX_CIS;
-			}
-
-		} else if ( !strcmp(at->at_syntax_oid, SYNTAX_IA5_OID) ) {
-			if ( at->at_equality_oid && (
-				!strcmp(at->at_equality_oid, SYNTAX_IA5CE_OID) ) )
-			{
-				sat->sat_syntax_compat = SYNTAX_CES;
-			} else {
-				sat->sat_syntax_compat = SYNTAX_CIS;
-			}
-
-		} else if ( !strcmp(at->at_syntax_oid, SYNTAX_DN_OID ) ) {
-			sat->sat_syntax_compat = SYNTAX_CIS | SYNTAX_DN;
-
-		} else if ( !strcmp(at->at_syntax_oid, SYNTAX_TEL_OID ) ) {
-			sat->sat_syntax_compat = SYNTAX_CIS | SYNTAX_TEL;
-
-		} else if ( !strcmp(at->at_syntax_oid, SYNTAX_BIN_OID ) ) {
-			sat->sat_syntax_compat = SYNTAX_BIN;
-
-		} else {
-			sat->sat_syntax_compat = DEFAULT_SYNTAX;
-		}
-#endif
-
-	} else if ( sat->sat_syntax == NULL ) {
-		return SLAP_SCHERR_ATTR_INCOMPLETE;
-	}
-
-	if ( sat->sat_equality_oid ) {
-		if ( (mr = mr_find(sat->sat_equality_oid)) ) {
-			sat->sat_equality = mr;
-		} else {
-			*err = sat->sat_equality_oid;
-			return SLAP_SCHERR_MR_NOT_FOUND;
-		}
-
-	}
-
-	if ( sat->sat_ordering_oid ) {
-		if ( (mr = mr_find(sat->sat_ordering_oid)) ) {
-			sat->sat_ordering = mr;
-		} else {
-			*err = sat->sat_ordering_oid;
-			return SLAP_SCHERR_MR_NOT_FOUND;
-		}
-	}
-
-	if ( sat->sat_substr_oid ) {
-		if ( (mr = mr_find(sat->sat_substr_oid)) ) {
-			sat->sat_substr = mr;
-		} else {
-			*err = sat->sat_substr_oid;
-			return SLAP_SCHERR_MR_NOT_FOUND;
-		}
-	}
-
-	code = at_insert(sat,err);
-	return code;
-}
-
-
-char *
-#ifdef SLAPD_SCHEMA_NOT_COMPAT
-at_canonical_name( AttributeType * atp )
-#else
-at_canonical_name( const char * a_type )
-#endif
-{
-#ifndef SLAPD_SCHEMA_NOT_COMPAT
-	AttributeType	*atp;
-
-	atp=at_find(a_type);
-#endif
-
-	if ( atp == NULL ) {
-#ifdef SLAPD_SCHEMA_NOT_COMPAT
-		return NULL;
-#else
-		return (char *) a_type;
-#endif
-
-	} else if ( atp->sat_names
-		&& atp->sat_names[0] && (*(atp->sat_names[0]) != '\0') )
-	{
-		return atp->sat_names[0];
-
-	} else if (atp->sat_oid && (*atp->sat_oid != '\0')) {
-		return atp->sat_oid;
-	}
-
-#ifdef SLAPD_SCHEMA_NOT_COMPAT
-	return NULL;
-#else
-	return (char *) a_type;
-#endif
-}
-
-#if defined( SLAPD_SCHEMA_DN )
-int
-at_schema_info( Entry *e )
-{
-	struct berval	val;
-	struct berval	*vals[2];
-	AttributeType	*at;
-
-	vals[0] = &val;
-	vals[1] = NULL;
-
-	for ( at = attr_list; at; at = at->sat_next ) {
-		val.bv_val = ldap_attributetype2str( &at->sat_atype );
-		if ( val.bv_val ) {
-			val.bv_len = strlen( val.bv_val );
-			Debug( LDAP_DEBUG_TRACE, "Merging at [%ld] %s\n",
-			       (long) val.bv_len, val.bv_val, 0 );
-			attr_merge( e, "attributeTypes", vals );
-			ldap_memfree( val.bv_val );
-		} else {
-			return -1;
-		}
-	}
-	return 0;
-}
-#endif
-
-#ifdef LDAP_DEBUG
-static int
-at_index_printnode( struct aindexrec *air )
-{
-
-	printf("%s = %s\n",
-		air->air_name,
-		ldap_attributetype2str(&air->air_at->sat_atype) );
-	return( 0 );
-}
-
-static void
-at_index_print( void )
-{
-	printf("Printing attribute type index:\n");
-	(void) avl_apply( attr_index, (AVL_APPLY) at_index_printnode,
-		0, -1, AVL_INORDER );
-}
-#endif
diff --git a/servers/slapd/back-bdb2/add.c b/servers/slapd/back-bdb2/add.c
index b72dc51512..2ab81e76a6 100644
--- a/servers/slapd/back-bdb2/add.c
+++ b/servers/slapd/back-bdb2/add.c
@@ -38,7 +38,7 @@ bdb2i_back_add_internal(
 		return( -1 );
 	}
 
-	if ( global_schemacheck && oc_schema_check( e ) != 0 ) {
+	if ( schema_check_entry( e ) != 0 ) {
 		Debug( LDAP_DEBUG_TRACE, "entry failed schema check\n",
 			0, 0, 0 );
 
diff --git a/servers/slapd/back-bdb2/modify.c b/servers/slapd/back-bdb2/modify.c
index badab589eb..bcb6f1c394 100644
--- a/servers/slapd/back-bdb2/modify.c
+++ b/servers/slapd/back-bdb2/modify.c
@@ -74,7 +74,7 @@ bdb2i_back_modify_internal(
 	}
 
 	/* check that the entry still obeys the schema */
-	if ( global_schemacheck && oc_schema_check( e ) != 0 ) {
+	if ( schema_check_entry( e ) != 0 ) {
 		Debug( LDAP_DEBUG_ANY, "entry failed schema check\n", 0, 0, 0 );
 		send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION,
 			NULL, NULL, NULL, NULL );
diff --git a/servers/slapd/back-ldbm/add.c b/servers/slapd/back-ldbm/add.c
index edeaf57a10..fce939ddd2 100644
--- a/servers/slapd/back-ldbm/add.c
+++ b/servers/slapd/back-ldbm/add.c
@@ -43,7 +43,7 @@ ldbm_back_add(
 		return( -1 );
 	}
 
-	if ( global_schemacheck && oc_schema_check( e ) != 0 ) {
+	if ( schema_check_entry( e ) != 0 ) {
 		ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
 
 		Debug( LDAP_DEBUG_TRACE, "entry failed schema check\n",
diff --git a/servers/slapd/back-ldbm/index.c b/servers/slapd/back-ldbm/index.c
index 1e746fc8f9..6c90a6f179 100644
--- a/servers/slapd/back-ldbm/index.c
+++ b/servers/slapd/back-ldbm/index.c
@@ -15,6 +15,7 @@
 #include "slap.h"
 #include "back-ldbm.h"
 
+
 static int	change_value(Backend *be,
 			  DBCache *db,
 			  char *type,
@@ -51,7 +52,11 @@ index_add_entry(
 	/* add the dn to the indexes */
 	{
 		char *dn = ch_strdup("dn");
+#ifdef SLAPD_SCHEMA_NOT_COMPAT
+		/* not yet implemented */
+#else
 		index_change_values( be, dn, bvals, e->e_id, SLAP_INDEX_ADD_OP );
+#endif
 		free( dn );
 	}
 
@@ -59,8 +64,12 @@ index_add_entry(
 
 	/* add each attribute to the indexes */
 	for ( ap = e->e_attrs; ap != NULL; ap = ap->a_next ) {
+#ifdef SLAPD_SCHEMA_NOT_COMPAT
+		/* index_change_values( be, SLAP_INDEX_ADD_OP, e->e_id, ap ); */
+#else
 		index_change_values( be, ap->a_type, ap->a_vals, e->e_id,
 				     SLAP_INDEX_ADD_OP );
+#endif
 	}
 
 	Debug( LDAP_DEBUG_TRACE, "<= index_add( %ld, \"%s\" ) 0\n", e->e_id,
diff --git a/servers/slapd/back-ldbm/modify.c b/servers/slapd/back-ldbm/modify.c
index d22fcc614c..f30a153a42 100644
--- a/servers/slapd/back-ldbm/modify.c
+++ b/servers/slapd/back-ldbm/modify.c
@@ -95,7 +95,7 @@ int ldbm_modify_internal(
 	ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
 
 	/* check that the entry still obeys the schema */
-	if ( global_schemacheck && oc_schema_check( e ) != 0 ) {
+	if ( schema_check_entry( e ) != 0 ) {
 		attrs_free( e->e_attrs );
 		e->e_attrs = save_attrs;
 		Debug( LDAP_DEBUG_ANY, "entry failed schema check\n", 0, 0, 0 );
diff --git a/servers/slapd/backend.c b/servers/slapd/backend.c
index c2ed169b9a..8dd65ff26e 100644
--- a/servers/slapd/backend.c
+++ b/servers/slapd/backend.c
@@ -633,26 +633,27 @@ backend_group(
 }
 
 #ifdef SLAPD_SCHEMA_DN
-Attribute *backend_subschemasubentry( Backend *be )
+Attribute *backend_operational(
+	Backend *be,
+	Entry *e )
 {
-	/*
-	 * This routine returns points to STATIC data!!!
-	 */
-	/* and should be backend specific */
-
-	static struct berval ss_val = {
-		sizeof(SLAPD_SCHEMA_DN)-1,
-		SLAPD_SCHEMA_DN };
-	static struct berval *ss_vals[2] = { &ss_val, NULL };
-	static Attribute ss_attr = {
-		"subschemasubentry",
-		ss_vals,
-#ifndef SLAPD_SCHEMA_NOT_COMPAT
-		SYNTAX_DN | SYNTAX_CIS,
+	Attribute *a = ch_malloc( sizeof( Attribute ) );
+#ifdef SLAPD_SCHEMA_NOT_COMPAT
+	/* not yet implemented */
+#else
+	a->a_type = "subschemasubentry";
+	a->a_syntax = SYNTAX_DN | SYNTAX_CIS;
 #endif
-		NULL
-	};
 
-	return &ss_attr;
+	/* Should be backend specific */
+	a->a_vals = ch_malloc( 2 * sizeof( struct berval * ) );
+	a->a_vals[0] = ch_malloc( sizeof( struct berval ) );
+	a->a_vals[0]->bv_val = strdup( SLAPD_SCHEMA_DN );
+	a->a_vals[0]->bv_len = sizeof( SLAPD_SCHEMA_DN ) - 1;
+	a->a_vals[1] = NULL;
+
+	a->a_next = NULL;
+
+	return a;
 }
 #endif
diff --git a/servers/slapd/entry.c b/servers/slapd/entry.c
index b0cd52e28f..86abbae9c1 100644
--- a/servers/slapd/entry.c
+++ b/servers/slapd/entry.c
@@ -197,9 +197,18 @@ entry2str(
 		/* put "<type>:[:] <value>" line for each value */
 		for ( i = 0; a->a_vals[i] != NULL; i++ ) {
 			bv = a->a_vals[i];
+#ifdef SLAPD_SCHEMA_NOT_COMPAT
+			tmplen = a->a_desc.ad_cname->bv_len;
+#else
 			tmplen = strlen( a->a_type );
+#endif
 			MAKE_SPACE( LDIF_SIZE_NEEDED( tmplen, bv->bv_len ));
-			ldif_sput( (char **) &ecur, LDIF_PUT_VALUE, a->a_type,
+			ldif_sput( (char **) &ecur, LDIF_PUT_VALUE,
+#ifdef SLAPD_SCHEMA_NOT_COMPAT
+				a->a_desc.ad_cname->bv_val,
+#else
+				a->a_type,
+#endif
 			    bv->bv_val, bv->bv_len );
 		}
 	}
diff --git a/servers/slapd/libslapd.dsp b/servers/slapd/libslapd.dsp
index 8e2d0200ca..fa3e332047 100644
--- a/servers/slapd/libslapd.dsp
+++ b/servers/slapd/libslapd.dsp
@@ -140,6 +140,10 @@ SOURCE=.\add.c
 # End Source File
 # Begin Source File
 
+SOURCE=.\at.c
+# End Source File
+# Begin Source File
+
 SOURCE=.\attr.c
 # End Source File
 # Begin Source File
@@ -236,6 +240,14 @@ SOURCE=.\monitor.c
 # End Source File
 # Begin Source File
 
+SOURCE=.\mr.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\oc.c
+# End Source File
+# Begin Source File
+
 SOURCE=.\operation.c
 # End Source File
 # Begin Source File
@@ -268,6 +280,10 @@ SOURCE=.\schema.c
 # End Source File
 # Begin Source File
 
+SOURCE=.\schema_check.c
+# End Source File
+# Begin Source File
+
 SOURCE=.\schema_init.c
 # End Source File
 # Begin Source File
@@ -292,6 +308,10 @@ SOURCE=.\suffixalias.c
 # End Source File
 # Begin Source File
 
+SOURCE=.\syntax.c
+# End Source File
+# Begin Source File
+
 SOURCE=.\unbind.c
 # End Source File
 # Begin Source File
diff --git a/servers/slapd/mr.c b/servers/slapd/mr.c
new file mode 100644
index 0000000000..8dbfb96c78
--- /dev/null
+++ b/servers/slapd/mr.c
@@ -0,0 +1,206 @@
+/* mr.c - routines to manage matching rule definitions */
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/ctype.h>
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "slap.h"
+#include "ldap_pvt.h"
+
+
+struct mindexrec {
+	char		*mir_name;
+	MatchingRule	*mir_mr;
+};
+
+static Avlnode	*mr_index = NULL;
+static MatchingRule *mr_list = NULL;
+
+static int
+mr_index_cmp(
+    struct mindexrec	*mir1,
+    struct mindexrec	*mir2
+)
+{
+	return (strcmp( mir1->mir_name, mir2->mir_name ));
+}
+
+static int
+mr_index_name_cmp(
+    char 		*name,
+    struct mindexrec	*mir
+)
+{
+	return (strcmp( name, mir->mir_name ));
+}
+
+MatchingRule *
+mr_find( const char *mrname )
+{
+	struct mindexrec	*mir = NULL;
+
+	if ( (mir = (struct mindexrec *) avl_find( mr_index, mrname,
+            (AVL_CMP) mr_index_name_cmp )) != NULL ) {
+		return( mir->mir_mr );
+	}
+	return( NULL );
+}
+
+static int
+mr_insert(
+    MatchingRule	*smr,
+    const char		**err
+)
+{
+	MatchingRule		**mrp;
+	struct mindexrec	*mir;
+	char			**names;
+
+	mrp = &mr_list;
+	while ( *mrp != NULL ) {
+		mrp = &(*mrp)->smr_next;
+	}
+	*mrp = smr;
+
+	if ( smr->smr_oid ) {
+		mir = (struct mindexrec *)
+			ch_calloc( 1, sizeof(struct mindexrec) );
+		mir->mir_name = smr->smr_oid;
+		mir->mir_mr = smr;
+		if ( avl_insert( &mr_index, (caddr_t) mir,
+				 (AVL_CMP) mr_index_cmp,
+				 (AVL_DUP) avl_dup_error ) ) {
+			*err = smr->smr_oid;
+			ldap_memfree(mir);
+			return SLAP_SCHERR_DUP_RULE;
+		}
+		/* FIX: temporal consistency check */
+		mr_find(mir->mir_name);
+	}
+	if ( (names = smr->smr_names) ) {
+		while ( *names ) {
+			mir = (struct mindexrec *)
+				ch_calloc( 1, sizeof(struct mindexrec) );
+			mir->mir_name = ch_strdup(*names);
+			mir->mir_mr = smr;
+			if ( avl_insert( &mr_index, (caddr_t) mir,
+					 (AVL_CMP) mr_index_cmp,
+					 (AVL_DUP) avl_dup_error ) ) {
+				*err = *names;
+				ldap_memfree(mir);
+				return SLAP_SCHERR_DUP_RULE;
+			}
+			/* FIX: temporal consistency check */
+			mr_find(mir->mir_name);
+			names++;
+		}
+	}
+	return 0;
+}
+
+int
+mr_add(
+    LDAP_MATCHING_RULE		*mr,
+	slap_mr_convert_func *convert,
+	slap_mr_normalize_func *normalize,
+    slap_mr_match_func	*match,
+	slap_mr_indexer_func *indexer,
+    slap_mr_filter_func	*filter,
+    const char		**err
+)
+{
+	MatchingRule	*smr;
+	Syntax		*syn;
+	int		code;
+
+	smr = (MatchingRule *) ch_calloc( 1, sizeof(MatchingRule) );
+	memcpy( &smr->smr_mrule, mr, sizeof(LDAP_MATCHING_RULE));
+
+	smr->smr_convert = convert;
+	smr->smr_normalize = normalize;
+	smr->smr_match = match;
+	smr->smr_indexer = indexer;
+	smr->smr_filter = filter;
+
+	if ( smr->smr_syntax_oid ) {
+		if ( (syn = syn_find(smr->smr_syntax_oid)) ) {
+			smr->smr_syntax = syn;
+		} else {
+			*err = smr->smr_syntax_oid;
+			return SLAP_SCHERR_SYN_NOT_FOUND;
+		}
+	} else {
+		*err = "";
+		return SLAP_SCHERR_MR_INCOMPLETE;
+	}
+	code = mr_insert(smr,err);
+	return code;
+}
+
+
+int
+register_matching_rule(
+	char * desc,
+	slap_mr_convert_func *convert,
+	slap_mr_normalize_func *normalize,
+	slap_mr_match_func *match,
+	slap_mr_indexer_func *indexer,
+	slap_mr_filter_func *filter )
+{
+	LDAP_MATCHING_RULE *mr;
+	int		code;
+	const char	*err;
+
+	mr = ldap_str2matchingrule( desc, &code, &err);
+	if ( !mr ) {
+		Debug( LDAP_DEBUG_ANY, "Error in register_matching_rule: %s before %s in %s\n",
+		    ldap_scherr2str(code), err, desc );
+		return( -1 );
+	}
+
+	code = mr_add( mr, convert, normalize, match, indexer, filter, &err );
+	if ( code ) {
+		Debug( LDAP_DEBUG_ANY, "Error in register_syntax: %s for %s in %s\n",
+		    scherr2str(code), err, desc );
+		return( -1 );
+	}
+	return( 0 );
+}
+
+
+#if defined( SLAPD_SCHEMA_DN )
+
+int mr_schema_info( Entry *e )
+{
+	struct berval	val;
+	struct berval	*vals[2];
+	MatchingRule	*mr;
+
+	vals[0] = &val;
+	vals[1] = NULL;
+
+	for ( mr = mr_list; mr; mr = mr->smr_next ) {
+		val.bv_val = ldap_matchingrule2str( &mr->smr_mrule );
+		if ( val.bv_val ) {
+			val.bv_len = strlen( val.bv_val );
+			Debug( LDAP_DEBUG_TRACE, "Merging mr [%ld] %s\n",
+			       (long) val.bv_len, val.bv_val, 0 );
+			attr_merge( e, "matchingRules", vals );
+			ldap_memfree( val.bv_val );
+		} else {
+			return -1;
+		}
+	}
+	return 0;
+}
+
+#endif
diff --git a/servers/slapd/oc.c b/servers/slapd/oc.c
new file mode 100644
index 0000000000..88e180983f
--- /dev/null
+++ b/servers/slapd/oc.c
@@ -0,0 +1,456 @@
+/* oc.c - object class routines */
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/ctype.h>
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "slap.h"
+#include "ldap_pvt.h"
+
+int is_entry_objectclass(
+	Entry*	e,
+	const char*	oc)
+{
+	Attribute *attr;
+	struct berval bv;
+
+	if( e == NULL || oc == NULL || *oc == '\0' )
+		return 0;
+
+	/*
+	 * find objectClass attribute
+	 */
+	attr = attr_find(e->e_attrs, "objectclass");
+
+	if( attr == NULL ) {
+		/* no objectClass attribute */
+		return 0;
+	}
+
+	bv.bv_val = (char *) oc;
+	bv.bv_len = strlen( bv.bv_val );
+
+#ifdef SLAPD_SCHEMA_NOT_COMPAT
+	/* not yet implemented */
+#else
+	if( value_find(attr->a_vals, &bv, attr->a_syntax, 1) != 0) {
+		/* entry is not of this objectclass */
+		return 0;
+	}
+#endif
+
+	return 1;
+}
+
+
+#ifndef SLAPD_SCHEMA_NOT_COMPAT
+	/* these shouldn't be hardcoded */
+
+static char *oc_op_usermod_attrs[] = {
+	/*
+	 * these are operational attributes which are
+	 * not defined as NO-USER_MODIFICATION and
+	 * which slapd supports modification of.
+	 *
+	 * Currently none.
+	 * Likely candidate, "aci"
+	 */
+	NULL
+};
+
+static char *oc_op_attrs[] = {
+	/*
+	 * these are operational attributes 
+	 * most could be user modifiable
+	 */
+	"objectClasses",
+	"attributeTypes",
+	"matchingRules",
+	"matchingRuleUse",
+	"dITStructureRules",
+	"dITContentRules",
+	"nameForms",
+	"ldapSyntaxes",
+	"namingContexts",
+	"supportedExtension",
+	"supportedControl",
+	"supportedSASLMechanisms",
+	"supportedLDAPversion",
+	"supportedACIMechanisms",
+	"subschemaSubentry",		/* NO USER MOD */
+	NULL
+
+};
+
+/* this list should be extensible  */
+static char *oc_op_no_usermod_attrs[] = {
+	/*
+	 * Operational and 'no user modification' attributes
+	 * which are STORED in the directory server.
+	 */
+
+	/* RFC2252, 3.2.1 */
+	"creatorsName",
+	"createTimestamp",
+	"modifiersName",
+	"modifyTimestamp",
+
+	NULL
+};
+#endif
+
+
+/*
+ * check to see if attribute is 'operational' or not.
+ */
+int
+oc_check_op_attr( const char *type )
+{
+#ifndef SLAPD_SCHEMA_NOT_COMPAT
+	return charray_inlist( oc_op_attrs, type )
+		|| charray_inlist( oc_op_usermod_attrs, type )
+		|| charray_inlist( oc_op_no_usermod_attrs, type );
+#else
+	AttributeType *at = at_find( type );
+
+	if( at == NULL ) return 0;
+
+	return at->sat_usage != LDAP_SCHEMA_USER_APPLICATIONS;
+#endif
+}
+
+/*
+ * check to see if attribute can be user modified or not.
+ */
+int
+oc_check_op_usermod_attr( const char *type )
+{
+#ifndef SLAPD_SCHEMA_NOT_COMPAT
+	return charray_inlist( oc_op_usermod_attrs, type );
+#else
+	/* not (yet) in schema */
+	return 0;
+#endif
+}
+
+/*
+ * check to see if attribute is 'no user modification' or not.
+ */
+int
+oc_check_op_no_usermod_attr( const char *type )
+{
+#ifndef SLAPD_SCHEMA_NOT_COMPAT
+	return charray_inlist( oc_op_no_usermod_attrs, type );
+#else
+	AttributeType *at = at_find( type );
+
+	if( at == NULL ) return 0;
+
+	return at->sat_no_user_mod;
+#endif
+}
+
+
+struct oindexrec {
+	char		*oir_name;
+	ObjectClass	*oir_oc;
+};
+
+static Avlnode	*oc_index = NULL;
+static ObjectClass *oc_list = NULL;
+
+static int
+oc_index_cmp(
+    struct oindexrec	*oir1,
+    struct oindexrec	*oir2
+)
+{
+	return (strcasecmp( oir1->oir_name, oir2->oir_name ));
+}
+
+static int
+oc_index_name_cmp(
+    char 		*name,
+    struct oindexrec	*oir
+)
+{
+	return (strcasecmp( name, oir->oir_name ));
+}
+
+ObjectClass *
+oc_find( const char *ocname )
+{
+	struct oindexrec	*oir = NULL;
+
+	if ( (oir = (struct oindexrec *) avl_find( oc_index, ocname,
+            (AVL_CMP) oc_index_name_cmp )) != NULL ) {
+		return( oir->oir_oc );
+	}
+	return( NULL );
+}
+
+static int
+oc_create_required(
+    ObjectClass		*soc,
+    char		**attrs,
+    const char		**err
+)
+{
+	char		**attrs1;
+	AttributeType	*sat;
+	AttributeType	**satp;
+	int		i;
+
+	if ( attrs ) {
+		attrs1 = attrs;
+		while ( *attrs1 ) {
+			sat = at_find(*attrs1);
+			if ( !sat ) {
+				*err = *attrs1;
+				return SLAP_SCHERR_ATTR_NOT_FOUND;
+			}
+			if ( at_find_in_list(sat, soc->soc_required) < 0) {
+				if ( at_append_to_list(sat, &soc->soc_required) ) {
+					*err = *attrs1;
+					return SLAP_SCHERR_OUTOFMEM;
+				}
+			}
+			attrs1++;
+		}
+		/* Now delete duplicates from the allowed list */
+		for ( satp = soc->soc_required; *satp; satp++ ) {
+			i = at_find_in_list(*satp,soc->soc_allowed);
+			if ( i >= 0 ) {
+				at_delete_from_list(i, &soc->soc_allowed);
+			}
+		}
+	}
+	return 0;
+}
+
+static int
+oc_create_allowed(
+    ObjectClass		*soc,
+    char		**attrs,
+    const char		**err
+)
+{
+	char		**attrs1;
+	AttributeType	*sat;
+
+	if ( attrs ) {
+		attrs1 = attrs;
+		while ( *attrs1 ) {
+			sat = at_find(*attrs1);
+			if ( !sat ) {
+				*err = *attrs1;
+				return SLAP_SCHERR_ATTR_NOT_FOUND;
+			}
+			if ( at_find_in_list(sat, soc->soc_required) < 0 &&
+			     at_find_in_list(sat, soc->soc_allowed) < 0 ) {
+				if ( at_append_to_list(sat, &soc->soc_allowed) ) {
+					*err = *attrs1;
+					return SLAP_SCHERR_OUTOFMEM;
+				}
+			}
+			attrs1++;
+		}
+	}
+	return 0;
+}
+
+static int
+oc_add_sups(
+    ObjectClass		*soc,
+    char		**sups,
+    const char		**err
+)
+{
+	int		code;
+	ObjectClass	*soc1;
+	int		nsups;
+	char		**sups1;
+	int		add_sups = 0;
+
+	if ( sups ) {
+		if ( !soc->soc_sups ) {
+			/* We are at the first recursive level */
+			add_sups = 1;
+			nsups = 0;
+			sups1 = sups;
+			while ( *sups1 ) {
+				nsups++;
+				sups1++;
+			}
+			nsups++;
+			soc->soc_sups = (ObjectClass **)ch_calloc(1,
+					  nsups*sizeof(ObjectClass *));
+		}
+		nsups = 0;
+		sups1 = sups;
+		while ( *sups1 ) {
+			soc1 = oc_find(*sups1);
+			if ( !soc1 ) {
+				*err = *sups1;
+				return SLAP_SCHERR_CLASS_NOT_FOUND;
+			}
+
+			if ( add_sups )
+				soc->soc_sups[nsups] = soc1;
+
+			code = oc_add_sups(soc,soc1->soc_sup_oids, err);
+			if ( code )
+				return code;
+
+			code = oc_create_required(soc,soc1->soc_at_oids_must,err);
+			if ( code )
+				return code;
+			code = oc_create_allowed(soc,soc1->soc_at_oids_may,err);
+			if ( code )
+				return code;
+
+			nsups++;
+			sups1++;
+		}
+	}
+	return 0;
+}
+
+static int
+oc_insert(
+    ObjectClass		*soc,
+    const char		**err
+)
+{
+	ObjectClass	**ocp;
+	struct oindexrec	*oir;
+	char			**names;
+
+	ocp = &oc_list;
+	while ( *ocp != NULL ) {
+		ocp = &(*ocp)->soc_next;
+	}
+	*ocp = soc;
+
+	if ( soc->soc_oid ) {
+		oir = (struct oindexrec *)
+			ch_calloc( 1, sizeof(struct oindexrec) );
+		oir->oir_name = soc->soc_oid;
+		oir->oir_oc = soc;
+		if ( avl_insert( &oc_index, (caddr_t) oir,
+				 (AVL_CMP) oc_index_cmp,
+				 (AVL_DUP) avl_dup_error ) ) {
+			*err = soc->soc_oid;
+			ldap_memfree(oir);
+			return SLAP_SCHERR_DUP_CLASS;
+		}
+		/* FIX: temporal consistency check */
+		oc_find(oir->oir_name);
+	}
+	if ( (names = soc->soc_names) ) {
+		while ( *names ) {
+			oir = (struct oindexrec *)
+				ch_calloc( 1, sizeof(struct oindexrec) );
+			oir->oir_name = ch_strdup(*names);
+			oir->oir_oc = soc;
+			if ( avl_insert( &oc_index, (caddr_t) oir,
+					 (AVL_CMP) oc_index_cmp,
+					 (AVL_DUP) avl_dup_error ) ) {
+				*err = *names;
+				ldap_memfree(oir);
+				return SLAP_SCHERR_DUP_CLASS;
+			}
+			/* FIX: temporal consistency check */
+			oc_find(oir->oir_name);
+			names++;
+		}
+	}
+	return 0;
+}
+
+int
+oc_add(
+    LDAP_OBJECT_CLASS	*oc,
+    const char		**err
+)
+{
+	ObjectClass	*soc;
+	int		code;
+
+	soc = (ObjectClass *) ch_calloc( 1, sizeof(ObjectClass) );
+	memcpy( &soc->soc_oclass, oc, sizeof(LDAP_OBJECT_CLASS));
+	if ( (code = oc_add_sups(soc,soc->soc_sup_oids,err)) != 0 )
+		return code;
+	if ( (code = oc_create_required(soc,soc->soc_at_oids_must,err)) != 0 )
+		return code;
+	if ( (code = oc_create_allowed(soc,soc->soc_at_oids_may,err)) != 0 )
+		return code;
+	code = oc_insert(soc,err);
+	return code;
+}
+
+#ifdef LDAP_DEBUG
+
+static void
+oc_print( ObjectClass *oc )
+{
+	int	i;
+	const char *mid;
+
+	printf( "objectclass %s\n", ldap_objectclass2name( &oc->soc_oclass ) );
+	if ( oc->soc_required != NULL ) {
+		mid = "\trequires ";
+		for ( i = 0; oc->soc_required[i] != NULL; i++, mid = "," )
+			printf( "%s%s", mid,
+			        ldap_attributetype2name( &oc->soc_required[i]->sat_atype ) );
+		printf( "\n" );
+	}
+	if ( oc->soc_allowed != NULL ) {
+		mid = "\tallows ";
+		for ( i = 0; oc->soc_allowed[i] != NULL; i++, mid = "," )
+			printf( "%s%s", mid,
+			        ldap_attributetype2name( &oc->soc_allowed[i]->sat_atype ) );
+		printf( "\n" );
+	}
+}
+
+#endif
+
+
+#if defined( SLAPD_SCHEMA_DN )
+
+int
+oc_schema_info( Entry *e )
+{
+	struct berval	val;
+	struct berval	*vals[2];
+	ObjectClass	*oc;
+
+	vals[0] = &val;
+	vals[1] = NULL;
+
+	for ( oc = oc_list; oc; oc = oc->soc_next ) {
+		val.bv_val = ldap_objectclass2str( &oc->soc_oclass );
+		if ( val.bv_val ) {
+			val.bv_len = strlen( val.bv_val );
+			Debug( LDAP_DEBUG_TRACE, "Merging oc [%ld] %s\n",
+			       (long) val.bv_len, val.bv_val, 0 );
+			attr_merge( e, "objectClasses", vals );
+			ldap_memfree( val.bv_val );
+		} else {
+			return -1;
+		}
+	}
+	return 0;
+}
+
+#endif
diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h
index 83d03eba59..0fdac434cb 100644
--- a/servers/slapd/proto-slap.h
+++ b/servers/slapd/proto-slap.h
@@ -70,14 +70,15 @@ LIBSLAPD_F (int) at_fake_if_needed LDAP_P(( const char *name ));
 LIBSLAPD_F (int) at_schema_info LDAP_P(( Entry *e ));
 LIBSLAPD_F (int) at_add LDAP_P(( LDAP_ATTRIBUTE_TYPE *at, const char **err ));
 
+LIBSLAPD_F (void) attrs_free LDAP_P(( Attribute *a ));
+LIBSLAPD_F (Attribute *) attrs_dup LDAP_P(( Attribute *a ));
+
 #ifdef SLAPD_SCHEMA_NOT_COMPAT
-LIBSLAPD_F (char *) at_canonical_name LDAP_P(( AttributeType *a_type ));
+#	define at_canonical_name(at) ((at)->sat_cname)	
 #else
 LIBSLAPD_F (char *) at_canonical_name LDAP_P(( const char * a_type ));
 #endif
 
-LIBSLAPD_F (void) attrs_free LDAP_P(( Attribute *a ));
-LIBSLAPD_F (Attribute *) attrs_dup LDAP_P(( Attribute *a ));
 
 /*
  * ava.c
@@ -138,10 +139,8 @@ LIBSLAPD_F (int) backend_group LDAP_P((Backend *be,
 ));
 #endif
 
-#ifdef SLAPD_SCHEMA_DN
-/* temporary extern for temporary routine*/
-LIBSLAPD_F (Attribute *) backend_subschemasubentry( Backend * );
-#endif
+LIBSLAPD_F (Attribute *) backend_operational( Backend *, Entry * );
+
 
 
 /*
@@ -455,11 +454,19 @@ LIBSLAPD_F (int) sasl_bind LDAP_P((Backend *,
 	char *, char *, char *, struct berval *, char **));
 #endif
 
+/* oc.c */
+LIBSLAPD_F (int) oc_schema_info( Entry *e );
+
+/* mr.c */
+LIBSLAPD_F (int) mr_schema_info( Entry *e );
+
+/* syntax.c */
+LIBSLAPD_F (int) syn_schema_info( Entry *e );
+
 /*
  * schema.c
  */
 
-LIBSLAPD_F (int) oc_schema_check LDAP_P(( Entry *e ));
 LIBSLAPD_F (int) oc_check_op_attr LDAP_P(( const char *type ));
 LIBSLAPD_F (int) oc_check_op_usermod_attr LDAP_P(( const char *type ));
 LIBSLAPD_F (int) oc_check_op_no_usermod_attr LDAP_P(( const char *type ));
@@ -503,6 +510,11 @@ LIBSLAPD_F (int) is_entry_objectclass LDAP_P((
 #define is_entry_alias(e)		is_entry_objectclass((e), "ALIAS")
 #define is_entry_referral(e)	is_entry_objectclass((e), "REFERRAL")
 
+/*
+ * schema_check.c
+ */
+LIBSLAPD_F (int) schema_check_entry LDAP_P(( Entry *e ));
+
 
 /*
  * schema_init.c
diff --git a/servers/slapd/result.c b/servers/slapd/result.c
index ab5b12750e..f90c92e930 100644
--- a/servers/slapd/result.c
+++ b/servers/slapd/result.c
@@ -612,7 +612,7 @@ send_search_entry(
 )
 {
 	BerElement	*ber;
-	Attribute	*a;
+	Attribute	*a, *aa;
 	int		i, rc=-1, bytes;
 	char            *edn;
 	int		userattrs;
@@ -659,36 +659,40 @@ send_search_entry(
 		: charray_inlist( attrs, LDAP_ALL_OPERATIONAL_ATTRIBUTES );
 
 	for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
+		char *desc;
+#ifdef SLAPD_SCHEMA_NOT_COMPAT
+		desc = a->a_desc.ad_type->sat_cname;
+#else
+		desc = a->a_type;
+#endif
+
 		if ( attrs == NULL ) {
 			/* all addrs request, skip operational attributes */
-			if( !opattrs && oc_check_op_attr( a->a_type ) ) {
+			if( !opattrs && oc_check_op_attr( desc ) ) {
 				continue;
 			}
 
 		} else {
 			/* specific addrs requested */
-			if (  oc_check_op_attr( a->a_type ) ) {
-				if( !opattrs && !charray_inlist( attrs, a->a_type ) )
-				{
+			if ( oc_check_op_attr( desc ) )
+			{
+				if( !opattrs && !charray_inlist( attrs, desc ) ) {
 					continue;
 				}
 			} else {
-				if (!userattrs && !charray_inlist( attrs, a->a_type ) )
-				{
+				if (!userattrs && !charray_inlist( attrs, desc ) ) {
 					continue;
 				}
 			}
 		}
 
-		if ( ! access_allowed( be, conn, op, e,
-			a->a_type, NULL, ACL_READ ) )
-		{
+		if ( ! access_allowed( be, conn, op, e, desc, NULL, ACL_READ ) ) {
 			Debug( LDAP_DEBUG_ACL, "acl: access to attribute %s not allowed\n",
-			    a->a_type, 0, 0 );
+			    desc, 0, 0 );
 			continue;
 		}
 
-		if (( rc = ber_printf( ber, "{s[" /*]}*/ , a->a_type )) == -1 ) {
+		if (( rc = ber_printf( ber, "{s[" /*]}*/ , desc )) == -1 ) {
 			Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
 			ber_free( ber, 1 );
 			send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
@@ -699,11 +703,11 @@ send_search_entry(
 		if ( ! attrsonly ) {
 			for ( i = 0; a->a_vals[i] != NULL; i++ ) {
 				if ( ! access_allowed( be, conn, op, e,
-					a->a_type, a->a_vals[i], ACL_READ ) )
+					desc, a->a_vals[i], ACL_READ ) )
 				{
 					Debug( LDAP_DEBUG_ACL,
 						"acl: access to attribute %s, value %d not allowed\n",
-			    		a->a_type, i, 0 );
+			    		desc, i, 0 );
 					continue;
 				}
 
@@ -727,42 +731,46 @@ send_search_entry(
 		}
 	}
 
-#ifdef SLAPD_SCHEMA_DN
 	/* eventually will loop through generated operational attributes */
 	/* only have subschemaSubentry implemented */
-	a = backend_subschemasubentry( be );
+	aa = backend_operational( be, e );
 	
-	do {
+	for (a = aa ; a == NULL; a = a->a_next ) {
+		char *desc;
+#ifdef SLAPD_SCHEMA_NOT_COMPAT
+		desc = a->a_desc.ad_type->sat_cname;
+#else
+		desc = a->a_type;
+#endif
+
 		if ( attrs == NULL ) {
 			/* all addrs request, skip operational attributes */
-			if( !opattrs && oc_check_op_attr( a->a_type ) ) {
+			if( !opattrs && oc_check_op_attr( desc ) ) {
 				continue;
 			}
 
 		} else {
 			/* specific addrs requested */
-			if (  oc_check_op_attr( a->a_type ) ) {
-				if( !opattrs && !charray_inlist( attrs, a->a_type ) )
+			if (  oc_check_op_attr( desc ) ) {
+				if( !opattrs && !charray_inlist( attrs, desc ) )
 				{
 					continue;
 				}
 			} else {
-				if (!userattrs && !charray_inlist( attrs, a->a_type ) )
+				if (!userattrs && !charray_inlist( attrs, desc ) )
 				{
 					continue;
 				}
 			}
 		}
 
-		if ( ! access_allowed( be, conn, op, e,
-			a->a_type, NULL, ACL_READ ) )
-		{
+		if ( ! access_allowed( be, conn, op, e,	desc, NULL, ACL_READ ) ) {
 			Debug( LDAP_DEBUG_ACL, "acl: access to attribute %s not allowed\n",
-			    a->a_type, 0, 0 );
+			    desc, 0, 0 );
 			continue;
 		}
 
-		if (( rc = ber_printf( ber, "{s[" /*]}*/ , a->a_type )) == -1 ) {
+		if (( rc = ber_printf( ber, "{s[" /*]}*/ , desc )) == -1 ) {
 			Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
 			ber_free( ber, 1 );
 			send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
@@ -773,11 +781,11 @@ send_search_entry(
 		if ( ! attrsonly ) {
 			for ( i = 0; a->a_vals[i] != NULL; i++ ) {
 				if ( ! access_allowed( be, conn, op, e,
-					a->a_type, a->a_vals[i], ACL_READ ) )
+					desc, a->a_vals[i], ACL_READ ) )
 				{
 					Debug( LDAP_DEBUG_ACL,
 						"acl: access to attribute %s, value %d not allowed\n",
-			    		a->a_type, i, 0 );
+			    		desc, i, 0 );
 					continue;
 				}
 
@@ -800,8 +808,9 @@ send_search_entry(
 			    NULL, "encode end error", NULL, NULL );
 			goto error_return;
 		}
-	} while (0);
-#endif
+	}
+
+	attrs_free( aa );
 
 	rc = ber_printf( ber, /*{{{*/ "}}}" );
 
diff --git a/servers/slapd/schema.c b/servers/slapd/schema.c
index ab847d391f..3318ee1aa9 100644
--- a/servers/slapd/schema.c
+++ b/servers/slapd/schema.c
@@ -1,4 +1,4 @@
-/* schema.c - routines to enforce schema definitions */
+/* schema.c - routines to manage schema definitions */
 /* $OpenLDAP$ */
 /*
  * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
@@ -16,959 +16,9 @@
 #include "slap.h"
 #include "ldap_pvt.h"
 
-static char *	oc_check_required(Entry *e, char *ocname);
-static int		oc_check_allowed(char *type, struct berval **ocl);
-
-/*
- * oc_check - check that entry e conforms to the schema required by
- * its object class(es). returns 0 if so, non-zero otherwise.
- */
-
-int
-oc_schema_check( Entry *e )
-{
-	Attribute	*a, *aoc;
-	ObjectClass *oc;
-	int		i;
-	int		ret = 0;
-
-
-	/* find the object class attribute - could error out here */
-	if ( (aoc = attr_find( e->e_attrs, "objectclass" )) == NULL ) {
-		Debug( LDAP_DEBUG_ANY, "No object class for entry (%s)\n",
-		    e->e_dn, 0, 0 );
-		return( 1 );
-	}
-
-	/* check that the entry has required attrs for each oc */
-	for ( i = 0; aoc->a_vals[i] != NULL; i++ ) {
-		if ( (oc = oc_find( aoc->a_vals[i]->bv_val )) == NULL ) {
-			Debug( LDAP_DEBUG_ANY,
-				"Objectclass \"%s\" not defined\n",
-				aoc->a_vals[i]->bv_val, 0, 0 );
-		}
-		else
-		{
-			char *s = oc_check_required( e, aoc->a_vals[i]->bv_val );
-
-			if (s != NULL) {
-				Debug( LDAP_DEBUG_ANY,
-					"Entry (%s), oc \"%s\" requires attr \"%s\"\n",
-					e->e_dn, aoc->a_vals[i]->bv_val, s );
-				ret = 1;
-			}
-		}
-	}
-
-	if ( ret != 0 ) {
-	    return( ret );
-	}
-
-	/* check that each attr in the entry is allowed by some oc */
-	for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
-		if ( oc_check_allowed( a->a_type, aoc->a_vals ) != 0 ) {
-			Debug( LDAP_DEBUG_ANY,
-			    "Entry (%s), attr \"%s\" not allowed\n",
-			    e->e_dn, a->a_type, 0 );
-			ret = 1;
-		}
-	}
-
-	return( ret );
-}
-
-static char *
-oc_check_required( Entry *e, char *ocname )
-{
-	ObjectClass	*oc;
-	AttributeType	*at;
-	int		i;
-	Attribute	*a;
-	char		**pp;
-
-	Debug( LDAP_DEBUG_TRACE,
-	       "oc_check_required entry (%s), objectclass \"%s\"\n",
-	       e->e_dn, ocname, 0 );
-
-	/* find global oc defn. it we don't know about it assume it's ok */
-	if ( (oc = oc_find( ocname )) == NULL ) {
-		return( 0 );
-	}
-
-	/* check for empty oc_required */
-	if(oc->soc_required == NULL) {
-		return( 0 );
-	}
-
-	/* for each required attribute */
-	for ( i = 0; oc->soc_required[i] != NULL; i++ ) {
-		at = oc->soc_required[i];
-		/* see if it's in the entry */
-		for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
-			if ( at->sat_oid &&
-			     strcmp( a->a_type, at->sat_oid ) == 0 ) {
-				break;
-			}
-			pp = at->sat_names;
-			if ( pp  == NULL ) {
-				/* Empty name list => not found */
-				a = NULL;
-				break;
-			}
-			while ( *pp ) {
-				if ( strcasecmp( a->a_type, *pp ) == 0 ) {
-					break;
-				}
-				pp++;
-			}
-			if ( *pp ) {
-				break;
-			}
-		}
-		/* not there => schema violation */
-		if ( a == NULL ) {
-			if ( at->sat_names && at->sat_names[0] ) {
-				return at->sat_names[0];
-			} else {
-				return at->sat_oid;
-			}
-		}
-	}
-
-	return( NULL );
-}
-
-static int
-oc_check_allowed( char *type, struct berval **ocl )
-{
-	ObjectClass	*oc;
-	AttributeType	*at;
-	int		i, j;
-	char		**pp;
-	char		*p, *t;
-
-	Debug( LDAP_DEBUG_TRACE,
-	       "oc_check_allowed type \"%s\"\n", type, 0, 0 );
-
-	/* always allow objectclass attribute */
-	if ( strcasecmp( type, "objectclass" ) == 0 ) {
-		return( 0 );
-	}
-
-#ifndef SLAPD_SCHEMA_NOT_COMPAT
-	/* Treat any attribute type with option as an unknown attribute type */
-	/*
-	 * The "type" we have received is actually an AttributeDescription.
-	 * Let's find out the corresponding type.
-	 */
-	p = strchr( type, ';' );
-	if ( p ) {
-		t = ch_malloc( p-type+1 );
-		strncpy( t, type, p-type );
-		t[p-type] = '\0';
-		Debug( LDAP_DEBUG_TRACE,
-		       "oc_check_allowed type \"%s\" from \"%s\"\n",
-		       t, type, 0 );
-
-	} else
-#endif
-	{
-		t = type;
-	}
-
-
-	/*
-	 * All operational attributions are allowed by schema rules.
-	 */
-	if ( oc_check_op_attr( t ) ) {
-		return( 0 );
-	}
-
-	/* check that the type appears as req or opt in at least one oc */
-	for ( i = 0; ocl[i] != NULL; i++ ) {
-		/* if we know about the oc */
-		if ( (oc = oc_find( ocl[i]->bv_val )) != NULL ) {
-			/* does it require the type? */
-			for ( j = 0; oc->soc_required != NULL && 
-				oc->soc_required[j] != NULL; j++ ) {
-				at = oc->soc_required[j];
-				if ( at->sat_oid &&
-				     strcmp(at->sat_oid, t ) == 0 ) {
-					if ( t != type )
-						ldap_memfree( t );
-					return( 0 );
-				}
-				pp = at->sat_names;
-				if ( pp == NULL )
-					continue;
-				while ( *pp ) {
-					if ( strcasecmp( *pp, t ) == 0 ) {
-						if ( t != type )
-							ldap_memfree( t );
-						return( 0 );
-					}
-					pp++;
-				}
-			}
-			/* does it allow the type? */
-			for ( j = 0; oc->soc_allowed != NULL && 
-				oc->soc_allowed[j] != NULL; j++ ) {
-				at = oc->soc_allowed[j];
-				if ( at->sat_oid &&
-				     strcmp( at->sat_oid, t ) == 0 ) {
-					if ( t != type )
-						ldap_memfree( t );
-					return( 0 );
-				}
-				pp = at->sat_names;
-				if ( pp == NULL )
-					continue;
-				while ( *pp ) {
-					if ( strcasecmp( *pp, t ) == 0 ||
-					     strcmp( *pp, "*" ) == 0 ) {
-						if ( t != type )
-							ldap_memfree( t );
-						return( 0 );
-					}
-					pp++;
-				}
-			}
-			/* maybe the next oc allows it */
-
-#ifdef OC_UNDEFINED_IMPLES_EXTENSIBLE
-		/* we don't know about the oc. assume it allows it */
-		} else {
-			if ( t != type )
-				ldap_memfree( t );
-			return( 0 );
-#endif
-		}
-	}
-
-	if ( t != type )
-		ldap_memfree( t );
-	/* not allowed by any oc */
-	return( 1 );
-}
-
-
-#ifndef SLAPD_SCHEMA_NOT_COMPAT
-	/* these shouldn't be hardcoded */
-
-static char *oc_op_usermod_attrs[] = {
-	/*
-	 * these are operational attributes which are
-	 * not defined as NO-USER_MODIFICATION and
-	 * which slapd supports modification of.
-	 *
-	 * Currently none.
-	 * Likely candidate, "aci"
-	 */
-	NULL
-};
-
-static char *oc_op_attrs[] = {
-	/*
-	 * these are operational attributes 
-	 * most could be user modifiable
-	 */
-	"objectClasses",
-	"attributeTypes",
-	"matchingRules",
-	"matchingRuleUse",
-	"dITStructureRules",
-	"dITContentRules",
-	"nameForms",
-	"ldapSyntaxes",
-	"namingContexts",
-	"supportedExtension",
-	"supportedControl",
-	"supportedSASLMechanisms",
-	"supportedLDAPversion",
-	"supportedACIMechanisms",
-	"subschemaSubentry",		/* NO USER MOD */
-	NULL
-
-};
-
-/* this list should be extensible  */
-static char *oc_op_no_usermod_attrs[] = {
-	/*
-	 * Operational and 'no user modification' attributes
-	 * which are STORED in the directory server.
-	 */
-
-	/* RFC2252, 3.2.1 */
-	"creatorsName",
-	"createTimestamp",
-	"modifiersName",
-	"modifyTimestamp",
-
-	NULL
-};
-#endif
-
-
-/*
- * check to see if attribute is 'operational' or not.
- */
-int
-oc_check_op_attr( const char *type )
-{
-#ifndef SLAPD_SCHEMA_NOT_COMPAT
-	return charray_inlist( oc_op_attrs, type )
-		|| charray_inlist( oc_op_usermod_attrs, type )
-		|| charray_inlist( oc_op_no_usermod_attrs, type );
-#else
-	AttributeType *at = at_find( type );
-
-	if( at == NULL ) return 0;
-
-	return at->sat_usage != LDAP_SCHEMA_USER_APPLICATIONS;
-#endif
-}
-
-/*
- * check to see if attribute can be user modified or not.
- */
-int
-oc_check_op_usermod_attr( const char *type )
-{
-#ifndef SLAPD_SCHEMA_NOT_COMPAT
-	return charray_inlist( oc_op_usermod_attrs, type );
-#else
-	/* not (yet) in schema */
-	return 0;
-#endif
-}
-
-/*
- * check to see if attribute is 'no user modification' or not.
- */
-int
-oc_check_op_no_usermod_attr( const char *type )
-{
-#ifndef SLAPD_SCHEMA_NOT_COMPAT
-	return charray_inlist( oc_op_no_usermod_attrs, type );
-#else
-	AttributeType *at = at_find( type );
-
-	if( at == NULL ) return 0;
-
-	return at->sat_no_user_mod;
-#endif
-}
-
-
-struct oindexrec {
-	char		*oir_name;
-	ObjectClass	*oir_oc;
-};
-
-static Avlnode	*oc_index = NULL;
-static ObjectClass *oc_list = NULL;
-
-static int
-oc_index_cmp(
-    struct oindexrec	*oir1,
-    struct oindexrec	*oir2
-)
-{
-	return (strcasecmp( oir1->oir_name, oir2->oir_name ));
-}
-
-static int
-oc_index_name_cmp(
-    char 		*name,
-    struct oindexrec	*oir
-)
-{
-	return (strcasecmp( name, oir->oir_name ));
-}
-
-ObjectClass *
-oc_find( const char *ocname )
-{
-	struct oindexrec	*oir = NULL;
-
-	if ( (oir = (struct oindexrec *) avl_find( oc_index, ocname,
-            (AVL_CMP) oc_index_name_cmp )) != NULL ) {
-		return( oir->oir_oc );
-	}
-	return( NULL );
-}
-
-static int
-oc_create_required(
-    ObjectClass		*soc,
-    char		**attrs,
-    const char		**err
-)
-{
-	char		**attrs1;
-	AttributeType	*sat;
-	AttributeType	**satp;
-	int		i;
-
-	if ( attrs ) {
-		attrs1 = attrs;
-		while ( *attrs1 ) {
-			sat = at_find(*attrs1);
-			if ( !sat ) {
-				*err = *attrs1;
-				return SLAP_SCHERR_ATTR_NOT_FOUND;
-			}
-			if ( at_find_in_list(sat, soc->soc_required) < 0) {
-				if ( at_append_to_list(sat, &soc->soc_required) ) {
-					*err = *attrs1;
-					return SLAP_SCHERR_OUTOFMEM;
-				}
-			}
-			attrs1++;
-		}
-		/* Now delete duplicates from the allowed list */
-		for ( satp = soc->soc_required; *satp; satp++ ) {
-			i = at_find_in_list(*satp,soc->soc_allowed);
-			if ( i >= 0 ) {
-				at_delete_from_list(i, &soc->soc_allowed);
-			}
-		}
-	}
-	return 0;
-}
-
-static int
-oc_create_allowed(
-    ObjectClass		*soc,
-    char		**attrs,
-    const char		**err
-)
-{
-	char		**attrs1;
-	AttributeType	*sat;
-
-	if ( attrs ) {
-		attrs1 = attrs;
-		while ( *attrs1 ) {
-			sat = at_find(*attrs1);
-			if ( !sat ) {
-				*err = *attrs1;
-				return SLAP_SCHERR_ATTR_NOT_FOUND;
-			}
-			if ( at_find_in_list(sat, soc->soc_required) < 0 &&
-			     at_find_in_list(sat, soc->soc_allowed) < 0 ) {
-				if ( at_append_to_list(sat, &soc->soc_allowed) ) {
-					*err = *attrs1;
-					return SLAP_SCHERR_OUTOFMEM;
-				}
-			}
-			attrs1++;
-		}
-	}
-	return 0;
-}
-
-static int
-oc_add_sups(
-    ObjectClass		*soc,
-    char		**sups,
-    const char		**err
-)
-{
-	int		code;
-	ObjectClass	*soc1;
-	int		nsups;
-	char		**sups1;
-	int		add_sups = 0;
-
-	if ( sups ) {
-		if ( !soc->soc_sups ) {
-			/* We are at the first recursive level */
-			add_sups = 1;
-			nsups = 0;
-			sups1 = sups;
-			while ( *sups1 ) {
-				nsups++;
-				sups1++;
-			}
-			nsups++;
-			soc->soc_sups = (ObjectClass **)ch_calloc(1,
-					  nsups*sizeof(ObjectClass *));
-		}
-		nsups = 0;
-		sups1 = sups;
-		while ( *sups1 ) {
-			soc1 = oc_find(*sups1);
-			if ( !soc1 ) {
-				*err = *sups1;
-				return SLAP_SCHERR_CLASS_NOT_FOUND;
-			}
-
-			if ( add_sups )
-				soc->soc_sups[nsups] = soc1;
-
-			code = oc_add_sups(soc,soc1->soc_sup_oids, err);
-			if ( code )
-				return code;
-
-			code = oc_create_required(soc,soc1->soc_at_oids_must,err);
-			if ( code )
-				return code;
-			code = oc_create_allowed(soc,soc1->soc_at_oids_may,err);
-			if ( code )
-				return code;
-
-			nsups++;
-			sups1++;
-		}
-	}
-	return 0;
-}
-
-static int
-oc_insert(
-    ObjectClass		*soc,
-    const char		**err
-)
-{
-	ObjectClass	**ocp;
-	struct oindexrec	*oir;
-	char			**names;
-
-	ocp = &oc_list;
-	while ( *ocp != NULL ) {
-		ocp = &(*ocp)->soc_next;
-	}
-	*ocp = soc;
-
-	if ( soc->soc_oid ) {
-		oir = (struct oindexrec *)
-			ch_calloc( 1, sizeof(struct oindexrec) );
-		oir->oir_name = soc->soc_oid;
-		oir->oir_oc = soc;
-		if ( avl_insert( &oc_index, (caddr_t) oir,
-				 (AVL_CMP) oc_index_cmp,
-				 (AVL_DUP) avl_dup_error ) ) {
-			*err = soc->soc_oid;
-			ldap_memfree(oir);
-			return SLAP_SCHERR_DUP_CLASS;
-		}
-		/* FIX: temporal consistency check */
-		oc_find(oir->oir_name);
-	}
-	if ( (names = soc->soc_names) ) {
-		while ( *names ) {
-			oir = (struct oindexrec *)
-				ch_calloc( 1, sizeof(struct oindexrec) );
-			oir->oir_name = ch_strdup(*names);
-			oir->oir_oc = soc;
-			if ( avl_insert( &oc_index, (caddr_t) oir,
-					 (AVL_CMP) oc_index_cmp,
-					 (AVL_DUP) avl_dup_error ) ) {
-				*err = *names;
-				ldap_memfree(oir);
-				return SLAP_SCHERR_DUP_CLASS;
-			}
-			/* FIX: temporal consistency check */
-			oc_find(oir->oir_name);
-			names++;
-		}
-	}
-	return 0;
-}
-
-int
-oc_add(
-    LDAP_OBJECT_CLASS	*oc,
-    const char		**err
-)
-{
-	ObjectClass	*soc;
-	int		code;
-
-	soc = (ObjectClass *) ch_calloc( 1, sizeof(ObjectClass) );
-	memcpy( &soc->soc_oclass, oc, sizeof(LDAP_OBJECT_CLASS));
-	if ( (code = oc_add_sups(soc,soc->soc_sup_oids,err)) != 0 )
-		return code;
-	if ( (code = oc_create_required(soc,soc->soc_at_oids_must,err)) != 0 )
-		return code;
-	if ( (code = oc_create_allowed(soc,soc->soc_at_oids_may,err)) != 0 )
-		return code;
-	code = oc_insert(soc,err);
-	return code;
-}
-
-struct sindexrec {
-	char		*sir_name;
-	Syntax		*sir_syn;
-};
-
-static Avlnode	*syn_index = NULL;
-static Syntax *syn_list = NULL;
-
-static int
-syn_index_cmp(
-    struct sindexrec	*sir1,
-    struct sindexrec	*sir2
-)
-{
-	return (strcmp( sir1->sir_name, sir2->sir_name ));
-}
-
-static int
-syn_index_name_cmp(
-    char 		*name,
-    struct sindexrec	*sir
-)
-{
-	return (strcmp( name, sir->sir_name ));
-}
-
-Syntax *
-syn_find( const char *synname )
-{
-	struct sindexrec	*sir = NULL;
-
-	if ( (sir = (struct sindexrec *) avl_find( syn_index, synname,
-            (AVL_CMP) syn_index_name_cmp )) != NULL ) {
-		return( sir->sir_syn );
-	}
-	return( NULL );
-}
-
-Syntax *
-syn_find_desc( const char *syndesc, int *len )
-{
-	Syntax		*synp;
-
-	for (synp = syn_list; synp; synp = synp->ssyn_next)
-		if ((*len = dscompare( synp->ssyn_syn.syn_desc, syndesc, '{')))
-			return synp;
-	return( NULL );
-}
-
-static int
-syn_insert(
-    Syntax		*ssyn,
-    const char		**err
-)
-{
-	Syntax		**synp;
-	struct sindexrec	*sir;
-
-	synp = &syn_list;
-	while ( *synp != NULL ) {
-		synp = &(*synp)->ssyn_next;
-	}
-	*synp = ssyn;
-
-	if ( ssyn->ssyn_oid ) {
-		sir = (struct sindexrec *)
-			ch_calloc( 1, sizeof(struct sindexrec) );
-		sir->sir_name = ssyn->ssyn_oid;
-		sir->sir_syn = ssyn;
-		if ( avl_insert( &syn_index, (caddr_t) sir,
-				 (AVL_CMP) syn_index_cmp,
-				 (AVL_DUP) avl_dup_error ) ) {
-			*err = ssyn->ssyn_oid;
-			ldap_memfree(sir);
-			return SLAP_SCHERR_DUP_SYNTAX;
-		}
-		/* FIX: temporal consistency check */
-		syn_find(sir->sir_name);
-	}
-	return 0;
-}
-
-int
-syn_add(
-    LDAP_SYNTAX		*syn,
-	int flags,
-    slap_syntax_validate_func	*validate,
-    slap_syntax_transform_func	*ber2str,
-    slap_syntax_transform_func	*str2ber,
-    const char		**err
-)
-{
-	Syntax		*ssyn;
-	int		code;
-
-	ssyn = (Syntax *) ch_calloc( 1, sizeof(Syntax) );
-	memcpy( &ssyn->ssyn_syn, syn, sizeof(LDAP_SYNTAX));
-
-	ssyn->ssyn_flags = flags;
-	ssyn->ssyn_validate = validate;
-	ssyn->ssyn_ber2str = ber2str;
-	ssyn->ssyn_str2ber = str2ber;
-
-	code = syn_insert(ssyn,err);
-	return code;
-}
-
-struct mindexrec {
-	char		*mir_name;
-	MatchingRule	*mir_mr;
-};
-
-static Avlnode	*mr_index = NULL;
-static MatchingRule *mr_list = NULL;
-
-static int
-mr_index_cmp(
-    struct mindexrec	*mir1,
-    struct mindexrec	*mir2
-)
-{
-	return (strcmp( mir1->mir_name, mir2->mir_name ));
-}
-
-static int
-mr_index_name_cmp(
-    char 		*name,
-    struct mindexrec	*mir
-)
-{
-	return (strcmp( name, mir->mir_name ));
-}
-
-MatchingRule *
-mr_find( const char *mrname )
-{
-	struct mindexrec	*mir = NULL;
-
-	if ( (mir = (struct mindexrec *) avl_find( mr_index, mrname,
-            (AVL_CMP) mr_index_name_cmp )) != NULL ) {
-		return( mir->mir_mr );
-	}
-	return( NULL );
-}
-
-static int
-mr_insert(
-    MatchingRule	*smr,
-    const char		**err
-)
-{
-	MatchingRule		**mrp;
-	struct mindexrec	*mir;
-	char			**names;
-
-	mrp = &mr_list;
-	while ( *mrp != NULL ) {
-		mrp = &(*mrp)->smr_next;
-	}
-	*mrp = smr;
-
-	if ( smr->smr_oid ) {
-		mir = (struct mindexrec *)
-			ch_calloc( 1, sizeof(struct mindexrec) );
-		mir->mir_name = smr->smr_oid;
-		mir->mir_mr = smr;
-		if ( avl_insert( &mr_index, (caddr_t) mir,
-				 (AVL_CMP) mr_index_cmp,
-				 (AVL_DUP) avl_dup_error ) ) {
-			*err = smr->smr_oid;
-			ldap_memfree(mir);
-			return SLAP_SCHERR_DUP_RULE;
-		}
-		/* FIX: temporal consistency check */
-		mr_find(mir->mir_name);
-	}
-	if ( (names = smr->smr_names) ) {
-		while ( *names ) {
-			mir = (struct mindexrec *)
-				ch_calloc( 1, sizeof(struct mindexrec) );
-			mir->mir_name = ch_strdup(*names);
-			mir->mir_mr = smr;
-			if ( avl_insert( &mr_index, (caddr_t) mir,
-					 (AVL_CMP) mr_index_cmp,
-					 (AVL_DUP) avl_dup_error ) ) {
-				*err = *names;
-				ldap_memfree(mir);
-				return SLAP_SCHERR_DUP_RULE;
-			}
-			/* FIX: temporal consistency check */
-			mr_find(mir->mir_name);
-			names++;
-		}
-	}
-	return 0;
-}
-
-int
-mr_add(
-    LDAP_MATCHING_RULE		*mr,
-	slap_mr_convert_func *convert,
-	slap_mr_normalize_func *normalize,
-    slap_mr_match_func	*match,
-	slap_mr_indexer_func *indexer,
-    slap_mr_filter_func	*filter,
-    const char		**err
-)
-{
-	MatchingRule	*smr;
-	Syntax		*syn;
-	int		code;
-
-	smr = (MatchingRule *) ch_calloc( 1, sizeof(MatchingRule) );
-	memcpy( &smr->smr_mrule, mr, sizeof(LDAP_MATCHING_RULE));
-
-	smr->smr_convert = convert;
-	smr->smr_normalize = normalize;
-	smr->smr_match = match;
-	smr->smr_indexer = indexer;
-	smr->smr_filter = filter;
-
-	if ( smr->smr_syntax_oid ) {
-		if ( (syn = syn_find(smr->smr_syntax_oid)) ) {
-			smr->smr_syntax = syn;
-		} else {
-			*err = smr->smr_syntax_oid;
-			return SLAP_SCHERR_SYN_NOT_FOUND;
-		}
-	} else {
-		*err = "";
-		return SLAP_SCHERR_MR_INCOMPLETE;
-	}
-	code = mr_insert(smr,err);
-	return code;
-}
-
-int
-register_syntax(
-	char * desc, int flags,
-	slap_syntax_validate_func *validate,
-	slap_syntax_transform_func *ber2str,
-	slap_syntax_transform_func *str2ber )
-{
-	LDAP_SYNTAX	*syn;
-	int		code;
-	const char	*err;
-
-	syn = ldap_str2syntax( desc, &code, &err);
-	if ( !syn ) {
-		Debug( LDAP_DEBUG_ANY, "Error in register_syntax: %s before %s in %s\n",
-		    ldap_scherr2str(code), err, desc );
-		return( -1 );
-	}
-
-	code = syn_add( syn, flags, validate, ber2str, str2ber, &err );
-	if ( code ) {
-		Debug( LDAP_DEBUG_ANY, "Error in register_syntax: %s %s in %s\n",
-		    scherr2str(code), err, desc );
-		return( -1 );
-	}
-
-	return( 0 );
-}
-
-int
-register_matching_rule(
-	char * desc,
-	slap_mr_convert_func *convert,
-	slap_mr_normalize_func *normalize,
-	slap_mr_match_func *match,
-	slap_mr_indexer_func *indexer,
-	slap_mr_filter_func *filter )
-{
-	LDAP_MATCHING_RULE *mr;
-	int		code;
-	const char	*err;
-
-	mr = ldap_str2matchingrule( desc, &code, &err);
-	if ( !mr ) {
-		Debug( LDAP_DEBUG_ANY, "Error in register_matching_rule: %s before %s in %s\n",
-		    ldap_scherr2str(code), err, desc );
-		return( -1 );
-	}
-
-	code = mr_add( mr, convert, normalize, match, indexer, filter, &err );
-	if ( code ) {
-		Debug( LDAP_DEBUG_ANY, "Error in register_syntax: %s for %s in %s\n",
-		    scherr2str(code), err, desc );
-		return( -1 );
-	}
-	return( 0 );
-}
-
 
 #if defined( SLAPD_SCHEMA_DN )
 
-static int
-syn_schema_info( Entry *e )
-{
-	struct berval	val;
-	struct berval	*vals[2];
-	Syntax		*syn;
-
-	vals[0] = &val;
-	vals[1] = NULL;
-
-	for ( syn = syn_list; syn; syn = syn->ssyn_next ) {
-		val.bv_val = ldap_syntax2str( &syn->ssyn_syn );
-		if ( val.bv_val ) {
-			val.bv_len = strlen( val.bv_val );
-			Debug( LDAP_DEBUG_TRACE, "Merging syn [%ld] %s\n",
-			       (long) val.bv_len, val.bv_val, 0 );
-			attr_merge( e, "ldapSyntaxes", vals );
-			ldap_memfree( val.bv_val );
-		} else {
-			return -1;
-		}
-	}
-	return 0;
-}
-
-static int
-mr_schema_info( Entry *e )
-{
-	struct berval	val;
-	struct berval	*vals[2];
-	MatchingRule	*mr;
-
-	vals[0] = &val;
-	vals[1] = NULL;
-
-	for ( mr = mr_list; mr; mr = mr->smr_next ) {
-		val.bv_val = ldap_matchingrule2str( &mr->smr_mrule );
-		if ( val.bv_val ) {
-			val.bv_len = strlen( val.bv_val );
-			Debug( LDAP_DEBUG_TRACE, "Merging mr [%ld] %s\n",
-			       (long) val.bv_len, val.bv_val, 0 );
-			attr_merge( e, "matchingRules", vals );
-			ldap_memfree( val.bv_val );
-		} else {
-			return -1;
-		}
-	}
-	return 0;
-}
-
-static int
-oc_schema_info( Entry *e )
-{
-	struct berval	val;
-	struct berval	*vals[2];
-	ObjectClass	*oc;
-
-	vals[0] = &val;
-	vals[1] = NULL;
-
-	for ( oc = oc_list; oc; oc = oc->soc_next ) {
-		val.bv_val = ldap_objectclass2str( &oc->soc_oclass );
-		if ( val.bv_val ) {
-			val.bv_len = strlen( val.bv_val );
-			Debug( LDAP_DEBUG_TRACE, "Merging oc [%ld] %s\n",
-			       (long) val.bv_len, val.bv_val, 0 );
-			attr_merge( e, "objectClasses", vals );
-			ldap_memfree( val.bv_val );
-		} else {
-			return -1;
-		}
-	}
-	return 0;
-}
-
 void
 schema_info( Connection *conn, Operation *op, char **attrs, int attrsonly )
 {
@@ -1001,24 +51,15 @@ schema_info( Connection *conn, Operation *op, char **attrs, int attrsonly )
 		free( rdn );
 	}
 
-	if ( syn_schema_info( e ) ) {
-		/* Out of memory, do something about it */
-		entry_free( e );
-		return;
-	}
-	if ( mr_schema_info( e ) ) {
-		/* Out of memory, do something about it */
-		entry_free( e );
-		return;
-	}
-	if ( at_schema_info( e ) ) {
-		/* Out of memory, do something about it */
-		entry_free( e );
-		return;
-	}
-	if ( oc_schema_info( e ) ) {
+	if ( syn_schema_info( e ) 
+		|| mr_schema_info( e )
+		|| at_schema_info( e )
+		|| oc_schema_info( e ) )
+	{
 		/* Out of memory, do something about it */
 		entry_free( e );
+		send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+			NULL, NULL, NULL, NULL );
 		return;
 	}
 	
@@ -1047,64 +88,3 @@ schema_info( Connection *conn, Operation *op, char **attrs, int attrsonly )
 }
 #endif
 
-#ifdef LDAP_DEBUG
-
-static void
-oc_print( ObjectClass *oc )
-{
-	int	i;
-	const char *mid;
-
-	printf( "objectclass %s\n", ldap_objectclass2name( &oc->soc_oclass ) );
-	if ( oc->soc_required != NULL ) {
-		mid = "\trequires ";
-		for ( i = 0; oc->soc_required[i] != NULL; i++, mid = "," )
-			printf( "%s%s", mid,
-			        ldap_attributetype2name( &oc->soc_required[i]->sat_atype ) );
-		printf( "\n" );
-	}
-	if ( oc->soc_allowed != NULL ) {
-		mid = "\tallows ";
-		for ( i = 0; oc->soc_allowed[i] != NULL; i++, mid = "," )
-			printf( "%s%s", mid,
-			        ldap_attributetype2name( &oc->soc_allowed[i]->sat_atype ) );
-		printf( "\n" );
-	}
-}
-
-#endif
-
-int is_entry_objectclass(
-	Entry*	e,
-	const char*	oc)
-{
-	Attribute *attr;
-	struct berval bv;
-
-	if( e == NULL || oc == NULL || *oc == '\0' )
-		return 0;
-
-	/*
-	 * find objectClass attribute
-	 */
-	attr = attr_find(e->e_attrs, "objectclass");
-
-	if( attr == NULL ) {
-		/* no objectClass attribute */
-		return 0;
-	}
-
-	bv.bv_val = (char *) oc;
-	bv.bv_len = strlen( bv.bv_val );
-
-#ifdef SLAPD_SCHEMA_NOT_COMPAT
-	/* not yet implemented */
-#else
-	if( value_find(attr->a_vals, &bv, attr->a_syntax, 1) != 0) {
-		/* entry is not of this objectclass */
-		return 0;
-	}
-#endif
-
-	return 1;
-}
diff --git a/servers/slapd/schema_check.c b/servers/slapd/schema_check.c
new file mode 100644
index 0000000000..25bbd5486a
--- /dev/null
+++ b/servers/slapd/schema_check.c
@@ -0,0 +1,271 @@
+/* schema_check.c - routines to enforce schema definitions */
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/ctype.h>
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "slap.h"
+#include "ldap_pvt.h"
+
+static char *	oc_check_required(Entry *e, char *ocname);
+static int		oc_check_allowed(char *type, struct berval **ocl);
+
+/*
+ * entry_schema_check - check that entry e conforms to the schema required
+ * by its object class(es).
+ *
+ * returns 0 if so, non-zero otherwise.
+ */
+
+int
+schema_check_entry( Entry *e )
+{
+	Attribute	*a, *aoc;
+	ObjectClass *oc;
+	int		i;
+	int		ret = 0;
+
+	if( !global_schemacheck ) return 0;
+
+	/* find the object class attribute - could error out here */
+	if ( (aoc = attr_find( e->e_attrs, "objectclass" )) == NULL ) {
+		Debug( LDAP_DEBUG_ANY, "No object class for entry (%s)\n",
+		    e->e_dn, 0, 0 );
+		return( 1 );
+	}
+
+	/* check that the entry has required attrs for each oc */
+	for ( i = 0; aoc->a_vals[i] != NULL; i++ ) {
+		if ( (oc = oc_find( aoc->a_vals[i]->bv_val )) == NULL ) {
+			Debug( LDAP_DEBUG_ANY,
+				"Objectclass \"%s\" not defined\n",
+				aoc->a_vals[i]->bv_val, 0, 0 );
+		}
+		else
+		{
+			char *s = oc_check_required( e, aoc->a_vals[i]->bv_val );
+
+			if (s != NULL) {
+				Debug( LDAP_DEBUG_ANY,
+					"Entry (%s), oc \"%s\" requires attr \"%s\"\n",
+					e->e_dn, aoc->a_vals[i]->bv_val, s );
+				ret = 1;
+			}
+		}
+	}
+
+	if ( ret != 0 ) {
+	    return( ret );
+	}
+
+	/* check that each attr in the entry is allowed by some oc */
+	for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
+#ifdef SLAPD_SCHEMA_NOT_COMPAT
+		if ( oc_check_allowed( a->a_desc.ad_type, aoc->a_vals ) != 0 ) {
+			Debug( LDAP_DEBUG_ANY,
+			    "Entry (%s), attr \"%s\" not allowed\n",
+			    e->e_dn, a->a_desc.ad_cname->bv_val, 0 );
+			ret = 1;
+		}
+#else
+		if ( oc_check_allowed( a->a_type, aoc->a_vals ) != 0 ) {
+			Debug( LDAP_DEBUG_ANY,
+			    "Entry (%s), attr \"%s\" not allowed\n",
+			    e->e_dn, a->a_type, 0 );
+			ret = 1;
+		}
+#endif
+	}
+
+	return( ret );
+}
+
+static char *
+oc_check_required( Entry *e, char *ocname )
+{
+	ObjectClass	*oc;
+	AttributeType	*at;
+	int		i;
+	Attribute	*a;
+
+	Debug( LDAP_DEBUG_TRACE,
+	       "oc_check_required entry (%s), objectclass \"%s\"\n",
+	       e->e_dn, ocname, 0 );
+
+	/* find global oc defn. it we don't know about it assume it's ok */
+	if ( (oc = oc_find( ocname )) == NULL ) {
+		return( 0 );
+	}
+
+	/* check for empty oc_required */
+	if(oc->soc_required == NULL) {
+		return( 0 );
+	}
+
+	/* for each required attribute */
+	for ( i = 0; oc->soc_required[i] != NULL; i++ ) {
+		at = oc->soc_required[i];
+		/* see if it's in the entry */
+		for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
+#ifdef SLAPD_SCHEMA_NOT_COMPAT
+			if( a->a_desc.ad_type == at ) {
+				break;
+			}
+#else
+			char		**pp;
+
+			if ( at->sat_oid &&
+			     strcmp( a->a_type, at->sat_oid ) == 0 ) {
+				break;
+			}
+			pp = at->sat_names;
+			if ( pp  == NULL ) {
+				/* Empty name list => not found */
+				a = NULL;
+				break;
+			}
+			while ( *pp ) {
+				if ( strcasecmp( a->a_type, *pp ) == 0 ) {
+					break;
+				}
+				pp++;
+			}
+			if ( *pp ) {
+				break;
+			}
+#endif
+		}
+		/* not there => schema violation */
+		if ( a == NULL ) {
+			if ( at->sat_names && at->sat_names[0] ) {
+				return at->sat_names[0];
+			} else {
+				return at->sat_oid;
+			}
+		}
+	}
+
+	return( NULL );
+}
+
+static int
+oc_check_allowed( char *type, struct berval **ocl )
+{
+	ObjectClass	*oc;
+	AttributeType	*at;
+	int		i, j;
+	char		**pp;
+	char		*p, *t;
+
+	Debug( LDAP_DEBUG_TRACE,
+	       "oc_check_allowed type \"%s\"\n", type, 0, 0 );
+
+	/* always allow objectclass attribute */
+	if ( strcasecmp( type, "objectclass" ) == 0 ) {
+		return( 0 );
+	}
+
+#ifndef SLAPD_SCHEMA_NOT_COMPAT
+	/* Treat any attribute type with option as an unknown attribute type */
+	/*
+	 * The "type" we have received is actually an AttributeDescription.
+	 * Let's find out the corresponding type.
+	 */
+	p = strchr( type, ';' );
+	if ( p ) {
+		t = ch_malloc( p-type+1 );
+		strncpy( t, type, p-type );
+		t[p-type] = '\0';
+		Debug( LDAP_DEBUG_TRACE,
+		       "oc_check_allowed type \"%s\" from \"%s\"\n",
+		       t, type, 0 );
+
+	} else
+#endif
+	{
+		t = type;
+	}
+
+
+	/*
+	 * All operational attributions are allowed by schema rules.
+	 */
+	if ( oc_check_op_attr( t ) ) {
+		return( 0 );
+	}
+
+	/* check that the type appears as req or opt in at least one oc */
+	for ( i = 0; ocl[i] != NULL; i++ ) {
+		/* if we know about the oc */
+		if ( (oc = oc_find( ocl[i]->bv_val )) != NULL ) {
+			/* does it require the type? */
+			for ( j = 0; oc->soc_required != NULL && 
+				oc->soc_required[j] != NULL; j++ ) {
+				at = oc->soc_required[j];
+				if ( at->sat_oid &&
+				     strcmp(at->sat_oid, t ) == 0 ) {
+					if ( t != type )
+						ldap_memfree( t );
+					return( 0 );
+				}
+				pp = at->sat_names;
+				if ( pp == NULL )
+					continue;
+				while ( *pp ) {
+					if ( strcasecmp( *pp, t ) == 0 ) {
+						if ( t != type )
+							ldap_memfree( t );
+						return( 0 );
+					}
+					pp++;
+				}
+			}
+			/* does it allow the type? */
+			for ( j = 0; oc->soc_allowed != NULL && 
+				oc->soc_allowed[j] != NULL; j++ ) {
+				at = oc->soc_allowed[j];
+				if ( at->sat_oid &&
+				     strcmp( at->sat_oid, t ) == 0 ) {
+					if ( t != type )
+						ldap_memfree( t );
+					return( 0 );
+				}
+				pp = at->sat_names;
+				if ( pp == NULL )
+					continue;
+				while ( *pp ) {
+					if ( strcasecmp( *pp, t ) == 0 ||
+					     strcmp( *pp, "*" ) == 0 ) {
+						if ( t != type )
+							ldap_memfree( t );
+						return( 0 );
+					}
+					pp++;
+				}
+			}
+			/* maybe the next oc allows it */
+
+#ifdef OC_UNDEFINED_IMPLES_EXTENSIBLE
+		/* we don't know about the oc. assume it allows it */
+		} else {
+			if ( t != type )
+				ldap_memfree( t );
+			return( 0 );
+#endif
+		}
+	}
+
+	if ( t != type )
+		ldap_memfree( t );
+	/* not allowed by any oc */
+	return( 1 );
+}
diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h
index 35b864562f..8403bfc0f5 100644
--- a/servers/slapd/slap.h
+++ b/servers/slapd/slap.h
@@ -143,10 +143,10 @@ typedef int slap_syntax_transform_func LDAP_P((
 
 typedef struct slap_syntax {
 	LDAP_SYNTAX			ssyn_syn;
-	int	ssyn_flags;
+	unsigned	ssyn_flags;
 
-#define SLAP_SYNTAX_NONE	0
-#define SLAP_SYNTAX_BINARY	1
+#define SLAP_SYNTAX_NONE	0x0U
+#define SLAP_SYNTAX_BINARY	0x1U
 
 	slap_syntax_validate_func	*ssyn_validate;
 
@@ -210,6 +210,9 @@ typedef struct slap_matching_rule {
 } MatchingRule;
 
 typedef struct slap_attribute_type {
+#ifdef SLAPD_SCHEMA_NOT_COMPAT
+	char					*sat_cname;
+#endif
 	LDAP_ATTRIBUTE_TYPE		sat_atype;
 	struct slap_attribute_type	*sat_sup;
 	struct slap_attribute_type	**sat_subtypes;
@@ -235,6 +238,11 @@ typedef struct slap_attribute_type {
 #define sat_usage		sat_atype.at_usage
 } AttributeType;
 
+#define is_at_operational(at)	((at)->sat_usage)
+#define is_at_single_value(at)	((at)->sat_single_value)
+#define is_at_collective(at)	((at)->sat_collective)
+#define is_at_no_user_mod(at)	((at)->sat_no_user_mod)
+
 typedef struct slap_object_class {
 	LDAP_OBJECT_CLASS		soc_oclass;
 	struct slap_object_class	**soc_sups;
@@ -279,6 +287,32 @@ typedef struct slap_mra {
 	struct berval	*mra_value;
 } Mra;
 
+#ifdef SLAPD_SCHEMA_NOT_COMPAT
+/*
+ * represents a recognized attribute description ( type + options )
+ */
+typedef struct slap_attr_desc {
+	struct berval *ad_cname;	/* canonical name */
+	AttributeType *ad_type;		/* NULL if unknown */
+	char *ad_lang;				/* NULL if no language tags */
+	unsigned ad_flags;
+#define SLAP_DESC_NONE		0x0U
+#define SLAP_DESC_BINARY	0x1U
+} AttributeDescription;
+
+typedef struct slap_attr_assertion {
+	AttributeDescription	aa_desc;
+	struct berval *aa_value;
+} AttributeAssertion;
+
+typedef struct slap_mr_assertion {
+	char					*ma_rule;	/* optional */
+	AttributeDescription	*ma_desc;	/* optional */
+	int						ma_dnattrs; /* boolean */
+	struct berval			*ma_value;	/* required */
+} MatchingRuleAssertion;
+#endif
+
 /*
  * represents a search filter
  */
@@ -331,14 +365,16 @@ typedef struct slap_filter {
 } Filter;
 
 /*
- * represents an attribute (type + values + syntax)
+ * represents an attribute (description + values)
  */
 typedef struct slap_attr {
+#ifdef SLAPD_SCHEMA_NOT_COMPAT
+	AttributeDescription a_desc;
+#else
 	char		*a_type;	/* description */
-	struct berval	**a_vals;
-#ifndef SLAPD_SCHEMA_NOT_COMPAT
 	int		a_syntax;
 #endif
+	struct berval	**a_vals;
 	struct slap_attr	*a_next;
 } Attribute;
 
diff --git a/servers/slapd/syntax.c b/servers/slapd/syntax.c
new file mode 100644
index 0000000000..e26fe835c5
--- /dev/null
+++ b/servers/slapd/syntax.c
@@ -0,0 +1,182 @@
+/* syntax.c - routines to manage syntax definitions */
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/ctype.h>
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "slap.h"
+#include "ldap_pvt.h"
+
+
+struct sindexrec {
+	char		*sir_name;
+	Syntax		*sir_syn;
+};
+
+static Avlnode	*syn_index = NULL;
+static Syntax *syn_list = NULL;
+
+static int
+syn_index_cmp(
+    struct sindexrec	*sir1,
+    struct sindexrec	*sir2
+)
+{
+	return (strcmp( sir1->sir_name, sir2->sir_name ));
+}
+
+static int
+syn_index_name_cmp(
+    char 		*name,
+    struct sindexrec	*sir
+)
+{
+	return (strcmp( name, sir->sir_name ));
+}
+
+Syntax *
+syn_find( const char *synname )
+{
+	struct sindexrec	*sir = NULL;
+
+	if ( (sir = (struct sindexrec *) avl_find( syn_index, synname,
+            (AVL_CMP) syn_index_name_cmp )) != NULL ) {
+		return( sir->sir_syn );
+	}
+	return( NULL );
+}
+
+Syntax *
+syn_find_desc( const char *syndesc, int *len )
+{
+	Syntax		*synp;
+
+	for (synp = syn_list; synp; synp = synp->ssyn_next)
+		if ((*len = dscompare( synp->ssyn_syn.syn_desc, syndesc, '{')))
+			return synp;
+	return( NULL );
+}
+
+static int
+syn_insert(
+    Syntax		*ssyn,
+    const char		**err
+)
+{
+	Syntax		**synp;
+	struct sindexrec	*sir;
+
+	synp = &syn_list;
+	while ( *synp != NULL ) {
+		synp = &(*synp)->ssyn_next;
+	}
+	*synp = ssyn;
+
+	if ( ssyn->ssyn_oid ) {
+		sir = (struct sindexrec *)
+			ch_calloc( 1, sizeof(struct sindexrec) );
+		sir->sir_name = ssyn->ssyn_oid;
+		sir->sir_syn = ssyn;
+		if ( avl_insert( &syn_index, (caddr_t) sir,
+				 (AVL_CMP) syn_index_cmp,
+				 (AVL_DUP) avl_dup_error ) ) {
+			*err = ssyn->ssyn_oid;
+			ldap_memfree(sir);
+			return SLAP_SCHERR_DUP_SYNTAX;
+		}
+		/* FIX: temporal consistency check */
+		syn_find(sir->sir_name);
+	}
+	return 0;
+}
+
+int
+syn_add(
+    LDAP_SYNTAX		*syn,
+	int flags,
+    slap_syntax_validate_func	*validate,
+    slap_syntax_transform_func	*ber2str,
+    slap_syntax_transform_func	*str2ber,
+    const char		**err
+)
+{
+	Syntax		*ssyn;
+	int		code;
+
+	ssyn = (Syntax *) ch_calloc( 1, sizeof(Syntax) );
+	memcpy( &ssyn->ssyn_syn, syn, sizeof(LDAP_SYNTAX));
+
+	ssyn->ssyn_flags = flags;
+	ssyn->ssyn_validate = validate;
+	ssyn->ssyn_ber2str = ber2str;
+	ssyn->ssyn_str2ber = str2ber;
+
+	code = syn_insert(ssyn,err);
+	return code;
+}
+
+int
+register_syntax(
+	char * desc, int flags,
+	slap_syntax_validate_func *validate,
+	slap_syntax_transform_func *ber2str,
+	slap_syntax_transform_func *str2ber )
+{
+	LDAP_SYNTAX	*syn;
+	int		code;
+	const char	*err;
+
+	syn = ldap_str2syntax( desc, &code, &err);
+	if ( !syn ) {
+		Debug( LDAP_DEBUG_ANY, "Error in register_syntax: %s before %s in %s\n",
+		    ldap_scherr2str(code), err, desc );
+		return( -1 );
+	}
+
+	code = syn_add( syn, flags, validate, ber2str, str2ber, &err );
+	if ( code ) {
+		Debug( LDAP_DEBUG_ANY, "Error in register_syntax: %s %s in %s\n",
+		    scherr2str(code), err, desc );
+		return( -1 );
+	}
+
+	return( 0 );
+}
+
+#if defined( SLAPD_SCHEMA_DN )
+
+int
+syn_schema_info( Entry *e )
+{
+	struct berval	val;
+	struct berval	*vals[2];
+	Syntax		*syn;
+
+	vals[0] = &val;
+	vals[1] = NULL;
+
+	for ( syn = syn_list; syn; syn = syn->ssyn_next ) {
+		val.bv_val = ldap_syntax2str( &syn->ssyn_syn );
+		if ( val.bv_val ) {
+			val.bv_len = strlen( val.bv_val );
+			Debug( LDAP_DEBUG_TRACE, "Merging syn [%ld] %s\n",
+			       (long) val.bv_len, val.bv_val, 0 );
+			attr_merge( e, "ldapSyntaxes", vals );
+			ldap_memfree( val.bv_val );
+		} else {
+			return -1;
+		}
+	}
+	return 0;
+}
+
+#endif
diff --git a/servers/slapd/tools/Makefile.in b/servers/slapd/tools/Makefile.in
index 17c9a94e17..f450db9f46 100644
--- a/servers/slapd/tools/Makefile.in
+++ b/servers/slapd/tools/Makefile.in
@@ -51,7 +51,8 @@ BDB2SRCS =
 QUIPUSRCS	= edb2ldif.c ldapsyntax.c chlog2replog.c
 SLAPD_OBJS = ../config.o ../ch_malloc.o ../backend.o ../charray.o \
 		../module.o ../aclparse.o ../filterentry.o \
-		../schema.o ../schema_init.o ../schemaparse.o \
+		../schema.o ../schema_check.o ../schema_init.o ../schemaparse.o \
+		../at.o ../mr.o ../oc.o ../syntax.o \
 		../acl.o ../phonetic.o ../attr.o ../value.o ../entry.o \
 		../dn.o ../filter.o ../str2filter.o ../ava.o ../init.o \
 		../controls.o ../kerberos.o ../passwd.o \
diff --git a/servers/slapd/tools/slapadd.c b/servers/slapd/tools/slapadd.c
index 73a4b7656a..0acdbdf453 100644
--- a/servers/slapd/tools/slapadd.c
+++ b/servers/slapd/tools/slapadd.c
@@ -69,7 +69,7 @@ main( int argc, char **argv )
 			}
 
 			/* check schema */
-			if ( global_schemacheck && oc_schema_check( e ) != 0 ) {
+			if ( schema_check_entry( e ) != 0 ) {
 				fprintf( stderr, "%s: schema violation in entry dn=\"%s\" (line=%d)\n",
 					progname, e->e_dn, lineno );
 				rc = EXIT_FAILURE;