[SCM] Samba Shared Repository - branch master updated

Andrew Bartlett abartlet at samba.org
Tue Aug 29 09:14:01 UTC 2017


The branch, master has been updated
       via  3164c0a ldb_tdb: Rework ltdb_modify_internal() to use ltdb_search_dn1() internally
       via  bff81a2 ldb: Add LDB_UNPACK_DATA_FLAG_NO_ATTRS
       via  b6e6379 selftest: Use a unique(ish) OU for every run of getnc_unpriv
       via  d6a384b s4-drsuapi/selftest: Add extra tests for invalid DNs
       via  37ed946 selftest: Update getnc_unpriv tests to pass against Samba
       via  2d0766a s4-drsuapi: Set getnc_state *after* we've checked request is valid
       via  6158f18 selftest: GetNCChanges can 'accept' a repeated bad request
       via  3c8fa7b s4-drsuapi: Change REPL_SECRET error code to match Windows
       via  122c8e1 selftest: Extend further getnc_unpriv tests to pass against windows 2012R2
       via  87bc8d8 selftest: Confirm privileged replication of an OU is not permitted
       via  cdb8c4a selftest: Move get_partial_attribute_set() to DrsBaseTestCase
       via  83f2338 selftest: encrypt the LDAP connection in drs_base.py
       via  607ba1a s4-drsuapi: Refuse to replicate an NC is that not actually an NC
       via  5351252 selftest: Make dirsync test use symobolic name and OA not A
       via  2feea24 dsdb: Use samba.generate_random_password() in dirsync test
       via  f8a30d3 s4-drsuapi: Use sam_ctx consistently in dcesrv_drsuapi_DsGetNCChanges()
       via  dd863b6 s4-drsuapi: Avoid segfault when replicating as a non-admin with GUID_DRS_GET_CHANGES
      from  f9d4158 tests/fake_snap: sanitize paths

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


- Log -----------------------------------------------------------------
commit 3164c0ac54685d6ae430e2cb3bb50a9ad7f3e7fc
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Wed Aug 16 12:51:09 2017 +1200

    ldb_tdb: Rework ltdb_modify_internal() to use ltdb_search_dn1() internally
    
    This avoids duplicate code and allows us to use the allocation-avoiding
    LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC flag.
    
    We can not use LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC as el2->values
    is talloc_realloc()ed in the routine.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>
    
    Autobuild-User(master): Andrew Bartlett <abartlet at samba.org>
    Autobuild-Date(master): Tue Aug 29 11:13:50 CEST 2017 on sn-devel-144

commit bff81a2c9cc43a2cfec822dde94944d0295dd87f
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Fri Aug 11 11:31:05 2017 +1200

    ldb: Add LDB_UNPACK_DATA_FLAG_NO_ATTRS
    
    This will allow us to avoid a full unpack in situations where we just want to confirm
    if the DN exists
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit b6e6379514ad49e798a80b8464ebfc2b77f86574
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Thu Aug 17 12:30:30 2017 +1200

    selftest: Use a unique(ish) OU for every run of getnc_unpriv
    
    An intermittent problem I noticed with tests in the past is that the
    setup can fail to create the base OU because it already exists.
    I believe this is because the previous testenv DC has replicated out the
    test object, but not its deletion at the point that the next testenv DC
    starts running the test.
    
    This only seemed to happen very occassionally (I haven't seen it
    happen with getnc_unpriv yet, but I also haven't run it through the
    autobuild yet).
    
    Using same randomness in the test OU should help avoid this sort of
    problem, and it matches what some other replication tests do.
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit d6a384b24bb762abc340158bbcd3aad828a4b490
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Thu Aug 17 11:36:24 2017 +1200

    s4-drsuapi/selftest: Add extra tests for invalid DNs
    
    Add some test cases to check for requests for invalid/non-existent DNs.
    This exercises the first return case added in commit:
      s4-drsuapi: Refuse to replicate an NC is that not actually an NC
    
    I've also updated the error code returned here to match Windows.
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit 37ed946c75e4f62b173b943b0db649fdbdbf72ed
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Wed Aug 16 15:00:31 2017 +1200

    selftest: Update getnc_unpriv tests to pass against Samba
    
    In general Windows seems to return BAD_DN rather than ACCESS_DENIED for
    an unprivileged user. In the the long-term, it's unrealistic to think
    that Samba and Windows will agree exactly on every error code returned.
    So for the tests to be maintainable and pass against Windows and Samba,
    they need to handle differences in expected errors. To get around this
    problem, I've changed the expected_error to be a set, so that multiple
    error codes (one for Microsoft, one for Samba) can be specified for each
    test case. This approach also highlights the cases where Microsoft and
    Samba currently differ.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit 2d0766a48b3a62de15aa834b1aedd0f6b8c7f6e1
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Wed Aug 16 16:20:37 2017 +1200

    s4-drsuapi: Set getnc_state *after* we've checked request is valid
    
    We were creating the getnc_state (and storing it on the connection)
    before we had done some basic checks that the request was valid. If the
    request was not valid and we returned early with an error, then the
    partially-initialized getnc_state was left hanging on the connection.
    The next request that got sent on the connection would try to use this,
    rather than creating a new getnc_state from scratch.
    
    The main side-effect of this was if you sent an invalid GetNCChanges
    request twice, then it could be rejected the first time and accepted the
    second time.
    
    Note that although an invalid request was accepted, it would typically
    not return any objects, so it would not actually leak any secure
    information.
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit 6158f1839fe42e9a5c9daacd3182f06527462fdf
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Mon Aug 14 15:31:08 2017 +1200

    selftest: GetNCChanges can 'accept' a repeated bad request
    
    In theory, if we send the exact same rejected request again, we should
    get the same response back from the DC. However, we don't - the request
    is accepted if we send it a second time.
    
    This patch updates the repl_rodc test to demonstrate the problem (which
    now causes the test to fail).
    
    Note that although the bad GetNCChanges request is not rejected outright,
    the response that gets sent back is empty - it has no objects in it, so
    it's not an actual security hole. It is annoying problem for writing
    self-tests though.
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit 3c8fa7b27f29baf9c1c8309db2ac91816255c931
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Wed Aug 16 15:09:55 2017 +1200

    s4-drsuapi: Change REPL_SECRET error code to match Windows
    
    The existing SOURCE_DISABLED error code doesn't seem to make a lot of
    sense. Window sends back an ACCESS_DENIED error in the same situation,
    which seems more appropriate.
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit 122c8e1fa294e7d929e3ddeb0ab0ed45d1b51f68
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Wed Aug 16 16:57:15 2017 +1200

    selftest: Extend further getnc_unpriv tests to pass against windows 2012R2
    
    An important change in this patch is changing the ACE type from
     A (Allow)
    to
     AO (Object Allow)
    
    as that will then respect the supplied GUID, which we also make use
    the constant from the security.idl.
    
    This reworks the tests to check replication with users with the
    following rights:
    - only GET_CHANGES
    - only GET_ALL_CHANGES
    - both GET_CHANGES and GET_ALL_CHANGES
    - no rights
    
    We basically want to test various different GetNCChanges requests
    against each type of user rights, and the only difference is the
    error/success value we get back. I've structured the tests this way, so
    that we have 4 test_repl_xyz_userpriv() functions (to cover each of the
    above user rights cases), and each test sends the same series of
    GetNCChanges requests of varying validity.
    
    Currently all these tests fail against Samba because Samba sends
    different error codes to Windows.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit 87bc8d8f16eca0a0e335a649106a80656b083a7d
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Tue Aug 8 16:52:04 2017 +1200

    selftest: Confirm privileged replication of an OU is not permitted
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit cdb8c4ae80a05852a50e0b383c9696799fb21293
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Tue Aug 8 16:50:11 2017 +1200

    selftest: Move get_partial_attribute_set() to DrsBaseTestCase
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit 83f2338009bc85669a76edcad876971d3d349942
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Tue Aug 8 16:49:24 2017 +1200

    selftest: encrypt the LDAP connection in drs_base.py
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit 607ba1a2036627d1a90c0ac03265221571dc6899
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Tue Aug 8 14:34:14 2017 +1200

    s4-drsuapi: Refuse to replicate an NC is that not actually an NC
    
    This prevents replication of an OU, you must replicate a whole NC per Windows 2012R2
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit 53512529beb3b05044cba3363eecb475ce36d610
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Wed Aug 9 13:56:07 2017 +1200

    selftest: Make dirsync test use symobolic name and OA not A
    
    A is for Allow, OA is for Object Allow, which means check the GUID.
    
    The previous ACE allowed all access, which was not the intention.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit 2feea24061466d14002581ebe6f69956343941d0
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Fri Aug 4 15:21:31 2017 +1200

    dsdb: Use samba.generate_random_password() in dirsync test
    
    We do not like fixed passwords
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12946
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit f8a30d31677bab7956a2176a2fa4aed45f124187
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Mon Aug 14 11:02:05 2017 +1200

    s4-drsuapi: Use sam_ctx consistently in dcesrv_drsuapi_DsGetNCChanges()
    
    Trying to use bstate->sam_ctx_system by mistake can cause crashes if
    non-admin users replicate. To avoid this problem we use the sam_ctx
    variable, however it wasn't used consistently everywhere. Replace the
    remaining references to b_state->sam_ctx to avoid potential confusion.
    
    This change was made based on review feedback from Metze.
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit dd863b604984c1504895f376ec64f58e27e53efa
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Fri Aug 4 11:44:19 2017 +1200

    s4-drsuapi: Avoid segfault when replicating as a non-admin with GUID_DRS_GET_CHANGES
    
    Users who are not administrator do not get b_state->sam_ctx_system filled in.
    
    We should probably use the 'sam_ctx' variable in all cases (instead of
    b_state->sam_ctx*), but I'll make this change in a separate patch, so
    that the bug fix remains independent from other tidy-ups.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12946
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

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

Summary of changes:
 lib/ldb/common/ldb_pack.c                  |   5 +
 lib/ldb/include/ldb_module.h               |   5 +
 lib/ldb/ldb_tdb/ldb_tdb.c                  |  40 ++--
 source4/dsdb/tests/python/dirsync.py       |   7 +-
 source4/rpc_server/drsuapi/getncchanges.c  |  93 ++++++---
 source4/selftest/tests.py                  |   5 +
 source4/torture/drs/python/drs_base.py     |  11 +-
 source4/torture/drs/python/getnc_exop.py   |  30 ++-
 source4/torture/drs/python/getnc_unpriv.py | 305 +++++++++++++++++++++++++++++
 source4/torture/drs/python/repl_rodc.py    |   7 +
 10 files changed, 439 insertions(+), 69 deletions(-)
 create mode 100644 source4/torture/drs/python/getnc_unpriv.py


Changeset truncated at 500 lines:

diff --git a/lib/ldb/common/ldb_pack.c b/lib/ldb/common/ldb_pack.c
index 1f1688a..448c577 100644
--- a/lib/ldb/common/ldb_pack.c
+++ b/lib/ldb/common/ldb_pack.c
@@ -301,6 +301,11 @@ int ldb_unpack_data_only_attr_list_flags(struct ldb_context *ldb,
 		goto failed;
 	}
 
+	
+	if (flags & LDB_UNPACK_DATA_FLAG_NO_ATTRS) {
+		return 0;
+	}
+	
 	if (message->num_elements == 0) {
 		return 0;
 	}
diff --git a/lib/ldb/include/ldb_module.h b/lib/ldb/include/ldb_module.h
index 8ad212a..71b4074 100644
--- a/lib/ldb/include/ldb_module.h
+++ b/lib/ldb/include/ldb_module.h
@@ -518,6 +518,10 @@ int ldb_unpack_data(struct ldb_context *ldb,
  * LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC is also specified.
  *
  * Likewise if LDB_UNPACK_DATA_FLAG_NO_DN is specified, the DN is omitted.
+ *
+ * If LDB_UNPACK_DATA_FLAG_NO_ATTRS is specified, then no attributes
+ * are unpacked or returned.
+ *
  */
 int ldb_unpack_data_only_attr_list_flags(struct ldb_context *ldb,
 					 const struct ldb_val *data,
@@ -530,6 +534,7 @@ int ldb_unpack_data_only_attr_list_flags(struct ldb_context *ldb,
 #define LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC   0x0001
 #define LDB_UNPACK_DATA_FLAG_NO_DN           0x0002
 #define LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC 0x0004
+#define LDB_UNPACK_DATA_FLAG_NO_ATTRS        0x0008
 
 /**
  Forces a specific ldb handle to use the global event context.
diff --git a/lib/ldb/ldb_tdb/ldb_tdb.c b/lib/ldb/ldb_tdb/ldb_tdb.c
index 2ac1967..bc8780a 100644
--- a/lib/ldb/ldb_tdb/ldb_tdb.c
+++ b/lib/ldb/ldb_tdb/ldb_tdb.c
@@ -686,52 +686,34 @@ int ltdb_modify_internal(struct ldb_module *module,
 			 struct ldb_request *req)
 {
 	struct ldb_context *ldb = ldb_module_get_ctx(module);
-	void *data = ldb_module_get_private(module);
-	struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
-	TDB_DATA tdb_key, tdb_data;
-	struct ldb_val ldb_data;
 	struct ldb_message *msg2;
 	unsigned int i, j;
 	int ret = LDB_SUCCESS, idx;
 	struct ldb_control *control_permissive = NULL;
+	TALLOC_CTX *mem_ctx = talloc_new(req);
 
+	if (mem_ctx == NULL) {
+		return ldb_module_oom(module);
+	}
+	
 	if (req) {
 		control_permissive = ldb_request_get_control(req,
 					LDB_CONTROL_PERMISSIVE_MODIFY_OID);
 	}
 
-	tdb_key = ltdb_key(module, msg->dn);
-	if (!tdb_key.dptr) {
-		return LDB_ERR_OTHER;
-	}
-
-	tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
-	if (!tdb_data.dptr) {
-		talloc_free(tdb_key.dptr);
-		return ltdb_err_map(tdb_error(ltdb->tdb));
-	}
-
-	msg2 = ldb_msg_new(tdb_key.dptr);
+	msg2 = ldb_msg_new(mem_ctx);
 	if (msg2 == NULL) {
-		free(tdb_data.dptr);
 		ret = LDB_ERR_OTHER;
 		goto done;
 	}
 
-	ldb_data.data = tdb_data.dptr;
-	ldb_data.length = tdb_data.dsize;
-
-	ret = ldb_unpack_data(ldb_module_get_ctx(module), &ldb_data, msg2);
-	free(tdb_data.dptr);
-	if (ret == -1) {
-		ret = LDB_ERR_OTHER;
+	ret = ltdb_search_dn1(module, msg->dn,
+			      msg2,
+			      LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC);
+	if (ret != LDB_SUCCESS) {
 		goto done;
 	}
 
-	if (!msg2->dn) {
-		msg2->dn = msg->dn;
-	}
-
 	for (i=0; i<msg->num_elements; i++) {
 		struct ldb_message_element *el = &msg->elements[i], *el2;
 		struct ldb_val *vals;
@@ -1018,7 +1000,7 @@ int ltdb_modify_internal(struct ldb_module *module,
 	}
 
 done:
-	talloc_free(tdb_key.dptr);
+	TALLOC_FREE(mem_ctx);
 	return ret;
 }
 
diff --git a/source4/dsdb/tests/python/dirsync.py b/source4/dsdb/tests/python/dirsync.py
index e6c5bba..e302c42 100755
--- a/source4/dsdb/tests/python/dirsync.py
+++ b/source4/dsdb/tests/python/dirsync.py
@@ -30,7 +30,7 @@ import base64
 from ldb import LdbError, SCOPE_BASE
 from ldb import Message, MessageElement, Dn
 from ldb import FLAG_MOD_ADD, FLAG_MOD_DELETE
-from samba.dcerpc import security, misc, drsblobs
+from samba.dcerpc import security, misc, drsblobs, security
 from samba.ndr import ndr_unpack, ndr_pack
 
 from samba.auth import system_session
@@ -79,7 +79,7 @@ class DirsyncBaseTests(samba.tests.TestCase):
         self.ldb_admin = SamDB(ldapshost, credentials=creds, session_info=system_session(lp), lp=lp)
         self.base_dn = self.ldb_admin.domain_dn()
         self.domain_sid = security.dom_sid(self.ldb_admin.get_domain_sid())
-        self.user_pass = "samba123 at AAA"
+        self.user_pass = samba.generate_random_password(12, 16)
         self.configuration_dn = self.ldb_admin.get_config_basedn().get_linearized()
         self.sd_utils = sd_utils.SDUtils(self.ldb_admin)
         #used for anonymous login
@@ -119,7 +119,8 @@ class SimpleDirsyncTests(DirsyncBaseTests):
         self.desc_sddl = self.sd_utils.get_sd_as_sddl(self.base_dn)
 
         user_sid = self.sd_utils.get_object_sid(self.get_user_dn(self.dirsync_user))
-        mod = "(A;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;%s)" % str(user_sid)
+        mod = "(OA;;CR;%s;;%s)" % (security.GUID_DRS_GET_CHANGES,
+                                   str(user_sid))
         self.sd_utils.dacl_add_ace(self.base_dn, mod)
 
         # add admins to the Domain Admins group
diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c
index 096162d..afed782 100644
--- a/source4/rpc_server/drsuapi/getncchanges.c
+++ b/source4/rpc_server/drsuapi/getncchanges.c
@@ -1178,7 +1178,7 @@ static WERROR getncchanges_repl_secret(struct drsuapi_bind_state *b_state,
 	if (b_state->sam_ctx_system == NULL) {
 		/* this operation needs system level access */
 		ctr6->extended_ret = DRSUAPI_EXOP_ERR_ACCESS_DENIED;
-		return WERR_DS_DRA_SOURCE_DISABLED;
+		return WERR_DS_DRA_ACCESS_DENIED;
 	}
 
 	/*
@@ -2043,6 +2043,7 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
 	DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
 	b_state = h->data;
 
+	/* sam_ctx_system is not present for non-administrator users */
 	sam_ctx = b_state->sam_ctx_system?b_state->sam_ctx_system:b_state->sam_ctx;
 
 	invocation_id = *(samdb_ntds_invocation_id(sam_ctx));
@@ -2107,7 +2108,7 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
 	user_sid = &dce_call->conn->auth_state.session_info->security_token->sids[PRIMARY_USER_SID_INDEX];
 
 	/* all clients must have GUID_DRS_GET_CHANGES */
-	werr = drs_security_access_check_nc_root(b_state->sam_ctx,
+	werr = drs_security_access_check_nc_root(sam_ctx,
 						 mem_ctx,
 						 dce_call->conn->auth_state.session_info->security_token,
 						 req10->naming_context,
@@ -2149,7 +2150,7 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
 		return werr;
 	}
 	if (is_gc_pas_request) {
-		werr = drs_security_access_check_nc_root(b_state->sam_ctx,
+		werr = drs_security_access_check_nc_root(sam_ctx,
 							 mem_ctx,
 							 dce_call->conn->auth_state.session_info->security_token,
 							 req10->naming_context,
@@ -2166,7 +2167,7 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
 		return werr;
 	}
 	if (is_secret_request) {
-		werr = drs_security_access_check_nc_root(b_state->sam_ctx,
+		werr = drs_security_access_check_nc_root(sam_ctx,
 							 mem_ctx,
 							 dce_call->conn->auth_state.session_info->security_token,
 							 req10->naming_context,
@@ -2220,8 +2221,8 @@ allowed:
 				 ldb_dn_get_linearized(new_dn),
 				 ldb_dn_get_linearized(getnc_state->ncRoot_dn),
 				 ldb_dn_get_linearized(getnc_state->last_dn)));
-			talloc_free(getnc_state);
-			getnc_state = NULL;
+			TALLOC_FREE(getnc_state);
+			b_state->getncchanges_state = NULL;
 		}
 	}
 
@@ -2234,37 +2235,38 @@ allowed:
 				 ldb_dn_get_linearized(getnc_state->ncRoot_dn),
 				 (ret > 0) ? "older" : "newer",
 				 ldb_dn_get_linearized(getnc_state->last_dn)));
-			talloc_free(getnc_state);
-			getnc_state = NULL;
+			TALLOC_FREE(getnc_state);
+			b_state->getncchanges_state = NULL;
 		}
 	}
 
 	if (getnc_state == NULL) {
-		getnc_state = talloc_zero(b_state, struct drsuapi_getncchanges_state);
-		if (getnc_state == NULL) {
-			return WERR_NOT_ENOUGH_MEMORY;
-		}
-		b_state->getncchanges_state = getnc_state;
-		getnc_state->ncRoot_dn = drs_ObjectIdentifier_to_dn(getnc_state, sam_ctx, ncRoot);
-		if (getnc_state->ncRoot_dn == NULL) {
+		struct ldb_result *res = NULL;
+		const char *attrs[] = {
+			"instanceType",
+			"objectGuID",
+			NULL
+		};
+		uint32_t nc_instanceType;
+		struct ldb_dn *ncRoot_dn;
+
+		ncRoot_dn = drs_ObjectIdentifier_to_dn(mem_ctx, sam_ctx, ncRoot);
+		if (ncRoot_dn == NULL) {
 			return WERR_NOT_ENOUGH_MEMORY;
 		}
 
-		ret = dsdb_find_guid_by_dn(b_state->sam_ctx_system,
-					   getnc_state->ncRoot_dn,
-					   &getnc_state->ncRoot_guid);
+		ret = dsdb_search_dn(sam_ctx, mem_ctx, &res,
+				     ncRoot_dn, attrs,
+				     DSDB_SEARCH_SHOW_DELETED |
+				     DSDB_SEARCH_SHOW_RECYCLED);
 		if (ret != LDB_SUCCESS) {
-			DEBUG(0,(__location__ ": Failed to find GUID of ncRoot_dn %s\n",
-				 ldb_dn_get_linearized(getnc_state->ncRoot_dn)));
-			return WERR_DS_DRA_INTERNAL_ERROR;
+			DBG_WARNING("Failed to find ncRoot_dn %s\n",
+				    ldb_dn_get_linearized(ncRoot_dn));
+			return WERR_DS_DRA_BAD_DN;
 		}
-		ncRoot->guid = getnc_state->ncRoot_guid;
-
-		/* find out if we are to replicate Schema NC */
-		ret = ldb_dn_compare_base(ldb_get_schema_basedn(b_state->sam_ctx),
-					  getnc_state->ncRoot_dn);
-
-		getnc_state->is_schema_nc = (0 == ret);
+		nc_instanceType = ldb_msg_find_attr_as_int(res->msgs[0],
+							   "instanceType",
+							   0);
 
 		if (req10->extended_op != DRSUAPI_EXOP_NONE) {
 			r->out.ctr->ctr6.extended_ret = DRSUAPI_EXOP_ERR_SUCCESS;
@@ -2278,6 +2280,16 @@ allowed:
 		 */
 		switch (req10->extended_op) {
 		case DRSUAPI_EXOP_NONE:
+			if ((nc_instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0) {
+				const char *dn_str
+					= ldb_dn_get_linearized(ncRoot_dn);
+
+				DBG_NOTICE("Rejecting full replication on "
+					   "not NC %s", dn_str);
+
+				return WERR_DS_CANT_FIND_EXPECTED_NC;
+			}
+
 			break;
 		case DRSUAPI_EXOP_FSMO_RID_ALLOC:
 			werr = getncchanges_rid_alloc(b_state, mem_ctx, req10, &r->out.ctr->ctr6, &search_dn);
@@ -2328,6 +2340,27 @@ allowed:
 				 (unsigned)req10->extended_op));
 			return WERR_DS_DRA_NOT_SUPPORTED;
 		}
+
+		/* Initialize the state we'll store over the replication cycle */
+		getnc_state = talloc_zero(b_state, struct drsuapi_getncchanges_state);
+		if (getnc_state == NULL) {
+			return WERR_NOT_ENOUGH_MEMORY;
+		}
+		b_state->getncchanges_state = getnc_state;
+
+		getnc_state->ncRoot_dn = ncRoot_dn;
+		talloc_steal(getnc_state, ncRoot_dn);
+
+		getnc_state->ncRoot_guid = samdb_result_guid(res->msgs[0],
+							     "objectGUID");
+		ncRoot->guid = getnc_state->ncRoot_guid;
+
+		/* find out if we are to replicate Schema NC */
+		ret = ldb_dn_compare_base(ldb_get_schema_basedn(sam_ctx),
+					  ncRoot_dn);
+		getnc_state->is_schema_nc = (0 == ret);
+
+		TALLOC_FREE(res);
 	}
 
 	if (!ldb_dn_validate(getnc_state->ncRoot_dn) ||
@@ -2532,7 +2565,7 @@ allowed:
 		struct dsdb_syntax_ctx syntax_ctx;
 		uint32_t j = 0;
 
-		dsdb_syntax_ctx_init(&syntax_ctx, b_state->sam_ctx, schema);
+		dsdb_syntax_ctx_init(&syntax_ctx, sam_ctx, schema);
 		syntax_ctx.pfm_remote = pfm_remote;
 
 		local_pas = talloc_array(b_state, uint32_t, req10->partial_attribute_set->num_attids);
@@ -2832,7 +2865,7 @@ allowed:
 		DEBUG(3,("UpdateRefs on getncchanges for %s\n",
 			 GUID_string(mem_ctx, &req10->destination_dsa_guid)));
 		ureq.naming_context = ncRoot;
-		ureq.dest_dsa_dns_name = samdb_ntds_msdcs_dns_name(b_state->sam_ctx, mem_ctx,
+		ureq.dest_dsa_dns_name = samdb_ntds_msdcs_dns_name(sam_ctx, mem_ctx,
 								   &req10->destination_dsa_guid);
 		if (!ureq.dest_dsa_dns_name) {
 			return WERR_NOT_ENOUGH_MEMORY;
diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
index 2152573..8aeba34 100755
--- a/source4/selftest/tests.py
+++ b/source4/selftest/tests.py
@@ -853,6 +853,11 @@ for env in ['vampire_dc', 'promoted_dc']:
                            name="samba4.drs.getnc_exop.python(%s)" % env,
                            environ={'DC1': "$DC_SERVER", 'DC2': '$%s_SERVER' % env.upper()},
                            extra_args=['-U$DOMAIN/$DC_USERNAME%$DC_PASSWORD'])
+    planoldpythontestsuite(env, "getnc_unpriv",
+                           extra_path=[os.path.join(samba4srcdir, 'torture/drs/python')],
+                           name="samba4.drs.getnc_unpriv.python(%s)" % env,
+                           environ={'DC1': "$DC_SERVER", 'DC2': '$%s_SERVER' % env.upper()},
+                           extra_args=['-U$DOMAIN/$DC_USERNAME%$DC_PASSWORD'])
     planoldpythontestsuite(env, "linked_attributes_drs",
                            extra_path=[os.path.join(samba4srcdir, 'torture/drs/python')],
                            name="samba4.drs.linked_attributes_drs.python(%s)" % env,
diff --git a/source4/torture/drs/python/drs_base.py b/source4/torture/drs/python/drs_base.py
index b19c51a..e79f076 100644
--- a/source4/torture/drs/python/drs_base.py
+++ b/source4/torture/drs/python/drs_base.py
@@ -32,7 +32,7 @@ from samba import dsdb
 from samba.dcerpc import drsuapi, misc, drsblobs, security
 from samba.ndr import ndr_unpack, ndr_pack
 from samba.drs_utils import drs_DsBind
-
+from samba import gensec
 from ldb import (
     SCOPE_BASE,
     Message,
@@ -49,6 +49,8 @@ class DrsBaseTestCase(SambaToolCmdTest):
 
     def setUp(self):
         super(DrsBaseTestCase, self).setUp()
+        creds = self.get_credentials()
+        creds.set_gensec_features(creds.get_gensec_features() | gensec.FEATURE_SEAL)
 
         # connect to DCs
         url_dc = samba.tests.env_get_var_value("DC1")
@@ -450,6 +452,13 @@ class DrsBaseTestCase(SambaToolCmdTest):
         (drs_handle, supported_extensions) = drs_DsBind(drs)
         return (drs, drs_handle)
 
+    def get_partial_attribute_set(self, attids=[drsuapi.DRSUAPI_ATTID_objectClass]):
+        partial_attribute_set = drsuapi.DsPartialAttributeSet()
+        partial_attribute_set.attids = attids
+        partial_attribute_set.num_attids = len(attids)
+        return partial_attribute_set
+
+
 
 class AbstractLink:
     def __init__(self, attid, flags, identifier, targetGUID,
diff --git a/source4/torture/drs/python/getnc_exop.py b/source4/torture/drs/python/getnc_exop.py
index caa7826..37e5333 100644
--- a/source4/torture/drs/python/getnc_exop.py
+++ b/source4/torture/drs/python/getnc_exop.py
@@ -35,6 +35,7 @@ from drs_base import AbstractLink
 
 import samba.tests
 import random
+from samba import werror, WERRORError
 
 import ldb
 from ldb import SCOPE_BASE
@@ -193,6 +194,29 @@ class DrsReplicaSyncTestCase(drs_base.DrsBaseTestCase):
         (level, ctr) = self.drs.DsGetNCChanges(self.drs_handle, 8, req8)
         self._check_ctr6(ctr, [ou2])
 
+    def test_do_full_repl_on_ou(self):
+        """
+        Make sure that a full replication on a not-an-nc fails with
+        the right error code
+        """
+
+        non_nc_ou = "OU=not-an-NC,%s" % self.ou
+        self.ldb_dc1.add({
+            "dn": non_nc_ou,
+            "objectclass": "organizationalUnit"
+            })
+        req8 = self._exop_req8(dest_dsa=None,
+                               invocation_id=self.ldb_dc1.get_invocation_id(),
+                               nc_dn_str=non_nc_ou,
+                               exop=drsuapi.DRSUAPI_EXOP_NONE,
+                               replica_flags=drsuapi.DRSUAPI_DRS_WRIT_REP)
+
+        try:
+            (level, ctr) = self.drs.DsGetNCChanges(self.drs_handle, 8, req8)
+            self.fail("Expected DsGetNCChanges to fail with WERR_DS_CANT_FIND_EXPECTED_NC")
+        except WERRORError as (enum, estr):
+            self.assertEquals(enum, werror.WERR_DS_CANT_FIND_EXPECTED_NC)
+
     def test_link_utdv_hwm(self):
         """Test verify the DRS_GET_ANC behavior."""
 
@@ -559,12 +583,6 @@ class DrsReplicaPrefixMapTestCase(drs_base.DrsBaseTestCase):
             if enum == ldb.ERR_NO_SUCH_OBJECT:
                 pass
 
-    def get_partial_attribute_set(self, attids=[drsuapi.DRSUAPI_ATTID_objectClass]):
-        partial_attribute_set = drsuapi.DsPartialAttributeSet()
-        partial_attribute_set.attids = attids
-        partial_attribute_set.num_attids = len(attids)
-        return partial_attribute_set
-
     def test_missing_prefix_map_dsa(self):
         partial_attribute_set = self.get_partial_attribute_set()
 
diff --git a/source4/torture/drs/python/getnc_unpriv.py b/source4/torture/drs/python/getnc_unpriv.py
new file mode 100644
index 0000000..8b242b1
--- /dev/null
+++ b/source4/torture/drs/python/getnc_unpriv.py
@@ -0,0 +1,305 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Tests replication scenarios with different user privileges.
+# We want to test every replication scenario we can think of against:
+# - users with only GET_CHANGES privileges
+# - users with only GET_ALL_CHANGES privileges
+# - users with both GET_CHANGES and GET_ALL_CHANGES privileges
+# - users with no privileges
+#
+# Copyright (C) Kamen Mazdrashki <kamenim at samba.org> 2011
+# Copyright (C) Andrew Bartlett <abartlet at samba.org> 2017
+#
+# 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_unpriv -U"$DOMAIN/$DC_USERNAME"%"$DC_PASSWORD"
+#
+
+import drs_base
+import samba.tests
+from samba import werror, WERRORError
+
+from samba import sd_utils
+import ldb
+from ldb import SCOPE_BASE
+import random
+
+from samba.dcerpc import drsuapi, security
+from samba.credentials import DONT_USE_KERBEROS
+
+class DrsReplicaSyncUnprivTestCase(drs_base.DrsBaseTestCase):
+    """Confirm the behaviour of DsGetNCChanges for unprivileged users"""
+
+    def setUp(self):
+        super(DrsReplicaSyncUnprivTestCase, self).setUp()
+        self.get_changes_user = "get-changes-user"
+        self.base_dn = self.ldb_dc1.get_default_basedn()
+        self.user_pass = samba.generate_random_password(12, 16)
+
+        # add some randomness to the test OU. (Deletion of the last test's


-- 
Samba Shared Repository



More information about the samba-cvs mailing list