diff options
Diffstat (limited to 'source4/dsdb')
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 277 |
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 */ |