summaryrefslogtreecommitdiff
path: root/source4/dsdb
diff options
context:
space:
mode:
Diffstat (limited to 'source4/dsdb')
-rw-r--r--source4/dsdb/samdb/ldb_modules/repl_meta_data.c277
1 files changed, 240 insertions, 37 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
index 0ea73dcbd4..78e7aca92f 100644
--- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
+++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
@@ -44,6 +44,7 @@
#include "lib/ldb/include/ldb_errors.h"
#include "lib/ldb/include/ldb_private.h"
#include "dsdb/samdb/samdb.h"
+#include "dsdb/common/flags.h"
#include "librpc/gen_ndr/ndr_misc.h"
#include "librpc/gen_ndr/ndr_drsuapi.h"
#include "librpc/gen_ndr/ndr_drsblobs.h"
@@ -114,19 +115,6 @@ static struct replmd_replicated_request *replmd_replicated_init_handle(struct ld
return ar;
}
-static struct ldb_message_element *replmd_find_attribute(const struct ldb_message *msg, const char *name)
-{
- int i;
-
- for (i = 0; i < msg->num_elements; i++) {
- if (ldb_attr_cmp(name, msg->elements[i].name) == 0) {
- return &msg->elements[i];
- }
- }
-
- return NULL;
-}
-
/*
add a time element to a record
*/
@@ -304,68 +292,283 @@ static int replmd_add_originating(struct ldb_module *module,
const struct dsdb_schema *schema,
const struct dsdb_control_current_partition *partition)
{
+ NTSTATUS nt_status;
struct ldb_request *down_req;
- struct ldb_message_element *attribute;
struct ldb_message *msg;
- struct ldb_val v;
+ uint32_t instance_type;
+ struct ldb_dn *new_dn;
+ const char *rdn_name;
+ const char *rdn_name_upper;
+ const struct ldb_val *rdn_value = NULL;
+ const struct dsdb_attribute *rdn_attr = NULL;
struct GUID guid;
+ struct ldb_val guid_value;
+ struct replPropertyMetaDataBlob nmd;
+ struct ldb_val nmd_value;
uint64_t seq_num;
- NTSTATUS nt_status;
- int ret;
+ const struct GUID *our_invocation_id;
time_t t = time(NULL);
+ NTTIME now;
+ char *time_str;
+ int ret;
+ uint32_t i, ni=0;
ldb_debug(module->ldb, LDB_DEBUG_TRACE, "replmd_add_originating\n");
- if ((attribute = replmd_find_attribute(req->op.add.message, "objectGUID")) != NULL ) {
- return ldb_next_request(module, req);
+ if (ldb_msg_find_element(req->op.add.message, "objectGUID")) {
+ ldb_debug_set(module->ldb, LDB_DEBUG_ERROR,
+ "replmd_add_originating: it's not allowed to add an object with objectGUID\n");
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
+ if (ldb_msg_find_element(req->op.add.message, "instanceType")) {
+ ldb_debug_set(module->ldb, LDB_DEBUG_ERROR,
+ "replmd_add_originating: it's not allowed to add an object with instanceType\n");
+ return LDB_ERR_UNWILLING_TO_PERFORM;
}
+ /* Get a sequence number from the backend */
+ ret = ldb_sequence_number(module->ldb, LDB_SEQ_NEXT, &seq_num);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ /* a new GUID */
+ guid = GUID_random();
+
+ /* get our invicationId */
+ our_invocation_id = samdb_ntds_invocation_id(module->ldb);
+ if (!our_invocation_id) {
+ ldb_debug_set(module->ldb, LDB_DEBUG_ERROR,
+ "replmd_add_originating: unable to find invocationId\n");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* create a copy of the request */
down_req = talloc(req, struct ldb_request);
if (down_req == NULL) {
+ ldb_oom(module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
-
*down_req = *req;
/* we have to copy the message as the caller might have it as a const */
down_req->op.add.message = msg = ldb_msg_copy_shallow(down_req, req->op.add.message);
if (msg == NULL) {
talloc_free(down_req);
+ ldb_oom(module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
- /* a new GUID */
- guid = GUID_random();
+ /* generated times */
+ unix_to_nt_time(&now, t);
+ time_str = ldb_timestring(msg, t);
+ if (!time_str) {
+ talloc_free(down_req);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
- nt_status = ndr_push_struct_blob(&v, msg, &guid,
- (ndr_push_flags_fn_t)ndr_push_GUID);
- if (!NT_STATUS_IS_OK(nt_status)) {
+ /*
+ * get details of the rdn name
+ */
+ rdn_name = ldb_dn_get_rdn_name(msg->dn);
+ if (!rdn_name) {
+ talloc_free(down_req);
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ rdn_attr = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
+ if (!rdn_attr) {
+ talloc_free(down_req);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ rdn_value = ldb_dn_get_rdn_val(msg->dn);
+ if (!rdn_value) {
talloc_free(down_req);
+ ldb_oom(module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
- ret = ldb_msg_add_value(msg, "objectGUID", &v, NULL);
- if (ret) {
+ /*
+ * remove autogenerated attributes
+ */
+ ldb_msg_remove_attr(msg, rdn_name);
+ ldb_msg_remove_attr(msg, "name");
+ ldb_msg_remove_attr(msg, "whenCreated");
+ ldb_msg_remove_attr(msg, "whenChanged");
+ ldb_msg_remove_attr(msg, "uSNCreated");
+ ldb_msg_remove_attr(msg, "uSNChanged");
+ ldb_msg_remove_attr(msg, "replPropertyMetaData");
+
+ /*
+ * TODO: construct a new DN out of:
+ * - the parent DN
+ * - the upper case of rdn_attr->LDAPDisplayName
+ * - rdn_value
+ */
+ new_dn = ldb_dn_copy(msg, msg->dn);
+ if (!new_dn) {
talloc_free(down_req);
- return ret;
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
}
-
- if (add_time_element(msg, "whenCreated", t) != 0 ||
- add_time_element(msg, "whenChanged", t) != 0) {
+ rdn_name_upper = strupper_talloc(msg, rdn_attr->lDAPDisplayName);
+ if (!rdn_name_upper) {
+ talloc_free(down_req);
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ret = ldb_dn_set_component(new_dn, 0, rdn_name_upper, *rdn_value);
+ if (ret != LDB_SUCCESS) {
talloc_free(down_req);
+ ldb_oom(module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
+ msg->dn = new_dn;
- /* Get a sequence number from the backend */
- ret = ldb_sequence_number(module->ldb, LDB_SEQ_NEXT, &seq_num);
- if (ret == LDB_SUCCESS) {
- if (add_uint64_element(msg, "uSNCreated", seq_num) != 0 ||
- add_uint64_element(msg, "uSNChanged", seq_num) != 0) {
+ /*
+ * TODO: calculate correct instance type
+ */
+ instance_type = INSTANCE_TYPE_WRITE;
+ if (ldb_dn_compare(partition->dn, msg->dn) == 0) {
+ instance_type |= INSTANCE_TYPE_IS_NC_HEAD;
+ if (ldb_dn_compare(msg->dn, samdb_base_dn(module->ldb)) != 0) {
+ instance_type |= INSTANCE_TYPE_NC_ABOVE;
+ }
+ }
+
+ /*
+ * readd replicated attributes
+ */
+ ret = ldb_msg_add_value(msg, rdn_attr->lDAPDisplayName, rdn_value, NULL);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(down_req);
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ret = ldb_msg_add_value(msg, "name", rdn_value, NULL);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(down_req);
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ret = ldb_msg_add_string(msg, "whenCreated", time_str);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(down_req);
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ret = ldb_msg_add_fmt(msg, "instanceType", "%u", instance_type);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(down_req);
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* build the replication meta_data */
+ ZERO_STRUCT(nmd);
+ nmd.version = 1;
+ nmd.ctr.ctr1.count = msg->num_elements;
+ nmd.ctr.ctr1.array = talloc_array(msg,
+ struct replPropertyMetaData1,
+ nmd.ctr.ctr1.count);
+ if (!nmd.ctr.ctr1.array) {
+ talloc_free(down_req);
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ for (i=0; i < msg->num_elements; i++) {
+ struct ldb_message_element *e = &msg->elements[i];
+ struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
+ const struct dsdb_attribute *sa;
+
+ sa = dsdb_attribute_by_lDAPDisplayName(schema, e->name);
+ if (!sa) {
+ ldb_debug_set(module->ldb, LDB_DEBUG_ERROR,
+ "replmd_add_originating: attribute '%s' not defined in schema\n",
+ e->name);
talloc_free(down_req);
- return LDB_ERR_OPERATIONS_ERROR;
+ return LDB_ERR_NO_SUCH_ATTRIBUTE;
}
+
+ if (sa->systemFlags & 0x00000001) {
+ /* attribute is not replicated so it has no meta data */
+ continue;
+ }
+
+ m->attid = sa->attributeID_id;
+ m->version = 1;
+ m->orginating_time = now;
+ m->orginating_invocation_id = *our_invocation_id;
+ m->orginating_usn = seq_num;
+ m->local_usn = seq_num;
+ ni++;
}
+ /* fix meta data count */
+ nmd.ctr.ctr1.count = ni;
+
+ /*
+ * sort meta data array, and move the rdn attribute entry to the end
+ */
+ replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, &rdn_attr->attributeID_id);
+
+ /* generated NDR encoded values */
+ nt_status = ndr_push_struct_blob(&guid_value, msg, &guid,
+ (ndr_push_flags_fn_t)ndr_push_GUID);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ talloc_free(down_req);
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ nt_status = ndr_push_struct_blob(&nmd_value, msg, &nmd,
+ (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ talloc_free(down_req);
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /*
+ * add the autogenerated values
+ */
+ ret = ldb_msg_add_value(msg, "objectGUID", &guid_value, NULL);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(down_req);
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ret = ldb_msg_add_string(msg, "whenChanged", time_str);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(down_req);
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ret = samdb_msg_add_uint64(module->ldb, msg, msg, "uSNCreated", seq_num);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(down_req);
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ret = samdb_msg_add_uint64(module->ldb, msg, msg, "uSNChanged", seq_num);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(down_req);
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(down_req);
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /*
+ * sort the attributes by attid before storing the object
+ */
+ replmd_ldb_message_sort(msg, schema);
+
ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
/* go on with the call chain */