[SCM] Samba Shared Repository - branch master updated

Kamen Mazdrashki kamenim at samba.org
Wed May 11 13:04:02 MDT 2011


The branch, master has been updated
       via  a8798d8 s4/drepl_fsmo: Add an CR so that message is visible in the logs
       via  d4481be s4/getnc_exop: Initial implementation of a testsuite for GetNCChanges extended opeartion handling
       via  647827d s4/getncchanges: Pre-mark extended requests as success in case a sub-function "forget" to do this
       via  55916e2 s4/getncchanges: Implement placeholder for handling ex-op collection of objects
       via  88a9f79 s4/getncchanges: Move the code that collects objects into separate function
       via  41496e7 s4/getncchanges: Don't mask Extended operation result - callers need it
       via  232a8df s4/getncchanges: Fail extended request rather than failing whole request
      from  f99d6f0 s3-printing: make cups_pull_comment_location() work again.

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit a8798d8bce9a191ccd6e0692c75e38ffadba1011
Author: Kamen Mazdrashki <kamenim at samba.org>
Date:   Wed May 11 21:05:42 2011 +0300

    s4/drepl_fsmo: Add an CR so that message is visible in the logs
    
    Autobuild-User: Kamen Mazdrashki <kamenim at samba.org>
    Autobuild-Date: Wed May 11 21:03:59 CEST 2011 on sn-devel-104

commit d4481be95c0c22ab8dd66edfdd82d1e9312b137d
Author: Kamen Mazdrashki <kamenim at samba.org>
Date:   Wed May 11 21:04:54 2011 +0300

    s4/getnc_exop: Initial implementation of a testsuite for GetNCChanges extended opeartion handling

commit 647827d09ccba7bcfa6454119afc22de96397128
Author: Kamen Mazdrashki <kamenim at samba.org>
Date:   Wed May 11 21:09:34 2011 +0300

    s4/getncchanges: Pre-mark extended requests as success in case a sub-function "forget" to do this

commit 55916e273f0853084f5bc2171eefc86af69e27dc
Author: Kamen Mazdrashki <kamenim at samba.org>
Date:   Wed May 11 20:49:42 2011 +0300

    s4/getncchanges: Implement placeholder for handling ex-op collection of objects
    
    Right now it is solely based on function that handles objects
    in normal DsGetNCChanges calls.

commit 88a9f793aa3cc7d7be073eef618fded87420f0d3
Author: Kamen Mazdrashki <kamenim at samba.org>
Date:   Wed May 11 20:48:53 2011 +0300

    s4/getncchanges: Move the code that collects objects into separate function

commit 41496e782df028a0fc8619aed6ca7a1173750677
Author: Kamen Mazdrashki <kamenim at samba.org>
Date:   Mon May 9 20:11:22 2011 +0300

    s4/getncchanges: Don't mask Extended operation result - callers need it

commit 232a8dfb060dcac27801b51b9576d76fb2f93655
Author: Kamen Mazdrashki <kamenim at samba.org>
Date:   Mon May 9 20:09:49 2011 +0300

    s4/getncchanges: Fail extended request rather than failing whole request
    
    in case that destination_dsa_guid is not valid

-----------------------------------------------------------------------

Summary of changes:
 source4/dsdb/repl/drepl_fsmo.c            |    2 +-
 source4/rpc_server/drsuapi/getncchanges.c |  168 ++++++++++++++++++++---------
 source4/torture/drs/python/getnc_exop.py  |  136 +++++++++++++++++++++++
 3 files changed, 252 insertions(+), 54 deletions(-)
 create mode 100644 source4/torture/drs/python/getnc_exop.py


Changeset truncated at 500 lines:

diff --git a/source4/dsdb/repl/drepl_fsmo.c b/source4/dsdb/repl/drepl_fsmo.c
index f8f4769..db63853 100644
--- a/source4/dsdb/repl/drepl_fsmo.c
+++ b/source4/dsdb/repl/drepl_fsmo.c
@@ -111,7 +111,7 @@ NTSTATUS drepl_take_FSMO_role(struct irpc_message *msg,
 
 	if (fsmo_master_equal(ntds_dn, role_owner_dn) ||
 	    (extended_op == DRSUAPI_EXOP_NONE)) {
-		DEBUG(0,("FSMO role check failed for DN %s and owner %s ",
+		DEBUG(0,("FSMO role check failed for DN %s and owner %s \n",
 			 ldb_dn_get_linearized(fsmo_role_dn),
 			 ldb_dn_get_linearized(role_owner_dn)));
 		r->out.result = WERR_OK;
diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c
index 8ae5368..0c196aa 100644
--- a/source4/rpc_server/drsuapi/getncchanges.c
+++ b/source4/rpc_server/drsuapi/getncchanges.c
@@ -993,12 +993,14 @@ static WERROR getncchanges_change_master(struct drsuapi_bind_state *b_state,
 	msg->dn = drs_ObjectIdentifier_to_dn(msg, ldb, req10->naming_context);
 	W_ERROR_HAVE_NO_MEMORY(msg->dn);
 
+	/* TODO: make sure ntds_dn is a valid nTDSDSA object */
 	ret = dsdb_find_dn_by_guid(ldb, msg, &req10->destination_dsa_guid, &ntds_dn);
 	if (ret != LDB_SUCCESS) {
 		DEBUG(0, (__location__ ": Unable to find NTDS object for guid %s - %s\n",
 			  GUID_string(mem_ctx, &req10->destination_dsa_guid), ldb_errstring(ldb)));
 		talloc_free(msg);
-		return WERR_DS_DRA_INTERNAL_ERROR;
+		ctr6->extended_ret = DRSUAPI_EXOP_ERR_UNKNOWN_CALLER;
+		return WERR_OK;
 	}
 
 	ret = ldb_msg_add_string(msg, "fSMORoleOwner", ldb_dn_get_linearized(ntds_dn));
@@ -1161,6 +1163,91 @@ getncchanges_map_req8(TALLOC_CTX *mem_ctx,
 }
 
 
+/**
+ * Collects object for normal replication cycle.
+ */
+static WERROR getncchanges_collect_objects(struct drsuapi_bind_state *b_state,
+					   TALLOC_CTX *mem_ctx,
+					   struct drsuapi_DsGetNCChangesRequest10 *req10,
+					   struct ldb_dn *search_dn,
+					   const char *extra_filter,
+					   struct ldb_result **search_res)
+{
+	int ret;
+	char* search_filter;
+	enum ldb_scope scope = LDB_SCOPE_SUBTREE;
+	//const char *extra_filter;
+	struct drsuapi_getncchanges_state *getnc_state = b_state->getncchanges_state;
+	const char *attrs[] = { "uSNChanged",
+				"objectGUID" ,
+				NULL };
+
+	if (req10->extended_op == DRSUAPI_EXOP_REPL_OBJ ||
+	    req10->extended_op == DRSUAPI_EXOP_REPL_SECRET) {
+		scope = LDB_SCOPE_BASE;
+	}
+
+	//extra_filter = lpcfg_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "drs", "object filter");
+
+	//getnc_state->min_usn = req10->highwatermark.highest_usn;
+
+	/* Construct response. */
+	search_filter = talloc_asprintf(mem_ctx,
+					"(uSNChanged>=%llu)",
+					(unsigned long long)(getnc_state->min_usn+1));
+
+	if (extra_filter) {
+		search_filter = talloc_asprintf(mem_ctx, "(&%s(%s))", search_filter, extra_filter);
+	}
+
+	if (req10->replica_flags & DRSUAPI_DRS_CRITICAL_ONLY) {
+		search_filter = talloc_asprintf(mem_ctx,
+						"(&%s(isCriticalSystemObject=TRUE))",
+						search_filter);
+	}
+
+	if (req10->replica_flags & DRSUAPI_DRS_ASYNC_REP) {
+		scope = LDB_SCOPE_BASE;
+	}
+
+	if (!search_dn) {
+		search_dn = getnc_state->ncRoot_dn;
+	}
+
+	DEBUG(2,(__location__ ": getncchanges on %s using filter %s\n",
+		 ldb_dn_get_linearized(getnc_state->ncRoot_dn), search_filter));
+	ret = drsuapi_search_with_extended_dn(b_state->sam_ctx, getnc_state, search_res,
+					      search_dn, scope, attrs,
+					      search_filter);
+	if (ret != LDB_SUCCESS) {
+		return WERR_DS_DRA_INTERNAL_ERROR;
+	}
+
+	return WERR_OK;
+}
+
+/**
+ * Collects object for normal replication cycle.
+ */
+static WERROR getncchanges_collect_objects_exop(struct drsuapi_bind_state *b_state,
+						TALLOC_CTX *mem_ctx,
+						struct drsuapi_DsGetNCChangesRequest10 *req10,
+						struct drsuapi_DsGetNCChangesCtr6 *ctr6,
+						struct ldb_dn *search_dn,
+						const char *extra_filter,
+						struct ldb_result **search_res)
+{
+	/* we have nothing to do in case of ex-op failure */
+	if (ctr6->extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
+		return WERR_OK;
+	}
+
+	/* TODO: implement extended op specific collection
+	 * of objects. Right now we just normal procedure
+	 * for collecting objects */
+	return getncchanges_collect_objects(b_state, mem_ctx, req10, search_dn, extra_filter, search_res);
+}
+
 /* 
   drsuapi_DsGetNCChanges
 
@@ -1177,9 +1264,6 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
 	struct drsuapi_DsReplicaObjectListItemEx **currentObject;
 	NTSTATUS status;
 	DATA_BLOB session_key;
-	const char *attrs[] = { "uSNChanged",
-				"objectGUID" ,
-				NULL };
 	WERROR werr;
 	struct dcesrv_handle *h;
 	struct drsuapi_bind_state *b_state;	
@@ -1327,6 +1411,10 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
 				     ldb_get_schema_basedn(b_state->sam_ctx));
 		getnc_state->is_schema_nc = (0 == ret);
 
+		if (req10->extended_op != DRSUAPI_EXOP_NONE) {
+			r->out.ctr->ctr6.extended_ret = DRSUAPI_EXOP_ERR_SUCCESS;
+		}
+
 		/*
 		 * This is the first replication cycle and it is
 		 * a good place to handle extended operations
@@ -1391,64 +1479,39 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
 	   Work out if this is the start of a new cycle */
 
 	if (getnc_state->guids == NULL) {
-		char* search_filter;
-		enum ldb_scope scope = LDB_SCOPE_SUBTREE;
 		const char *extra_filter;
-		struct ldb_result *search_res;
-
-		if (req10->extended_op == DRSUAPI_EXOP_REPL_OBJ ||
-		    req10->extended_op == DRSUAPI_EXOP_REPL_SECRET) {
-			scope = LDB_SCOPE_BASE;
-		}
+		struct ldb_result *search_res = NULL;
 
 		extra_filter = lpcfg_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "drs", "object filter");
 
 		getnc_state->min_usn = req10->highwatermark.highest_usn;
 
-		/* Construct response. */
-		search_filter = talloc_asprintf(mem_ctx,
-						"(uSNChanged>=%llu)",
-						(unsigned long long)(getnc_state->min_usn+1));
-	
-		if (extra_filter) {
-			search_filter = talloc_asprintf(mem_ctx, "(&%s(%s))", search_filter, extra_filter);
-		}
-
-		if (req10->replica_flags & DRSUAPI_DRS_CRITICAL_ONLY) {
-			search_filter = talloc_asprintf(mem_ctx,
-							"(&%s(isCriticalSystemObject=TRUE))",
-							search_filter);
-		}
-		
-		if (req10->replica_flags & DRSUAPI_DRS_ASYNC_REP) {
-			scope = LDB_SCOPE_BASE;
-		}
-		
-		if (!search_dn) {
-			search_dn = getnc_state->ncRoot_dn;
-		}
-
-		DEBUG(2,(__location__ ": getncchanges on %s using filter %s\n",
-			 ldb_dn_get_linearized(getnc_state->ncRoot_dn), search_filter));
-		ret = drsuapi_search_with_extended_dn(sam_ctx, getnc_state, &search_res,
-						      search_dn, scope, attrs,
-						      search_filter);
-		if (ret != LDB_SUCCESS) {
-			return WERR_DS_DRA_INTERNAL_ERROR;
-		}
-
-		if (req10->replica_flags & DRSUAPI_DRS_GET_ANC) {
-			TYPESAFE_QSORT(search_res->msgs,
-				       search_res->count,
-				       site_res_cmp_parent_order);
+		if (req10->extended_op == DRSUAPI_EXOP_NONE) {
+			werr = getncchanges_collect_objects(b_state, mem_ctx, req10,
+							    search_dn, extra_filter,
+							    &search_res);
 		} else {
-			TYPESAFE_QSORT(search_res->msgs,
-				       search_res->count,
-				       site_res_cmp_usn_order);
+			werr = getncchanges_collect_objects_exop(b_state, mem_ctx, req10,
+								 &r->out.ctr->ctr6,
+								 search_dn, extra_filter,
+								 &search_res);
+		}
+		W_ERROR_NOT_OK_RETURN(werr);
+
+		if (search_res) {
+			if (req10->replica_flags & DRSUAPI_DRS_GET_ANC) {
+				TYPESAFE_QSORT(search_res->msgs,
+					       search_res->count,
+					       site_res_cmp_parent_order);
+			} else {
+				TYPESAFE_QSORT(search_res->msgs,
+					       search_res->count,
+					       site_res_cmp_usn_order);
+			}
 		}
 
 		/* extract out the GUIDs list */
-		getnc_state->num_records = search_res->count;
+		getnc_state->num_records = search_res ? search_res->count : 0;
 		getnc_state->guids = talloc_array(getnc_state, struct GUID, getnc_state->num_records);
 		W_ERROR_HAVE_NO_MEMORY(getnc_state->guids);
 
@@ -1705,7 +1768,6 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
 		r->out.ctr->ctr6.uptodateness_vector = NULL;
 		r->out.ctr->ctr6.nc_object_count = 0;
 		ZERO_STRUCT(r->out.ctr->ctr6.new_highwatermark);
-		r->out.ctr->ctr6.extended_ret = DRSUAPI_EXOP_ERR_SUCCESS;
 	}
 
 	DEBUG(r->out.ctr->ctr6.more_data?4:2,
diff --git a/source4/torture/drs/python/getnc_exop.py b/source4/torture/drs/python/getnc_exop.py
new file mode 100644
index 0000000..3aeb7e0
--- /dev/null
+++ b/source4/torture/drs/python/getnc_exop.py
@@ -0,0 +1,136 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Tests various schema replication scenarios
+#
+# Copyright (C) Kamen Mazdrashki <kamenim at samba.org> 2011
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+#
+# Usage:
+#  export DC1=dc1_dns_name
+#  export DC2=dc2_dns_name
+#  export SUBUNITRUN=$samba4srcdir/scripting/bin/subunitrun
+#  PYTHONPATH="$PYTHONPATH:$samba4srcdir/torture/drs/python" $SUBUNITRUN getnc_exop -U"$DOMAIN/$DC_USERNAME"%"$DC_PASSWORD"
+#
+
+import drs_base
+import samba.tests
+
+from ldb import SCOPE_BASE
+
+from samba.dcerpc import drsuapi, misc, drsblobs
+from samba.drs_utils import drs_DsBind
+
+
+class DrsReplicaSyncTestCase(drs_base.DrsBaseTestCase):
+    """Intended as a semi-black box test case for DsGetNCChanges
+       implementation for extended operations. It should be testing
+       how DsGetNCChanges handles different input params (mostly invalid).
+       Final goal is to make DsGetNCChanges as binary compatible to
+       Windows implementation as possible"""
+
+    def setUp(self):
+        super(DrsReplicaSyncTestCase, self).setUp()
+
+    def tearDown(self):
+        super(DrsReplicaSyncTestCase, self).tearDown()
+
+    def _exop_req8(self, dest_dsa, invocation_id, nc_dn_str, exop):
+        req8 = drsuapi.DsGetNCChangesRequest8()
+    
+        req8.destination_dsa_guid = misc.GUID(dest_dsa)
+        req8.source_dsa_invocation_id = misc.GUID(invocation_id)
+        req8.naming_context = drsuapi.DsReplicaObjectIdentifier()
+        req8.naming_context.dn = unicode(nc_dn_str)
+        req8.highwatermark = drsuapi.DsReplicaHighWaterMark()
+        req8.highwatermark.tmp_highest_usn = 0
+        req8.highwatermark.reserved_usn = 0
+        req8.highwatermark.highest_usn = 0
+        req8.uptodateness_vector = None
+        req8.replica_flags = 0
+        req8.max_object_count = 0
+        req8.max_ndr_size = 402116
+        req8.extended_op = exop
+        req8.fsmo_info = 0
+        req8.partial_attribute_set = None
+        req8.partial_attribute_set_ex = None
+        req8.mapping_ctr.num_mappings = 0
+        req8.mapping_ctr.mappings = None
+    
+        return req8
+
+    def _ds_bind(self, server_name):
+        binding_str = "ncacn_ip_tcp:%s[print,seal]" % server_name
+
+        drs = drsuapi.drsuapi(binding_str, self.get_loadparm(), self.get_credentials())
+        (drs_handle, supported_extensions) = drs_DsBind(drs)
+        return (drs, drs_handle)
+
+    def _determine_fSMORoleOwner(self, fsmo_obj_dn):
+        """Returns (owner, not_owner) pair where:
+             owner: dns name for FSMO owner
+             not_owner: dns name for DC not owning the FSMO"""
+        res = self.ldb_dc1.search(fsmo_obj_dn,
+                                  scope=SCOPE_BASE, attrs=["fSMORoleOwner"])
+        assert len(res) == 1, "Only one fSMORoleOwner value expected for %s!"%fsmo_obj_dn
+        fsmo_owner = res[0]["fSMORoleOwner"][0]
+        if fsmo_owner == self.info_dc1["dsServiceName"][0]:
+            return (self.dnsname_dc1, self.dnsname_dc2)
+        return (self.dnsname_dc2, self.dnsname_dc1)
+
+    def _check_exop_failed(self, ctr6, expected_failure):
+        c = drsuapi.DsGetNCChangesCtr6()
+        self.assertEqual(ctr6.extended_ret, expected_failure)
+        self.assertEqual(ctr6.object_count, 0)
+        self.assertEqual(ctr6.first_object, None)
+        self.aserrtEqual(ctr6.more_data, False)
+        self.assertEqual(ctr6.nc_object_count, 0)
+        self.assertEqual(ctr6.nc_linked_attributes_count, 0)
+        self.assertEqual(ctr6.linked_attributes_count, 0)
+        self.assertEqual(ctr6.linked_attributes, None)
+        self.assertEqual(ctr6.drs_error, 0)
+
+    def test_FSMONotOwner(self):
+        """Test role transfer with against DC not owner of the role"""
+        fsmo_dn = self.ldb_dc1.get_schema_basedn()
+        (fsmo_owner_dc, fsmo_not_owner_dc) = self._determine_fSMORoleOwner(fsmo_dn)
+
+        req8 = self._exop_req8(dest_dsa="9c637462-5b8c-4467-aef2-bdb1f57bc4ef",
+                               invocation_id=self.ldb_dc1.get_invocation_id(),
+                               nc_dn_str=fsmo_dn,
+                               exop=drsuapi.DRSUAPI_EXOP_FSMO_REQ_ROLE)
+
+        (drs, drs_handle) = self._ds_bind(fsmo_not_owner_dc)
+        (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+        self.assertEqual(level, 6, "Expected level 6 response!")
+        self._check_exop_failed(ctr, drsuapi.DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER)
+
+    def test_InvalidDestDSA(self):
+        """Test role transfer with invalid destination DSA guid"""
+        fsmo_dn = self.ldb_dc1.get_schema_basedn()
+        (fsmo_owner_dc, fsmo_not_owner_dc) = self._determine_fSMORoleOwner(fsmo_dn)
+
+        req8 = self._exop_req8(dest_dsa="9c637462-5b8c-4467-aef2-bdb1f57bc4ef",
+                               invocation_id=self.ldb_dc1.get_invocation_id(),
+                               nc_dn_str=self.ldb_dc1.get_schema_basedn(),
+                               exop=drsuapi.DRSUAPI_EXOP_FSMO_REQ_ROLE)
+
+        (drs, drs_handle) = self._ds_bind(fsmo_owner_dc)
+        (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+        self.assertEqual(level, 6, "Expected level 6 response!")
+        #ctr = drsuapi.DsGetNCChangesCtr6()
+        self._check_exop_failed(ctr, drsuapi.DRSUAPI_EXOP_ERR_UNKNOWN_CALLER)


-- 
Samba Shared Repository


More information about the samba-cvs mailing list