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 42221a161fd0b288b0d7be2d95e940660e015dbe Author: Mark Reynolds mreynolds@redhat.com Date: Thu Nov 7 12:41:41 2013 -0500
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 4bd14a8..0e49b94 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'}; @@ -1579,33 +1579,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 6539f95..9487bf7 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(). @@ -1002,6 +1004,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 6fdb99f..1e677c9 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 ); @@ -1889,13 +1892,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 @@ -5870,6 +5894,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;
@@ -5882,6 +5907,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 @@ -5903,8 +5933,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 */ @@ -5933,8 +5967,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; + } } } } @@ -5963,10 +6001,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; + } } } } @@ -5975,6 +6017,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) { @@ -5986,8 +6407,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; @@ -6027,8 +6460,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;
@@ -6072,3 +6540,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 ffee433..3513cfd 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;
/*