s4:libnet_vampire: simplify schema handling
authorStefan Metzmacher <metze@samba.org>
Wed, 20 Feb 2019 07:35:59 +0000 (08:35 +0100)
committerStefan Metzmacher <metze@samba.org>
Fri, 29 Mar 2019 14:42:56 +0000 (15:42 +0100)
This should work in the same way the online schema cycle works:
- dsdb_repl_make_working_schema() creates a temporary working_schema
  using the initial schema and the replicated objects.
- dsdb_replicated_objects_convert() uses the working_schema to
  convert everything.
- dsdb_replicated_objects_commit() also takes the working_schema
  and makes sure we store the objects, store the new prefixMap,
  make sure the metadata_usn for the schema is updated and
  reload the schema from the changed database.

source4/libnet/libnet_vampire.c

index 6374946244e78566cdcaf9585d5796acc8f93442..58c1459b2704c1795af87b53639e23e1ce8edcaf 100644 (file)
@@ -64,16 +64,11 @@ struct libnet_vampire_cb_state {
        const char *realm;
        struct cli_credentials *machine_account;
 
-       /* Schema loaded from local LDIF files */
-       struct dsdb_schema *provision_schema;
-
-        /* 1st pass, with some OIDs/attribute names/class names not
-        * converted, because we may not know them yet */
-       struct dsdb_schema *self_made_schema;
-
-       /* prefixMap in LDB format, from the remote DRS server */
-       DATA_BLOB prefixmap_blob;
-       const struct dsdb_schema *schema;
+       /*
+        * What we had before this replication cycle
+        * or after the complete cycle.
+        */
+       struct dsdb_schema *schema;
 
        struct ldb_context *ldb;
 
@@ -105,8 +100,7 @@ void *libnet_vampire_replicate_init(TALLOC_CTX *mem_ctx,
 
        s->ldb              = samdb;
        s->lp_ctx           = lp_ctx;
-       s->provision_schema = dsdb_get_schema(s->ldb, s);
-       s->schema           = s->provision_schema;
+       s->schema           = dsdb_get_schema(s->ldb, s);
        s->netbios_name     = lpcfg_netbios_name(lp_ctx);
        s->domain_name      = lpcfg_workgroup(lp_ctx);
        s->realm            = lpcfg_realm(lp_ctx);
@@ -175,7 +169,7 @@ NTSTATUS libnet_vampire_cb_prepare_db(void *private_data,
 
        s->ldb = talloc_steal(s, result.samdb);
        s->lp_ctx = talloc_reparent(talloc_parent(result.lp_ctx), s, result.lp_ctx);
-       s->provision_schema = dsdb_get_schema(s->ldb, s);
+       s->schema = dsdb_get_schema(s->ldb, s);
        s->server_dn_str = talloc_steal(s, p->dest_dsa->server_dn_str);
 
        /* wrap the entire vapire operation in a transaction.  This
@@ -224,9 +218,8 @@ static WERROR libnet_vampire_cb_apply_schema(struct libnet_vampire_cb_state *s,
                                             const struct libnet_BecomeDC_StoreChunk *c)
 {
        WERROR status;
-       struct dsdb_schema_prefixmap *pfm_remote;
        const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
-       struct dsdb_schema *provision_schema;
+       struct dsdb_schema *working_schema = NULL;
        uint32_t object_count = 0;
        struct drsuapi_DsReplicaObjectListItemEx *first_object;
        uint32_t linked_attributes_count;
@@ -235,15 +228,10 @@ static WERROR libnet_vampire_cb_apply_schema(struct libnet_vampire_cb_state *s,
        struct dsdb_extended_replicated_objects *schema_objs;
        struct repsFromTo1 *s_dsa;
        char *tmp_dns_name;
-       struct ldb_context *schema_ldb;
        struct ldb_dn *partition_dn;
-       struct ldb_message *msg;
-       struct ldb_message_element *prefixMap_el;
        uint32_t i;
-       int ret;
        bool ok;
        uint64_t seq_num = 0;
-       uint32_t cycle_before_switching;
 
        DEBUG(0,("Analyze and apply schema objects\n"));
 
@@ -295,14 +283,6 @@ static WERROR libnet_vampire_cb_apply_schema(struct libnet_vampire_cb_state *s,
                return WERR_INTERNAL_ERROR;
        }
 
-       status = dsdb_schema_pfm_from_drsuapi_pfm(mapping_ctr, true,
-                                                 s, &pfm_remote, NULL);
-       if (!W_ERROR_IS_OK(status)) {
-               DEBUG(0,(__location__ ": Failed to decode remote prefixMap: %s",
-                        win_errstr(status)));
-               return status;
-       }
-
        s_dsa->replica_flags            = DRSUAPI_DRS_WRIT_REP
                                        | DRSUAPI_DRS_INIT_SYNC
                                        | DRSUAPI_DRS_PER_SYNC;
@@ -318,67 +298,19 @@ static WERROR libnet_vampire_cb_apply_schema(struct libnet_vampire_cb_state *s,
        }
        s_dsa->other_info->dns_name = tmp_dns_name;
 
-       if (s->self_made_schema == NULL) {
-               DEBUG(0,("libnet_vampire_cb_apply_schema: called with out self_made_schema\n"));
-               return WERR_INTERNAL_ERROR;
-       }
-
-       schema_ldb = provision_get_schema(s, s->lp_ctx,
-                                         c->forest->schema_dn_str,
-                                         &s->prefixmap_blob);
-       if (!schema_ldb) {
-               DEBUG(0,("Failed to re-load from local provision using remote prefixMap. "
-                        "Will continue with local prefixMap\n"));
-               provision_schema = dsdb_get_schema(s->ldb, s);
-       } else {
-               provision_schema = dsdb_get_schema(schema_ldb, s);
-               ret = dsdb_reference_schema(s->ldb, provision_schema, SCHEMA_MEMORY_ONLY);
-               if (ret != LDB_SUCCESS) {
-                       DEBUG(0,("Failed to attach schema from local provision using remote prefixMap."));
-                       return WERR_INTERNAL_ERROR;
-               }
-               talloc_unlink(s, schema_ldb);
-       }
-
-       cycle_before_switching = lpcfg_parm_long(s->lp_ctx, NULL,
-                                                "become dc",
-                                                "schema convert retrial", 1);
-
-       provision_schema->resolving_in_progress = true;
-       s->self_made_schema->resolving_in_progress = true;
-
-       status = dsdb_repl_resolve_working_schema(s->ldb,
-                                                 pfm_remote,
-                                                 cycle_before_switching,
-                                                 provision_schema,
-                                                 s->self_made_schema,
-                                                 object_count,
-                                                 first_object);
+       status = dsdb_repl_make_working_schema(s->ldb,
+                                              s->schema,
+                                              mapping_ctr,
+                                              object_count,
+                                              first_object,
+                                              s,
+                                              &working_schema);
        if (!W_ERROR_IS_OK(status)) {
-               DEBUG(0, ("%s: dsdb_repl_resolve_working_schema() failed: %s",
-                         __location__, win_errstr(status)));
+               DBG_ERR("%s: dsdb_repl_make_working_schema() failed: %s",
+                       __location__, win_errstr(status));
                return status;
        }
 
-       /* free temp objects for 1st conversion phase */
-       talloc_unlink(s, provision_schema);
-
-       s->self_made_schema->resolving_in_progress = false;
-
-       /*
-        * attach the schema we just brought over DRS to the ldb,
-        * so we can use it in dsdb_convert_object_ex below
-        */
-       ret = dsdb_set_schema(s->ldb, s->self_made_schema, SCHEMA_WRITE);
-       if (ret != LDB_SUCCESS) {
-               DEBUG(0,("Failed to attach working schema from DRS.\n"));
-               return WERR_INTERNAL_ERROR;
-       }
-
-       /* we don't want to access the self made schema anymore */
-       s->schema = s->self_made_schema;
-       s->self_made_schema = NULL;
-
        partition_dn = ldb_dn_new(s, s->ldb, c->partition->nc.dn);
        if (partition_dn == NULL) {
                DEBUG(0,("Failed to parse partition DN from DRS.\n"));
@@ -387,7 +319,7 @@ static WERROR libnet_vampire_cb_apply_schema(struct libnet_vampire_cb_state *s,
 
        /* Now convert the schema elements again, using the schema we finalised, ready to actually import */
        status = dsdb_replicated_objects_convert(s->ldb,
-                                                s->schema,
+                                                working_schema,
                                                 partition_dn,
                                                 mapping_ctr,
                                                 object_count,
@@ -415,41 +347,17 @@ static WERROR libnet_vampire_cb_apply_schema(struct libnet_vampire_cb_state *s,
                }
        }
 
-       status = dsdb_replicated_objects_commit(s->ldb, NULL, schema_objs, &seq_num);
+       status = dsdb_replicated_objects_commit(s->ldb, working_schema, schema_objs, &seq_num);
        if (!W_ERROR_IS_OK(status)) {
                DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
                return status;
        }
 
-       msg = ldb_msg_new(schema_objs);
-       if (msg == NULL) {
-               return WERR_NOT_ENOUGH_MEMORY;
-       }
-       msg->dn = schema_objs->partition_dn;
-
-       /* We must ensure a prefixMap has been written.  Unlike other
-        * attributes (including schemaInfo), it is not replicated in
-        * the normal replication stream.  We can use the one from
-        * s->prefixmap_blob because we operate with one, unchanging
-        * prefixMap for this entire operation.  */
-       ret = ldb_msg_add_value(msg, "prefixMap", &s->prefixmap_blob, &prefixMap_el);
-       if (ret != LDB_SUCCESS) {
-               return WERR_NOT_ENOUGH_MEMORY;
-       }
-       /* We want to know if a prefixMap was written already, as it
-        * would mean that the above comment was not true, and we have
-        * somehow updated the prefixMap during this transaction */
-       prefixMap_el->flags = LDB_FLAG_MOD_ADD;
-
-       ret = dsdb_modify(s->ldb, msg, DSDB_FLAG_AS_SYSTEM);
-       if (ret != LDB_SUCCESS) {
-               DEBUG(0,("Failed to add prefixMap: %s\n", ldb_errstring(s->ldb)));
-               return WERR_INTERNAL_ERROR;
-       }
-
        talloc_free(s_dsa);
        talloc_free(schema_objs);
 
+       talloc_unlink(s, working_schema);
+       talloc_unlink(s, s->schema);
        s->schema = dsdb_get_schema(s->ldb, s);
        if (!s->schema) {
                DEBUG(0,("Failed to get loaded dsdb_schema\n"));
@@ -463,8 +371,6 @@ WERROR libnet_vampire_cb_schema_chunk(void *private_data,
                                      const struct libnet_BecomeDC_StoreChunk *c)
 {
        struct libnet_vampire_cb_state *s = talloc_get_type(private_data, struct libnet_vampire_cb_state);
-       WERROR werr;
-       const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
        uint32_t nc_object_count;
        uint32_t nc_total_received = 0;
        uint32_t object_count;
@@ -473,9 +379,14 @@ WERROR libnet_vampire_cb_schema_chunk(void *private_data,
        uint32_t nc_linked_attributes_count;
        uint32_t linked_attributes_count;
 
+       if (s->schema == NULL) {
+               DEBUG(0,("libnet_vampire_cb_apply_schema: called with out self_made_schema\n"));
+               smb_panic(__location__);
+               return WERR_INTERNAL_ERROR;
+       }
+
        switch (c->ctr_level) {
        case 1:
-               mapping_ctr                     = &c->ctr1->mapping_ctr;
                nc_object_count                 = c->ctr1->extended_ret; /* maybe w2k send this unexpected? */
                object_count                    = c->ctr1->object_count;
                first_object                    = c->ctr1->first_object;
@@ -483,7 +394,6 @@ WERROR libnet_vampire_cb_schema_chunk(void *private_data,
                linked_attributes_count         = 0;
                break;
        case 6:
-               mapping_ctr                     = &c->ctr6->mapping_ctr;
                nc_object_count                 = c->ctr6->nc_object_count;
                object_count                    = c->ctr6->object_count;
                first_object                    = c->ctr6->first_object;
@@ -508,44 +418,6 @@ WERROR libnet_vampire_cb_schema_chunk(void *private_data,
                c->partition->nc.dn, nc_total_received, linked_attributes_count));
        }
 
-       if (!s->self_made_schema) {
-               struct drsuapi_DsReplicaOIDMapping_Ctr mapping_ctr_without_schema_info;
-               /* Put the DRS prefixmap aside for the schema we are
-                * about to load in the provision, and into the one we
-                * are making with the help of DRS */
-
-               mapping_ctr_without_schema_info = *mapping_ctr;
-
-               /* This strips off the 0xFF schema info from the end,
-                * because we don't want it in the blob */
-               if (mapping_ctr_without_schema_info.num_mappings > 0) {
-                       mapping_ctr_without_schema_info.num_mappings--;
-               }
-               werr = dsdb_get_drsuapi_prefixmap_as_blob(&mapping_ctr_without_schema_info, s, &s->prefixmap_blob);
-               if (!W_ERROR_IS_OK(werr)) {
-                       return werr;
-               }
-
-               /* Set up two manually-constructed schema - the local
-                * schema from the provision will be used to build
-                * one, which will then in turn be used to build the
-                * other. */
-               s->self_made_schema = dsdb_new_schema(s);
-               if (s->self_made_schema == NULL) {
-                       return WERR_NOT_ENOUGH_MEMORY;
-               }
-
-               werr = dsdb_load_prefixmap_from_drsuapi(s->self_made_schema, mapping_ctr);
-               if (!W_ERROR_IS_OK(werr)) {
-                       return werr;
-               }
-       } else {
-               werr = dsdb_schema_pfm_contains_drsuapi_pfm(s->self_made_schema->prefixmap, mapping_ctr);
-               if (!W_ERROR_IS_OK(werr)) {
-                       return werr;
-               }
-       }
-
        if (!s->schema_part.first_object) {
                s->schema_part.object_count = object_count;
                s->schema_part.first_object = talloc_steal(s, first_object);