svn commit: samba r20975 - in branches/SAMBA_4_0/source/dsdb/samdb/ldb_modules: .

metze at samba.org metze at samba.org
Tue Jan 23 16:18:45 GMT 2007


Author: metze
Date: 2007-01-23 16:18:45 +0000 (Tue, 23 Jan 2007)
New Revision: 20975

WebSVN: http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=20975

Log:
- 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
Modified:
   branches/SAMBA_4_0/source/dsdb/samdb/ldb_modules/repl_meta_data.c


Changeset:
Modified: branches/SAMBA_4_0/source/dsdb/samdb/ldb_modules/repl_meta_data.c
===================================================================
--- branches/SAMBA_4_0/source/dsdb/samdb/ldb_modules/repl_meta_data.c	2007-01-23 16:06:47 UTC (rev 20974)
+++ branches/SAMBA_4_0/source/dsdb/samdb/ldb_modules/repl_meta_data.c	2007-01-23 16:18:45 UTC (rev 20975)
@@ -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 @@
 	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 @@
 				  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;
+	const struct GUID *our_invocation_id;
+	time_t t = time(NULL);
+	NTTIME now;
+	char *time_str;
 	int ret;
-	time_t t = time(NULL);
+	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 */



More information about the samba-cvs mailing list