dsdb-schema: make deduplication of class and schema possible (bug #8680)
authorMatthieu Patou <mat@matws.net>
Sun, 27 Jan 2013 07:42:10 +0000 (23:42 -0800)
committerAndrew Bartlett <abartlet@samba.org>
Thu, 23 May 2013 10:26:07 +0000 (20:26 +1000)
When a class or an attribute is replicated it might already exists in
the existing schema, so while replicating the new version of this object
we want to get rid of the old version of the object is the current
validating schema so that we don't end up having duplicates.

Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>

Signed-off-by: Matthieu Patou <mat@matws.net>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
source4/dsdb/schema/schema.h
source4/dsdb/schema/schema_init.c
source4/dsdb/schema/schema_set.c

index 66df1c5f75ec5bf670d47f5e59040d4610bcdc5f..538b8581234c150ab405fda33513f2706d550f7b 100644 (file)
@@ -221,6 +221,11 @@ struct dsdb_schema {
        struct dsdb_attribute *attributes;
        struct dsdb_class *classes;
 
+       struct dsdb_attribute **attributes_to_remove;
+       uint32_t attributes_to_remove_size;
+       struct dsdb_class **classes_to_remove;
+       uint32_t classes_to_remove_size;
+
        /* lists of classes sorted by various attributes, for faster
           access */
        uint32_t num_classes;
index 752d4f57dd1c7dde8bb218d47c59c42e087955ea..efbd38a4ba39540c994f52152d75b4a58d6e6c3f 100644 (file)
@@ -699,9 +699,10 @@ WERROR dsdb_attribute_from_ldb(const struct dsdb_schema *schema,
        return WERR_OK;
 }
 
-WERROR dsdb_set_attribute_from_ldb(struct ldb_context *ldb,
-                              struct dsdb_schema *schema,
-                              struct ldb_message *msg)
+WERROR dsdb_set_attribute_from_ldb_dups(struct ldb_context *ldb,
+                                       struct dsdb_schema *schema,
+                                       struct ldb_message *msg,
+                                       bool checkdups)
 {
        WERROR status;
        struct dsdb_attribute *attr = talloc_zero(schema, struct dsdb_attribute);
@@ -729,12 +730,44 @@ WERROR dsdb_set_attribute_from_ldb(struct ldb_context *ldb,
                return WERR_DS_ATT_SCHEMA_REQ_SYNTAX;
        }
 
+       if (checkdups) {
+               const struct dsdb_attribute *a2;
+               struct dsdb_attribute **a;
+               uint32_t i;
+
+               a2 = dsdb_attribute_by_attributeID_id(schema,
+                                                     attr->attributeID_id);
+               if (a2 == NULL) {
+                       goto done;
+               }
+
+               i = schema->attributes_to_remove_size;
+               a = talloc_realloc(schema, schema->attributes_to_remove,
+                                  struct dsdb_attribute *, i + 1);
+               if (a == NULL) {
+                       return WERR_NOMEM;
+               }
+               /* Mark the old attribute as to be removed */
+               a[i] = discard_const_p(struct dsdb_attribute, a2);
+               schema->attributes_to_remove = a;
+               schema->attributes_to_remove_size++;
+       }
+
+done:
        DLIST_ADD(schema->attributes, attr);
        return WERR_OK;
 }
 
-WERROR dsdb_set_class_from_ldb(struct dsdb_schema *schema,
-                          struct ldb_message *msg)
+WERROR dsdb_set_attribute_from_ldb(struct ldb_context *ldb,
+                                  struct dsdb_schema *schema,
+                                  struct ldb_message *msg)
+{
+       return dsdb_set_attribute_from_ldb_dups(ldb, schema, msg, false);
+}
+
+WERROR dsdb_set_class_from_ldb_dups(struct dsdb_schema *schema,
+                                   struct ldb_message *msg,
+                                   bool checkdups)
 {
        WERROR status;
        struct dsdb_class *obj = talloc_zero(schema, struct dsdb_class);
@@ -792,10 +825,39 @@ WERROR dsdb_set_class_from_ldb(struct dsdb_schema *schema,
        GET_BOOL_LDB(msg, "isDefunct", obj, isDefunct, false);
        GET_BOOL_LDB(msg, "systemOnly", obj, systemOnly, false);
 
+       if (checkdups) {
+               const struct dsdb_class *c2;
+               struct dsdb_class **c;
+               uint32_t i;
+
+               c2 = dsdb_class_by_governsID_id(schema, obj->governsID_id);
+               if (c2 == NULL) {
+                       goto done;
+               }
+
+               i = schema->classes_to_remove_size;
+               c = talloc_realloc(schema, schema->classes_to_remove,
+                                  struct dsdb_class *, i + 1);
+               if (c == NULL) {
+                       return WERR_NOMEM;
+               }
+               /* Mark the old class to be removed */
+               c[i] = discard_const_p(struct dsdb_class, c2);
+               schema->classes_to_remove = c;
+               schema->classes_to_remove_size++;
+       }
+
+done:
        DLIST_ADD(schema->classes, obj);
        return WERR_OK;
 }
 
+WERROR dsdb_set_class_from_ldb(struct dsdb_schema *schema,
+                              struct ldb_message *msg)
+{
+       return dsdb_set_class_from_ldb_dups(schema, msg, false);
+}
+
 #define dsdb_oom(error_string, mem_ctx) *error_string = talloc_asprintf(mem_ctx, "dsdb out of memory at %s:%d\n", __FILE__, __LINE__)
 
 /* 
index 31862a43b789b08d95bb2a95f871ebf02281f0e4..73264f9545a6906fcebbfacd67f83c0befabd969 100644 (file)
@@ -329,6 +329,18 @@ int dsdb_setup_sorted_accessors(struct ldb_context *ldb,
        unsigned int num_int_id;
        int ret;
 
+       for (i=0; i < schema->classes_to_remove_size; i++) {
+               DLIST_REMOVE(schema->classes, schema->classes_to_remove[i]);
+               TALLOC_FREE(schema->classes_to_remove[i]);
+       }
+       for (i=0; i < schema->attributes_to_remove_size; i++) {
+               DLIST_REMOVE(schema->attributes, schema->attributes_to_remove[i]);
+               TALLOC_FREE(schema->attributes_to_remove[i]);
+       }
+
+       TALLOC_FREE(schema->attributes_to_remove);
+       TALLOC_FREE(schema->classes_to_remove);
+
        /* free all caches */
        dsdb_sorted_accessors_free(schema);
 
@@ -669,10 +681,26 @@ int dsdb_schema_fill_extended_dn(struct ldb_context *ldb, struct dsdb_schema *sc
 }
 
 /**
- * Add an element to the schema (attribute or class) from an LDB message
+ * @brief Add a new element to the schema and checks if it's a duplicate
+ *
+ * This function will add a new element to the schema and checks for existing
+ * duplicates.
+ *
+ * @param[in]  ldb                A pointer to an LDB context
+ *
+ * @param[in]  schema             A pointer to the dsdb_schema where the element
+ *                                will be added.
+ *
+ * @param[in]  msg                The ldb_message object representing the element
+ *                                to add.
+ *
+ * @param[in]  checkdups          A boolean to indicate if checks for duplicates
+ *                                should be done.
+ *
+ * @return                        A WERROR code
  */
-WERROR dsdb_schema_set_el_from_ldb_msg(struct ldb_context *ldb, struct dsdb_schema *schema,
-                                      struct ldb_message *msg)
+WERROR dsdb_schema_set_el_from_ldb_msg_dups(struct ldb_context *ldb, struct dsdb_schema *schema,
+                                           struct ldb_message *msg, bool checkdups)
 {
        const char* tstring;
        time_t ts;
@@ -686,15 +714,23 @@ WERROR dsdb_schema_set_el_from_ldb_msg(struct ldb_context *ldb, struct dsdb_sche
        }
        if (samdb_find_attribute(ldb, msg,
                                 "objectclass", "attributeSchema") != NULL) {
-               return dsdb_set_attribute_from_ldb(ldb, schema, msg);
+
+               return dsdb_set_attribute_from_ldb_dups(ldb, schema, msg, checkdups);
        } else if (samdb_find_attribute(ldb, msg,
                                 "objectclass", "classSchema") != NULL) {
-               return dsdb_set_class_from_ldb(schema, msg);
+               return dsdb_set_class_from_ldb_dups(schema, msg, checkdups);
        }
        /* Don't fail on things not classes or attributes */
        return WERR_OK;
 }
 
+WERROR dsdb_schema_set_el_from_ldb_msg(struct ldb_context *ldb,
+                                      struct dsdb_schema *schema,
+                                      struct ldb_message *msg)
+{
+       return dsdb_schema_set_el_from_ldb_msg_dups(ldb, schema, msg, false);
+}
+
 /**
  * Rather than read a schema from the LDB itself, read it from an ldif
  * file.  This allows schema to be loaded and used while adding the