dsdb: reset schema->{classes,attributes}_to_remove_size to 0
[obnox/samba/samba-obnox.git] / source4 / dsdb / schema / schema_set.c
index c5ac6127d1d526b2ae59d18e6abfda7803fc69a0..ce8facbef3c9e62f0ad027cf9d435cff44b30098 100644 (file)
@@ -50,8 +50,13 @@ const struct ldb_schema_attribute *dsdb_attribute_handler_override(struct ldb_co
        }
        return a->ldb_schema_attribute;
 }
-
-static int dsdb_schema_set_attributes(struct ldb_context *ldb, struct dsdb_schema *schema, bool write_attributes)
+/*
+ * Set the attribute handlers onto the LDB, and potentially write the
+ * @INDEXLIST, @IDXONE and @ATTRIBUTES records.  The @ATTRIBUTES records
+ * are required so we can operate on a schema-less database (say the
+ * backend during emergency fixes) and during the schema load.
+ */
+static int dsdb_schema_set_indices_and_attributes(struct ldb_context *ldb, struct dsdb_schema *schema, bool write_indices_and_attributes)
 {
        int ret = LDB_SUCCESS;
        struct ldb_result *res;
@@ -65,7 +70,7 @@ static int dsdb_schema_set_attributes(struct ldb_context *ldb, struct dsdb_schem
        /* setup our own attribute name to schema handler */
        ldb_schema_attribute_set_override_handler(ldb, dsdb_attribute_handler_override, schema);
 
-       if (!write_attributes) {
+       if (!write_indices_and_attributes) {
                return ret;
        }
 
@@ -241,7 +246,8 @@ static void dsdb_setup_attribute_shortcuts(struct ldb_context *ldb, struct dsdb_
                        continue;
                }
                /* handle attributes with a linkID but no backlink */
-               if (dsdb_attribute_by_linkID(schema, attribute->linkID) == NULL) {
+               if ((attribute->linkID & 1) == 0 &&
+                   dsdb_attribute_by_linkID(schema, attribute->linkID + 1) == NULL) {
                        attribute->one_way_link = true;
                        continue;
                }
@@ -321,6 +327,21 @@ int dsdb_setup_sorted_accessors(struct ldb_context *ldb,
        struct dsdb_attribute *a;
        unsigned int i;
        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->classes_to_remove);
+       schema->classes_to_remove_size = 0;
+       TALLOC_FREE(schema->attributes_to_remove);
+       schema->attributes_to_remove_size = 0;
 
        /* free all caches */
        dsdb_sorted_accessors_free(schema);
@@ -405,6 +426,12 @@ int dsdb_setup_sorted_accessors(struct ldb_context *ldb,
 
        dsdb_setup_attribute_shortcuts(ldb, schema);
 
+       ret = schema_fill_constructed(schema);
+       if (ret != LDB_SUCCESS) {
+               dsdb_sorted_accessors_free(schema);
+               return ret;
+       }
+
        return LDB_SUCCESS;
 
 failed:
@@ -412,24 +439,6 @@ failed:
        return ldb_oom(ldb);
 }
 
-int dsdb_setup_schema_inversion(struct ldb_context *ldb, struct dsdb_schema *schema)
-{
-       /* Walk the list of schema classes */
-
-       /*  For each subClassOf, add us to subclasses of the parent */
-
-       /* collect these subclasses into a recursive list of total subclasses, preserving order */
-
-       /* For each subclass under 'top', write the index from it's
-        * order as an integer in the dsdb_class (for sorting
-        * objectClass lists efficiently) */
-
-       /* Walk the list of schema classes */
-
-       /*  Create a 'total possible superiors' on each class */
-       return LDB_SUCCESS;
-}
-
 /**
  * Attach the schema to an opaque pointer on the ldb,
  * so ldb modules can find it
@@ -444,11 +453,6 @@ int dsdb_set_schema(struct ldb_context *ldb, struct dsdb_schema *schema)
                return ret;
        }
 
-       ret = schema_fill_constructed(schema);
-       if (ret != LDB_SUCCESS) {
-               return ret;
-       }
-
        old_schema = ldb_get_opaque(ldb, "dsdb_schema");
 
        ret = ldb_set_opaque(ldb, "dsdb_schema", schema);
@@ -469,7 +473,7 @@ int dsdb_set_schema(struct ldb_context *ldb, struct dsdb_schema *schema)
        }
 
        /* Set the new attributes based on the new schema */
-       ret = dsdb_schema_set_attributes(ldb, schema, true);
+       ret = dsdb_schema_set_indices_and_attributes(ldb, schema, true);
        if (ret != LDB_SUCCESS) {
                return ret;
        }
@@ -484,9 +488,13 @@ static struct dsdb_schema *global_schema;
 
 /**
  * Make this ldb use a specified schema, already fully calculated and belonging to another ldb
+ *
+ * The write_indices_and_attributes controls writing of the @ records
+ * because we cannot write to a database that does not yet exist on
+ * disk.
  */
 int dsdb_reference_schema(struct ldb_context *ldb, struct dsdb_schema *schema,
-                         bool write_attributes)
+                         bool write_indices_and_attributes)
 {
        int ret;
        struct dsdb_schema *old_schema;
@@ -510,7 +518,7 @@ int dsdb_reference_schema(struct ldb_context *ldb, struct dsdb_schema *schema,
                return ret;
        }
 
-       ret = dsdb_schema_set_attributes(ldb, schema, write_attributes);
+       ret = dsdb_schema_set_indices_and_attributes(ldb, schema, write_indices_and_attributes);
        if (ret != LDB_SUCCESS) {
                return ret;
        }
@@ -534,7 +542,7 @@ int dsdb_set_global_schema(struct ldb_context *ldb)
        }
 
        /* Set the new attributes based on the new schema */
-       ret = dsdb_schema_set_attributes(ldb, global_schema, false /* Don't write attributes, it's expensive */);
+       ret = dsdb_schema_set_indices_and_attributes(ldb, global_schema, false /* Don't write indices and attributes, it's expensive */);
        if (ret == LDB_SUCCESS) {
                /* Keep a reference to this schema, just in case the original copy is replaced */
                if (talloc_reference(ldb, global_schema) == NULL) {
@@ -675,30 +683,65 @@ 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;
+       tstring = ldb_msg_find_attr_as_string(msg, "whenChanged", NULL);
+       /* keep a trace of the ts of the most recently changed object */
+       if (tstring) {
+               ts = ldb_string_to_time(tstring);
+               if (ts > schema->ts_last_change) {
+                       schema->ts_last_change = ts;
+               }
+       }
        if (samdb_find_attribute(ldb, msg,
                                 "objectclass", "attributeSchema") != NULL) {
-               return dsdb_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_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
  * schema itself to the directory.
  */
 
-WERROR dsdb_set_schema_from_ldif(struct ldb_context *ldb, const char *pf, const char *df)
+WERROR dsdb_set_schema_from_ldif(struct ldb_context *ldb,
+                                const char *pf, const char *df,
+                                const char *dn)
 {
        struct ldb_ldif *ldif;
        struct ldb_message *msg;
@@ -717,9 +760,16 @@ WERROR dsdb_set_schema_from_ldif(struct ldb_context *ldb, const char *pf, const
        }
 
        schema = dsdb_new_schema(mem_ctx);
-
+       if (!schema) {
+               goto nomem;
+       }
+       schema->base_dn = ldb_dn_new(schema, ldb, dn);
+       if (!schema->base_dn) {
+               goto nomem;
+       }
        schema->fsmo.we_are_master = true;
-       schema->fsmo.master_dn = ldb_dn_new_fmt(schema, ldb, "@PROVISION_SCHEMA_MASTER");
+       schema->fsmo.update_allowed = true;
+       schema->fsmo.master_dn = ldb_dn_new(schema, ldb, "@PROVISION_SCHEMA_MASTER");
        if (!schema->fsmo.master_dn) {
                goto nomem;
        }
@@ -759,6 +809,7 @@ WERROR dsdb_set_schema_from_ldif(struct ldb_context *ldb, const char *pf, const
                goto failed;
        }
 
+       schema->ts_last_change = 0;
        /* load the attribute and class definitions out of df */
        while ((ldif = ldb_ldif_read_string(ldb, &df))) {
                talloc_steal(mem_ctx, ldif);