[SCM] Samba Shared Repository - branch master updated

Stefan Metzmacher metze at samba.org
Wed Jun 12 03:54:02 MDT 2013


The branch, master has been updated
       via  68f8f4e dsdb-tests ldap.py: Add test for usn behaviour on certain changes
       via  51298d3 dsdb-tests ldap.py: Fix quoting of print statements
       via  96980f7 dsdb: Fix behaviour for when to update the USN when there is no change
       via  e461ff5 dsdb: Allow dsdb_find_dn_by_guid to show deleted DNs
       via  eec29db python samba-tool drs: Correctly print KCC references to deleted servers
      from  3e66cb7 Fix bug #9932 - Currently the maximum number of aces in an SD is limited to 1000, but Microsoft supports around 1800.

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


- Log -----------------------------------------------------------------
commit 68f8f4ec4dbbdb20c4c51a6059535b5ef669373f
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Fri May 31 14:14:54 2013 +1000

    dsdb-tests ldap.py: Add test for usn behaviour on certain changes
    
    This probes when the usn is updated, and when it is not.
    
    Andrew Bartlett
    
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    
    Autobuild-User(master): Stefan Metzmacher <metze at samba.org>
    Autobuild-Date(master): Wed Jun 12 11:54:01 CEST 2013 on sn-devel-104

commit 51298d33dd28e034967db38312e0129935a27a66
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Fri May 31 11:15:51 2013 +1000

    dsdb-tests ldap.py: Fix quoting of print statements
    
    While python didn't mind (oddly) it really confused my editor.
    
    Andrew Bartlett
    
    Reviewed-by: Stefan Metzmacher <metze at samba.org>

commit 96980f7c04cc4226ed109654025b8254921f8d58
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Fri May 31 14:16:02 2013 +1000

    dsdb: Fix behaviour for when to update the USN when there is no change
    
    This handles deletions and replacements with no value, or with an
    exactly specified value, as well as modifies.
    
    Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
    
    Andrew Bartlett
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>

commit e461ff530046199b7e647b81d6dfb2746f68b0d7
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Mon Jun 10 12:22:40 2013 +1000

    dsdb: Allow dsdb_find_dn_by_guid to show deleted DNs
    
    This helps us in the KCC as we need to return the deleted DN for the GUID
    in DsReplicaGetInfo calls (tested for deleted servers against Windows 2008R2).
    
    Andrew Bartlett
    
    Reviewed-by: Stefan Metzmacher <metze at samba.org>

commit eec29db7c237c70732f94e33147c960fa8df39fb
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Mon Jun 10 11:43:18 2013 +1000

    python samba-tool drs: Correctly print KCC references to deleted servers
    
    Tested against Windows 2008R2, presumably before the KCC ran.
    
    Andrew Bartlett
    
    Reviewed-by: Stefan Metzmacher <metze at samba.org>

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

Summary of changes:
 python/samba/netcmd/drs.py                      |   15 ++-
 source4/dsdb/common/util.c                      |    6 +-
 source4/dsdb/kcc/kcc_connection.c               |    4 +-
 source4/dsdb/kcc/kcc_drs_replica_info.c         |   10 +-
 source4/dsdb/repl/drepl_partitions.c            |    2 +-
 source4/dsdb/samdb/ldb_modules/repl_meta_data.c |   34 +++-
 source4/dsdb/tests/python/ldap.py               |  229 ++++++++++++++++-------
 source4/rpc_server/drsuapi/getncchanges.c       |    4 +-
 8 files changed, 222 insertions(+), 82 deletions(-)


Changeset truncated at 500 lines:

diff --git a/python/samba/netcmd/drs.py b/python/samba/netcmd/drs.py
index ff8d830..de78ac7 100644
--- a/python/samba/netcmd/drs.py
+++ b/python/samba/netcmd/drs.py
@@ -170,10 +170,19 @@ class cmd_drs_showrepl(Command):
 
         self.message("==== KCC CONNECTION OBJECTS ====\n")
         for c in conn:
-            c_rdn, sep, c_server_dn = c['fromServer'][0].partition(',')
-            c_server_res = self.samdb.search(base=c_server_dn, scope=ldb.SCOPE_BASE, attrs=["dnsHostName"])
-            c_server_dns = c_server_res[0]["dnsHostName"][0]
             self.message("Connection --")
+
+            c_rdn, sep, c_server_dn = c['fromServer'][0].partition(',')
+            try:
+                c_server_res = self.samdb.search(base=c_server_dn, scope=ldb.SCOPE_BASE, attrs=["dnsHostName"])
+                c_server_dns = c_server_res[0]["dnsHostName"][0]
+            except ldb.LdbError, (errno, _):
+                if errno == ldb.ERR_NO_SUCH_OBJECT:
+                    self.message("\tWARNING: Connection to DELETED server!")
+                c_server_dns = ""
+            except KeyError:
+                c_server_dns = ""
+
             self.message("\tConnection name: %s" % c['name'][0])
             self.message("\tEnabled        : %s" % attr_default(c, 'enabledConnection', 'TRUE'))
             self.message("\tServer DNS name : %s" % c_server_dns)
diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c
index 8e40776..7a243c3 100644
--- a/source4/dsdb/common/util.c
+++ b/source4/dsdb/common/util.c
@@ -2458,7 +2458,9 @@ struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
  */
 int dsdb_find_dn_by_guid(struct ldb_context *ldb, 
 			 TALLOC_CTX *mem_ctx,
-			 const struct GUID *guid, struct ldb_dn **dn)
+			 const struct GUID *guid,
+			 uint32_t dsdb_flags,
+			 struct ldb_dn **dn)
 {
 	int ret;
 	struct ldb_result *res;
@@ -2472,7 +2474,7 @@ int dsdb_find_dn_by_guid(struct ldb_context *ldb,
 	ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
 			  DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
 			  DSDB_SEARCH_SHOW_EXTENDED_DN |
-			  DSDB_SEARCH_ONE_ONLY,
+			  DSDB_SEARCH_ONE_ONLY | dsdb_flags,
 			  "objectGUID=%s", guid_str);
 	talloc_free(guid_str);
 	if (ret != LDB_SUCCESS) {
diff --git a/source4/dsdb/kcc/kcc_connection.c b/source4/dsdb/kcc/kcc_connection.c
index ea63833..f85ed13 100644
--- a/source4/dsdb/kcc/kcc_connection.c
+++ b/source4/dsdb/kcc/kcc_connection.c
@@ -70,7 +70,7 @@ static int kccsrv_add_connection(struct kccsrv_service *s,
 		ret = LDB_ERR_INVALID_DN_SYNTAX;
 		goto done;
 	}
-	ret = dsdb_find_dn_by_guid(s->samdb, tmp_ctx, &conn->dsa_guid, &server_dn);
+	ret = dsdb_find_dn_by_guid(s->samdb, tmp_ctx, &conn->dsa_guid, 0, &server_dn);
 	if (ret != LDB_SUCCESS) {
 		DEBUG(0, ("failed to find fromServer DN '%s'\n",
 			  GUID_string(tmp_ctx, &conn->dsa_guid)));
@@ -111,7 +111,7 @@ static int kccsrv_delete_connection(struct kccsrv_service *s,
 	int ret;
 
 	tmp_ctx = talloc_new(s);
-	ret = dsdb_find_dn_by_guid(s->samdb, tmp_ctx, &conn->obj_guid, &dn);
+	ret = dsdb_find_dn_by_guid(s->samdb, tmp_ctx, &conn->obj_guid, 0, &dn);
 	if (ret != LDB_SUCCESS) {
 		DEBUG(0, ("failed to find nTDSConnection's DN: %s\n",
 			  ldb_strerror(ret)));
diff --git a/source4/dsdb/kcc/kcc_drs_replica_info.c b/source4/dsdb/kcc/kcc_drs_replica_info.c
index 7aa7f5a..ac22312 100644
--- a/source4/dsdb/kcc/kcc_drs_replica_info.c
+++ b/source4/dsdb/kcc/kcc_drs_replica_info.c
@@ -533,6 +533,7 @@ static WERROR fill_neighbor_from_repsFrom(TALLOC_CTX *mem_ctx,
 	neigh->source_dsa_obj_guid = reps_from->source_dsa_obj_guid;
 
 	ret = dsdb_find_dn_by_guid(samdb, mem_ctx, &reps_from->source_dsa_obj_guid,
+				   DSDB_SEARCH_SHOW_RECYCLED,
 				   &source_dsa_dn);
 
 	if (ret != LDB_SUCCESS) {
@@ -544,13 +545,15 @@ static WERROR fill_neighbor_from_repsFrom(TALLOC_CTX *mem_ctx,
 	neigh->source_dsa_obj_dn = ldb_dn_get_linearized(source_dsa_dn);
 	neigh->naming_context_dn = ldb_dn_get_linearized(nc_dn);
 
-	if (dsdb_find_guid_by_dn(samdb, nc_dn, &neigh->naming_context_obj_guid)
+	if (dsdb_find_guid_by_dn(samdb, nc_dn,
+				 &neigh->naming_context_obj_guid)
 			!= LDB_SUCCESS) {
 		return WERR_DS_DRA_INTERNAL_ERROR;
 	}
 
 	if (!GUID_all_zero(&reps_from->transport_guid)) {
 		ret = dsdb_find_dn_by_guid(samdb, mem_ctx, &reps_from->transport_guid,
+					   DSDB_SEARCH_SHOW_RECYCLED,
 					   &transport_obj_dn);
 		if (ret != LDB_SUCCESS) {
 			return WERR_DS_DRA_INTERNAL_ERROR;
@@ -668,7 +671,10 @@ static WERROR fill_neighbor_from_repsTo(TALLOC_CTX *mem_ctx,
 	neigh->last_attempt = reps_to->last_attempt;
 	neigh->source_dsa_obj_guid = reps_to->source_dsa_obj_guid;
 
-	ret = dsdb_find_dn_by_guid(samdb, mem_ctx, &reps_to->source_dsa_obj_guid, &source_dsa_dn);
+	ret = dsdb_find_dn_by_guid(samdb, mem_ctx,
+				   &reps_to->source_dsa_obj_guid,
+				   DSDB_SEARCH_SHOW_RECYCLED,
+				   &source_dsa_dn);
 	if (ret != LDB_SUCCESS) {
 		DEBUG(0,(__location__ ": Failed to find DN for neighbor GUID %s\n",
 			 GUID_string(mem_ctx, &reps_to->source_dsa_obj_guid)));
diff --git a/source4/dsdb/repl/drepl_partitions.c b/source4/dsdb/repl/drepl_partitions.c
index 2a16a45..4c5dde2 100644
--- a/source4/dsdb/repl/drepl_partitions.c
+++ b/source4/dsdb/repl/drepl_partitions.c
@@ -172,7 +172,7 @@ NTSTATUS dreplsrv_get_target_principal(struct dreplsrv_service *s,
 	tmp_ctx = talloc_new(mem_ctx);
 
 	/* we need to find their hostname */
-	ret = dsdb_find_dn_by_guid(s->samdb, tmp_ctx, &rft->source_dsa_obj_guid, &ntds_dn);
+	ret = dsdb_find_dn_by_guid(s->samdb, tmp_ctx, &rft->source_dsa_obj_guid, 0, &ntds_dn);
 	if (ret != LDB_SUCCESS) {
 		talloc_free(tmp_ctx);
 		/* its OK for their NTDSDSA DN not to be in our database */
diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
index 24dcc6f..0f2aa58 100644
--- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
+++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
@@ -1086,6 +1086,7 @@ static int replmd_update_rpmd_element(struct ldb_context *ldb,
 	uint32_t i;
 	const struct dsdb_attribute *a;
 	struct replPropertyMetaData1 *md1;
+	bool may_skip = false;
 
 	a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
 	if (a == NULL) {
@@ -1104,13 +1105,34 @@ static int replmd_update_rpmd_element(struct ldb_context *ldb,
 		return LDB_SUCCESS;
 	}
 
-	/* if the attribute's value haven't changed then return LDB_SUCCESS
-	 * Unless we have the provision control or if the attribute is
-	 * interSiteTopologyGenerator as this page explain: http://support.microsoft.com/kb/224815
-	 * this attribute is periodicaly written by the DC responsible for the intersite generation
-	 * in a given site
+	/*
+	 * if the attribute's value haven't changed, and this isn't
+	 * just a delete of everything then return LDB_SUCCESS Unless
+	 * we have the provision control or if the attribute is
+	 * interSiteTopologyGenerator as this page explain:
+	 * http://support.microsoft.com/kb/224815 this attribute is
+	 * periodicaly written by the DC responsible for the intersite
+	 * generation in a given site
+	 *
+	 * Unchanged could be deleting or replacing an already-gone
+	 * thing with an unconstrained delete/empty replace or a
+	 * replace with the same value, but not an add with the same
+	 * value because that could be about adding a duplicate (which
+	 * is for someone else to error out on).
 	 */
-	if (old_el != NULL && ldb_msg_element_compare(el, old_el) == 0) {
+	if (old_el != NULL && ldb_msg_element_equal_ordered(el, old_el)) {
+		if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
+			may_skip = true;
+		}
+	} else if (old_el == NULL && el->num_values == 0) {
+		if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
+			may_skip = true;
+		} else if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
+			may_skip = true;
+		}
+	}
+
+	if (may_skip) {
 		if (strcmp(el->name, "interSiteTopologyGenerator") != 0 &&
 		    !ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
 			/*
diff --git a/source4/dsdb/tests/python/ldap.py b/source4/dsdb/tests/python/ldap.py
index 5ca4c26..0a95b2a 100755
--- a/source4/dsdb/tests/python/ldap.py
+++ b/source4/dsdb/tests/python/ldap.py
@@ -712,7 +712,7 @@ class BasicTests(samba.tests.TestCase):
 
     def test_attribute_ranges(self):
         """Test attribute ranges"""
-        print "Test attribute ranges"""
+        print "Test attribute ranges"
 
         # Too short (min. 1)
         try:
@@ -833,7 +833,7 @@ class BasicTests(samba.tests.TestCase):
 
     def test_instanceType(self):
         """Tests the 'instanceType' attribute"""
-        print "Tests the 'instanceType' attribute"""
+        print "Tests the 'instanceType' attribute"
 
         # The instance type is single-valued
         try:
@@ -902,7 +902,7 @@ class BasicTests(samba.tests.TestCase):
 
     def test_distinguished_name(self):
         """Tests the 'distinguishedName' attribute"""
-        print "Tests the 'distinguishedName' attribute"""
+        print "Tests the 'distinguishedName' attribute"
 
         # The "dn" shortcut isn't supported
         m = Message()
@@ -982,7 +982,7 @@ class BasicTests(samba.tests.TestCase):
 
     def test_rdn_name(self):
         """Tests the RDN"""
-        print "Tests the RDN"""
+        print "Tests the RDN"
 
         # Search
 
@@ -1177,7 +1177,7 @@ objectClass: container
 
     def test_rename(self):
         """Tests the rename operation"""
-        print "Tests the rename operations"""
+        print "Tests the rename operations"
 
         try:
             # cannot rename to be a child of itself
@@ -1288,7 +1288,7 @@ objectClass: container
 
     def test_rename_twice(self):
         """Tests the rename operation twice - this corresponds to a past bug"""
-        print "Tests the rename twice operation"""
+        print "Tests the rename twice operation"
 
         self.ldb.add({
              "dn": "cn=ldaptestuser5,cn=users," + self.base_dn,
@@ -1327,60 +1327,6 @@ objectGUID: bd3480c9-58af-4cd8-92df-bc4a18b6e44d
             "dn": "cn=ldaptestcontainer," + self.base_dn,
             "objectClass": "container" })
 
-        res = ldb.search("cn=ldaptestcontainer," + self.base_dn,
-                         scope=SCOPE_BASE,
-                         attrs=["objectGUID", "uSNCreated", "uSNChanged", "whenCreated", "whenChanged"])
-        self.assertTrue(len(res) == 1)
-        self.assertTrue("objectGUID" in res[0])
-        self.assertTrue("uSNCreated" in res[0])
-        self.assertTrue("uSNChanged" in res[0])
-        self.assertTrue("whenCreated" in res[0])
-        self.assertTrue("whenChanged" in res[0])
-
-        delete_force(self.ldb, "cn=ldaptestcontainer," + self.base_dn)
-
-        # All the following attributes are specificable on add operations
-        self.ldb.add({
-            "dn": "cn=ldaptestcontainer," + self.base_dn,
-            "objectClass": "container",
-            "uSNCreated" : "1",
-            "uSNChanged" : "1",
-            "whenCreated": timestring(long(time.time())),
-            "whenChanged": timestring(long(time.time())) })
-
-        res = ldb.search("cn=ldaptestcontainer," + self.base_dn,
-                         scope=SCOPE_BASE,
-                         attrs=["objectGUID", "uSNCreated", "uSNChanged", "whenCreated", "whenChanged"])
-        self.assertTrue(len(res) == 1)
-        self.assertTrue("objectGUID" in res[0])
-        self.assertTrue("uSNCreated" in res[0])
-        self.assertFalse(res[0]["uSNCreated"][0] == "1") # these are corrected
-        self.assertTrue("uSNChanged" in res[0])
-        self.assertFalse(res[0]["uSNChanged"][0] == "1") # these are corrected
-
-        delete_force(self.ldb, "cn=ldaptestcontainer," + self.base_dn)
-
-        # All this attributes are specificable on add operations
-        self.ldb.add({
-            "dn": "cn=ldaptestcontainer," + self.base_dn,
-            "objectclass": "container",
-            "uSNCreated" : "1",
-            "uSNChanged" : "1",
-            "whenCreated": timestring(long(time.time())),
-            "whenChanged": timestring(long(time.time())) })
-
-        res = ldb.search("cn=ldaptestcontainer," + self.base_dn,
-                         scope=SCOPE_BASE,
-                         attrs=["objectGUID", "uSNCreated", "uSNChanged", "whenCreated", "whenChanged"])
-        self.assertTrue(len(res) == 1)
-        self.assertTrue("objectGUID" in res[0])
-        self.assertTrue("uSNCreated" in res[0])
-        self.assertFalse(res[0]["uSNCreated"][0] == "1") # these are corrected
-        self.assertTrue("uSNChanged" in res[0])
-        self.assertFalse(res[0]["uSNChanged"][0] == "1") # these are corrected
-        self.assertTrue("whenCreated" in res[0])
-        self.assertTrue("whenChanged" in res[0])
-
         # The objectGUID cannot directly be changed
         try:
             self.ldb.modify_ldif("""
@@ -1469,6 +1415,161 @@ objectGUID: bd3480c9-58af-4cd8-92df-bc4a18b6e44d
         delete_force(self.ldb, "cn=parentguidtest,cn=testotherusers," + self.base_dn)
         delete_force(self.ldb, "cn=testotherusers," + self.base_dn)
 
+    def test_usnChanged(self):
+        """Test usnChanged behaviour"""
+        print "Testing usnChanged behaviour\n"
+
+        self.ldb.add({
+            "dn": "cn=ldaptestcontainer," + self.base_dn,
+            "objectClass": "container" })
+
+        res = ldb.search("cn=ldaptestcontainer," + self.base_dn,
+                         scope=SCOPE_BASE,
+                         attrs=["objectGUID", "uSNCreated", "uSNChanged", "whenCreated", "whenChanged", "description"])
+        self.assertTrue(len(res) == 1)
+        self.assertFalse("description" in res[0])
+        self.assertTrue("objectGUID" in res[0])
+        self.assertTrue("uSNCreated" in res[0])
+        self.assertTrue("uSNChanged" in res[0])
+        self.assertTrue("whenCreated" in res[0])
+        self.assertTrue("whenChanged" in res[0])
+
+        delete_force(self.ldb, "cn=ldaptestcontainer," + self.base_dn)
+
+        # All this attributes are specificable on add operations
+        self.ldb.add({
+            "dn": "cn=ldaptestcontainer," + self.base_dn,
+            "objectclass": "container",
+            "uSNCreated" : "1",
+            "uSNChanged" : "1",
+            "whenCreated": timestring(long(time.time())),
+            "whenChanged": timestring(long(time.time())) })
+
+        res = ldb.search("cn=ldaptestcontainer," + self.base_dn,
+                         scope=SCOPE_BASE,
+                         attrs=["objectGUID", "uSNCreated", "uSNChanged", "whenCreated", "whenChanged", "description"])
+        self.assertTrue(len(res) == 1)
+        self.assertFalse("description" in res[0])
+        self.assertTrue("objectGUID" in res[0])
+        self.assertTrue("uSNCreated" in res[0])
+        self.assertFalse(res[0]["uSNCreated"][0] == "1") # these are corrected
+        self.assertTrue("uSNChanged" in res[0])
+        self.assertFalse(res[0]["uSNChanged"][0] == "1") # these are corrected
+        self.assertTrue("whenCreated" in res[0])
+        self.assertTrue("whenChanged" in res[0])
+
+        ldb.modify_ldif("""
+dn: cn=ldaptestcontainer,""" + self.base_dn + """
+changetype: modify
+replace: description
+""")
+
+        res2 = ldb.search("cn=ldaptestcontainer," + self.base_dn,
+                         scope=SCOPE_BASE,
+                         attrs=["uSNCreated", "uSNChanged", "description"])
+        self.assertTrue(len(res) == 1)
+        self.assertFalse("description" in res2[0])
+        self.assertEqual(res[0]["usnCreated"], res2[0]["usnCreated"])
+        self.assertEqual(res[0]["usnCreated"], res2[0]["usnChanged"])
+        self.assertEqual(res[0]["usnChanged"], res2[0]["usnChanged"])
+
+        ldb.modify_ldif("""
+dn: cn=ldaptestcontainer,""" + self.base_dn + """
+changetype: modify
+replace: description
+description: test
+""")
+
+        res3 = ldb.search("cn=ldaptestcontainer," + self.base_dn,
+                         scope=SCOPE_BASE,
+                         attrs=["uSNCreated", "uSNChanged", "description"])
+        self.assertTrue(len(res) == 1)
+        self.assertTrue("description" in res3[0])
+        self.assertEqual("test", str(res3[0]["description"][0]))
+        self.assertEqual(res[0]["usnCreated"], res3[0]["usnCreated"])
+        self.assertNotEqual(res[0]["usnCreated"], res3[0]["usnChanged"])
+        self.assertNotEqual(res[0]["usnChanged"], res3[0]["usnChanged"])
+
+        ldb.modify_ldif("""
+dn: cn=ldaptestcontainer,""" + self.base_dn + """
+changetype: modify
+replace: description
+description: test
+""")
+
+        res4 = ldb.search("cn=ldaptestcontainer," + self.base_dn,
+                         scope=SCOPE_BASE,
+                         attrs=["uSNCreated", "uSNChanged", "description"])
+        self.assertTrue(len(res) == 1)
+        self.assertTrue("description" in res4[0])
+        self.assertEqual("test", str(res4[0]["description"][0]))
+        self.assertEqual(res[0]["usnCreated"], res4[0]["usnCreated"])
+        self.assertNotEqual(res3[0]["usnCreated"], res4[0]["usnChanged"])
+        self.assertEqual(res3[0]["usnChanged"], res4[0]["usnChanged"])
+
+        ldb.modify_ldif("""
+dn: cn=ldaptestcontainer,""" + self.base_dn + """
+changetype: modify
+replace: description
+description: test2
+""")
+
+        res5 = ldb.search("cn=ldaptestcontainer," + self.base_dn,
+                         scope=SCOPE_BASE,
+                         attrs=["uSNCreated", "uSNChanged", "description"])
+        self.assertTrue(len(res) == 1)
+        self.assertTrue("description" in res5[0])
+        self.assertEqual("test2", str(res5[0]["description"][0]))
+        self.assertEqual(res[0]["usnCreated"], res5[0]["usnCreated"])
+        self.assertNotEqual(res3[0]["usnChanged"], res5[0]["usnChanged"])
+
+        ldb.modify_ldif("""
+dn: cn=ldaptestcontainer,""" + self.base_dn + """
+changetype: modify
+delete: description
+description: test2
+""")
+
+        res6 = ldb.search("cn=ldaptestcontainer," + self.base_dn,
+                         scope=SCOPE_BASE,
+                         attrs=["uSNCreated", "uSNChanged", "description"])
+        self.assertTrue(len(res) == 1)
+        self.assertFalse("description" in res6[0])
+        self.assertEqual(res[0]["usnCreated"], res6[0]["usnCreated"])
+        self.assertNotEqual(res5[0]["usnChanged"], res6[0]["usnChanged"])
+
+        ldb.modify_ldif("""
+dn: cn=ldaptestcontainer,""" + self.base_dn + """
+changetype: modify
+add: description
+description: test3
+""")
+
+        res7 = ldb.search("cn=ldaptestcontainer," + self.base_dn,
+                         scope=SCOPE_BASE,
+                         attrs=["uSNCreated", "uSNChanged", "description"])
+        self.assertTrue(len(res) == 1)
+        self.assertTrue("description" in res7[0])
+        self.assertEqual("test3", str(res7[0]["description"][0]))
+        self.assertEqual(res[0]["usnCreated"], res7[0]["usnCreated"])
+        self.assertNotEqual(res6[0]["usnChanged"], res7[0]["usnChanged"])
+
+        ldb.modify_ldif("""
+dn: cn=ldaptestcontainer,""" + self.base_dn + """
+changetype: modify
+delete: description
+""")
+
+        res8 = ldb.search("cn=ldaptestcontainer," + self.base_dn,
+                         scope=SCOPE_BASE,
+                         attrs=["uSNCreated", "uSNChanged", "description"])
+        self.assertTrue(len(res) == 1)
+        self.assertFalse("description" in res8[0])
+        self.assertEqual(res[0]["usnCreated"], res8[0]["usnCreated"])
+        self.assertNotEqual(res7[0]["usnChanged"], res8[0]["usnChanged"])
+
+        delete_force(self.ldb, "cn=ldaptestcontainer," + self.base_dn)
+
     def test_groupType_int32(self):
         """Test groupType (int32) behaviour (should appear to be casted to a 32 bit signed integer before comparsion)"""
         print "Testing groupType (int32) behaviour\n"
@@ -1576,7 +1677,7 @@ objectGUID: bd3480c9-58af-4cd8-92df-bc4a18b6e44d
 
     def test_wkguid(self):
         """Test Well known GUID behaviours (including DN+Binary)"""
-        print "Test Well known GUID behaviours (including DN+Binary)"""
+        print "Test Well known GUID behaviours (including DN+Binary)"
 
         res = self.ldb.search(base=("<WKGUID=ab1d30f3768811d1aded00c04fd8d5cd,%s>" % self.base_dn), scope=SCOPE_BASE, attrs=[])
         self.assertEquals(len(res), 1)
@@ -1593,7 +1694,7 @@ objectGUID: bd3480c9-58af-4cd8-92df-bc4a18b6e44d
 
     def test_subschemasubentry(self):
         """Test subSchemaSubEntry appears when requested, but not when not requested"""
-        print "Test subSchemaSubEntry"""
+        print "Test subSchemaSubEntry"
 
         res = self.ldb.search(base=self.base_dn, scope=SCOPE_BASE, attrs=["subSchemaSubEntry"])
         self.assertEquals(len(res), 1)
@@ -2720,7 +2821,7 @@ nTSecurityDescriptor:: """ + desc_base64
 
     def test_dsheuristics(self):
         """Tests the 'dSHeuristics' attribute"""
-        print "Tests the 'dSHeuristics' attribute"""
+        print "Tests the 'dSHeuristics' attribute"
 
         # Get the current value to restore it later
         dsheuristics = self.ldb.get_dsheuristics()
@@ -2763,7 +2864,7 @@ nTSecurityDescriptor:: """ + desc_base64
 
     def test_operational(self):
         """Tests operational attributes"""
-        print "Tests operational attributes"""
+        print "Tests operational attributes"
 
         res = self.ldb.search(self.base_dn, scope=SCOPE_BASE,
                               attrs=["createTimeStamp", "modifyTimeStamp",
diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c
index 219ddbc..5ee87cb 100644
--- a/source4/rpc_server/drsuapi/getncchanges.c


-- 
Samba Shared Repository


More information about the samba-cvs mailing list