s4:drepl_out_helpers: don't look at the internals of 'struct rpc_request'
[ira/wip.git] / source4 / dsdb / repl / replicated_objects.c
index ecf2856eb580b07988aa55ecc698818c7ede7379..b95bf87e3660232f1415e5cec99182965b771c24 100644 (file)
@@ -39,7 +39,6 @@ static WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
                                     struct dsdb_extended_replicated_object *out)
 {
        NTSTATUS nt_status;
-       enum ndr_err_code ndr_err;
        WERROR status;
        uint32_t i;
        struct ldb_message *msg;
@@ -150,9 +149,25 @@ static WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
        }
 
        if (rdn_m) {
-               ret = ldb_msg_add_value(msg, rdn_attr->lDAPDisplayName, rdn_value, NULL);
-               if (ret != LDB_SUCCESS) {
-                       return WERR_FOOBAR;
+               struct ldb_message_element *el;
+               el = ldb_msg_find_element(msg, rdn_attr->lDAPDisplayName);
+               if (!el) {
+                       ret = ldb_msg_add_value(msg, rdn_attr->lDAPDisplayName, rdn_value, NULL);
+                       if (ret != LDB_SUCCESS) {
+                               return WERR_FOOBAR;
+                       }
+               } else {
+                       if (el->num_values != 1) {
+                               DEBUG(0,(__location__ ": Unexpected num_values=%u\n",
+                                        el->num_values));
+                               return WERR_FOOBAR;                             
+                       }
+                       if (!ldb_val_equal_exact(&el->values[0], rdn_value)) {
+                               DEBUG(0,(__location__ ": RDN value changed? '%*.*s' '%*.*s'\n",
+                                        (int)el->values[0].length, (int)el->values[0].length, el->values[0].data,
+                                        (int)rdn_value->length, (int)rdn_value->length, rdn_value->data));
+                               return WERR_FOOBAR;                             
+                       }
                }
 
                rdn_m->attid                            = rdn_attid;
@@ -169,12 +184,8 @@ static WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
        whenChanged_s = ldb_timestring(msg, whenChanged_t);
        W_ERROR_HAVE_NO_MEMORY(whenChanged_s);
 
-       ndr_err = ndr_push_struct_blob(&guid_value, msg, 
-                                      lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
-                                      &in->object.identifier->guid,
-                                        (ndr_push_flags_fn_t)ndr_push_GUID);
-       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-               nt_status = ndr_map_error2ntstatus(ndr_err);
+       nt_status = GUID_to_ndr_blob(&in->object.identifier->guid, msg, &guid_value);
+       if (!NT_STATUS_IS_OK(nt_status)) {
                return ntstatus_to_werror(nt_status);
        }
 
@@ -185,33 +196,31 @@ static WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
        return WERR_OK;
 }
 
-WERROR dsdb_extended_replicated_objects_commit(struct ldb_context *ldb,
-                                              const char *partition_dn,
-                                              const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr,
-                                              uint32_t object_count,
-                                              const struct drsuapi_DsReplicaObjectListItemEx *first_object,
-                                              uint32_t linked_attributes_count,
-                                              const struct drsuapi_DsReplicaLinkedAttribute *linked_attributes,
-                                              const struct repsFromTo1 *source_dsa,
-                                              const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector,
-                                              const DATA_BLOB *gensec_skey,
-                                              TALLOC_CTX *mem_ctx,
-                                              struct dsdb_extended_replicated_objects **_out)
+WERROR dsdb_extended_replicated_objects_convert(struct ldb_context *ldb,
+                                               const char *partition_dn,
+                                               const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr,
+                                               uint32_t object_count,
+                                               const struct drsuapi_DsReplicaObjectListItemEx *first_object,
+                                               uint32_t linked_attributes_count,
+                                               const struct drsuapi_DsReplicaLinkedAttribute *linked_attributes,
+                                               const struct repsFromTo1 *source_dsa,
+                                               const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector,
+                                               const DATA_BLOB *gensec_skey,
+                                               TALLOC_CTX *mem_ctx,
+                                               struct dsdb_extended_replicated_objects **objects)
 {
        WERROR status;
        const struct dsdb_schema *schema;
        struct dsdb_extended_replicated_objects *out;
-       struct ldb_result *ext_res;
        const struct drsuapi_DsReplicaObjectListItemEx *cur;
        uint32_t i;
-       int ret;
 
        schema = dsdb_get_schema(ldb);
        if (!schema) {
                return WERR_DS_SCHEMA_NOT_LOADED;
        }
 
-       status = dsdb_verify_oid_mappings_drsuapi(schema, mapping_ctr);
+       status = dsdb_schema_pfm_contains_drsuapi_pfm(schema->prefixmap, mapping_ctr);
        W_ERROR_NOT_OK_RETURN(status);
 
        out = talloc_zero(mem_ctx, struct dsdb_extended_replicated_objects);
@@ -252,6 +261,18 @@ WERROR dsdb_extended_replicated_objects_commit(struct ldb_context *ldb,
                return WERR_FOOBAR;
        }
 
+       *objects = out;
+       return WERR_OK;
+}
+
+WERROR dsdb_extended_replicated_objects_commit(struct ldb_context *ldb,
+                                              struct dsdb_extended_replicated_objects *objects,
+                                              uint64_t *notify_uSN)
+{
+       struct ldb_result *ext_res;
+       int ret;
+       uint64_t seq_num1, seq_num2;
+
        /* TODO: handle linked attributes */
 
        /* wrap the extended operation in a transaction 
@@ -260,33 +281,57 @@ WERROR dsdb_extended_replicated_objects_commit(struct ldb_context *ldb,
        ret = ldb_transaction_start(ldb);
        if (ret != LDB_SUCCESS) {
                DEBUG(0,(__location__ " Failed to start transaction\n"));
-               talloc_free(out);
                return WERR_FOOBAR;
        }
 
-       ret = ldb_extended(ldb, DSDB_EXTENDED_REPLICATED_OBJECTS_OID, out, &ext_res);
+       ret = dsdb_load_partition_usn(ldb, objects->partition_dn, &seq_num1, NULL);
+       if (ret != LDB_SUCCESS) {
+               DEBUG(0,(__location__ " Failed to load partition uSN\n"));
+               ldb_transaction_cancel(ldb);
+               return WERR_FOOBAR;             
+       }
+
+       ret = ldb_extended(ldb, DSDB_EXTENDED_REPLICATED_OBJECTS_OID, objects, &ext_res);
        if (ret != LDB_SUCCESS) {
                DEBUG(0,("Failed to apply records: %s: %s\n",
                         ldb_errstring(ldb), ldb_strerror(ret)));
-               talloc_free(out);
                ldb_transaction_cancel(ldb);
                return WERR_FOOBAR;
        }
        talloc_free(ext_res);
 
+       ret = ldb_transaction_prepare_commit(ldb);
+       if (ret != LDB_SUCCESS) {
+               DEBUG(0,(__location__ " Failed to prepare commit of transaction: %s\n",
+                        ldb_errstring(ldb)));
+               return WERR_FOOBAR;
+       }
+
+       ret = dsdb_load_partition_usn(ldb, objects->partition_dn, &seq_num2, NULL);
+       if (ret != LDB_SUCCESS) {
+               DEBUG(0,(__location__ " Failed to load partition uSN\n"));
+               ldb_transaction_cancel(ldb);
+               return WERR_FOOBAR;             
+       }
+
+       /* if this replication partner didn't need to be notified
+          before this transaction then it still doesn't need to be
+          notified, as the changes came from this server */    
+       if (seq_num2 > seq_num1 && seq_num1 <= *notify_uSN) {
+               *notify_uSN = seq_num2;
+       }
+
        ret = ldb_transaction_commit(ldb);
        if (ret != LDB_SUCCESS) {
                DEBUG(0,(__location__ " Failed to commit transaction\n"));
-               talloc_free(out);
                return WERR_FOOBAR;
        }
 
-       if (_out) {
-               *_out = out;
-       } else {
-               talloc_free(out);
-       }
 
+       DEBUG(2,("Replicated %u objects (%u linked attributes) for %s\n",
+                objects->num_objects, objects->linked_attributes_count,
+                ldb_dn_get_linearized(objects->partition_dn)));
+                
        return WERR_OK;
 }
 
@@ -370,31 +415,78 @@ WERROR dsdb_origin_objects_commit(struct ldb_context *ldb,
                return WERR_OK;
        }
 
+       ret = ldb_transaction_start(ldb);
+       if (ret != LDB_SUCCESS) {
+               return WERR_DS_INTERNAL_FAILURE;
+       }
+
        objects = talloc_array(mem_ctx, struct ldb_message *,
                               num_objects);
-       W_ERROR_HAVE_NO_MEMORY(objects);
+       if (objects == NULL) {
+               status = WERR_NOMEM;
+               goto cancel;
+       }
 
        for (i=0, cur = first_object; cur; cur = cur->next_object, i++) {
                status = dsdb_convert_object(ldb, schema,
                                             cur, objects, &objects[i]);
-               W_ERROR_NOT_OK_RETURN(status);
+               if (!W_ERROR_IS_OK(status)) {
+                       goto cancel;
+               }
        }
 
        ids = talloc_array(mem_ctx,
                           struct drsuapi_DsReplicaObjectIdentifier2,
                           num_objects);
-       W_ERROR_HAVE_NO_MEMORY(objects);
+       if (ids == NULL) {
+               status = WERR_NOMEM;
+               goto cancel;
+       }
 
        for (i=0; i < num_objects; i++) {
                struct dom_sid *sid = NULL;
-               ret = ldb_add(ldb, objects[i]);
-               if (ret != 0) {
+               struct ldb_request *add_req;
+
+               DEBUG(6,(__location__ ": adding %s\n", 
+                        ldb_dn_get_linearized(objects[i]->dn)));
+
+               ret = ldb_build_add_req(&add_req,
+                                       ldb,
+                                       objects,
+                                       objects[i],
+                                       NULL,
+                                       NULL,
+                                       ldb_op_default_callback,
+                                       NULL);
+               if (ret != LDB_SUCCESS) {
+                       status = WERR_DS_INTERNAL_FAILURE;
+                       goto cancel;
+               }
+
+               ret = ldb_request_add_control(add_req, LDB_CONTROL_RELAX_OID, true, NULL);
+               if (ret != LDB_SUCCESS) {
+                       status = WERR_DS_INTERNAL_FAILURE;
                        goto cancel;
                }
+               
+               ret = ldb_request(ldb, add_req);
+               if (ret == LDB_SUCCESS) {
+                       ret = ldb_wait(add_req->handle, LDB_WAIT_ALL);
+               }
+               if (ret != LDB_SUCCESS) {
+                       DEBUG(0,(__location__ ": Failed add of %s - %s\n",
+                                ldb_dn_get_linearized(objects[i]->dn), ldb_errstring(ldb)));
+                       status = WERR_DS_INTERNAL_FAILURE;
+                       goto cancel;
+               }
+
+               talloc_free(add_req);
+
                ret = ldb_search(ldb, objects, &res, objects[i]->dn,
                                 LDB_SCOPE_BASE, attrs,
                                 "(objectClass=*)");
-               if (ret != 0) {
+               if (ret != LDB_SUCCESS) {
+                       status = WERR_DS_INTERNAL_FAILURE;
                        goto cancel;
                }
                ids[i].guid = samdb_result_guid(res->msgs[0], "objectGUID");
@@ -406,13 +498,19 @@ WERROR dsdb_origin_objects_commit(struct ldb_context *ldb,
                }
        }
 
+       ret = ldb_transaction_commit(ldb);
+       if (ret != LDB_SUCCESS) {
+               return WERR_DS_INTERNAL_FAILURE;
+       }
+
        talloc_free(objects);
 
        *_num = num_objects;
        *_ids = ids;
        return WERR_OK;
+
 cancel:
        talloc_free(objects);
        ldb_transaction_cancel(ldb);
-       return WERR_FOOBAR;
+       return status;
 }