s4:drepl_out_helpers: don't look at the internals of 'struct rpc_request'
[ira/wip.git] / source4 / dsdb / repl / replicated_objects.c
index 78af3c8f6df35c530146c713c16bd027501e255e..b95bf87e3660232f1415e5cec99182965b771c24 100644 (file)
 #include "libcli/auth/libcli_auth.h"
 #include "param/param.h"
 
-static WERROR dsdb_convert_object(struct ldb_context *ldb,
-                                 const struct dsdb_schema *schema,
-                                 struct dsdb_extended_replicated_objects *ctr,
-                                 const struct drsuapi_DsReplicaObjectListItemEx *in,
-                                 const DATA_BLOB *gensec_skey,
-                                 TALLOC_CTX *mem_ctx,
-                                 struct dsdb_extended_replicated_object *out)
+static WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
+                                    const struct dsdb_schema *schema,
+                                    const struct drsuapi_DsReplicaObjectListItemEx *in,
+                                    const DATA_BLOB *gensec_skey,
+                                    TALLOC_CTX *mem_ctx,
+                                    struct dsdb_extended_replicated_object *out)
 {
        NTSTATUS nt_status;
-       enum ndr_err_code ndr_err;
        WERROR status;
        uint32_t i;
        struct ldb_message *msg;
@@ -117,14 +115,17 @@ static WERROR dsdb_convert_object(struct ldb_context *ldb,
                struct drsuapi_DsReplicaMetaData *d;
                struct replPropertyMetaData1 *m;
                struct ldb_message_element *e;
+               int j;
 
                a = &in->object.attribute_ctr.attributes[i];
                d = &in->meta_data_ctr->meta_data[i];
                m = &md->ctr.ctr1.array[i];
                e = &msg->elements[i];
 
-               status = drsuapi_decrypt_attribute(a->value_ctr.values[0].blob, gensec_skey, rid, a);
-               W_ERROR_NOT_OK_RETURN(status);
+               for (j=0; j<a->value_ctr.num_values; j++) {
+                       status = drsuapi_decrypt_attribute(a->value_ctr.values[j].blob, gensec_skey, rid, a);
+                       W_ERROR_NOT_OK_RETURN(status);
+               }
 
                status = dsdb_attribute_drsuapi_to_ldb(ldb, schema, a, msg->elements, e);
                W_ERROR_NOT_OK_RETURN(status);
@@ -148,9 +149,25 @@ static WERROR dsdb_convert_object(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;
@@ -167,12 +184,8 @@ static WERROR dsdb_convert_object(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);
        }
 
@@ -183,33 +196,31 @@ static WERROR dsdb_convert_object(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);
@@ -228,34 +239,278 @@ WERROR dsdb_extended_replicated_objects_commit(struct ldb_context *ldb,
                                               out->num_objects);
        W_ERROR_HAVE_NO_MEMORY(out->objects);
 
+       /* pass the linked attributes down to the repl_meta_data
+          module */
+       out->linked_attributes_count = linked_attributes_count;
+       out->linked_attributes       = linked_attributes;
+
        for (i=0, cur = first_object; cur; cur = cur->next_object, i++) {
                if (i == out->num_objects) {
                        return WERR_FOOBAR;
                }
 
-               status = dsdb_convert_object(ldb, schema, out, cur, gensec_skey, out->objects, &out->objects[i]);
-               W_ERROR_NOT_OK_RETURN(status);
+               status = dsdb_convert_object_ex(ldb, schema,
+                                               cur, gensec_skey,
+                                               out->objects, &out->objects[i]);
+               if (!W_ERROR_IS_OK(status)) {
+                       DEBUG(0,("Failed to convert object %s\n", cur->object.identifier->dn));
+                       return status;
+               }
        }
        if (i != out->num_objects) {
                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 */
 
-       ret = ldb_extended(ldb, DSDB_EXTENDED_REPLICATED_OBJECTS_OID, out, &ext_res);
+       /* wrap the extended operation in a transaction 
+          See [MS-DRSR] 3.3.2 Transactions
+        */
+       ret = ldb_transaction_start(ldb);
+       if (ret != LDB_SUCCESS) {
+               DEBUG(0,(__location__ " Failed to start transaction\n"));
+               return WERR_FOOBAR;
+       }
+
+       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);
 
-       if (_out) {
-               *_out = out;
-       } else {
-               talloc_free(out);
+       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"));
+               return WERR_FOOBAR;
+       }
+
+
+       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;
 }
+
+static WERROR dsdb_convert_object(struct ldb_context *ldb,
+                                 const struct dsdb_schema *schema,
+                                 const struct drsuapi_DsReplicaObjectListItem *in,
+                                 TALLOC_CTX *mem_ctx,
+                                 struct ldb_message **_msg)
+{
+       WERROR status;
+       uint32_t i;
+       struct ldb_message *msg;
+
+       if (!in->object.identifier) {
+               return WERR_FOOBAR;
+       }
+
+       if (!in->object.identifier->dn || !in->object.identifier->dn[0]) {
+               return WERR_FOOBAR;
+       }
+
+       msg = ldb_msg_new(mem_ctx);
+       W_ERROR_HAVE_NO_MEMORY(msg);
+
+       msg->dn = ldb_dn_new(msg, ldb, in->object.identifier->dn);
+       W_ERROR_HAVE_NO_MEMORY(msg->dn);
+
+       msg->num_elements       = in->object.attribute_ctr.num_attributes;
+       msg->elements           = talloc_array(msg, struct ldb_message_element,
+                                              msg->num_elements);
+       W_ERROR_HAVE_NO_MEMORY(msg->elements);
+
+       for (i=0; i < msg->num_elements; i++) {
+               struct drsuapi_DsReplicaAttribute *a;
+               struct ldb_message_element *e;
+
+               a = &in->object.attribute_ctr.attributes[i];
+               e = &msg->elements[i];
+
+               status = dsdb_attribute_drsuapi_to_ldb(ldb, schema, a, msg->elements, e);
+               W_ERROR_NOT_OK_RETURN(status);
+       }
+
+
+       *_msg = msg;
+
+       return WERR_OK;
+}
+
+WERROR dsdb_origin_objects_commit(struct ldb_context *ldb,
+                                 TALLOC_CTX *mem_ctx,
+                                 const struct drsuapi_DsReplicaObjectListItem *first_object,
+                                 uint32_t *_num,
+                                 struct drsuapi_DsReplicaObjectIdentifier2 **_ids)
+{
+       WERROR status;
+       const struct dsdb_schema *schema;
+       const struct drsuapi_DsReplicaObjectListItem *cur;
+       struct ldb_message **objects;
+       struct drsuapi_DsReplicaObjectIdentifier2 *ids;
+       uint32_t i;
+       uint32_t num_objects = 0;
+       const char * const attrs[] = {
+               "objectGUID",
+               "objectSid",
+               NULL
+       };
+       struct ldb_result *res;
+       int ret;
+
+       schema = dsdb_get_schema(ldb);
+       if (!schema) {
+               return WERR_DS_SCHEMA_NOT_LOADED;
+       }
+
+       for (cur = first_object; cur; cur = cur->next_object) {
+               num_objects++;
+       }
+
+       if (num_objects == 0) {
+               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);
+       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]);
+               if (!W_ERROR_IS_OK(status)) {
+                       goto cancel;
+               }
+       }
+
+       ids = talloc_array(mem_ctx,
+                          struct drsuapi_DsReplicaObjectIdentifier2,
+                          num_objects);
+       if (ids == NULL) {
+               status = WERR_NOMEM;
+               goto cancel;
+       }
+
+       for (i=0; i < num_objects; i++) {
+               struct dom_sid *sid = NULL;
+               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 != LDB_SUCCESS) {
+                       status = WERR_DS_INTERNAL_FAILURE;
+                       goto cancel;
+               }
+               ids[i].guid = samdb_result_guid(res->msgs[0], "objectGUID");
+               sid = samdb_result_dom_sid(objects, res->msgs[0], "objectSid");
+               if (sid) {
+                       ids[i].sid = *sid;
+               } else {
+                       ZERO_STRUCT(ids[i].sid);
+               }
+       }
+
+       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 status;
+}