diff options
author | Stefan Metzmacher <metze@samba.org> | 2007-01-23 16:18:45 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 14:44:06 -0500 |
commit | c601a9ddcdd27464d8a3f871fef2f959b47f66a0 (patch) | |
tree | 1862bd6b874b2cf617e93e2cef6c7e41a85d7172 /source4 | |
parent | faa9c2374ce284ac23ab42d314da54226ee68c35 (diff) | |
download | samba-c601a9ddcdd27464d8a3f871fef2f959b47f66a0.tar.gz samba-c601a9ddcdd27464d8a3f871fef2f959b47f66a0.tar.bz2 samba-c601a9ddcdd27464d8a3f871fef2f959b47f66a0.zip |
r20975: - implement handling of meta data an on originating add
there're a few things TODO, but it's a good start
we need to research if an originating change causes the replUpToDateVector
attribute to change...(I assume it, but needs testing)
metze
(This used to be commit fde0aabd9ae79fcefbcba34e6f9143f93ffcf96c)
Diffstat (limited to 'source4')
-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 */ |