tests/dnsserver: Check security descriptors
authorGarming Sam <garming@catalyst.net.nz>
Mon, 5 Dec 2016 22:00:17 +0000 (11:00 +1300)
committerGarming Sam <garming@samba.org>
Mon, 12 Dec 2016 04:00:18 +0000 (05:00 +0100)
These tests discover that there are some discrepancies between Windows and Samba.
Although there are failures, they do not appear to be critical, however
some of the SD differences will be important for 2012 support.

Signed-off-by: Garming Sam <garming@catalyst.net.nz>
Pair-programmed-with: Bob Campbell <bobcampbell@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
python/samba/tests/dcerpc/dnsserver.py
selftest/knownfail

index ae19c24520ccfc7441ce5c61cbf566076b0e7225..960206633bea0a9e47e2d0e3b5c74bd885f94822 100644 (file)
@@ -23,9 +23,10 @@ import ldb
 from samba.auth import system_session
 from samba.samdb import SamDB
 from samba.ndr import ndr_unpack, ndr_pack
-from samba.dcerpc import dnsp, dnsserver
+from samba.dcerpc import dnsp, dnsserver, security
 from samba.tests import RpcInterfaceTestCase, env_get_var_value
 from samba.netcmd.dns import ARecord, AAAARecord, PTRRecord, CNameRecord, NSRecord, MXRecord, SRVRecord, TXTRecord
+from samba import sd_utils, descriptor
 
 class DnsserverTests(RpcInterfaceTestCase):
 
@@ -856,3 +857,203 @@ class DnsserverTests(RpcInterfaceTestCase):
                                         select_flags,
                                         None,
                                         None)
+
+    # The following tests do not pass against Samba because the owner and
+    # group are not consistent with Windows, as well as some ACEs.
+    #
+    # The following ACE are also required for 2012R2:
+    #
+    # (OA;CIIO;WP;ea1b7b93-5e48-46d5-bc6c-4df4fda78a35;bf967a86-0de6-11d0-a285-00aa003049e2;PS)
+    # (OA;OICI;RPWP;3f78c3e5-f79a-46bd-a0b8-9d18116ddc79;;PS)"
+    #
+    # [TPM + Allowed-To-Act-On-Behalf-Of-Other-Identity]
+    def test_security_descriptor_msdcs_zone(self):
+        """
+        Make sure that security descriptors of the msdcs zone is
+        as expected.
+        """
+
+        zones = self.samdb.search(base="DC=ForestDnsZones,%s" % self.samdb.get_default_basedn(),
+                                  scope=ldb.SCOPE_SUBTREE,
+                                  expression="(&(objectClass=dnsZone)(name=_msdcs*))",
+                                  attrs=["nTSecurityDescriptor", "objectClass"])
+        self.assertEqual(len(zones), 1)
+        self.assertTrue("nTSecurityDescriptor" in zones[0])
+        tmp = zones[0]["nTSecurityDescriptor"][0]
+        utils = sd_utils.SDUtils(self.samdb)
+        sd = ndr_unpack(security.descriptor, tmp)
+
+        domain_sid = security.dom_sid(self.samdb.get_domain_sid())
+
+        res = self.samdb.search(base=self.samdb.get_default_basedn(), scope=ldb.SCOPE_SUBTREE,
+                                expression="(sAMAccountName=DnsAdmins)",
+                                attrs=["objectSid"])
+
+        dns_admin = str(ndr_unpack(security.dom_sid, res[0]['objectSid'][0]))
+
+        packed_sd = descriptor.sddl2binary("O:SYG:BA" \
+                                           "D:AI(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;DA)" \
+                                           "(A;;CC;;;AU)" \
+                                           "(A;;RPLCLORC;;;WD)" \
+                                           "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
+                                           "(A;CI;RPWPCRCCDCLCRCWOWDSDDTSW;;;ED)",
+                                           domain_sid, {"DnsAdmins": dns_admin})
+        expected_sd = descriptor.get_clean_sd(ndr_unpack(security.descriptor, packed_sd))
+
+        diff = descriptor.get_diff_sds(expected_sd, sd, domain_sid)
+        self.assertEqual(diff, '', "SD of msdcs zone different to expected.\n"
+                         "Difference was:\n%s\nExpected: %s\nGot: %s" %
+                         (diff, expected_sd.as_sddl(utils.domain_sid),
+                          sd.as_sddl(utils.domain_sid)))
+
+    def test_security_descriptor_forest_zone(self):
+        """
+        Make sure that security descriptors of forest dns zones are
+        as expected.
+        """
+        forest_zone = "test_forest_zone"
+        zone_create_info = dnsserver.DNS_RPC_ZONE_CREATE_INFO_LONGHORN()
+        zone_create_info.dwZoneType = dnsp.DNS_ZONE_TYPE_PRIMARY
+        zone_create_info.fAging = 0
+        zone_create_info.fDsIntegrated = 1
+        zone_create_info.fLoadExisting = 1
+
+        zone_create_info.pszZoneName = forest_zone
+        zone_create_info.dwDpFlags = dnsserver.DNS_DP_FOREST_DEFAULT
+
+        self.conn.DnssrvOperation2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
+                                   0,
+                                   self.server,
+                                   None,
+                                   0,
+                                   'ZoneCreate',
+                                   dnsserver.DNSSRV_TYPEID_ZONE_CREATE,
+                                   zone_create_info)
+
+        partition_dn = self.samdb.get_default_basedn()
+        partition_dn.add_child("DC=ForestDnsZones")
+        zones = self.samdb.search(base=partition_dn, scope=ldb.SCOPE_SUBTREE,
+                                  expression="(name=%s)" % forest_zone,
+                                  attrs=["nTSecurityDescriptor"])
+        self.assertEqual(len(zones), 1)
+        current_dn = zones[0].dn
+        self.assertTrue("nTSecurityDescriptor" in zones[0])
+        tmp = zones[0]["nTSecurityDescriptor"][0]
+        utils = sd_utils.SDUtils(self.samdb)
+        sd = ndr_unpack(security.descriptor, tmp)
+
+        domain_sid = security.dom_sid(self.samdb.get_domain_sid())
+
+        res = self.samdb.search(base=self.samdb.get_default_basedn(),
+                                scope=ldb.SCOPE_SUBTREE,
+                                expression="(sAMAccountName=DnsAdmins)",
+                                attrs=["objectSid"])
+
+        dns_admin = str(ndr_unpack(security.dom_sid, res[0]['objectSid'][0]))
+
+        packed_sd = descriptor.sddl2binary("O:DAG:DA" \
+                                           "D:AI(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;DA)" \
+                                           "(A;;CC;;;AU)" \
+                                           "(A;;RPLCLORC;;;WD)" \
+                                           "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
+                                           "(A;CI;RPWPCRCCDCLCRCWOWDSDDTSW;;;ED)",
+                                           domain_sid, {"DnsAdmins": dns_admin})
+        expected_sd = descriptor.get_clean_sd(ndr_unpack(security.descriptor, packed_sd))
+
+        packed_msdns = descriptor.get_dns_forest_microsoft_dns_descriptor(domain_sid,
+                                                                          {"DnsAdmins": dns_admin})
+        expected_msdns_sd = descriptor.get_clean_sd(ndr_unpack(security.descriptor, packed_msdns))
+
+        packed_part_sd = descriptor.get_dns_partition_descriptor(domain_sid)
+        expected_part_sd = descriptor.get_clean_sd(ndr_unpack(security.descriptor,
+                                                              packed_part_sd))
+        try:
+            msdns_dn = ldb.Dn(self.samdb, "CN=MicrosoftDNS,%s" % str(partition_dn))
+            security_desc_dict = [(current_dn.get_linearized(),  expected_sd),
+                                  (msdns_dn.get_linearized(), expected_msdns_sd),
+                                  (partition_dn.get_linearized(), expected_part_sd)]
+
+            for (key, sec_desc) in security_desc_dict:
+                zones = self.samdb.search(base=key, scope=ldb.SCOPE_BASE,
+                                          attrs=["nTSecurityDescriptor"])
+                self.assertTrue("nTSecurityDescriptor" in zones[0])
+                tmp = zones[0]["nTSecurityDescriptor"][0]
+                utils = sd_utils.SDUtils(self.samdb)
+
+                sd = ndr_unpack(security.descriptor, tmp)
+                diff = descriptor.get_diff_sds(sec_desc, sd, domain_sid)
+
+                self.assertEqual(diff, '', "Security descriptor of forest DNS zone with DN '%s' different to expected. Difference was:\n%s\nExpected: %s\nGot: %s"
+                                 % (key, diff, sec_desc.as_sddl(utils.domain_sid), sd.as_sddl(utils.domain_sid)))
+
+        finally:
+            self.conn.DnssrvOperation2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
+                                       0,
+                                       self.server,
+                                       forest_zone,
+                                       0,
+                                       'DeleteZoneFromDs',
+                                       dnsserver.DNSSRV_TYPEID_NULL,
+                                       None)
+
+    def test_security_descriptor_domain_zone(self):
+        """
+        Make sure that security descriptors of domain dns zones are
+        as expected.
+        """
+
+        partition_dn = self.samdb.get_default_basedn()
+        partition_dn.add_child("DC=DomainDnsZones")
+        zones = self.samdb.search(base=partition_dn, scope=ldb.SCOPE_SUBTREE,
+                                  expression="(name=%s)" % self.custom_zone,
+                                  attrs=["nTSecurityDescriptor"])
+        self.assertEqual(len(zones), 1)
+        current_dn = zones[0].dn
+        self.assertTrue("nTSecurityDescriptor" in zones[0])
+        tmp = zones[0]["nTSecurityDescriptor"][0]
+        utils = sd_utils.SDUtils(self.samdb)
+        sd = ndr_unpack(security.descriptor, tmp)
+        sddl = sd.as_sddl(utils.domain_sid)
+
+        domain_sid = security.dom_sid(self.samdb.get_domain_sid())
+
+        res = self.samdb.search(base=self.samdb.get_default_basedn(), scope=ldb.SCOPE_SUBTREE,
+                                expression="(sAMAccountName=DnsAdmins)",
+                                attrs=["objectSid"])
+
+        dns_admin = str(ndr_unpack(security.dom_sid, res[0]['objectSid'][0]))
+
+        packed_sd = descriptor.sddl2binary("O:DAG:DA" \
+                                           "D:AI(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;DA)" \
+                                           "(A;;CC;;;AU)" \
+                                           "(A;;RPLCLORC;;;WD)" \
+                                           "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
+                                           "(A;CI;RPWPCRCCDCLCRCWOWDSDDTSW;;;ED)",
+                                           domain_sid, {"DnsAdmins": dns_admin})
+        expected_sd = descriptor.get_clean_sd(ndr_unpack(security.descriptor, packed_sd))
+
+        packed_msdns = descriptor.get_dns_domain_microsoft_dns_descriptor(domain_sid,
+                                                                          {"DnsAdmins": dns_admin})
+        expected_msdns_sd = descriptor.get_clean_sd(ndr_unpack(security.descriptor, packed_msdns))
+
+        packed_part_sd = descriptor.get_dns_partition_descriptor(domain_sid)
+        expected_part_sd = descriptor.get_clean_sd(ndr_unpack(security.descriptor,
+                                                              packed_part_sd))
+
+        msdns_dn = ldb.Dn(self.samdb, "CN=MicrosoftDNS,%s" % str(partition_dn))
+        security_desc_dict = [(current_dn.get_linearized(),  expected_sd),
+                              (msdns_dn.get_linearized(), expected_msdns_sd),
+                              (partition_dn.get_linearized(), expected_part_sd)]
+
+        for (key, sec_desc) in security_desc_dict:
+            zones = self.samdb.search(base=key, scope=ldb.SCOPE_BASE,
+                                      attrs=["nTSecurityDescriptor"])
+            self.assertTrue("nTSecurityDescriptor" in zones[0])
+            tmp = zones[0]["nTSecurityDescriptor"][0]
+            utils = sd_utils.SDUtils(self.samdb)
+
+            sd = ndr_unpack(security.descriptor, tmp)
+            diff = descriptor.get_diff_sds(sec_desc, sd, domain_sid)
+
+            self.assertEqual(diff, '', "Security descriptor of domain DNS zone with DN '%s' different to expected. Difference was:\n%s\nExpected: %s\nGot: %s"
+                             % (key, diff, sec_desc.as_sddl(utils.domain_sid), sd.as_sddl(utils.domain_sid)))
index 6fa60a3935a8f3fb43b7abd7207a48aca13c4d63..7141f430945ea8dcde72deef269a74104bd09782 100644 (file)
 ^samba4.rpc.echo.*on.*ncacn_ip_tcp.*with.object.*nt4_dc
 ^samba.tests.dcerpc.dnsserver.samba.tests.dcerpc.dnsserver.DnsserverTests.test_add_duplicate_different_type.*
 ^samba.tests.dcerpc.dnsserver.samba.tests.dcerpc.dnsserver.DnsserverTests.test_rank_none.*
+^samba.tests.dcerpc.dnsserver.samba.tests.dcerpc.dnsserver.DnsserverTests.test_security_descriptor.*
 ^samba.tests.dcerpc.dnsserver.samba.tests.dcerpc.dnsserver.DnsserverTests.test_reject_invalid_commands
 ^samba.tests.samba_tool.dnscmd.samba.tests.samba_tool.dnscmd.DnsCmdTestCase.test_reject_invalid_commands