From 87b86a52e4bc136e0c4cd279ca867de599a25b0b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Julio=20S=C3=A1nchez=20Fern=C3=A1ndez?=
 <jsanchez@openldap.org>
Date: Mon, 14 Jun 1999 19:10:07 +0000
Subject: [PATCH] Matching rules and syntaxes, initial step. schema_init,
 seeding of standard syntaxes and matching rules.

---
 servers/slapd/attr.c        |  41 +++-
 servers/slapd/main.c        |   5 +
 servers/slapd/proto-slap.h  |   5 +
 servers/slapd/schema.c      | 387 +++++++++++++++++++++++++++++++++++-
 servers/slapd/schemaparse.c |   8 +-
 servers/slapd/slap.h        |   8 +
 6 files changed, 449 insertions(+), 5 deletions(-)

diff --git a/servers/slapd/attr.c b/servers/slapd/attr.c
index e64b5f307f..163cac3f0d 100644
--- a/servers/slapd/attr.c
+++ b/servers/slapd/attr.c
@@ -476,13 +476,18 @@ at_add(
 {
 	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 {
+	} 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));
@@ -500,6 +505,14 @@ at_add(
 	}
 
 	if ( at->at_syntax_oid ) {
+#if 0
+		if ( (syn = syn_find(sat->sat_syntax_oid)) ) {
+			sat->sat_syntax = syn;
+		} else {
+			*err = sat->sat_syntax_oid;
+			return SLAP_SCHERR_SYN_NOT_FOUND;
+		}
+#endif
 		if ( !strcmp(at->at_syntax_oid,
 			     "1.3.6.1.4.1.1466.115.121.1.15") ) {
 			if ( at->at_equality_oid &&
@@ -524,6 +537,32 @@ at_add(
 		sat->sat_syntax_compat = DEFAULT_SYNTAX;
 	}
 
+#if 0
+	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;
+		}
+	}
+#endif
 	code = at_insert(sat,err);
 	return code;
 }
diff --git a/servers/slapd/main.c b/servers/slapd/main.c
index e1e85ac113..fbc38f6ce0 100644
--- a/servers/slapd/main.c
+++ b/servers/slapd/main.c
@@ -268,6 +268,11 @@ main( int argc, char **argv )
 		goto destroy;
 	}
 
+	if ( schema_init( ) != 0 ) {
+		rc = 1;
+		goto destroy;
+	}
+
 	if ( read_config( configfile ) != 0 ) {
 		rc = 1;
 		goto destroy;
diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h
index 4ae19d112e..89348359e1 100644
--- a/servers/slapd/proto-slap.h
+++ b/servers/slapd/proto-slap.h
@@ -240,7 +240,12 @@ void send_ldap_search_result LDAP_P(( Connection *conn, Operation *op, int err,
 int oc_schema_check LDAP_P(( Entry *e ));
 ObjectClass *oc_find LDAP_P((const char *ocname));
 int oc_add LDAP_P((LDAP_OBJECT_CLASS *oc, const char **err));
+Syntax *syn_find LDAP_P((const char *synname));
+int syn_add LDAP_P((LDAP_SYNTAX *syn, slap_syntax_check_func *check, const char **err));
+MatchingRule *mr_find LDAP_P((const char *mrname));
+int mr_add LDAP_P((LDAP_MATCHING_RULE *mr, slap_mr_normalize_func *normalize, slap_mr_compare_func *compare, const char **err));
 void schema_info LDAP_P((Connection *conn, Operation *op, char **attrs, int attrsonly));
+int schema_init LDAP_P((void));
 
 
 /*
diff --git a/servers/slapd/schema.c b/servers/slapd/schema.c
index 9ca5fdb715..e9eee40396 100644
--- a/servers/slapd/schema.c
+++ b/servers/slapd/schema.c
@@ -228,11 +228,11 @@ oc_index_cmp(
 
 static int
 oc_index_name_cmp(
-    char 		*type,
+    char 		*name,
     struct oindexrec	*oir
 )
 {
-	return (strcasecmp( type, oir->oir_name ));
+	return (strcasecmp( name, oir->oir_name ));
 }
 
 ObjectClass *
@@ -446,8 +446,379 @@ oc_add(
 	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 );
+}
+
+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,
+    slap_syntax_check_func	*check,
+    const char		**err
+)
+{
+	Syntax		*ssyn;
+	int		code;
+
+	ssyn = (Syntax *) ch_calloc( 1, sizeof(Syntax) );
+	memcpy( &ssyn->ssyn_syn, syn, sizeof(LDAP_SYNTAX));
+	ssyn->ssyn_check = check;
+	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_normalize_func	*normalize,
+    slap_mr_compare_func	*compare,
+    const char		**err
+)
+{
+	MatchingRule	*smr;
+	int		code;
+
+	smr = (MatchingRule *) ch_calloc( 1, sizeof(MatchingRule) );
+	memcpy( &smr->smr_mrule, mr, sizeof(LDAP_MATCHING_RULE));
+	smr->smr_normalize = normalize;
+	smr->smr_compare = compare;
+	code = mr_insert(smr,err);
+	return code;
+}
+
+int
+register_syntax(
+	char * desc,
+	slap_syntax_check_func *check )
+{
+	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, check, &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 );
+}
+
+int
+register_matching_rule(
+	char * desc,
+	slap_mr_normalize_func *normalize,
+	slap_mr_compare_func *compare )
+{
+	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, normalize, compare, &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 );
+}
+
+struct syntax_defs_rec {
+	char *sd_desc;
+	slap_syntax_check_func *sd_check;
+};
+
+struct syntax_defs_rec syntax_defs[] = {
+	{"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )", NULL},
+	{"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'DN' )", NULL},
+	{"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )", NULL},
+	{"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )", NULL},
+	{"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )", NULL},
+	{"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )", NULL},
+	{"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )", NULL},
+	{"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )", NULL},
+	{"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'INTEGER' )", NULL},
+	{"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )", NULL},
+	{"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )", NULL},
+	{"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )", NULL},
+	{"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )", NULL},
+	{"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )", NULL},
+	{"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )", NULL},
+	{"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )", NULL},
+	{NULL, NULL}
+};
+
+struct mrule_defs_rec {
+	char *mrd_desc;
+	slap_mr_normalize_func *mrd_normalize;
+	slap_mr_compare_func *mrd_compare;
+};
+
+struct mrule_defs_rec mrule_defs[] = {
+	{"( 2.5.13.0 NAME 'objectIdentifierMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )", NULL, NULL},
+	{"( 2.5.13.1 NAME 'distinguishedNameMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )", NULL, NULL},
+	{"( 2.5.13.2 NAME 'caseIgnoreMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )", NULL, NULL},
+	{"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", NULL, NULL},
+	{"( 2.5.13.8 NAME 'numericStringMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )", NULL, NULL},
+	{"( 2.5.13.27 NAME 'generalizedTimeMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )", NULL, NULL},
+	{"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )", NULL, NULL},
+	{"( 2.5.13.29 NAME 'integerFirstComponentMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", NULL, NULL},
+	{"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )", NULL, NULL},
+	{NULL, NULL, NULL}
+};
+
+int
+schema_init( void )
+{
+	int		res;
+	int		code;
+	const char	*err;
+	int		i;
+
+	/* For now */
+	return( 0 );
+	for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
+		res = register_syntax( syntax_defs[i].sd_desc,
+		    syntax_defs[i].sd_check );
+		if ( res ) {
+			fprintf( stderr, "schema_init: Error registering syntax %s\n",
+				 syntax_defs[i].sd_desc );
+			exit( 1 );
+		}
+	}
+	for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
+		res = register_matching_rule( mrule_defs[i].mrd_desc,
+		    mrule_defs[i].mrd_normalize,
+		    mrule_defs[i].mrd_compare );
+		if ( res ) {
+			fprintf( stderr, "schema_init: Error registering matching rule %s\n",
+				 mrule_defs[i].mrd_desc );
+			exit( 1 );
+		}
+	}
+}
+
 #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 [%d] %s\n",
+			       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 [%d] %s\n",
+			       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 )
 {
@@ -464,7 +835,7 @@ oc_schema_info( Entry *e )
 			val.bv_len = strlen( val.bv_val );
 			Debug( LDAP_DEBUG_TRACE, "Merging oc [%d] %s\n",
 			       val.bv_len, val.bv_val, 0 );
-			attr_merge( e, "objectclasses", vals );
+			attr_merge( e, "objectClasses", vals );
 			ldap_memfree( val.bv_val );
 		} else {
 			return -1;
@@ -500,6 +871,16 @@ schema_info( Connection *conn, Operation *op, char **attrs, int attrsonly )
 	attr_merge( e, "objectclass", vals );
 	ldap_memfree( val.bv_val );
 
+	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 );
diff --git a/servers/slapd/schemaparse.c b/servers/slapd/schemaparse.c
index 07de1d2997..49d95281f8 100644
--- a/servers/slapd/schemaparse.c
+++ b/servers/slapd/schemaparse.c
@@ -23,7 +23,13 @@ static char *err2text[] = {
 	"Objectclass not found",
 	"Attribute type not found",
 	"Duplicate objectclass",
-	"Duplicate attributetype"
+	"Duplicate attributetype",
+	"Duplicate syntax",
+	"Duplicate matchingrule",
+	"OID or name required",
+	"Syntax or superior required",
+	"Matchingrule not found",
+	"Syntax not found"
 };
 
 char *
diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h
index 85eac8096c..c162d76c4e 100644
--- a/servers/slapd/slap.h
+++ b/servers/slapd/slap.h
@@ -57,6 +57,12 @@
 #define SLAP_SCHERR_ATTR_NOT_FOUND	3
 #define SLAP_SCHERR_DUP_CLASS		4
 #define SLAP_SCHERR_DUP_ATTR		5
+#define SLAP_SCHERR_DUP_SYNTAX		6
+#define SLAP_SCHERR_DUP_RULE		7
+#define SLAP_SCHERR_NO_NAME		8
+#define SLAP_SCHERR_ATTR_INCOMPLETE	9
+#define SLAP_SCHERR_MR_NOT_FOUND	10
+#define SLAP_SCHERR_SYN_NOT_FOUND	11
 
 LDAP_BEGIN_DECL
 
@@ -220,6 +226,7 @@ typedef int slap_syntax_check_func LDAP_P((struct berval * val));
 typedef struct slap_syntax {
 	LDAP_SYNTAX			ssyn_syn;
 	slap_syntax_check_func		*ssyn_check;
+	struct slap_syntax		*ssyn_next;
 } Syntax;
 #define ssyn_oid			ssyn_syn.syn_oid
 #define ssyn_desc			ssyn_syn.syn_desc
@@ -232,6 +239,7 @@ typedef struct slap_matching_rule {
 	slap_mr_normalize_func		*smr_normalize;
 	slap_mr_compare_func		*smr_compare;
 	Syntax				smr_syntax;
+	struct slap_matching_rule	*smr_next;
 } MatchingRule;
 #define smr_oid				smr_mrule.mr_oid
 #define smr_names			smr_mrule.mr_names
-- 
GitLab