ldap/servers/plugins/replication/repl5_connection.c | 80 +-
ldap/servers/slapd/attrsyntax.c | 86 ++-
ldap/servers/slapd/log.c | 1
ldap/servers/slapd/proto-slap.h | 3
ldap/servers/slapd/schema.c | 542 +++++++++++++++++++-
ldap/servers/slapd/schemaparse.c | 6
ldap/servers/slapd/slap.h | 3
7 files changed, 664 insertions(+), 57 deletions(-)
New commits:
commit 5582b14982b8d1d02748ef66f9320daf0211c07f
Author: Thierry bordaz (tbordaz) <tbordaz(a)redhat.com>
Date: Tue May 20 10:24:34 2014 +0200
Ticket 47541 - Replication of the schema may overwrite
consumer 'attributetypes' even if
consumer definition is a superset
Bug Description: Need to check consumer attributetypes to make sure it doesn't
get
overwritten if it is a superset.
Fix Description: First, extended the attribute syntax struct to make it a double
linked list. This allows us to easily look through all the
attributeTypes.
Then check for supersets by looking at single vs multi-valued, and
syntax oid's. Matching rules are not being evalauated at this
time.
https://fedorahosted.org/389/ticket/47541
Reveiwed by: rmeggins(Thanks!)
diff --git a/ldap/servers/plugins/replication/repl5_connection.c
b/ldap/servers/plugins/replication/repl5_connection.c
index 2069a98..3d29a79 100644
--- a/ldap/servers/plugins/replication/repl5_connection.c
+++ b/ldap/servers/plugins/replication/repl5_connection.c
@@ -98,7 +98,7 @@ typedef struct repl_connection
/*** from proto-slap.h ***/
int schema_objectclasses_superset_check(struct berval **remote_schema, char *type);
-
+int schema_attributetypes_superset_check(struct berval **remote_schema, char *type);
/* Controls we add on every outbound operation */
static LDAPControl manageDSAITControl = {LDAP_CONTROL_MANAGEDSAIT, {0, ""},
'\0'};
@@ -1589,33 +1589,57 @@ conn_push_schema(Repl_Connection *conn, CSN **remotecsn)
/* Need to free the remote_schema_csn_bervals */
ber_bvecfree(remote_schema_csn_bervals);
}
- if (return_value != CONN_SCHEMA_NO_UPDATE_NEEDED) {
- struct berval
**remote_schema_objectclasses_bervals;
- /* before pushing the schema do some checking */
-
- /* First objectclasses */
- return_value = conn_read_entry_attribute(conn,
"cn=schema", "objectclasses",
&remote_schema_objectclasses_bervals);
- if (return_value == CONN_OPERATION_SUCCESS) {
- /* Check if the consumer objectclasses
are a superset of the local supplier schema */
- if
(schema_objectclasses_superset_check(remote_schema_objectclasses_bervals, OC_SUPPLIER)) {
- slapi_log_error(SLAPI_LOG_FATAL,
repl_plugin_name,
- "Schema %s must not
be overwritten (set replication log for additional info)\n",
-
agmt_get_long_name(conn->agmt));
- return_value =
CONN_OPERATION_FAILED;
- }
- } else {
- slapi_log_error(SLAPI_LOG_FATAL,
repl_plugin_name,
- "%s: Fail to retrieve the
remote schema objectclasses\n",
-
agmt_get_long_name(conn->agmt));
- }
-
- /* In case of success, possibly log a message */
- if (return_value == CONN_OPERATION_SUCCESS) {
- slapi_log_error(SLAPI_LOG_REPL,
repl_plugin_name,
- "Schema checking successful:
ok to push the schema (%s)\n", agmt_get_long_name(conn->agmt));
- }
- }
-
+ if (return_value != CONN_SCHEMA_NO_UPDATE_NEEDED) {
+ struct berval **remote_schema_objectclasses_bervals = NULL;
+ struct berval **remote_schema_attributetypes_bervals = NULL;
+ /* before pushing the schema do some checking */
+
+ /* First objectclasses */
+ return_value = conn_read_entry_attribute(conn, "cn=schema",
"objectclasses",
+ &remote_schema_objectclasses_bervals);
+ if (return_value == CONN_OPERATION_SUCCESS) {
+ /* Check if the consumer objectclasses are a superset of the local supplier schema
*/
+ if (schema_objectclasses_superset_check(remote_schema_objectclasses_bervals,
OC_SUPPLIER)) {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "Schema %s must not be overwritten (set replication log for additional
info)\n",
+ agmt_get_long_name(conn->agmt));
+ return_value = CONN_OPERATION_FAILED;
+ }
+ if(remote_schema_objectclasses_bervals){
+ ber_bvecfree(remote_schema_objectclasses_bervals);
+ }
+ } else {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Fail to retrieve the remote schema objectclasses\n",
+ agmt_get_long_name(conn->agmt));
+ }
+ if (return_value == CONN_OPERATION_SUCCESS) {
+ /* Next attribute types */
+ return_value = conn_read_entry_attribute(conn, "cn=schema",
"attributetypes",
+ &remote_schema_attributetypes_bervals);
+ if (return_value == CONN_OPERATION_SUCCESS) {
+ /* Check if the consumer attributes are a superset of the local supplier schema
*/
+ if (schema_attributetypes_superset_check(remote_schema_attributetypes_bervals,
OC_SUPPLIER)) {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "Schema %s must not be overwritten (set replication log for additional
info)\n",
+ agmt_get_long_name(conn->agmt));
+ return_value = CONN_OPERATION_FAILED;
+ }
+ if(remote_schema_attributetypes_bervals){
+ ber_bvecfree(remote_schema_attributetypes_bervals);
+ }
+ } else {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Fail to retrieve the remote schema attribute types\n",
+ agmt_get_long_name(conn->agmt));
+ }
+ }
+ /* In case of success, possibly log a message */
+ if (return_value == CONN_OPERATION_SUCCESS) {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "Schema checking successful: ok to push the schema (%s)\n",
agmt_get_long_name(conn->agmt));
+ }
+ }
}
}
}
diff --git a/ldap/servers/slapd/attrsyntax.c b/ldap/servers/slapd/attrsyntax.c
index 6386fbe..885d02a 100644
--- a/ldap/servers/slapd/attrsyntax.c
+++ b/ldap/servers/slapd/attrsyntax.c
@@ -58,6 +58,9 @@ static PLHashTable *oid2asi = NULL;
static Slapi_RWLock *oid2asi_lock = NULL;
static PLHashTable *internalasi = NULL;
+/* global attribute linked list */
+static asyntaxinfo *global_at = NULL;
+
/*
* This hashtable maps the name or alias of the attribute to the
* syntax info structure for that attribute. An attribute type has as
@@ -82,12 +85,20 @@ static void attr_syntax_delete_no_lock( struct asyntaxinfo *asip,
PRBool remove_from_oid_table );
static struct asyntaxinfo *attr_syntax_get_by_oid_locking_optional( const
char *oid, PRBool use_lock);
+static void attr_syntax_insert( struct asyntaxinfo *asip );
+static void attr_syntax_remove( struct asyntaxinfo *asip );
#ifdef ATTR_LDAP_DEBUG
static void attr_syntax_print();
#endif
static int attr_syntax_init(void);
+struct asyntaxinfo *
+attr_syntax_get_global_at()
+{
+ return global_at;
+}
+
void
attr_syntax_read_lock(void)
{
@@ -202,13 +213,14 @@ attr_syntax_free( struct asyntaxinfo *a )
PR_ASSERT( a->asi_refcnt == 0 );
cool_charray_free( a->asi_aliases );
- slapi_ch_free( (void**)&a->asi_name );
- slapi_ch_free( (void **)&a->asi_desc );
- slapi_ch_free( (void **)&a->asi_oid );
- slapi_ch_free( (void **)&a->asi_superior );
- slapi_ch_free( (void **)&a->asi_mr_equality );
- slapi_ch_free( (void **)&a->asi_mr_ordering );
- slapi_ch_free( (void **)&a->asi_mr_substring );
+ slapi_ch_free_string(&a->asi_name );
+ slapi_ch_free_string(&a->asi_desc );
+ slapi_ch_free_string(&a->asi_oid );
+ slapi_ch_free_string(&a->asi_superior );
+ slapi_ch_free_string(&a->asi_mr_equality );
+ slapi_ch_free_string(&a->asi_mr_ordering );
+ slapi_ch_free_string(&a->asi_mr_substring );
+ slapi_ch_free_string(&a->asi_syntax_oid);
schema_free_extensions(a->asi_extensions);
slapi_ch_free( (void **) &a );
}
@@ -380,6 +392,7 @@ attr_syntax_return_locking_optional(struct asyntaxinfo *asi, PRBool
use_lock)
}
/* ref count is 0 and it's flagged for
* deletion, so it's safe to free now */
+ attr_syntax_remove(asi);
attr_syntax_free(asi);
if(use_lock) {
AS_UNLOCK_WRITE(name2asi_lock);
@@ -411,6 +424,9 @@ attr_syntax_add_by_name(struct asyntaxinfo *a, int lock)
AS_LOCK_WRITE(name2asi_lock);
}
+ /* insert the attr into the global linked list */
+ attr_syntax_insert(a);
+
PL_HashTableAdd(name2asi, a->asi_name, a);
if ( a->asi_aliases != NULL ) {
int i;
@@ -475,6 +491,7 @@ attr_syntax_delete_no_lock( struct asyntaxinfo *asi,
* then to call return. The last return will then take care of
* the free. The only way this free would happen here is if
* you return the syntax before calling delete. */
+ attr_syntax_remove(asi);
attr_syntax_free(asi);
}
}
@@ -764,10 +781,46 @@ attr_syntax_dup( struct asyntaxinfo *a )
newas->asi_mr_eq_plugin = a->asi_mr_eq_plugin;
newas->asi_mr_ord_plugin = a->asi_mr_ord_plugin;
newas->asi_mr_sub_plugin = a->asi_mr_sub_plugin;
+ newas->asi_syntax_oid = slapi_ch_strdup(a->asi_syntax_oid);
+ newas->asi_next = NULL;
+ newas->asi_prev = NULL;
return( newas );
}
+static void
+attr_syntax_insert(struct asyntaxinfo *asip )
+{
+ /* Insert at top of list */
+ asip->asi_prev = NULL;
+ asip->asi_next = global_at;
+ if(global_at){
+ global_at->asi_prev = asip;
+ global_at = asip;
+ } else {
+ global_at = asip;
+ }
+}
+
+static void
+attr_syntax_remove(struct asyntaxinfo *asip )
+{
+ struct asyntaxinfo *prev, *next;
+
+ prev = asip->asi_prev;
+ next = asip->asi_next;
+ if(prev){
+ prev->asi_next = next;
+ if(next){
+ next->asi_prev = prev;
+ }
+ } else {
+ if(next){
+ next->asi_prev = NULL;
+ }
+ global_at = next;
+ }
+}
/*
* Add a new attribute type to the schema.
@@ -918,6 +971,7 @@ attr_syntax_create(
a.asi_mr_substring = (char*)mr_substring;
a.asi_extensions = extensions;
a.asi_plugin = plugin_syntax_find( attr_syntax );
+ a.asi_syntax_oid = (char *)attr_syntax ;
a.asi_syntaxlength = syntaxlength;
/* ideally, we would report an error and fail to start if there was some problem
with the matching rule - but since this functionality is new, and we might
@@ -1503,3 +1557,21 @@ slapi_reload_internal_attr_syntax()
attr_syntax_enumerate_attrs_ext(internalasi, attr_syntax_internal_asi_add, NULL);
return rc;
}
+
+/*
+ * See if the attribute at1 is in the list of at2. Change by name, and oid(if
necessary).
+ */
+struct asyntaxinfo *
+attr_syntax_find(struct asyntaxinfo *at1, struct asyntaxinfo *at2)
+{
+ struct asyntaxinfo *asi;
+
+ for(asi = at2; asi != NULL; asi = asi->asi_next){
+ if(strcasecmp(at1->asi_name, asi->asi_name) == 0 || strcmp(at1->asi_oid,
asi->asi_oid) == 0){
+ /* found it */
+ return asi;
+ }
+ }
+
+ return NULL;
+}
diff --git a/ldap/servers/slapd/log.c b/ldap/servers/slapd/log.c
index a2908d6..944876c 100644
--- a/ldap/servers/slapd/log.c
+++ b/ldap/servers/slapd/log.c
@@ -2031,7 +2031,6 @@ slapi_log_error_ext(int severity, char *subsystem, char *fmt,
va_list varg1, va_
int
slapi_is_loglevel_set ( const int loglevel )
{
-
return (
#ifdef _WIN32
*module_ldap_debug
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
index 2d10a09..2424dce 100644
--- a/ldap/servers/slapd/proto-slap.h
+++ b/ldap/servers/slapd/proto-slap.h
@@ -136,6 +136,8 @@ struct asyntaxinfo *attr_syntax_get_by_oid ( const char *oid );
struct asyntaxinfo *attr_syntax_get_by_name ( const char *name );
struct asyntaxinfo *attr_syntax_get_by_name_with_default ( const char *name );
struct asyntaxinfo *attr_syntax_get_by_name_locking_optional ( const char *name, PRBool
use_lock );
+struct asyntaxinfo *attr_syntax_get_global_at();
+struct asyntaxinfo *attr_syntax_find(struct asyntaxinfo *at1, struct asyntaxinfo *at2);
/*
* Call attr_syntax_return() when you are done using a value returned
* by attr_syntax_get_by_oid() or attr_syntax_get_by_name().
@@ -1013,6 +1015,7 @@ int slapi_reload_schema_files(char *schemadir);
void schema_free_extensions(schemaext *extensions);
schemaext *schema_copy_extensions(schemaext *extensions);
int schema_objectclasses_superset_check(struct berval **remote_schema, char *type);
+int schema_attributypes_superset_check(struct berval **remote_schema, char *type);
/*
* schemaparse.c
diff --git a/ldap/servers/slapd/schema.c b/ldap/servers/slapd/schema.c
index 2145b83..42689f4 100644
--- a/ldap/servers/slapd/schema.c
+++ b/ldap/servers/slapd/schema.c
@@ -145,6 +145,9 @@ static void schema_create_errormsg( char *errorbuf, size_t
errorbufsize,
#else
;
#endif
+static int schema_at_superset_check(struct asyntaxinfo *at_list1, struct asyntaxinfo
*at_list2, char *message);
+static int schema_at_superset_check_syntax_oids(char *oid1, char *oid2);
+static int schema_at_superset_check_mr(struct asyntaxinfo *a1, struct asyntaxinfo *a2,
char *info);
static int parse_at_str(const char *input, struct asyntaxinfo **asipp, char *errorbuf,
size_t errorbufsize,
PRUint32 schema_flags, int is_user_defined, int schema_ds4x_compat, int
is_remote);
static int extension_is_user_defined( schemaext *extensions );
@@ -1893,13 +1896,34 @@ modify_schema_dse (Slapi_PBlock *pb, Slapi_Entry *entryBefore,
Slapi_Entry *entr
rc = SLAPI_DSE_CALLBACK_ERROR;
} else {
if (strcasecmp (mods[i]->mod_type, "attributetypes") == 0) {
- /*
- * Replace all attribute types
- */
- *returncode = schema_replace_attributes( pb, mods[i], returntext,
- SLAPI_DSE_RETURNTEXT_SIZE );
+ if (is_replicated_operation) {
+ /*
+ * before accepting the schema checks if the local consumer schema is not
+ * a superset of the supplier schema
+ */
+ if (schema_attributetypes_superset_check(mods[i]->mod_bvalues, OC_CONSUMER))
{
+ schema_create_errormsg( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ schema_errprefix_generic, mods[i]->mod_type,
+ "Replace is not possible, local consumer schema is a superset
of the supplier" );
+ slapi_log_error(SLAPI_LOG_FATAL, "schema",
+ "Local %s must not be overwritten (set replication log for
additional info)\n",
+ mods[i]->mod_type);
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ } else {
+ /*
+ * Replace all attributes
+ */
+ *returncode = schema_replace_attributes( pb, mods[i], returntext,
+ SLAPI_DSE_RETURNTEXT_SIZE );
+ }
+ } else {
+ /*
+ * Replace all objectclasses
+ */
+ *returncode = schema_replace_attributes( pb, mods[i], returntext,
+ SLAPI_DSE_RETURNTEXT_SIZE );
+ }
} else if (strcasecmp (mods[i]->mod_type, "objectclasses") == 0) {
-
if (is_replicated_operation) {
/* before accepting the schema checks if the local
consumer schema is not
* a superset of the supplier schema
@@ -5890,6 +5914,7 @@ static int
schema_oc_superset_check(struct objclass *oc_list1, struct objclass *oc_list2, char
*message) {
struct objclass *oc_1, *oc_2;
char *description;
+ int debug_logging = 0;
int rc, i, j;
int found;
@@ -5902,6 +5927,11 @@ schema_oc_superset_check(struct objclass *oc_list1, struct objclass
*oc_list2, c
/* by default assum oc_list1 == oc_list2 */
rc = 0;
+ /* Are we doing replication logging */
+ if(slapi_is_loglevel_set(SLAPI_LOG_REPL)){
+ debug_logging = 1;
+ }
+
/* Check if all objectclass in oc_list1
* - exists in oc_list2
* - required attributes are also required in oc_2
@@ -5923,8 +5953,12 @@ schema_oc_superset_check(struct objclass *oc_list1, struct objclass
*oc_list2, c
/* The oc_1 objectclasses is supperset */
rc = 1;
-
- continue; /* we continue to check all the objectclass */
+ if(debug_logging){
+ /* we continue to check all the objectclasses so we log what
is wrong */
+ continue;
+ } else {
+ break;
+ }
}
/* First check the MUST */
@@ -5953,8 +5987,12 @@ schema_oc_superset_check(struct objclass *oc_list1, struct objclass
*oc_list2, c
/* The oc_1 objectclasses is supperset */
rc = 1;
-
- continue; /* we continue to check all attributes
*/
+ if(debug_logging){
+ /* we continue to check all attributes so we
log what is wrong */
+ continue;
+ } else {
+ break;
+ }
}
}
}
@@ -5983,10 +6021,14 @@ schema_oc_superset_check(struct objclass *oc_list1, struct
objclass *oc_list2, c
oc_1->oc_name,
description);
- /* The oc_1 objectclasses is supperset */
+ /* The oc_1 objectclasses is superset */
rc = 1;
-
- continue; /* we continue to check all attributes
*/
+ if(debug_logging){
+ /* we continue to check all attributes so we
log what is wrong */
+ continue;
+ } else {
+ break;
+ }
}
}
}
@@ -5995,6 +6037,385 @@ schema_oc_superset_check(struct objclass *oc_list1, struct
objclass *oc_list2, c
return rc;
}
+static int
+schema_at_superset_check(struct asyntaxinfo *at_list1, struct asyntaxinfo *at_list2, char
*message)
+{
+ struct asyntaxinfo *at_1, *at_2;
+ char *info = NULL;
+ int debug_logging = 0;
+ int found = 0;
+ int rc = 0;
+
+ if(at_list1 == NULL || at_list2 == NULL){
+ return 0;
+ }
+
+ /* Are we doing replication logging */
+ if(slapi_is_loglevel_set(SLAPI_LOG_REPL)){
+ debug_logging = 1;
+ }
+
+ for (at_1 = at_list1; at_1 != NULL; at_1 = at_1->asi_next){
+
+ /* check if at_1 exists in at_list2 */
+ if((at_2 = attr_syntax_find(at_1, at_list2))){
+ /*
+ * Check for single vs. multi value
+ */
+ if(!(at_1->asi_flags & SLAPI_ATTR_FLAG_SINGLE) &&
(at_2->asi_flags & SLAPI_ATTR_FLAG_SINGLE)){
+ /* at_list 1 is a superset */
+ rc = 1;
+ if(debug_logging){
+ slapi_log_error(SLAPI_LOG_REPL, "schema", "%s schema
attribute [%s] is not "
+ "\"single-valued\" \n",message,
at_1->asi_name);
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ /*
+ * Check the syntaxes
+ */
+ if(schema_at_superset_check_syntax_oids(at_1->asi_syntax_oid,
at_2->asi_syntax_oid)){
+ /* at_list 1 is a superset */
+ rc = 1;
+ if(debug_logging){
+ slapi_log_error(SLAPI_LOG_REPL, "schema", "%s schema
attribute [%s] syntax "
+ "can not be overwritten\n",message,
at_1->asi_name);
+ continue;
+ } else {
+ break;
+ }
+ }
+ /*
+ * Check some matching rules - not finished yet...
+ *
+ if(schema_at_superset_check_mr(at_1, at_2, info)){
+ rc = 1;
+ if(debug_logging){
+ slapi_log_error(SLAPI_LOG_REPL, "schema", "%s schema
attribute [%s] matching "
+ "rule can not be overwritten\n",message,
at_1->asi_name);
+ continue;
+ } else {
+ break;
+ }
+ }
+ */
+ } else {
+ rc = 1;
+ if(debug_logging){
+ /* we continue to check all attributes so we log what is wrong */
+ slapi_log_error(SLAPI_LOG_REPL, "schema", "Fail to
retrieve in the %s schema [%s or %s]\n",
+ message, at_1->asi_name, at_1->asi_oid);
+ continue;
+ } else {
+ break;
+ }
+ }
+ }
+
+
+ return rc;
+}
+
+/*
+ * Return 1 if a1's matching rules are superset(not to be overwritten). If just one
of
+ * the matching rules should not be overwritten, even if one should, we can not allow
it.
+ */
+static int
+schema_at_superset_check_mr(struct asyntaxinfo *a1, struct asyntaxinfo *a2, char *info)
+{
+ char *a1_mrtype[3] = { a1->asi_mr_equality, a1->asi_mr_substring,
a1->asi_mr_ordering };
+ char *a2_mrtype[3] = { a2->asi_mr_equality, a2->asi_mr_substring,
a2->asi_mr_ordering };
+ int rc = 0, i;
+
+ /*
+ * Loop over the three matching rule types
+ */
+ for(i = 0; i < 3; i++){
+ if(a1_mrtype[i]){
+ if(a2_mrtype[i]){
+ /*
+ * Future action item - determine matching rule precedence:
+ *
+ ces
+ "caseExactIA5Match",
"1.3.6.1.4.1.1466.109.114.1"
+ "caseExactMatch", "2.5.13.5"
+ "caseExactOrderingMatch", "2.5.13.6"
+ "caseExactSubstringsMatch", "2.5.13.7"
+ "caseExactIA5SubstringsMatch",
"2.16.840.1.113730.3.3.1"
+
+ cis
+ "generalizedTimeMatch", "2.5.13.27"
+ "generalizedTimeOrderingMatch", "2.5.13.28"
+ "booleanMatch", "2.5.13.13"
+ "caseIgnoreIA5Match",
"1.3.6.1.4.1.1466.109.114.2"
+ "caseIgnoreIA5SubstringsMatch",
"1.3.6.1.4.1.1466.109.114.3"
+ "caseIgnoreListMatch", "2.5.13.11"
+ "caseIgnoreListSubstringsMatch", "2.5.13.12"
+ "caseIgnoreMatch", "2.5.13.2"
-------------------------------
+ "caseIgnoreOrderingMatch", "2.5.13.3"
-----------------------> can have lang options
+ "caseIgnoreSubstringsMatch", "2.5.13.4"
--------------------- (as seen in the console)!
+ "directoryStringFirstComponentMatch",
"2.5.13.31"
+ "objectIdentifierMatch", "2.5.13.0"
+ "objectIdentifierFirstComponentMatch",
"2.5.13.30"
+
+ bitstring
+ "bitStringMatch",
"2.5.13.16","2.16.840.1.113730.3.3.1"
+
+ bin
+ "octetStringMatch", "2.5.13.17"
+ "octetStringOrderingMatch", "2.5.13.18"
+
+ DN
+ "distinguishedNameMatch", "2.5.13.1"
+
+ Int
+ "integerMatch", "2.5.13.14"
+ "integerOrderingMatch", "2.5.13.15"
+ "integerFirstComponentMatch", "2.5.13.29"
+
+ NameAndOptUID
+ "uniqueMemberMatch", "2.5.13.23"
+
+ NumericString
+ "numericStringMatch", "2.5.13.8"
+ "numericStringOrderingMatch", "2.5.13.9"
+ "numericStringSubstringsMatch", "2.5.13.10"
+
+ Telephone
+ "telephoneNumberMatch", "2.5.13.20"
+ "telephoneNumberSubstringsMatch", "2.5.13.21"
+ */
+ }
+ }
+ }
+
+ return rc;
+}
+
+/*
+ * Return 1 if oid1 is a superset(oid1 is not to be overwritten)
+ */
+static int
+schema_at_superset_check_syntax_oids(char *oid1, char *oid2)
+{
+ if(oid1 == NULL && oid2 == NULL){
+ return 0;
+ } else if (oid2 == NULL){
+ return 0;
+ } else if (oid1 == NULL){
+ return 1;
+ }
+
+ if(strcmp(oid1, BINARY_SYNTAX_OID) == 0){
+ if(strcmp(oid2, BINARY_SYNTAX_OID) &&
+ strcmp(oid2, INTEGER_SYNTAX_OID) &&
+ strcmp(oid2, NUMERICSTRING_SYNTAX_OID) &&
+ strcmp(oid2, IA5STRING_SYNTAX_OID) &&
+ strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
+ strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
+ strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
+ strcmp(oid2, FACSIMILE_SYNTAX_OID) &&
+ strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
+ strcmp(oid2, TELEPHONE_SYNTAX_OID) &&
+ strcmp(oid2, TELETEXTERMID_SYNTAX_OID) &&
+ strcmp(oid2, TELEXNUMBER_SYNTAX_OID))
+
+ {
+ return 1;
+ }
+ } else if(strcmp(oid1, BITSTRING_SYNTAX_OID) == 0){
+ if(strcmp(oid2, BINARY_SYNTAX_OID) &&
+ strcmp(oid2, BITSTRING_SYNTAX_OID) &&
+ strcmp(oid2, INTEGER_SYNTAX_OID) &&
+ strcmp(oid2, NUMERICSTRING_SYNTAX_OID) &&
+ strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
+ strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
+ strcmp(oid2, IA5STRING_SYNTAX_OID) &&
+ strcmp(oid2, FACSIMILE_SYNTAX_OID) &&
+ strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
+ strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
+ strcmp(oid2, TELEPHONE_SYNTAX_OID) &&
+ strcmp(oid2, TELETEXTERMID_SYNTAX_OID) &&
+ strcmp(oid2, TELEXNUMBER_SYNTAX_OID))
+ {
+ return 1;
+ }
+ } else if(strcmp(oid1, BOOLEAN_SYNTAX_OID) == 0){
+ if(strcmp(oid2, BOOLEAN_SYNTAX_OID) &&
+ strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
+ strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
+ strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
+ strcmp(oid2, IA5STRING_SYNTAX_OID))
+ {
+ return 1;
+ }
+ } else if(strcmp(oid1, COUNTRYSTRING_SYNTAX_OID) ==0){
+ if(strcmp(oid2, COUNTRYSTRING_SYNTAX_OID) &&
+ strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
+ strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
+ strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
+ strcmp(oid2, IA5STRING_SYNTAX_OID))
+ {
+ return 1;
+ }
+ } else if(strcmp(oid1, DN_SYNTAX_OID) == 0){
+ if(strcmp(oid2, DN_SYNTAX_OID) &&
+ strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
+ strcmp(oid2, DIRSTRING_SYNTAX_OID) )
+ {
+ return 1;
+ }
+ } else if(strcmp(oid1, DELIVERYMETHOD_SYNTAX_OID) ==0){
+ if(strcmp(oid2, DELIVERYMETHOD_SYNTAX_OID) &&
+ strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
+ strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
+ strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
+ strcmp(oid2, IA5STRING_SYNTAX_OID))
+ {
+ return 1;
+ }
+ } else if(strcmp(oid1, DIRSTRING_SYNTAX_OID) == 0){
+ if(strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
+ strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID)){
+ return 1;
+ }
+ } else if(strcmp(oid1, ENHANCEDGUIDE_SYNTAX_OID) == 0){
+ if(strcmp(oid2, ENHANCEDGUIDE_SYNTAX_OID) &&
+ strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
+ strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
+ strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
+ strcmp(oid2, IA5STRING_SYNTAX_OID))
+ {
+ return 1;
+ }
+ } else if(strcmp(oid1, IA5STRING_SYNTAX_OID) == 0){
+ if(strcmp(oid2, IA5STRING_SYNTAX_OID) &&
+ strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
+ strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
+ strcmp(oid2, PRINTABLESTRING_SYNTAX_OID))
+ {
+ return 1;
+ }
+ } else if(strcmp(oid1, INTEGER_SYNTAX_OID) == 0){
+ if(strcmp(oid2, INTEGER_SYNTAX_OID) &&
+ strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
+ strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
+ strcmp(oid2, NUMERICSTRING_SYNTAX_OID) &&
+ strcmp(oid2, TELEPHONE_SYNTAX_OID) &&
+ strcmp(oid2, TELETEXTERMID_SYNTAX_OID) &&
+ strcmp(oid2, TELEXNUMBER_SYNTAX_OID) &&
+ strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
+ strcmp(oid2, IA5STRING_SYNTAX_OID) )
+ {
+ return 1;
+ }
+ } else if(strcmp(oid1, JPEG_SYNTAX_OID) == 0){
+ if(strcmp(oid2, JPEG_SYNTAX_OID) &&
+ strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
+ strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
+ strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
+ strcmp(oid2, IA5STRING_SYNTAX_OID))
+ {
+ return 1;
+ }
+ } else if(strcmp(oid1, NAMEANDOPTIONALUID_SYNTAX_OID) == 0){
+ if(strcmp(oid2, NAMEANDOPTIONALUID_SYNTAX_OID) &&
+ strcmp(oid2, NAMEANDOPTIONALUID_SYNTAX_OID) &&
+ strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
+ strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
+ strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
+ strcmp(oid2, IA5STRING_SYNTAX_OID))
+ {
+ return 1;
+ }
+ } else if(strcmp(oid1, NUMERICSTRING_SYNTAX_OID) == 0){
+ if(strcmp(oid2, NUMERICSTRING_SYNTAX_OID) &&
+ strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
+ strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
+ strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
+ strcmp(oid2, IA5STRING_SYNTAX_OID))
+ {
+ return 1;
+ }
+ } else if(strcmp(oid1, OID_SYNTAX_OID) == 0){
+ if(strcmp(oid2, OID_SYNTAX_OID) &&
+ strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
+ strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
+ strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
+ strcmp(oid2, IA5STRING_SYNTAX_OID))
+ {
+ return 1;
+ }
+ } else if (strcmp(oid1, OCTETSTRING_SYNTAX_OID) == 0){
+ if(strcmp(oid2, OCTETSTRING_SYNTAX_OID) &&
+ strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
+ strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
+ strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
+ strcmp(oid2, IA5STRING_SYNTAX_OID))
+ {
+ return 1;
+ }
+ } else if(strcmp(oid1, POSTALADDRESS_SYNTAX_OID) ==0){
+ if(strcmp(oid2, POSTALADDRESS_SYNTAX_OID) &&
+ strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
+ strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
+ strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
+ strcmp(oid2, IA5STRING_SYNTAX_OID))
+ {
+ return 1;
+ }
+ } else if(strcmp(oid1, PRINTABLESTRING_SYNTAX_OID) == 0){
+ if(strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
+ strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
+ strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
+ strcmp(oid2, IA5STRING_SYNTAX_OID))
+ {
+ return 1;
+ }
+ } else if(strcmp(oid1, TELEPHONE_SYNTAX_OID) == 0){
+ if(strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
+ strcmp(oid2, TELEPHONE_SYNTAX_OID) &&
+ strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
+ strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
+ strcmp(oid2, IA5STRING_SYNTAX_OID))
+ {
+ return 1;
+ }
+ } else if(strcmp(oid1, TELETEXTERMID_SYNTAX_OID) == 0){
+ if(strcmp(oid2, TELETEXTERMID_SYNTAX_OID) &&
+ strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
+ strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
+ strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
+ strcmp(oid2, IA5STRING_SYNTAX_OID))
+ {
+ return 1;
+ }
+ } else if(strcmp(oid1, TELEXNUMBER_SYNTAX_OID) == 0){
+ if(strcmp(oid2, TELEXNUMBER_SYNTAX_OID) &&
+ strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
+ strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
+ strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
+ strcmp(oid2, IA5STRING_SYNTAX_OID))
+ {
+ return 1;
+ }
+ } else if (strcmp(oid1, SPACE_INSENSITIVE_STRING_SYNTAX_OID) == 0){
+ if(strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
+ strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
+ strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
+ strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
+ strcmp(oid2, IA5STRING_SYNTAX_OID))
+ {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
static void
schema_oclist_free(struct objclass *oc_list)
{
@@ -6006,8 +6427,20 @@ schema_oclist_free(struct objclass *oc_list)
}
}
-static
-struct objclass *schema_berval_to_oclist(struct berval **oc_berval) {
+static void
+schema_atlist_free(struct asyntaxinfo *at_list)
+{
+ struct asyntaxinfo *at, *at_next;
+
+ for (at = at_list; at != NULL; at = at_next) {
+ at_next = at->asi_next;
+ attr_syntax_free(at);
+ }
+}
+
+static struct objclass *
+schema_berval_to_oclist(struct berval **oc_berval)
+{
struct objclass *oc, *oc_list, *oc_tail;
char errorbuf[BUFSIZ];
int schema_ds4x_compat, rc;
@@ -6047,8 +6480,43 @@ struct objclass *schema_berval_to_oclist(struct berval **oc_berval)
{
return oc_list;
}
+static struct asyntaxinfo *
+schema_berval_to_atlist(struct berval **at_berval)
+{
+ struct asyntaxinfo *at, *head = NULL, *prev, *at_list = NULL;
+ char errorbuf[BUFSIZ];
+ int schema_ds4x_compat, rc = 0, i;
+
+ schema_ds4x_compat = config_get_ds4_compatible_schema();
+
+ if (at_berval != NULL) {
+ for (i = 0; at_berval[i] != NULL; i++) {
+ /* parse the objectclass value */
+ rc = parse_at_str(at_berval[i]->bv_val, &at, errorbuf, sizeof
(errorbuf),
+ DSE_SCHEMA_NO_CHECK | DSE_SCHEMA_USE_PRIV_SCHEMA, 0,
schema_ds4x_compat, 0);
+ if(rc){
+ attr_syntax_free(at);
+ break;
+ }
+ if(!head){
+ head = at_list = at;
+ } else {
+ at_list->asi_next = at;
+ at->asi_prev = at_list;
+ at_list = at;
+ }
+ }
+ }
+ if (rc) {
+ schema_atlist_free(head);
+ }
+
+ return head;
+}
+
int
-schema_objectclasses_superset_check(struct berval **remote_schema, char *type) {
+schema_objectclasses_superset_check(struct berval **remote_schema, char *type)
+{
int rc;
struct objclass *remote_oc_list;
@@ -6092,3 +6560,45 @@ schema_objectclasses_superset_check(struct berval **remote_schema,
char *type) {
}
return rc;
}
+
+int
+schema_attributetypes_superset_check(struct berval **remote_schema, char *type)
+{
+ struct asyntaxinfo *remote_at_list = NULL;
+ int rc = 0;
+
+ if (remote_schema != NULL) {
+ /* First build an attribute list from the remote schema */
+ if ((remote_at_list = schema_berval_to_atlist(remote_schema)) == NULL) {
+ rc = 1;
+ return rc;
+ }
+
+ /*
+ * Check that for each object from the remote schema
+ * - MUST attributes are also MUST in local schema
+ * - ALLOWED attributes are also ALLOWED in local schema
+ */
+ if (remote_at_list) {
+ attr_syntax_read_lock();
+ if (strcmp(type, OC_SUPPLIER) == 0) {
+ /*
+ * Check if the remote_at_list from a consumer are or not
+ * a superset of the attributetypes of the local supplier schema
+ */
+ rc = schema_at_superset_check(remote_at_list,
attr_syntax_get_global_at(), "local supplier" );
+ } else {
+ /*
+ * Check if the attributeypes of the local consumer schema are or not
+ * a superset of the remote_at_list from a supplier
+ */
+ rc = schema_at_superset_check(attr_syntax_get_global_at(),
remote_at_list, "remote supplier");
+ }
+ attr_syntax_unlock_read();
+ }
+
+ /* Free the remote schema list */
+ schema_atlist_free(remote_at_list);
+ }
+ return rc;
+}
diff --git a/ldap/servers/slapd/schemaparse.c b/ldap/servers/slapd/schemaparse.c
index eb68f88..9636be5 100644
--- a/ldap/servers/slapd/schemaparse.c
+++ b/ldap/servers/slapd/schemaparse.c
@@ -51,15 +51,11 @@
/* global_oc and global_schema_csn are both protected by oc locks */
struct objclass *global_oc;
CSN *global_schema_csn = NULL; /* Timestamp for last update CSN. NULL = epoch */
+static Slapi_RWLock *oc_lock = NULL;
static int is_duplicate( char *target, char **list, int list_max );
static void normalize_list( char **list );
-
-
-/* R/W lock used to protect the global objclass linked list. */
-static Slapi_RWLock *oc_lock = NULL;
-
/*
* The oc_init_lock_callonce structure is used by NSPR to ensure
* that oc_init_lock() is called at most once.
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
index 522a130..a03b968 100644
--- a/ldap/servers/slapd/slap.h
+++ b/ldap/servers/slapd/slap.h
@@ -517,6 +517,7 @@ typedef struct asyntaxinfo {
char *asi_mr_substring; /* substring matching rule */
schemaext *asi_extensions; /* schema extensions (X-ORIGIN, X-?????, ...) */
struct slapdplugin *asi_plugin; /* syntax */
+ char *asi_syntax_oid; /* syntax oid */
unsigned long asi_flags; /* SLAPI_ATTR_FLAG_... */
int asi_syntaxlength; /* length associated w/syntax */
int asi_refcnt; /* outstanding references */
@@ -524,6 +525,8 @@ typedef struct asyntaxinfo {
struct slapdplugin *asi_mr_eq_plugin; /* EQUALITY matching rule plugin */
struct slapdplugin *asi_mr_sub_plugin; /* SUBSTR matching rule plugin */
struct slapdplugin *asi_mr_ord_plugin; /* ORDERING matching rule plugin */
+ struct asyntaxinfo *asi_next;
+ struct asyntaxinfo *asi_prev;
} asyntaxinfo;
/*