summaryrefslogtreecommitdiffstats
path: root/python/samba/tests/dcerpc
diff options
context:
space:
mode:
Diffstat (limited to 'python/samba/tests/dcerpc')
-rw-r--r--python/samba/tests/dcerpc/__init__.py19
-rw-r--r--python/samba/tests/dcerpc/array.py206
-rw-r--r--python/samba/tests/dcerpc/bare.py61
-rw-r--r--python/samba/tests/dcerpc/binding.py101
-rw-r--r--python/samba/tests/dcerpc/createtrustrelax.py129
-rw-r--r--python/samba/tests/dcerpc/dnsserver.py1314
-rw-r--r--python/samba/tests/dcerpc/integer.py250
-rw-r--r--python/samba/tests/dcerpc/lsa.py333
-rw-r--r--python/samba/tests/dcerpc/mdssvc.py194
-rw-r--r--python/samba/tests/dcerpc/misc.py101
-rwxr-xr-xpython/samba/tests/dcerpc/raw_protocol.py7514
-rw-r--r--python/samba/tests/dcerpc/raw_testcase.py1177
-rw-r--r--python/samba/tests/dcerpc/registry.py51
-rw-r--r--python/samba/tests/dcerpc/rpc_talloc.py86
-rw-r--r--python/samba/tests/dcerpc/rpcecho.py71
-rw-r--r--python/samba/tests/dcerpc/sam.py783
-rw-r--r--python/samba/tests/dcerpc/samr_change_password.py187
-rw-r--r--python/samba/tests/dcerpc/srvsvc.py68
-rw-r--r--python/samba/tests/dcerpc/string_tests.py132
-rw-r--r--python/samba/tests/dcerpc/testrpc.py143
-rw-r--r--python/samba/tests/dcerpc/unix.py43
21 files changed, 12963 insertions, 0 deletions
diff --git a/python/samba/tests/dcerpc/__init__.py b/python/samba/tests/dcerpc/__init__.py
new file mode 100644
index 0000000..b8df5a2
--- /dev/null
+++ b/python/samba/tests/dcerpc/__init__.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+#
+# Unix SMB/CIFS implementation.
+# Copyright © Jelmer Vernooij <jelmer@samba.org> 2008
+#
+# 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/>.
+
+"""Tests for the DCE/RPC Python bindings."""
diff --git a/python/samba/tests/dcerpc/array.py b/python/samba/tests/dcerpc/array.py
new file mode 100644
index 0000000..073d2c2
--- /dev/null
+++ b/python/samba/tests/dcerpc/array.py
@@ -0,0 +1,206 @@
+# Unix SMB/CIFS implementation.
+# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2016
+#
+# 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/>.
+#
+
+"""Tests for array handling in PIDL generated bindings samba.dcerpc.*"""
+
+from samba.dcerpc import drsblobs
+import samba.tests
+from samba.ndr import ndr_unpack, ndr_pack
+import talloc
+import gc
+
+
+class ArrayTests(samba.tests.TestCase):
+
+ def setUp(self):
+ super().setUp()
+ talloc.enable_null_tracking()
+ self.startup_blocks = talloc.total_blocks()
+
+ def tearDown(self):
+ super().tearDown()
+ gc.collect()
+ if talloc.total_blocks() != self.startup_blocks:
+ talloc.report_full()
+ self.fail("it appears we are leaking memory")
+
+ def test_array_from_python(self):
+ rmd = drsblobs.replPropertyMetaDataBlob()
+
+ rmd.version = 1
+ rmd.ctr = drsblobs.replPropertyMetaDataCtr1()
+ rmd.ctr.count = 3
+
+ rmd1 = drsblobs.replPropertyMetaData1()
+ rmd1.attid = 1
+ rmd1.version = 2
+
+ rmd2 = drsblobs.replPropertyMetaData1()
+ rmd2.attid = 2
+ rmd2.version = 2
+
+ rmd3 = drsblobs.replPropertyMetaData1()
+ rmd3.attid = 3
+ rmd3.version = 2
+
+ rmd.ctr.array = [rmd1, rmd2, rmd3]
+ gc.collect()
+
+ self.assertIsNotNone(rmd)
+ self.assertEqual(rmd.version, 1)
+ self.assertIsNotNone(rmd.ctr)
+ self.assertEqual(rmd.ctr.count, 3)
+ self.assertEqual(len(rmd.ctr.array), rmd.ctr.count)
+ self.assertIsNotNone(rmd.ctr.array[0])
+ self.assertEqual(rmd.ctr.array[0].attid, 1)
+
+ def test_array_with_exception(self):
+ try:
+ rmd = drsblobs.replPropertyMetaDataBlob()
+
+ rmd.version = 1
+ rmd.ctr = drsblobs.replPropertyMetaDataCtr1()
+ rmd.ctr.count = 3
+
+ rmd1 = drsblobs.replPropertyMetaData1()
+ rmd1.attid = 1
+ rmd1.version = 2
+
+ rmd2 = drsblobs.replPropertyMetaData1()
+ rmd2.attid = 2
+ rmd2.version = 2
+
+ rmd3 = drsblobs.replPropertyMetaData1()
+ rmd3.attid = 3
+ rmd3.version = 2
+
+ rmd.ctr.array = [rmd1, rmd2, rmd3]
+
+ gc.collect()
+
+ self.assertIsNotNone(rmd)
+ self.assertEqual(rmd.version, 1)
+ self.assertIsNotNone(rmd.ctr)
+ self.assertEqual(rmd.ctr.count, 3)
+ self.assertEqual(len(rmd.ctr.array), rmd.ctr.count)
+ self.assertIsNotNone(rmd.ctr.array[0])
+ self.assertEqual(rmd.ctr.array[0].attid, 1)
+
+ raise Exception()
+ except:
+ pass
+
+ def test_array_from_python_function(self):
+ def get_rmd():
+ rmd = drsblobs.replPropertyMetaDataBlob()
+
+ rmd.version = 1
+ rmd.ctr = drsblobs.replPropertyMetaDataCtr1()
+ rmd.ctr.count = 3
+
+ rmd1 = drsblobs.replPropertyMetaData1()
+ rmd1.attid = 1
+ rmd1.version = 2
+
+ rmd2 = drsblobs.replPropertyMetaData1()
+ rmd2.attid = 2
+ rmd2.version = 2
+
+ rmd3 = drsblobs.replPropertyMetaData1()
+ rmd3.attid = 3
+ rmd3.version = 2
+
+ rmd.ctr.array = [rmd1, rmd2, rmd3]
+ return rmd
+
+ rmd = get_rmd()
+ gc.collect()
+ self.assertIsNotNone(rmd)
+ self.assertEqual(rmd.version, 1)
+ self.assertIsNotNone(rmd.ctr)
+ self.assertEqual(rmd.ctr.count, 3)
+ self.assertEqual(len(rmd.ctr.array), rmd.ctr.count)
+ self.assertIsNotNone(rmd.ctr.array[0])
+ self.assertEqual(rmd.ctr.array[0].attid, 1)
+
+ def test_array_from_ndr(self):
+ rmd = drsblobs.replPropertyMetaDataBlob()
+
+ rmd.version = 1
+ rmd.ctr = drsblobs.replPropertyMetaDataCtr1()
+ rmd.ctr.count = 3
+
+ rmd1 = drsblobs.replPropertyMetaData1()
+ rmd1.attid = 1
+ rmd1.version = 2
+
+ rmd2 = drsblobs.replPropertyMetaData1()
+ rmd2.attid = 2
+ rmd2.version = 2
+
+ rmd3 = drsblobs.replPropertyMetaData1()
+ rmd3.attid = 3
+ rmd3.version = 2
+
+ rmd.ctr.array = [rmd1, rmd2, rmd3]
+
+ packed = ndr_pack(rmd)
+ gc.collect()
+
+ rmd_unpacked = ndr_unpack(drsblobs.replPropertyMetaDataBlob, packed)
+ self.assertIsNotNone(rmd_unpacked)
+ self.assertEqual(rmd_unpacked.version, 1)
+ self.assertIsNotNone(rmd_unpacked.ctr)
+ self.assertEqual(rmd_unpacked.ctr.count, 3)
+ self.assertEqual(len(rmd_unpacked.ctr.array), rmd_unpacked.ctr.count)
+ self.assertIsNotNone(rmd_unpacked.ctr.array[0])
+ self.assertEqual(rmd_unpacked.ctr.array[0].attid, 1)
+
+ self.assertEqual(rmd.ctr.array[0].attid,
+ rmd_unpacked.ctr.array[0].attid)
+
+ def test_array_delete(self):
+ rmd = drsblobs.replPropertyMetaDataBlob()
+
+ rmd.version = 1
+ rmd.ctr = drsblobs.replPropertyMetaDataCtr1()
+ rmd.ctr.count = 3
+
+ rmd1 = drsblobs.replPropertyMetaData1()
+ rmd1.attid = 1
+ rmd1.version = 2
+
+ rmd2 = drsblobs.replPropertyMetaData1()
+ rmd2.attid = 2
+ rmd2.version = 2
+
+ rmd3 = drsblobs.replPropertyMetaData1()
+ rmd3.attid = 3
+ rmd3.version = 2
+
+ rmd.ctr.array = [rmd1, rmd2, rmd3]
+ try:
+ del rmd1.version
+ self.fail("succeeded in deleting rmd1.version")
+ except AttributeError as e:
+ pass
+
+ try:
+ del rmd.ctr.array
+ self.fail("succeeded in deleting rmd.ctr.array")
+ except AttributeError as e:
+ pass
diff --git a/python/samba/tests/dcerpc/bare.py b/python/samba/tests/dcerpc/bare.py
new file mode 100644
index 0000000..6229652
--- /dev/null
+++ b/python/samba/tests/dcerpc/bare.py
@@ -0,0 +1,61 @@
+# -*- coding: utf-8 -*-
+#
+# Unix SMB/CIFS implementation.
+# Copyright © Jelmer Vernooij <jelmer@samba.org> 2008
+#
+# 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/>.
+#
+
+"""Tests for samba.tests.dcerpc.bare."""
+
+import os
+from samba.dcerpc import ClientConnection
+import samba.tests
+
+
+class BareTestCase(samba.tests.TestCase):
+
+ def test_bare(self):
+ # Connect to the echo pipe
+ x = ClientConnection("ncalrpc:localhost[DEFAULT]",
+ ("60a15ec5-4de8-11d7-a637-005056a20182", 1),
+ lp_ctx=samba.tests.env_loadparm())
+ self.assertEqual(b"\x01\x00\x00\x00", x.request(0, chr(0) * 4))
+
+ def test_two_contexts(self):
+ x = ClientConnection("ncalrpc:localhost[DEFAULT]",
+ ("12345778-1234-abcd-ef00-0123456789ac", 1),
+ lp_ctx=samba.tests.env_loadparm())
+ y = ClientConnection("ncalrpc:localhost",
+ ("60a15ec5-4de8-11d7-a637-005056a20182", 1),
+ basis_connection=x, lp_ctx=samba.tests.env_loadparm())
+ self.assertEqual(24, len(x.request(0, chr(0) * 8)))
+ self.assertEqual(b"\x01\x00\x00\x00", y.request(0, chr(0) * 4))
+
+ def test_bare_tcp(self):
+ # Connect to the echo pipe
+ x = ClientConnection("ncacn_ip_tcp:%s" % os.environ["SERVER"],
+ ("60a15ec5-4de8-11d7-a637-005056a20182", 1),
+ lp_ctx=samba.tests.env_loadparm())
+ self.assertEqual(b"\x01\x00\x00\x00", x.request(0, chr(0) * 4))
+
+ def test_two_contexts_tcp(self):
+ x = ClientConnection("ncacn_ip_tcp:%s" % os.environ["SERVER"],
+ ("12345778-1234-abcd-ef00-0123456789ac", 1),
+ lp_ctx=samba.tests.env_loadparm())
+ y = ClientConnection("ncacn_ip_tcp:%s" % os.environ["SERVER"],
+ ("60a15ec5-4de8-11d7-a637-005056a20182", 1),
+ basis_connection=x, lp_ctx=samba.tests.env_loadparm())
+ self.assertEqual(24, len(x.request(0, chr(0) * 8)))
+ self.assertEqual(b"\x01\x00\x00\x00", y.request(0, chr(0) * 4))
diff --git a/python/samba/tests/dcerpc/binding.py b/python/samba/tests/dcerpc/binding.py
new file mode 100644
index 0000000..1ad1f29
--- /dev/null
+++ b/python/samba/tests/dcerpc/binding.py
@@ -0,0 +1,101 @@
+#
+# Unix SMB/CIFS implementation.
+# Copyright (c) 2020 Andreas Schneider <asn@samba.org>
+#
+# 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/>.
+#
+
+"""Tests for samba.dcerpc., credentials and binding strings"""
+
+import samba.tests
+from samba.tests import RpcInterfaceTestCase, TestCase
+from samba.dcerpc import lsa
+import samba.dcerpc.security as security
+from samba.credentials import Credentials, SMB_ENCRYPTION_REQUIRED, SMB_ENCRYPTION_OFF
+from samba import NTSTATUSError
+
+class RpcBindingTests(RpcInterfaceTestCase):
+
+ def get_user_creds(self):
+ c = Credentials()
+ c.guess()
+ domain = samba.tests.env_get_var_value('DOMAIN')
+ username = samba.tests.env_get_var_value('USERNAME')
+ password = samba.tests.env_get_var_value('PASSWORD')
+ c.set_domain(domain)
+ c.set_username(username)
+ c.set_password(password)
+ return c
+
+ def test_smb3_dcerpc_no_encryption(self):
+ creds = self.get_user_creds()
+ creds.set_smb_encryption(SMB_ENCRYPTION_OFF)
+
+ lp = self.get_loadparm()
+ lp.set('client ipc max protocol', 'SMB3')
+ lp.set('client ipc min protocol', 'SMB3')
+
+ binding_string = ("ncacn_np:%s" % (samba.tests.env_get_var_value('SERVER')))
+ lsa_conn = lsa.lsarpc(binding_string, lp, creds)
+ self.assertFalse(lsa_conn.transport_encrypted())
+
+ objectAttr = lsa.ObjectAttribute()
+ objectAttr.sec_qos = lsa.QosInfo()
+
+ pol_handle = lsa_conn.OpenPolicy2('',
+ objectAttr,
+ security.SEC_FLAG_MAXIMUM_ALLOWED)
+ self.assertIsNotNone(pol_handle)
+
+ def test_smb3_dcerpc_encryption(self):
+ creds = self.get_user_creds()
+ creds.set_smb_encryption(SMB_ENCRYPTION_REQUIRED)
+
+ lp = self.get_loadparm()
+ lp.set('client ipc max protocol', 'SMB3')
+ lp.set('client ipc min protocol', 'SMB3')
+
+ binding_string = ("ncacn_np:%s" % (samba.tests.env_get_var_value('SERVER')))
+ lsa_conn = lsa.lsarpc(binding_string, lp, creds)
+ self.assertTrue(lsa_conn.transport_encrypted())
+
+ objectAttr = lsa.ObjectAttribute()
+ objectAttr.sec_qos = lsa.QosInfo()
+
+ pol_handle = lsa_conn.OpenPolicy2('',
+ objectAttr,
+ security.SEC_FLAG_MAXIMUM_ALLOWED)
+ self.assertIsNotNone(pol_handle)
+
+ def test_smb2_dcerpc_encryption(self):
+ creds = self.get_user_creds()
+ creds.set_smb_encryption(SMB_ENCRYPTION_REQUIRED)
+
+ lp = self.get_loadparm()
+ lp.set('client ipc max protocol', 'SMB2')
+ lp.set('client ipc min protocol', 'SMB2')
+
+ binding_string = ("ncacn_np:%s" % (samba.tests.env_get_var_value('SERVER')))
+ self.assertRaises(NTSTATUSError, lsa.lsarpc, binding_string, lp, creds)
+
+ def test_smb1_dcerpc_encryption(self):
+ creds = self.get_user_creds()
+ creds.set_smb_encryption(SMB_ENCRYPTION_REQUIRED)
+
+ lp = self.get_loadparm()
+ lp.set('client ipc max protocol', 'NT1')
+ lp.set('client ipc min protocol', 'NT1')
+
+ binding_string = ("ncacn_np:%s" % (samba.tests.env_get_var_value('SERVER')))
+ self.assertRaises(NTSTATUSError, lsa.lsarpc, binding_string, lp, creds)
diff --git a/python/samba/tests/dcerpc/createtrustrelax.py b/python/samba/tests/dcerpc/createtrustrelax.py
new file mode 100644
index 0000000..5dcb937
--- /dev/null
+++ b/python/samba/tests/dcerpc/createtrustrelax.py
@@ -0,0 +1,129 @@
+# Unix SMB/CIFS implementation.
+#
+# Copyright (C) Andrew Bartlett 2011
+# Copyright (C) Isaac Boukris 2020
+#
+# 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/>.
+#
+
+"""Tests for the CreateTrustedDomainRelax wrapper"""
+
+import os
+import samba
+from samba.tests import TestCase
+from samba.dcerpc import lsa, security, drsblobs
+from samba.credentials import Credentials, SMB_ENCRYPTION_REQUIRED, SMB_ENCRYPTION_OFF
+from samba.trust_utils import CreateTrustedDomainRelax
+
+class CreateTrustedDomainRelaxTest(TestCase):
+
+ def get_user_creds(self):
+ c = Credentials()
+ c.guess()
+ domain = samba.tests.env_get_var_value('DOMAIN')
+ username = samba.tests.env_get_var_value('USERNAME')
+ password = samba.tests.env_get_var_value('PASSWORD')
+ c.set_domain(domain)
+ c.set_username(username)
+ c.set_password(password)
+ return c
+
+ def _create_trust_relax(self, smbencrypt=True):
+ creds = self.get_user_creds()
+
+ if smbencrypt:
+ creds.set_smb_encryption(SMB_ENCRYPTION_REQUIRED)
+ else:
+ creds.set_smb_encryption(SMB_ENCRYPTION_OFF)
+
+ lp = self.get_loadparm()
+
+ binding_string = ("ncacn_np:%s" % (samba.tests.env_get_var_value('SERVER')))
+ lsa_conn = lsa.lsarpc(binding_string, lp, creds)
+
+ if smbencrypt:
+ self.assertTrue(lsa_conn.transport_encrypted())
+ else:
+ self.assertFalse(lsa_conn.transport_encrypted())
+
+ objectAttr = lsa.ObjectAttribute()
+ objectAttr.sec_qos = lsa.QosInfo()
+
+ pol_handle = lsa_conn.OpenPolicy2('',
+ objectAttr,
+ security.SEC_FLAG_MAXIMUM_ALLOWED)
+ self.assertIsNotNone(pol_handle)
+
+ name = lsa.String()
+ name.string = "tests.samba.example.com"
+ try:
+ info = lsa_conn.QueryTrustedDomainInfoByName(pol_handle, name,
+ lsa.LSA_TRUSTED_DOMAIN_INFO_FULL_INFO)
+
+ lsa_conn.DeleteTrustedDomain(pol_handle, info.info_ex.sid)
+ except RuntimeError:
+ pass
+
+ info = lsa.TrustDomainInfoInfoEx()
+ info.domain_name.string = name.string
+ info.netbios_name.string = "createtrustrelax"
+ info.sid = security.dom_sid("S-1-5-21-538490383-3740119673-95748416")
+ info.trust_direction = lsa.LSA_TRUST_DIRECTION_INBOUND | lsa.LSA_TRUST_DIRECTION_OUTBOUND
+ info.trust_type = lsa.LSA_TRUST_TYPE_UPLEVEL
+ info.trust_attributes = lsa.LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
+
+ password_blob = samba.string_to_byte_array("password".encode('utf-16-le'))
+
+ clear_value = drsblobs.AuthInfoClear()
+ clear_value.size = len(password_blob)
+ clear_value.password = password_blob
+
+ clear_authentication_information = drsblobs.AuthenticationInformation()
+ clear_authentication_information.LastUpdateTime = 0
+ clear_authentication_information.AuthType = lsa.TRUST_AUTH_TYPE_CLEAR
+ clear_authentication_information.AuthInfo = clear_value
+
+ authentication_information_array = drsblobs.AuthenticationInformationArray()
+ authentication_information_array.count = 1
+ authentication_information_array.array = [clear_authentication_information]
+
+ outgoing = drsblobs.trustAuthInOutBlob()
+ outgoing.count = 1
+ outgoing.current = authentication_information_array
+
+ trustdom_handle = None
+ try:
+ trustdom_handle = CreateTrustedDomainRelax(lsa_conn,
+ pol_handle,
+ info,
+ security.SEC_STD_DELETE,
+ outgoing,
+ outgoing)
+ except samba.NTSTATUSError as nt:
+ raise AssertionError(nt)
+ except OSError as e:
+ if smbencrypt:
+ raise AssertionError(e)
+
+ if smbencrypt:
+ self.assertIsNotNone(trustdom_handle)
+ lsa_conn.DeleteTrustedDomain(pol_handle, info.sid)
+ else:
+ self.assertIsNone(trustdom_handle)
+
+ def test_create_trust_relax_encrypt(self):
+ self._create_trust_relax(True)
+
+ def test_create_trust_relax_no_enc(self):
+ self._create_trust_relax(False)
diff --git a/python/samba/tests/dcerpc/dnsserver.py b/python/samba/tests/dcerpc/dnsserver.py
new file mode 100644
index 0000000..13c9af8
--- /dev/null
+++ b/python/samba/tests/dcerpc/dnsserver.py
@@ -0,0 +1,1314 @@
+# Unix SMB/CIFS implementation.
+# Copyright (C) Amitay Isaacs <amitay@gmail.com> 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/>.
+#
+
+"""Tests for samba.dcerpc.dnsserver"""
+
+import os
+import ldb
+
+from samba.auth import system_session
+from samba.samdb import SamDB
+from samba.ndr import ndr_unpack
+from samba.dcerpc import dnsp, dnsserver, security
+from samba.tests import RpcInterfaceTestCase, env_get_var_value
+from samba.dnsserver import record_from_string, flag_from_string, ARecord
+from samba import sd_utils, descriptor
+from samba import WERRORError, werror
+
+
+class DnsserverTests(RpcInterfaceTestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ super().setUpClass()
+
+ good_dns = ["SAMDOM.EXAMPLE.COM",
+ "1.EXAMPLE.COM",
+ "%sEXAMPLE.COM" % ("1." * 100),
+ "EXAMPLE",
+ "\n.COM",
+ "!@#$%^&*()_",
+ "HIGH\xFFBYTE",
+ "@.EXAMPLE.COM",
+ "."]
+ bad_dns = ["...",
+ ".EXAMPLE.COM",
+ ".EXAMPLE.",
+ "",
+ "SAMDOM..EXAMPLE.COM"]
+
+ good_mx = ["SAMDOM.EXAMPLE.COM 65535"]
+ bad_mx = []
+
+ good_srv = ["SAMDOM.EXAMPLE.COM 65535 65535 65535"]
+ bad_srv = []
+
+ for bad_dn in bad_dns:
+ bad_mx.append("%s 1" % bad_dn)
+ bad_srv.append("%s 0 0 0" % bad_dn)
+ for good_dn in good_dns:
+ good_mx.append("%s 1" % good_dn)
+ good_srv.append("%s 0 0 0" % good_dn)
+
+ cls.good_records = {
+ "A": ["192.168.0.1",
+ "255.255.255.255"],
+ "AAAA": ["1234:5678:9ABC:DEF0:0000:0000:0000:0000",
+ "0000:0000:0000:0000:0000:0000:0000:0000",
+ "1234:5678:9ABC:DEF0:1234:5678:9ABC:DEF0",
+ "1234:1234:1234::",
+ "1234:1234:1234:1234:1234::",
+ "1234:5678:9ABC:DEF0::",
+ "0000:0000::0000",
+ "1234::5678:9ABC:0000:0000:0000:0000",
+ "::1",
+ "::",
+ "1:1:1:1:1:1:1:1"],
+ "PTR": good_dns,
+ "CNAME": good_dns,
+ "NS": good_dns,
+ "MX": good_mx,
+ "SRV": good_srv,
+ "TXT": ["text", "", "@#!", "\n"]
+ }
+
+ cls.bad_records = {
+ "A": ["192.168.0.500",
+ "255.255.255.255/32"],
+ "AAAA": ["GGGG:1234:5678:9ABC:0000:0000:0000:0000",
+ "0000:0000:0000:0000:0000:0000:0000:0000/1",
+ "AAAA:AAAA:AAAA:AAAA:G000:0000:0000:1234",
+ "1234:5678:9ABC:DEF0:1234:5678:9ABC:DEF0:1234",
+ "1234:5678:9ABC:DEF0:1234:5678:9ABC",
+ "1111::1111::1111"],
+ "PTR": bad_dns,
+ "CNAME": bad_dns,
+ "NS": bad_dns,
+ "MX": bad_mx,
+ "SRV": bad_srv
+ }
+
+ # Because we use uint16_t for these numbers, we can't
+ # actually create these records.
+ invalid_mx = ["SAMDOM.EXAMPLE.COM -1",
+ "SAMDOM.EXAMPLE.COM 65536",
+ "%s 1" % ("A" * 256)]
+ invalid_srv = ["SAMDOM.EXAMPLE.COM 0 65536 0",
+ "SAMDOM.EXAMPLE.COM 0 0 65536",
+ "SAMDOM.EXAMPLE.COM 65536 0 0"]
+ cls.invalid_records = {
+ "MX": invalid_mx,
+ "SRV": invalid_srv
+ }
+
+ def setUp(self):
+ super().setUp()
+ self.server = os.environ["DC_SERVER"]
+ self.zone = env_get_var_value("REALM").lower()
+ self.conn = dnsserver.dnsserver("ncacn_ip_tcp:%s[sign]" % (self.server),
+ self.get_loadparm(),
+ self.get_credentials())
+
+ self.samdb = SamDB(url="ldap://%s" % os.environ["DC_SERVER_IP"],
+ lp=self.get_loadparm(),
+ session_info=system_session(),
+ credentials=self.get_credentials())
+
+ self.custom_zone = "zone"
+ zone_create_info = dnsserver.DNS_RPC_ZONE_CREATE_INFO_LONGHORN()
+ zone_create_info.pszZoneName = self.custom_zone
+ 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.dwDpFlags = dnsserver.DNS_DP_DOMAIN_DEFAULT
+
+ self.conn.DnssrvOperation2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
+ 0,
+ self.server,
+ None,
+ 0,
+ 'ZoneCreate',
+ dnsserver.DNSSRV_TYPEID_ZONE_CREATE,
+ zone_create_info)
+
+ def tearDown(self):
+ self.conn.DnssrvOperation2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
+ 0,
+ self.server,
+ self.custom_zone,
+ 0,
+ 'DeleteZoneFromDs',
+ dnsserver.DNSSRV_TYPEID_NULL,
+ None)
+ super().tearDown()
+
+ def test_enum_is_sorted(self):
+ """
+ Confirm the zone is sorted
+ """
+
+ record_str = "192.168.50.50"
+ record_type_str = "A"
+ self.add_record(self.custom_zone, "atestrecord-1", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-2", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-3", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-4", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-0", record_type_str, record_str)
+
+ # This becomes an extra A on the zone itself by server-side magic
+ self.add_record(self.custom_zone, self.custom_zone, record_type_str, record_str)
+
+ _, result = self.conn.DnssrvEnumRecords2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
+ 0,
+ self.server,
+ self.custom_zone,
+ "@",
+ None,
+ flag_from_string(record_type_str),
+ dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA,
+ None,
+ None)
+
+ self.assertEqual(len(result.rec), 6)
+ self.assertEqual(result.rec[0].dnsNodeName.str, "")
+ self.assertEqual(result.rec[1].dnsNodeName.str, "atestrecord-0")
+ self.assertEqual(result.rec[2].dnsNodeName.str, "atestrecord-1")
+ self.assertEqual(result.rec[3].dnsNodeName.str, "atestrecord-2")
+ self.assertEqual(result.rec[4].dnsNodeName.str, "atestrecord-3")
+ self.assertEqual(result.rec[5].dnsNodeName.str, "atestrecord-4")
+
+ def test_enum_is_sorted_with_zone_dup(self):
+ """
+ Confirm the zone is sorted
+ """
+
+ record_str = "192.168.50.50"
+ record_type_str = "A"
+ self.add_record(self.custom_zone, "atestrecord-1", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-2", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-3", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-4", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-0", record_type_str, record_str)
+
+ # This triggers a bug in old Samba
+ self.add_record(self.custom_zone, self.custom_zone + "1", record_type_str, record_str)
+
+ dn, record = self.get_record_from_db(self.custom_zone, self.custom_zone + "1")
+
+ new_dn = ldb.Dn(self.samdb, str(dn))
+ new_dn.set_component(0, "dc", self.custom_zone)
+ self.samdb.rename(dn, new_dn)
+
+ _, result = self.conn.DnssrvEnumRecords2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
+ 0,
+ self.server,
+ self.custom_zone,
+ "@",
+ None,
+ flag_from_string(record_type_str),
+ dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA,
+ None,
+ None)
+
+ self.assertEqual(len(result.rec), 7)
+ self.assertEqual(result.rec[0].dnsNodeName.str, "")
+ self.assertEqual(result.rec[1].dnsNodeName.str, "atestrecord-0")
+ self.assertEqual(result.rec[2].dnsNodeName.str, "atestrecord-1")
+ self.assertEqual(result.rec[3].dnsNodeName.str, "atestrecord-2")
+ self.assertEqual(result.rec[4].dnsNodeName.str, "atestrecord-3")
+ self.assertEqual(result.rec[5].dnsNodeName.str, "atestrecord-4")
+
+ # Windows doesn't reload the zone fast enough, but doesn't
+ # have the bug anyway, it will sort last on both names (where
+ # it should)
+ if result.rec[6].dnsNodeName.str != (self.custom_zone + "1"):
+ self.assertEqual(result.rec[6].dnsNodeName.str, self.custom_zone)
+
+ def test_enum_is_sorted_children_prefix_first(self):
+ """
+ Confirm the zone returns the selected prefix first but no more
+ as Samba is flappy for the full sort
+ """
+
+ record_str = "192.168.50.50"
+ record_type_str = "A"
+ self.add_record(self.custom_zone, "atestrecord-1.a.b", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-2.a.b", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-3.a.b", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-4.a.b", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-0.a.b", record_type_str, record_str)
+
+ # Not expected to be returned
+ self.add_record(self.custom_zone, "atestrecord-0.b.b", record_type_str, record_str)
+
+ _, result = self.conn.DnssrvEnumRecords2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
+ 0,
+ self.server,
+ self.custom_zone,
+ "a.b",
+ None,
+ flag_from_string(record_type_str),
+ dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA,
+ None,
+ None)
+
+ self.assertEqual(len(result.rec), 6)
+ self.assertEqual(result.rec[0].dnsNodeName.str, "")
+
+ def test_enum_is_sorted_children(self):
+ """
+ Confirm the zone is sorted
+ """
+
+ record_str = "192.168.50.50"
+ record_type_str = "A"
+ self.add_record(self.custom_zone, "atestrecord-1.a.b", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-2.a.b", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-3.a.b", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-4.a.b", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-0.a.b", record_type_str, record_str)
+
+ # Not expected to be returned
+ self.add_record(self.custom_zone, "atestrecord-0.b.b", record_type_str, record_str)
+
+ _, result = self.conn.DnssrvEnumRecords2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
+ 0,
+ self.server,
+ self.custom_zone,
+ "a.b",
+ None,
+ flag_from_string(record_type_str),
+ dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA,
+ None,
+ None)
+
+ self.assertEqual(len(result.rec), 6)
+ self.assertEqual(result.rec[0].dnsNodeName.str, "")
+ self.assertEqual(result.rec[1].dnsNodeName.str, "atestrecord-0")
+ self.assertEqual(result.rec[2].dnsNodeName.str, "atestrecord-1")
+ self.assertEqual(result.rec[3].dnsNodeName.str, "atestrecord-2")
+ self.assertEqual(result.rec[4].dnsNodeName.str, "atestrecord-3")
+ self.assertEqual(result.rec[5].dnsNodeName.str, "atestrecord-4")
+
+ # This test fails against Samba (but passes against Windows),
+ # because Samba does not return the record when we enum records.
+ # Records can be given DNS_RANK_NONE when the zone they are in
+ # does not have DNS_ZONE_TYPE_PRIMARY. Since such records can be
+ # deleted, however, we do not consider this urgent to fix and
+ # so this test is a knownfail.
+ def test_rank_none(self):
+ """
+ See what happens when we set a record's rank to
+ DNS_RANK_NONE.
+ """
+
+ record_str = "192.168.50.50"
+ record_type_str = "A"
+ self.add_record(self.custom_zone, "testrecord", record_type_str, record_str)
+
+ dn, record = self.get_record_from_db(self.custom_zone, "testrecord")
+ record.rank = 0 # DNS_RANK_NONE
+ res = self.samdb.dns_replace_by_dn(dn, [record])
+ if res is not None:
+ self.fail("Unable to update dns record to have DNS_RANK_NONE.")
+
+ self.assert_num_records(self.custom_zone, "testrecord", record_type_str)
+ self.add_record(self.custom_zone, "testrecord", record_type_str, record_str, assertion=False)
+ self.delete_record(self.custom_zone, "testrecord", record_type_str, record_str)
+ self.assert_num_records(self.custom_zone, "testrecord", record_type_str, 0)
+
+ def test_dns_tombstoned_zero_timestamp(self):
+ """What happens with a zero EntombedTime tombstone?"""
+ # A zero-timestamp tombstone record has a special meaning for
+ # dns_common_replace(), which is the function exposed by
+ # samdb.dns_replace_by_dn(), and which is *NOT* a general
+ # purpose record replacement function but a specialised part
+ # of the dns update mechanism (for both DLZ and internal).
+ #
+ # In the earlier stages of handling updates, a record that
+ # needs to be deleted is set to be a tombstone with a zero
+ # timestamp. dns_common_replace() notices this specific
+ # marker, and if there are no other records, marks the node as
+ # tombstoned, in the process adding a "real" tombstone.
+ #
+ # If the tombstone has a non-zero timestamp, as you'll see in
+ # the next test, dns_common_replace will decide that the node
+ # is already tombstoned, and that no action needs to be taken.
+ #
+ # This test has worked historically, entirely by accident, as
+ # changing the wType appears to
+
+ record_str = "192.168.50.50"
+ self.add_record(self.custom_zone, "testrecord", 'A', record_str)
+
+ dn, record = self.get_record_from_db(self.custom_zone, "testrecord")
+ record.wType = dnsp.DNS_TYPE_TOMBSTONE
+ record.data = 0
+ self.samdb.dns_replace_by_dn(dn, [record])
+
+ # there should be no A record, and one TOMBSTONE record.
+ self.assert_num_records(self.custom_zone, "testrecord", 'A', 0)
+ # we can't make assertions about the tombstone count based on
+ # RPC calls, as there are no tombstones in RPCs (there is
+ # "DNS_TYPE_ZERO" instead). Nor do tombstones show up if we
+ # use DNS_TYPE_ALL.
+ self.assert_num_records(self.custom_zone, "testrecord", 'ALL', 0)
+
+ # But we can use LDAP:
+ records = self.ldap_get_records(self.custom_zone, "testrecord")
+ self.assertEqual(len(records), 1)
+ r = records[0]
+ self.assertEqual(r.wType, dnsp.DNS_TYPE_TOMBSTONE)
+ self.assertGreater(r.data, 1e17) # ~ October 1916
+
+ # this should fail, because no A records.
+ self.delete_record(self.custom_zone, "testrecord", 'A', record_str,
+ assertion=False)
+
+ def test_dns_tombstoned_nonzero_timestamp(self):
+ """See what happens when we set a record to be tombstoned with an
+ EntombedTime timestamp.
+ """
+ # Because this tombstone has a non-zero EntombedTime,
+ # dns_common_replace() will decide the node was already
+ # tombstoned and there is nothing to be done, leaving the A
+ # record where it was.
+
+ record_str = "192.168.50.50"
+ self.add_record(self.custom_zone, "testrecord", 'A', record_str)
+
+ dn, record = self.get_record_from_db(self.custom_zone, "testrecord")
+ record.wType = dnsp.DNS_TYPE_TOMBSTONE
+ record.data = 0x123456789A
+ self.samdb.dns_replace_by_dn(dn, [record])
+
+ # there should be the A record and no TOMBSTONE
+ self.assert_num_records(self.custom_zone, "testrecord", 'A', 1)
+ self.assert_num_records(self.custom_zone, "testrecord", 'TOMBSTONE', 0)
+ # this should succeed
+ self.delete_record(self.custom_zone, "testrecord", 'A', record_str,
+ assertion=True)
+ self.assert_num_records(self.custom_zone, "testrecord", 'TOMBSTONE', 0)
+ self.assert_num_records(self.custom_zone, "testrecord", 'A', 0)
+
+ def get_record_from_db(self, zone_name, record_name):
+ """
+ Returns (dn of record, record)
+ """
+
+ zones = self.samdb.search(base="DC=DomainDnsZones,%s" % self.samdb.get_default_basedn(), scope=ldb.SCOPE_SUBTREE,
+ expression="(objectClass=dnsZone)",
+ attrs=["cn"])
+
+ zone_dn = None
+ for zone in zones:
+ if "DC=%s," % zone_name in str(zone.dn):
+ zone_dn = zone.dn
+ break
+
+ if zone_dn is None:
+ raise AssertionError("Couldn't find zone '%s'." % zone_name)
+
+ records = self.samdb.search(base=zone_dn, scope=ldb.SCOPE_SUBTREE,
+ expression="(objectClass=dnsNode)",
+ attrs=["dnsRecord"])
+
+ for old_packed_record in records:
+ if record_name in str(old_packed_record.dn):
+ rec = ndr_unpack(dnsp.DnssrvRpcRecord, old_packed_record["dnsRecord"][0])
+ return (old_packed_record.dn, rec)
+
+ def ldap_get_records(self, zone, name):
+ zone_dn = (f"DC={zone},CN=MicrosoftDNS,DC=DomainDNSZones,"
+ f"{self.samdb.get_default_basedn()}")
+
+ expr = f"(&(objectClass=dnsNode)(name={name}))"
+ nodes = self.samdb.search(base=zone_dn,
+ scope=ldb.SCOPE_SUBTREE,
+ expression=expr,
+ attrs=["dnsRecord"])
+
+ records = nodes[0].get('dnsRecord')
+ return [ndr_unpack(dnsp.DnssrvRpcRecord, r) for r in records]
+
+ def test_duplicate_matching(self):
+ """
+ Make sure that records which should be distinct from each other or duplicate
+ to each other behave as expected.
+ """
+
+ distinct_dns = [("SAMDOM.EXAMPLE.COM",
+ "SAMDOM.EXAMPLE.CO",
+ "EXAMPLE.COM", "SAMDOM.EXAMPLE")]
+ duplicate_dns = [("SAMDOM.EXAMPLE.COM", "samdom.example.com", "SAMDOM.example.COM"),
+ ("EXAMPLE.", "EXAMPLE")]
+
+ # Every tuple has entries which should be considered duplicate to one another.
+ duplicates = {
+ "AAAA": [("AAAA::", "aaaa::"),
+ ("AAAA::", "AAAA:0000::"),
+ ("AAAA::", "AAAA:0000:0000:0000:0000:0000:0000:0000"),
+ ("AAAA::", "AAAA:0:0:0:0:0:0:0"),
+ ("0123::", "123::"),
+ ("::", "::0", "0000:0000:0000:0000:0000:0000:0000:0000")],
+ }
+
+ # Every tuple has entries which should be considered distinct from one another.
+ distinct = {
+ "A": [("192.168.1.0", "192.168.1.1", "192.168.2.0", "192.169.1.0", "193.168.1.0")],
+ "AAAA": [("AAAA::1234:5678:9ABC", "::AAAA:1234:5678:9ABC"),
+ ("1000::", "::1000"),
+ ("::1", "::11", "::1111"),
+ ("1234::", "0234::")],
+ "SRV": [("SAMDOM.EXAMPLE.COM 1 1 1", "SAMDOM.EXAMPLE.COM 1 1 0", "SAMDOM.EXAMPLE.COM 1 0 1",
+ "SAMDOM.EXAMPLE.COM 0 1 1", "SAMDOM.EXAMPLE.COM 2 1 0", "SAMDOM.EXAMPLE.COM 2 2 2")],
+ "MX": [("SAMDOM.EXAMPLE.COM 1", "SAMDOM.EXAMPLE.COM 0")],
+ "TXT": [("A RECORD", "B RECORD", "a record")]
+ }
+
+ for record_type_str in ("PTR", "CNAME", "NS"):
+ distinct[record_type_str] = distinct_dns
+ duplicates[record_type_str] = duplicate_dns
+
+ for record_type_str in duplicates:
+ for duplicate_tuple in duplicates[record_type_str]:
+ # Attempt to add duplicates and make sure that all after the first fails
+ self.add_record(self.custom_zone, "testrecord", record_type_str, duplicate_tuple[0])
+ for record in duplicate_tuple:
+ self.add_record(self.custom_zone, "testrecord", record_type_str, record, assertion=False)
+ self.assert_num_records(self.custom_zone, "testrecord", record_type_str)
+ self.delete_record(self.custom_zone, "testrecord", record_type_str, duplicate_tuple[0])
+
+ # Repeatedly: add the first duplicate, and attempt to remove all of the others, making sure this succeeds
+ for record in duplicate_tuple:
+ self.add_record(self.custom_zone, "testrecord", record_type_str, duplicate_tuple[0])
+ self.delete_record(self.custom_zone, "testrecord", record_type_str, record)
+
+ for record_type_str in distinct:
+ for distinct_tuple in distinct[record_type_str]:
+ # Attempt to add distinct and make sure that they all succeed within a tuple
+ i = 0
+ for record in distinct_tuple:
+ i = i + 1
+ try:
+ self.add_record(self.custom_zone, "testrecord", record_type_str, record)
+ # All records should have been added.
+ self.assert_num_records(self.custom_zone, "testrecord", record_type_str, expected_num=i)
+ except AssertionError as e:
+ raise AssertionError("Failed to add %s, which should be distinct from all others in the set. "
+ "Original error: %s\nDistinct set: %s." % (record, e, distinct_tuple))
+ for record in distinct_tuple:
+ self.delete_record(self.custom_zone, "testrecord", record_type_str, record)
+ # CNAMEs should not have been added, since they conflict.
+ if record_type_str == 'CNAME':
+ continue
+
+ # Add the first distinct and attempt to remove all of the others, making sure this fails
+ # Windows fails this test. This is probably due to weird tombstoning behavior.
+ self.add_record(self.custom_zone, "testrecord", record_type_str, distinct_tuple[0])
+ for record in distinct_tuple:
+ if record == distinct_tuple[0]:
+ continue
+ try:
+ self.delete_record(self.custom_zone, "testrecord", record_type_str, record, assertion=False)
+ except AssertionError as e:
+ raise AssertionError("Managed to remove %s by attempting to remove %s. Original error: %s"
+ % (distinct_tuple[0], record, e))
+ self.delete_record(self.custom_zone, "testrecord", record_type_str, distinct_tuple[0])
+
+ def test_accept_valid_commands(self):
+ """
+ Make sure that we can add, update and delete a variety
+ of valid records.
+ """
+ for record_type_str in self.good_records:
+ for record_str in self.good_records[record_type_str]:
+ self.add_record(self.custom_zone, "testrecord", record_type_str, record_str)
+ self.assert_num_records(self.custom_zone, "testrecord", record_type_str)
+ self.delete_record(self.custom_zone, "testrecord", record_type_str, record_str)
+
+ def check_params(self, wDataLength, rank, flags, dwTtlSeconds, dwReserved, data,
+ wType, dwTimeStamp=0, zone="zone", rec_name="testrecord"):
+ res = self.get_record_from_db(zone, rec_name)
+ self.assertIsNotNone(res, "Expected record %s but was not found over LDAP." % data)
+ (rec_dn, rec) = res
+ self.assertEqual(wDataLength, rec.wDataLength, "Unexpected data length for record %s. Got %s, expected %s." % (data, rec.wDataLength, wDataLength))
+ self.assertEqual(rank, rec.rank, "Unexpected rank for record %s. Got %s, expected %s." % (data, rec.rank, rank))
+ self.assertEqual(flags, rec.flags, "Unexpected flags for record %s. Got %s, expected %s." % (data, rec.flags, flags))
+ self.assertEqual(dwTtlSeconds, rec.dwTtlSeconds, "Unexpected time to live for record %s. Got %s, expected %s." % (data, rec.dwTtlSeconds, dwTtlSeconds))
+ self.assertEqual(dwReserved, rec.dwReserved, "Unexpected dwReserved for record %s. Got %s, expected %s." % (data, rec.dwReserved, dwReserved))
+ self.assertEqual(data.lower(), rec.data.lower(), "Unexpected data for record %s. Got %s, expected %s." % (data, rec.data.lower(), data.lower()))
+ self.assertEqual(wType, rec.wType, "Unexpected wType for record %s. Got %s, expected %s." % (data, rec.wType, wType))
+ self.assertEqual(dwTimeStamp, rec.dwTimeStamp, "Unexpected timestamp for record %s. Got %s, expected %s." % (data, rec.dwTimeStamp, dwTimeStamp))
+
+ def test_record_params(self):
+ """
+ Make sure that, when we add records to the database,
+ they're added with reasonable parameters.
+ """
+ self.add_record(self.custom_zone, "testrecord", "A", "192.168.50.50")
+ self.check_params(4, 240, 0, 900, 0, "192.168.50.50", 1)
+ self.delete_record(self.custom_zone, "testrecord", "A", "192.168.50.50")
+ self.add_record(self.custom_zone, "testrecord", "AAAA", "AAAA:AAAA::")
+ self.check_params(16, 240, 0, 900, 0, "AAAA:AAAA:0000:0000:0000:0000:0000:0000", 28)
+ self.delete_record(self.custom_zone, "testrecord", "AAAA", "AAAA:AAAA::")
+ self.add_record(self.custom_zone, "testrecord", "CNAME", "cnamedest")
+ self.check_params(13, 240, 0, 900, 0, "cnamedest", 5)
+ self.delete_record(self.custom_zone, "testrecord", "CNAME", "cnamedest")
+
+ def test_reject_invalid_commands(self):
+ """
+ Make sure that we can't add a variety of invalid records,
+ and that we can't update valid records to invalid ones.
+ """
+ num_failures = 0
+ for record_type_str in self.bad_records:
+ for record_str in self.bad_records[record_type_str]:
+ # Attempt to add the bad record, which should fail. Then, attempt to query for and delete
+ # it. Since it shouldn't exist, these should fail too.
+ try:
+ self.add_record(self.custom_zone, "testrecord", record_type_str, record_str, assertion=False)
+ self.assert_num_records(self.custom_zone, "testrecord", record_type_str, expected_num=0)
+ self.delete_record(self.custom_zone, "testrecord", record_type_str, record_str, assertion=False)
+ except AssertionError as e:
+ print(e)
+ num_failures = num_failures + 1
+
+ # Also try to update valid records to invalid ones, making sure this fails
+ for record_type_str in self.bad_records:
+ for record_str in self.bad_records[record_type_str]:
+ good_record_str = self.good_records[record_type_str][0]
+ self.add_record(self.custom_zone, "testrecord", record_type_str, good_record_str)
+ try:
+ self.add_record(self.custom_zone, "testrecord", record_type_str, record_str, assertion=False)
+ except AssertionError as e:
+ print(e)
+ num_failures = num_failures + 1
+ self.delete_record(self.custom_zone, "testrecord", record_type_str, good_record_str)
+
+ self.assertTrue(num_failures == 0, "Failed to reject invalid commands. Total failures: %d." % num_failures)
+
+ def test_add_duplicate_different_type(self):
+ """
+ Attempt to add some values which have the same name as
+ existing ones, just a different type.
+ """
+ num_failures = 0
+ for record_type_str_1 in self.good_records:
+ record1 = self.good_records[record_type_str_1][0]
+ self.add_record(self.custom_zone, "testrecord", record_type_str_1, record1)
+ for record_type_str_2 in self.good_records:
+ if record_type_str_1 == record_type_str_2:
+ continue
+
+ record2 = self.good_records[record_type_str_2][0]
+
+ has_a = record_type_str_1 == 'A' or record_type_str_2 == 'A'
+ has_aaaa = record_type_str_1 == 'AAAA' or record_type_str_2 == 'AAAA'
+ has_cname = record_type_str_1 == 'CNAME' or record_type_str_2 == 'CNAME'
+ has_ptr = record_type_str_1 == 'PTR' or record_type_str_2 == 'PTR'
+ has_mx = record_type_str_1 == 'MX' or record_type_str_2 == 'MX'
+ has_srv = record_type_str_1 == 'SRV' or record_type_str_2 == 'SRV'
+ has_txt = record_type_str_1 == 'TXT' or record_type_str_2 == 'TXT'
+
+ # If we attempt to add any record except A or AAAA when we already have an NS record,
+ # the add should fail.
+ add_error_ok = False
+ if record_type_str_1 == 'NS' and not has_a and not has_aaaa:
+ add_error_ok = True
+ # If we attempt to add a CNAME when an A, PTR or MX record exists, the add should fail.
+ if record_type_str_2 == 'CNAME' and (has_ptr or has_mx or has_a or has_aaaa):
+ add_error_ok = True
+ # If we have a CNAME, adding an A, AAAA, SRV or TXT record should fail.
+ # If we have an A, AAAA, SRV or TXT record, adding a CNAME should fail.
+ if has_cname and (has_a or has_aaaa or has_srv or has_txt):
+ add_error_ok = True
+
+ try:
+ self.add_record(self.custom_zone, "testrecord", record_type_str_2, record2)
+ if add_error_ok:
+ num_failures = num_failures + 1
+ print("Expected error when adding %s while a %s existed."
+ % (record_type_str_2, record_type_str_1))
+ except AssertionError as e:
+ if not add_error_ok:
+ num_failures = num_failures + 1
+ print("Didn't expect error when adding %s while a %s existed."
+ % (record_type_str_2, record_type_str_1))
+
+ if not add_error_ok:
+ # In the "normal" case, we expect the add to work and us to have one of each type of record afterwards.
+ expected_num_type_1 = 1
+ expected_num_type_2 = 1
+
+ # If we have an MX record, a PTR record should replace it when added.
+ # If we have a PTR record, an MX record should replace it when added.
+ if has_ptr and has_mx:
+ expected_num_type_1 = 0
+
+ # If we have a CNAME, SRV or TXT record, a PTR or MX record should replace it when added.
+ if (has_cname or has_srv or has_txt) and (record_type_str_2 == 'PTR' or record_type_str_2 == 'MX'):
+ expected_num_type_1 = 0
+
+ if (record_type_str_1 == 'NS' and (has_a or has_aaaa)):
+ expected_num_type_2 = 0
+
+ try:
+ self.assert_num_records(self.custom_zone, "testrecord", record_type_str_1, expected_num=expected_num_type_1)
+ except AssertionError as e:
+ num_failures = num_failures + 1
+ print("Expected %s %s records after adding a %s record and a %s record already existed."
+ % (expected_num_type_1, record_type_str_1, record_type_str_2, record_type_str_1))
+ try:
+ self.assert_num_records(self.custom_zone, "testrecord", record_type_str_2, expected_num=expected_num_type_2)
+ except AssertionError as e:
+ num_failures = num_failures + 1
+ print("Expected %s %s records after adding a %s record and a %s record already existed."
+ % (expected_num_type_2, record_type_str_2, record_type_str_2, record_type_str_1))
+
+ try:
+ self.delete_record(self.custom_zone, "testrecord", record_type_str_2, record2)
+ except AssertionError as e:
+ pass
+
+ self.delete_record(self.custom_zone, "testrecord", record_type_str_1, record1)
+
+ self.assertTrue(num_failures == 0, "Failed collision and replacement behavior. Total failures: %d." % num_failures)
+
+ # Windows fails this test in the same way we do.
+ def _test_cname(self):
+ """
+ Test some special properties of CNAME records.
+ """
+
+ # RFC 1912: When there is a CNAME record, there must not be any other records with the same alias
+ cname_record = self.good_records["CNAME"][1]
+ self.add_record(self.custom_zone, "testrecord", "CNAME", cname_record)
+
+ for record_type_str in self.good_records:
+ other_record = self.good_records[record_type_str][0]
+ self.add_record(self.custom_zone, "testrecord", record_type_str, other_record, assertion=False)
+ self.assert_num_records(self.custom_zone, "testrecord", record_type_str, expected_num=0)
+
+ # RFC 2181: MX & NS records must not be allowed to point to a CNAME alias
+ mx_record = "testrecord 1"
+ ns_record = "testrecord"
+
+ self.add_record(self.custom_zone, "mxrec", "MX", mx_record, assertion=False)
+ self.add_record(self.custom_zone, "nsrec", "NS", ns_record, assertion=False)
+
+ self.delete_record(self.custom_zone, "testrecord", "CNAME", cname_record)
+
+ def test_add_duplicate_value(self):
+ """
+ Make sure that we can't add duplicate values of any type.
+ """
+ for record_type_str in self.good_records:
+ record = self.good_records[record_type_str][0]
+
+ self.add_record(self.custom_zone, "testrecord", record_type_str, record)
+ self.add_record(self.custom_zone, "testrecord", record_type_str, record, assertion=False)
+ self.assert_num_records(self.custom_zone, "testrecord", record_type_str)
+ self.delete_record(self.custom_zone, "testrecord", record_type_str, record)
+
+ def test_add_similar_value(self):
+ """
+ Attempt to add values with the same name and type in the same
+ zone. This should work, and should result in both values
+ existing (except with some types).
+ """
+ for record_type_str in self.good_records:
+ for i in range(1, len(self.good_records[record_type_str])):
+ record1 = self.good_records[record_type_str][i - 1]
+ record2 = self.good_records[record_type_str][i]
+
+ if record_type_str == 'CNAME':
+ continue
+ # We expect CNAME records to override one another, as
+ # an alias can only map to one CNAME record.
+ # Also, on Windows, when the empty string is added and
+ # another record is added afterwards, the empty string
+ # will be silently overridden by the new one, so it
+ # fails this test for the empty string.
+ expected_num = 1 if record_type_str == 'CNAME' else 2
+
+ self.add_record(self.custom_zone, "testrecord", record_type_str, record1)
+ self.add_record(self.custom_zone, "testrecord", record_type_str, record2)
+ self.assert_num_records(self.custom_zone, "testrecord", record_type_str, expected_num=expected_num)
+ self.delete_record(self.custom_zone, "testrecord", record_type_str, record1)
+ self.delete_record(self.custom_zone, "testrecord", record_type_str, record2)
+
+ def assert_record(self, zone, name, record_type_str, expected_record_str,
+ assertion=True, client_version=dnsserver.DNS_CLIENT_VERSION_LONGHORN):
+ """
+ Asserts whether or not the given record with the given type exists in the
+ given zone.
+ """
+ try:
+ _, result = self.query_records(zone, name, record_type_str)
+ except RuntimeError as e:
+ if assertion:
+ raise AssertionError("Record '%s' of type '%s' was not present when it should have been."
+ % (expected_record_str, record_type_str))
+ else:
+ return
+
+ found = False
+ for record in result.rec[0].records:
+ if record.data == expected_record_str:
+ found = True
+ break
+
+ if found and not assertion:
+ raise AssertionError("Record '%s' of type '%s' was present when it shouldn't have been." % (expected_record_str, record_type_str))
+ elif not found and assertion:
+ raise AssertionError("Record '%s' of type '%s' was not present when it should have been." % (expected_record_str, record_type_str))
+
+ def assert_num_records(self, zone, name, record_type_str, expected_num=1,
+ client_version=dnsserver.DNS_CLIENT_VERSION_LONGHORN):
+ """
+ Asserts that there are a given amount of records with the given type in
+ the given zone.
+ """
+ try:
+ _, result = self.query_records(zone, name, record_type_str)
+ num_results = len(result.rec[0].records)
+ if not num_results == expected_num:
+ raise AssertionError("There were %d records of type '%s' with the name '%s' when %d were expected."
+ % (num_results, record_type_str, name, expected_num))
+ except RuntimeError:
+ if not expected_num == 0:
+ raise AssertionError("There were no records of type '%s' with the name '%s' when %d were expected."
+ % (record_type_str, name, expected_num))
+
+ def query_records(self, zone, name, record_type_str, client_version=dnsserver.DNS_CLIENT_VERSION_LONGHORN):
+ return self.conn.DnssrvEnumRecords2(client_version,
+ 0,
+ self.server,
+ zone,
+ name,
+ None,
+ flag_from_string(record_type_str),
+ dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA | dnsserver.DNS_RPC_VIEW_NO_CHILDREN,
+ None,
+ None)
+
+ def add_record(self, zone, name, record_type_str, record_str,
+ assertion=True, client_version=dnsserver.DNS_CLIENT_VERSION_LONGHORN):
+ """
+ Attempts to add a map from the given name to a record of the given type,
+ in the given zone.
+ Also asserts whether or not the add was successful.
+ This can also update existing records if they have the same name.
+ """
+ record = record_from_string(record_type_str, record_str, sep=' ')
+ add_rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
+ add_rec_buf.rec = record
+
+ try:
+ self.conn.DnssrvUpdateRecord2(client_version,
+ 0,
+ self.server,
+ zone,
+ name,
+ add_rec_buf,
+ None)
+ if not assertion:
+ raise AssertionError("Successfully added record '%s' of type '%s', which should have failed."
+ % (record_str, record_type_str))
+ except RuntimeError as e:
+ if assertion:
+ raise AssertionError("Failed to add record '%s' of type '%s', which should have succeeded. Error was '%s'."
+ % (record_str, record_type_str, str(e)))
+
+ def delete_record(self, zone, name, record_type_str, record_str,
+ assertion=True, client_version=dnsserver.DNS_CLIENT_VERSION_LONGHORN):
+ """
+ Attempts to delete a record with the given name, record and record type
+ from the given zone.
+ Also asserts whether or not the deletion was successful.
+ """
+ record = record_from_string(record_type_str, record_str, sep=' ')
+ del_rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
+ del_rec_buf.rec = record
+
+ try:
+ self.conn.DnssrvUpdateRecord2(client_version,
+ 0,
+ self.server,
+ zone,
+ name,
+ None,
+ del_rec_buf)
+ if not assertion:
+ raise AssertionError("Successfully deleted record '%s' of type '%s', which should have failed." % (record_str, record_type_str))
+ except RuntimeError as e:
+ if assertion:
+ raise AssertionError("Failed to delete record '%s' of type '%s', which should have succeeded. Error was '%s'." % (record_str, record_type_str, str(e)))
+
+ def test_query2(self):
+ typeid, result = self.conn.DnssrvQuery2(dnsserver.DNS_CLIENT_VERSION_W2K,
+ 0,
+ self.server,
+ None,
+ 'ServerInfo')
+ self.assertEqual(dnsserver.DNSSRV_TYPEID_SERVER_INFO_W2K, typeid)
+
+ typeid, result = self.conn.DnssrvQuery2(dnsserver.DNS_CLIENT_VERSION_DOTNET,
+ 0,
+ self.server,
+ None,
+ 'ServerInfo')
+ self.assertEqual(dnsserver.DNSSRV_TYPEID_SERVER_INFO_DOTNET, typeid)
+
+ typeid, result = self.conn.DnssrvQuery2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
+ 0,
+ self.server,
+ None,
+ 'ServerInfo')
+ self.assertEqual(dnsserver.DNSSRV_TYPEID_SERVER_INFO, typeid)
+
+
+ # This test is to confirm that we do not support multizone operations,
+ # which are designated by a non-zero dwContext value (the 3rd argument
+ # to DnssrvOperation).
+ def test_operation_invalid(self):
+ non_zone = 'a-zone-that-does-not-exist'
+ typeid = dnsserver.DNSSRV_TYPEID_NAME_AND_PARAM
+ name_and_param = dnsserver.DNS_RPC_NAME_AND_PARAM()
+ name_and_param.pszNodeName = 'AllowUpdate'
+ name_and_param.dwParam = dnsp.DNS_ZONE_UPDATE_SECURE
+ try:
+ res = self.conn.DnssrvOperation(self.server,
+ non_zone,
+ 1,
+ 'ResetDwordProperty',
+ typeid,
+ name_and_param)
+ except WERRORError as e:
+ if e.args[0] == werror.WERR_DNS_ERROR_ZONE_DOES_NOT_EXIST:
+ return
+
+ # We should always encounter a DOES_NOT_EXIST error.
+ self.fail()
+
+ # This test is to confirm that we do not support multizone operations,
+ # which are designated by a non-zero dwContext value (the 5th argument
+ # to DnssrvOperation2).
+ def test_operation2_invalid(self):
+ client_version = dnsserver.DNS_CLIENT_VERSION_LONGHORN
+ non_zone = 'a-zone-that-does-not-exist'
+ typeid = dnsserver.DNSSRV_TYPEID_NAME_AND_PARAM
+ name_and_param = dnsserver.DNS_RPC_NAME_AND_PARAM()
+ name_and_param.pszNodeName = 'AllowUpdate'
+ name_and_param.dwParam = dnsp.DNS_ZONE_UPDATE_SECURE
+ try:
+ res = self.conn.DnssrvOperation2(client_version,
+ 0,
+ self.server,
+ non_zone,
+ 1,
+ 'ResetDwordProperty',
+ typeid,
+ name_and_param)
+ except WERRORError as e:
+ if e.args[0] == werror.WERR_DNS_ERROR_ZONE_DOES_NOT_EXIST:
+ return
+
+ # We should always encounter a DOES_NOT_EXIST error.
+ self.fail()
+
+ def test_operation2(self):
+ client_version = dnsserver.DNS_CLIENT_VERSION_LONGHORN
+ rev_zone = '1.168.192.in-addr.arpa'
+
+ zone_create = dnsserver.DNS_RPC_ZONE_CREATE_INFO_LONGHORN()
+ zone_create.pszZoneName = rev_zone
+ zone_create.dwZoneType = dnsp.DNS_ZONE_TYPE_PRIMARY
+ zone_create.fAllowUpdate = dnsp.DNS_ZONE_UPDATE_SECURE
+ zone_create.fAging = 0
+ zone_create.dwDpFlags = dnsserver.DNS_DP_DOMAIN_DEFAULT
+
+ # Create zone
+ self.conn.DnssrvOperation2(client_version,
+ 0,
+ self.server,
+ None,
+ 0,
+ 'ZoneCreate',
+ dnsserver.DNSSRV_TYPEID_ZONE_CREATE,
+ zone_create)
+
+ request_filter = (dnsserver.DNS_ZONE_REQUEST_REVERSE |
+ dnsserver.DNS_ZONE_REQUEST_PRIMARY)
+ _, zones = self.conn.DnssrvComplexOperation2(client_version,
+ 0,
+ self.server,
+ None,
+ 'EnumZones',
+ dnsserver.DNSSRV_TYPEID_DWORD,
+ request_filter)
+ self.assertEqual(1, zones.dwZoneCount)
+
+ # Delete zone
+ self.conn.DnssrvOperation2(client_version,
+ 0,
+ self.server,
+ rev_zone,
+ 0,
+ 'DeleteZoneFromDs',
+ dnsserver.DNSSRV_TYPEID_NULL,
+ None)
+
+ typeid, zones = self.conn.DnssrvComplexOperation2(client_version,
+ 0,
+ self.server,
+ None,
+ 'EnumZones',
+ dnsserver.DNSSRV_TYPEID_DWORD,
+ request_filter)
+ self.assertEqual(0, zones.dwZoneCount)
+
+ def test_complexoperation2(self):
+ client_version = dnsserver.DNS_CLIENT_VERSION_LONGHORN
+ request_filter = (dnsserver.DNS_ZONE_REQUEST_FORWARD |
+ dnsserver.DNS_ZONE_REQUEST_PRIMARY)
+
+ typeid, zones = self.conn.DnssrvComplexOperation2(client_version,
+ 0,
+ self.server,
+ None,
+ 'EnumZones',
+ dnsserver.DNSSRV_TYPEID_DWORD,
+ request_filter)
+ self.assertEqual(dnsserver.DNSSRV_TYPEID_ZONE_LIST, typeid)
+ self.assertEqual(3, zones.dwZoneCount)
+
+ request_filter = (dnsserver.DNS_ZONE_REQUEST_REVERSE |
+ dnsserver.DNS_ZONE_REQUEST_PRIMARY)
+ typeid, zones = self.conn.DnssrvComplexOperation2(client_version,
+ 0,
+ self.server,
+ None,
+ 'EnumZones',
+ dnsserver.DNSSRV_TYPEID_DWORD,
+ request_filter)
+ self.assertEqual(dnsserver.DNSSRV_TYPEID_ZONE_LIST, typeid)
+ self.assertEqual(0, zones.dwZoneCount)
+
+ def test_enumrecords2(self):
+ client_version = dnsserver.DNS_CLIENT_VERSION_LONGHORN
+ record_type = dnsp.DNS_TYPE_NS
+ select_flags = (dnsserver.DNS_RPC_VIEW_ROOT_HINT_DATA |
+ dnsserver.DNS_RPC_VIEW_ADDITIONAL_DATA)
+ _, roothints = self.conn.DnssrvEnumRecords2(client_version,
+ 0,
+ self.server,
+ '..RootHints',
+ '.',
+ None,
+ record_type,
+ select_flags,
+ None,
+ None)
+ self.assertEqual(14, roothints.count) # 1 NS + 13 A records (a-m)
+
+ def test_updaterecords2(self):
+ client_version = dnsserver.DNS_CLIENT_VERSION_LONGHORN
+ record_type = dnsp.DNS_TYPE_A
+ select_flags = dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA
+ name = 'dummy'
+ rec = ARecord('1.2.3.4')
+ rec2 = ARecord('5.6.7.8')
+
+ # Add record
+ add_rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
+ add_rec_buf.rec = rec
+ self.conn.DnssrvUpdateRecord2(client_version,
+ 0,
+ self.server,
+ self.zone,
+ name,
+ add_rec_buf,
+ None)
+
+ _, result = self.conn.DnssrvEnumRecords2(client_version,
+ 0,
+ self.server,
+ self.zone,
+ name,
+ None,
+ record_type,
+ select_flags,
+ None,
+ None)
+ self.assertEqual(1, result.count)
+ self.assertEqual(1, result.rec[0].wRecordCount)
+ self.assertEqual(dnsp.DNS_TYPE_A, result.rec[0].records[0].wType)
+ self.assertEqual('1.2.3.4', result.rec[0].records[0].data)
+
+ # Update record
+ add_rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
+ add_rec_buf.rec = rec2
+ del_rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
+ del_rec_buf.rec = rec
+ self.conn.DnssrvUpdateRecord2(client_version,
+ 0,
+ self.server,
+ self.zone,
+ name,
+ add_rec_buf,
+ del_rec_buf)
+
+ buflen, result = self.conn.DnssrvEnumRecords2(client_version,
+ 0,
+ self.server,
+ self.zone,
+ name,
+ None,
+ record_type,
+ select_flags,
+ None,
+ None)
+ self.assertEqual(1, result.count)
+ self.assertEqual(1, result.rec[0].wRecordCount)
+ self.assertEqual(dnsp.DNS_TYPE_A, result.rec[0].records[0].wType)
+ self.assertEqual('5.6.7.8', result.rec[0].records[0].data)
+
+ # Delete record
+ del_rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
+ del_rec_buf.rec = rec2
+ self.conn.DnssrvUpdateRecord2(client_version,
+ 0,
+ self.server,
+ self.zone,
+ name,
+ None,
+ del_rec_buf)
+
+ self.assertRaises(RuntimeError, self.conn.DnssrvEnumRecords2,
+ client_version,
+ 0,
+ self.server,
+ self.zone,
+ name,
+ None,
+ record_type,
+ 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.assertIn("nTSecurityDescriptor", 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.assertIn("nTSecurityDescriptor", 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.assertIn("nTSecurityDescriptor", 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.assertIn("nTSecurityDescriptor", 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.assertIn("nTSecurityDescriptor", 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)))
diff --git a/python/samba/tests/dcerpc/integer.py b/python/samba/tests/dcerpc/integer.py
new file mode 100644
index 0000000..69a6a09
--- /dev/null
+++ b/python/samba/tests/dcerpc/integer.py
@@ -0,0 +1,250 @@
+# Unix SMB/CIFS implementation.
+# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2015
+#
+# 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/>.
+#
+
+"""Tests for integer handling in PIDL generated bindings samba.dcerpc.*"""
+
+from samba.dcerpc import server_id, misc, srvsvc, samr
+import samba.tests
+
+
+class IntegerTests(samba.tests.TestCase):
+
+ def test_uint32_into_hyper(self):
+ s = server_id.server_id()
+ s.unique_id = server_id.NONCLUSTER_VNN
+ self.assertEqual(s.unique_id, 0xFFFFFFFF)
+
+ def test_int_into_hyper(self):
+ s = server_id.server_id()
+ s.unique_id = 1
+ self.assertEqual(s.unique_id, 1)
+
+ def test_negative_int_into_hyper(self):
+ s = server_id.server_id()
+
+ def assign():
+ s.unique_id = -1
+ self.assertRaises(OverflowError, assign)
+
+ def test_hyper_into_uint32(self):
+ s = server_id.server_id()
+
+ def assign():
+ s.vnn = server_id.SERVERID_UNIQUE_ID_NOT_TO_VERIFY
+ self.assertRaises(OverflowError, assign)
+
+ def test_hyper_into_int32(self):
+ s = srvsvc.NetRemoteTODInfo()
+
+ def assign():
+ s.timezone = server_id.SERVERID_UNIQUE_ID_NOT_TO_VERIFY
+ self.assertRaises(OverflowError, assign)
+
+ def test_int_into_int32(self):
+ s = srvsvc.NetRemoteTODInfo()
+ s.timezone = 5
+ self.assertEqual(s.timezone, 5)
+
+ def test_uint32_into_int32(self):
+ s = srvsvc.NetRemoteTODInfo()
+
+ def assign():
+ s.timezone = server_id.NONCLUSTER_VNN
+ self.assertRaises(OverflowError, assign)
+
+ def test_long_into_int32(self):
+ s = srvsvc.NetRemoteTODInfo()
+ # here we force python2 to convert its 32/64 bit python int into
+ # an arbitrarily long python long, then reduce the number back
+ # down to something that would fit in an int anyway. In a pure
+ # python2 world, you could achieve the same thing by writing
+ # s.timezone = 5L
+ # but that is a syntax error in py3.
+ s.timezone = (5 << 65) >> 65
+ self.assertEqual(s.timezone, 5)
+
+ def test_larger_long_int_into_int32(self):
+ s = srvsvc.NetRemoteTODInfo()
+
+ def assign():
+ s.timezone = 2147483648
+ self.assertRaises(OverflowError, assign)
+
+ def test_larger_int_into_int32(self):
+ s = srvsvc.NetRemoteTODInfo()
+ s.timezone = 2147483647
+ self.assertEqual(s.timezone, 2147483647)
+
+ def test_float_into_int32(self):
+ s = srvsvc.NetRemoteTODInfo()
+
+ def assign():
+ s.timezone = 2.5
+ self.assertRaises(TypeError, assign)
+
+ def test_int_float_into_int32(self):
+ s = srvsvc.NetRemoteTODInfo()
+
+ def assign():
+ s.timezone = 2.0
+ self.assertRaises(TypeError, assign)
+
+ def test_negative_int_into_int32(self):
+ s = srvsvc.NetRemoteTODInfo()
+ s.timezone = -2147483648
+ self.assertEqual(s.timezone, -2147483648)
+
+ def test_negative_into_uint32(self):
+ s = server_id.server_id()
+
+ def assign():
+ s.vnn = -1
+ self.assertRaises(OverflowError, assign)
+
+ def test_hyper_into_uint16(self):
+ g = misc.GUID()
+
+ def assign():
+ g.time_mid = server_id.SERVERID_UNIQUE_ID_NOT_TO_VERIFY
+ self.assertRaises(OverflowError, assign)
+
+ def test_int_into_uint16(self):
+ g = misc.GUID()
+
+ def assign():
+ g.time_mid = 200000
+ self.assertRaises(OverflowError, assign)
+
+ def test_negative_int_into_uint16(self):
+ g = misc.GUID()
+
+ def assign():
+ g.time_mid = -2
+ self.assertRaises(OverflowError, assign)
+
+ def test_enum_into_uint16(self):
+ g = misc.GUID()
+ g.time_mid = misc.SEC_CHAN_DOMAIN
+ self.assertEqual(g.time_mid, misc.SEC_CHAN_DOMAIN)
+
+ def test_bitmap_into_uint16(self):
+ g = misc.GUID()
+ g.time_mid = misc.SV_TYPE_WFW
+ self.assertEqual(g.time_mid, misc.SV_TYPE_WFW)
+
+ def test_overflow_bitmap_into_uint16(self):
+ g = misc.GUID()
+
+ def assign():
+ g.time_mid = misc.SV_TYPE_LOCAL_LIST_ONLY
+ self.assertRaises(OverflowError, assign)
+
+ def test_overflow_bitmap_into_uint16_2(self):
+ g = misc.GUID()
+
+ def assign():
+ g.time_mid = misc.SV_TYPE_DOMAIN_ENUM
+ self.assertRaises(OverflowError, assign)
+
+ def test_hyper_into_int64(self):
+ s = samr.DomInfo1()
+
+ def assign():
+ s.max_password_age = server_id.SERVERID_UNIQUE_ID_NOT_TO_VERIFY
+ self.assertRaises(OverflowError, assign)
+
+ def test_int_into_int64(self):
+ s = samr.DomInfo1()
+ s.max_password_age = 5
+ self.assertEqual(s.max_password_age, 5)
+
+ def test_negative_int_into_int64(self):
+ s = samr.DomInfo1()
+ s.max_password_age = -5
+ self.assertEqual(s.max_password_age, -5)
+
+ def test_larger_int_into_int64(self):
+ s = samr.DomInfo1()
+ s.max_password_age = server_id.NONCLUSTER_VNN
+ self.assertEqual(s.max_password_age, 0xFFFFFFFF)
+
+ def test_larger_negative_int_into_int64(self):
+ s = samr.DomInfo1()
+ s.max_password_age = -2147483649
+ self.assertEqual(s.max_password_age, -2147483649)
+
+ def test_int_list_over_list(self):
+ g = misc.GUID()
+ g.node = [5, 0, 5, 0, 7, 4]
+ self.assertEqual(g.node[0], 5)
+
+ def test_long_int_list_over_uint8_list(self):
+ g = misc.GUID()
+ g.node = [5, 0, 5, 0, 7, 4]
+ self.assertEqual(g.node[0], 5)
+
+ def test_negative_list_over_uint8_list(self):
+ g = misc.GUID()
+
+ def assign():
+ g.node = [-1, 0, 5, 0, 7, 4]
+ self.assertRaises(OverflowError, assign)
+
+ def test_overflow_list_over_uint8_list(self):
+ g = misc.GUID()
+
+ def assign():
+ g.node = [256, 0, 5, 0, 7, 4]
+ self.assertRaises(OverflowError, assign)
+
+ def test_short_list_over_uint8_list(self):
+ g = misc.GUID()
+
+ def assign():
+ g.node = [5, 0, 5]
+ self.assertRaises(TypeError, assign)
+
+ def test_long_list_over_uint8_list(self):
+ g = misc.GUID()
+
+ def assign():
+ g.node = [5, 0, 5, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]
+ self.assertRaises(TypeError, assign)
+
+ # Due to our PIDL bindings generating a python List, modifications
+ # to a list of non-objects are not reflected in the C list
+ # (modifications objects in lists of objects work because the
+ # objects are modified), so changes essentially vanish and are not
+ # type checked either.
+ def test_assign_into_uint8_list(self):
+ g = misc.GUID()
+ g.node[1] = 5
+ self.assertEqual(g.node[1], 5)
+
+ def test_negative_into_uint8_list(self):
+ g = misc.GUID()
+
+ def assign():
+ g.node[1] = -1
+ self.assertRaises(OverflowError, assign)
+
+ def test_overflow_into_uint8_list(self):
+ g = misc.GUID()
+
+ def assign():
+ g.node[1] = 256
+ self.assertRaises(OverflowError, assign)
diff --git a/python/samba/tests/dcerpc/lsa.py b/python/samba/tests/dcerpc/lsa.py
new file mode 100644
index 0000000..355bb1f
--- /dev/null
+++ b/python/samba/tests/dcerpc/lsa.py
@@ -0,0 +1,333 @@
+# -*- coding: utf-8 -*-
+#
+# Unix SMB/CIFS implementation.
+# Copyright © Andrew Bartlett <abartlet@samba.org> 2021
+# Copyright (C) Catalyst IT Ltd. 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/>.
+#
+
+"""Tests for samba.dcerpc.lsa."""
+
+from samba.dcerpc import lsa
+from samba.credentials import Credentials
+from samba.tests import TestCase
+from samba.dcerpc.security import dom_sid
+from samba import NTSTATUSError
+from samba.ntstatus import NT_STATUS_ACCESS_DENIED
+import samba.tests
+
+class LsaTests(TestCase):
+
+ def setUp(self):
+ self.lp = self.get_loadparm()
+ self.server = samba.tests.env_get_var_value('SERVER')
+
+ def test_lsa_LookupSids3_multiple(self):
+ machine_creds = Credentials()
+ machine_creds.guess(self.lp)
+ machine_creds.set_machine_account()
+
+ c = lsa.lsarpc(
+ "ncacn_ip_tcp:%s[schannel,seal]" % self.server,
+ self.lp,
+ machine_creds)
+
+ sids = lsa.SidArray()
+ sid = lsa.SidPtr()
+ # Need a set
+ x = dom_sid("S-1-5-7")
+ sid.sid = x
+ sids.sids = [sid]
+ sids.num_sids = 1
+ names = lsa.TransNameArray2()
+ level = lsa.LSA_LOOKUP_NAMES_ALL
+ count = 0
+ lookup_options = lsa.LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES
+ client_revision = lsa.LSA_CLIENT_REVISION_2
+
+ # We want to run LookupSids3 multiple times on the same
+ # connection as we have code to re-use the sam.ldb and we need
+ # to check things work for the second request.
+ (domains, names, count) = c.LookupSids3(sids, names, level, count, lookup_options, client_revision)
+ self.assertEqual(count, 1)
+ self.assertEqual(names.count, 1)
+ self.assertEqual(names.names[0].name.string,
+ "ANONYMOUS LOGON")
+ (domains2, names2, count2) = c.LookupSids3(sids, names, level, count, lookup_options, client_revision)
+ self.assertEqual(count2, 1)
+ self.assertEqual(names2.count, 1)
+ self.assertEqual(names2.names[0].name.string,
+ "ANONYMOUS LOGON")
+
+ # Just looking for any exceptions in the last couple of loops
+ c.LookupSids3(sids, names, level, count, lookup_options, client_revision)
+ c.LookupSids3(sids, names, level, count, lookup_options, client_revision)
+
+ def test_lsa_LookupSids3_multiple_conns(self):
+ machine_creds = Credentials()
+ machine_creds.guess(self.lp)
+ machine_creds.set_machine_account()
+
+ c = lsa.lsarpc(
+ "ncacn_ip_tcp:%s[schannel,seal]" % self.server,
+ self.lp,
+ machine_creds)
+
+ sids = lsa.SidArray()
+ sid = lsa.SidPtr()
+ # Need a set
+ x = dom_sid("S-1-5-7")
+ sid.sid = x
+ sids.sids = [sid]
+ sids.num_sids = 1
+ names = lsa.TransNameArray2()
+ level = lsa.LSA_LOOKUP_NAMES_ALL
+ count = 0
+ lookup_options = lsa.LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES
+ client_revision = lsa.LSA_CLIENT_REVISION_2
+
+ # We want to run LookupSids3, and then again on a new
+ # connection to show that we don't have an issue with the DB
+ # being tied to the wrong connection.
+ (domains, names, count) = c.LookupSids3(sids,
+ names,
+ level,
+ count,
+ lookup_options,
+ client_revision)
+ self.assertEqual(count, 1)
+ self.assertEqual(names.count, 1)
+ self.assertEqual(names.names[0].name.string,
+ "ANONYMOUS LOGON")
+
+ c = lsa.lsarpc(
+ "ncacn_ip_tcp:%s[schannel,seal]" % self.server,
+ self.lp,
+ machine_creds)
+
+ (domains, names, count) = c.LookupSids3(sids,
+ names,
+ level,
+ count,
+ lookup_options,
+ client_revision)
+ self.assertEqual(count, 1)
+ self.assertEqual(names.count, 1)
+ self.assertEqual(names.names[0].name.string,
+ "ANONYMOUS LOGON")
+
+
+ def test_lsa_LookupNames4_LookupSids3_multiple(self):
+ """
+ Test by going back and forward between real DB lookups
+ name->sid->name to ensure the sam.ldb handle is fine once
+ shared
+ """
+
+ machine_creds = Credentials()
+ machine_creds.guess(self.lp)
+ machine_creds.set_machine_account()
+
+ c_normal = lsa.lsarpc(
+ "ncacn_np:%s[seal]" % self.server,
+ self.lp,
+ machine_creds)
+
+ username, domain = c_normal.GetUserName(None, None, None)
+
+ c = lsa.lsarpc(
+ "ncacn_ip_tcp:%s[schannel,seal]" % self.server,
+ self.lp,
+ machine_creds)
+
+ sids = lsa.TransSidArray3()
+ names = [username]
+ level = lsa.LSA_LOOKUP_NAMES_ALL
+ count = 0
+ lookup_options = lsa.LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES
+ client_revision = lsa.LSA_CLIENT_REVISION_2
+ (domains, sids, count) = c.LookupNames4(names,
+ sids,
+ level,
+ count,
+ lookup_options,
+ client_revision)
+
+ # Another lookup on the same connection, will re-used the
+ # server-side implicit state handle on the connection
+ (domains, sids, count) = c.LookupNames4(names,
+ sids,
+ level,
+ count,
+ lookup_options,
+ client_revision)
+
+ self.assertEqual(count, 1)
+ self.assertEqual(sids.count, 1)
+
+ # Now look the SIDs back up
+ names = lsa.TransNameArray2()
+ sid = lsa.SidPtr()
+ sid.sid = sids.sids[0].sid
+ lookup_sids = lsa.SidArray()
+ lookup_sids.sids = [sid]
+ lookup_sids.num_sids = 1
+ level = lsa.LSA_LOOKUP_NAMES_ALL
+ count = 1
+ lookup_options = 0
+ client_revision = lsa.LSA_CLIENT_REVISION_2
+
+ (domains, names, count) = c.LookupSids3(lookup_sids,
+ names,
+ level,
+ count,
+ lookup_options,
+ client_revision)
+ self.assertEqual(count, 1)
+ self.assertEqual(names.count, 1)
+ self.assertEqual(names.names[0].name.string,
+ username.string)
+
+ # And once more just to be sure, just checking for a fault
+ sids = lsa.TransSidArray3()
+ names = [username]
+ level = lsa.LSA_LOOKUP_NAMES_ALL
+ count = 0
+ lookup_options = lsa.LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES
+ client_revision = lsa.LSA_CLIENT_REVISION_2
+ (domains, sids, count) = c.LookupNames4(names,
+ sids,
+ level,
+ count,
+ lookup_options,
+ client_revision)
+
+
+ def test_lsa_LookupNames4_multiple_conns(self):
+ """
+ Test by going back and forward between real DB lookups
+ name->sid->name to ensure the sam.ldb handle is fine once
+ shared
+ """
+
+ machine_creds = Credentials()
+ machine_creds.guess(self.lp)
+ machine_creds.set_machine_account()
+
+ c_normal = lsa.lsarpc(
+ "ncacn_np:%s[seal]" % self.server,
+ self.lp,
+ machine_creds)
+
+ username, domain = c_normal.GetUserName(None, None, None)
+
+ c = lsa.lsarpc(
+ "ncacn_ip_tcp:%s[schannel,seal]" % self.server,
+ self.lp,
+ machine_creds)
+
+ sids = lsa.TransSidArray3()
+ names = [username]
+ level = lsa.LSA_LOOKUP_NAMES_ALL
+ count = 0
+ lookup_options = lsa.LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES
+ client_revision = lsa.LSA_CLIENT_REVISION_2
+ (domains, sids, count) = c.LookupNames4(names,
+ sids,
+ level,
+ count,
+ lookup_options,
+ client_revision)
+
+ c = lsa.lsarpc(
+ "ncacn_ip_tcp:%s[schannel,seal]" % self.server,
+ self.lp,
+ machine_creds)
+
+ sids = lsa.TransSidArray3()
+ names = [username]
+ level = lsa.LSA_LOOKUP_NAMES_ALL
+ count = 0
+ lookup_options = lsa.LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES
+ client_revision = lsa.LSA_CLIENT_REVISION_2
+ (domains, sids, count) = c.LookupNames4(names,
+ sids,
+ level,
+ count,
+ lookup_options,
+ client_revision)
+
+ def test_lsa_LookupNames4_without_schannel(self):
+
+ machine_creds = Credentials()
+ machine_creds.guess(self.lp)
+ machine_creds.set_machine_account()
+
+ c_normal = lsa.lsarpc(
+ "ncacn_np:%s[seal]" % self.server,
+ self.lp,
+ machine_creds)
+
+ username, domain = c_normal.GetUserName(None, None, None)
+
+ sids = lsa.TransSidArray3()
+ names = [username]
+ level = lsa.LSA_LOOKUP_NAMES_ALL
+ count = 0
+ lookup_options = lsa.LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES
+ client_revision = lsa.LSA_CLIENT_REVISION_2
+
+ with self.assertRaises(NTSTATUSError) as e:
+ c_normal.LookupNames4(names,
+ sids,
+ level,
+ count,
+ lookup_options,
+ client_revision)
+ if (e.exception.args[0] != NT_STATUS_ACCESS_DENIED):
+ raise AssertionError("LookupNames4 without schannel must fail with ACCESS_DENIED")
+
+ def test_lsa_LookupSids3_without_schannel(self):
+ machine_creds = Credentials()
+ machine_creds.guess(self.lp)
+ machine_creds.set_machine_account()
+
+ c = lsa.lsarpc(
+ "ncacn_ip_tcp:%s[seal]" % self.server,
+ self.lp,
+ machine_creds)
+
+ sids = lsa.SidArray()
+ sid = lsa.SidPtr()
+ # Need a set
+ x = dom_sid("S-1-5-7")
+ sid.sid = x
+ sids.sids = [sid]
+ sids.num_sids = 1
+ names = lsa.TransNameArray2()
+ level = lsa.LSA_LOOKUP_NAMES_ALL
+ count = 0
+ lookup_options = lsa.LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES
+ client_revision = lsa.LSA_CLIENT_REVISION_2
+
+ with self.assertRaises(NTSTATUSError) as e:
+ c.LookupSids3(sids,
+ names,
+ level,
+ count,
+ lookup_options,
+ client_revision)
+ if (e.exception.args[0] != NT_STATUS_ACCESS_DENIED):
+ raise AssertionError("LookupSids3 without schannel must fail with ACCESS_DENIED")
diff --git a/python/samba/tests/dcerpc/mdssvc.py b/python/samba/tests/dcerpc/mdssvc.py
new file mode 100644
index 0000000..1d53676
--- /dev/null
+++ b/python/samba/tests/dcerpc/mdssvc.py
@@ -0,0 +1,194 @@
+#
+# Unix SMB/CIFS implementation.
+# Copyright Ralph Boehme <slow@samba.org> 2019
+#
+# 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/>.
+#
+
+"""Tests for samba.dcerpc.mdssvc"""
+
+import os
+import time
+import threading
+import logging
+import json
+from http.server import HTTPServer, BaseHTTPRequestHandler
+from samba.dcerpc import mdssvc
+from samba.tests import RpcInterfaceTestCase
+from samba.samba3 import mdscli
+from samba.logger import get_samba_logger
+
+logger = get_samba_logger(name=__name__)
+
+testfiles = [
+ "foo",
+ "bar",
+ "x+x",
+ "x*x",
+ "x=x",
+ "x'x",
+ "x?x",
+ "x\"x",
+ "x\\x",
+ "x(x",
+ "x x",
+]
+
+class MdssvcHTTPRequestHandler(BaseHTTPRequestHandler):
+ def do_POST(self):
+ content_length = int(self.headers['content-length'])
+ body = self.rfile.read(content_length)
+
+ actual_json = json.loads((body))
+ expected_json = json.loads(self.server.json_in)
+
+ if actual_json != expected_json:
+ logger.error("Bad request, expected:\n%s\nGot:\n%s\n" % (expected_json, actual_json))
+ self.send_error(400,
+ "Bad request",
+ "Expected: %s\n"
+ "Got: %s\n" %
+ (expected_json, actual_json))
+ return
+
+ resp = bytes(self.server.json_out, encoding="utf-8")
+
+ self.send_response(200)
+ self.send_header('content-type', 'application/json; charset=UTF-8')
+ self.send_header('content-length', len(resp))
+ self.end_headers()
+ self.wfile.write(resp)
+
+class MdssvcTests(RpcInterfaceTestCase):
+
+ def setUp(self):
+ super().setUp()
+
+ self.pipe = mdssvc.mdssvc('ncacn_np:fileserver[/pipe/mdssvc]', self.get_loadparm())
+
+ self.server = HTTPServer(('10.53.57.35', 8080),
+ MdssvcHTTPRequestHandler,
+ bind_and_activate=False)
+
+ self.t = threading.Thread(target=MdssvcTests.http_server, args=(self,))
+ self.t.setDaemon(True)
+ self.t.start()
+ self.sharepath = os.environ["LOCAL_PATH"]
+ time.sleep(1)
+
+ conn = mdscli.conn(self.pipe, 'spotlight', '/foo')
+ self.fakepath = conn.sharepath()
+ conn.disconnect(self.pipe)
+
+ for file in testfiles:
+ f = open("%s/%s" % (self.sharepath, file), "w")
+ f.close()
+
+ def tearDown(self):
+ super().tearDown()
+ for file in testfiles:
+ os.remove("%s/%s" % (self.sharepath, file))
+
+ def http_server(self):
+ self.server.server_bind()
+ self.server.server_activate()
+ self.server.serve_forever()
+
+ def run_test(self, query, expect, json_in, json_out):
+ self.server.json_in = json_in.replace("%BASEPATH%", self.sharepath)
+ self.server.json_out = json_out.replace("%BASEPATH%", self.sharepath)
+
+ self.conn = mdscli.conn(self.pipe, 'spotlight', '/foo')
+ search = self.conn.search(self.pipe, query, self.fakepath)
+
+ # Give it some time, the get_results() below returns immediately
+ # what's available, so if we ask to soon, we might get back no results
+ # as the server is still processing the request
+ time.sleep(1)
+
+ results = search.get_results(self.pipe)
+ self.assertEqual(results, expect)
+
+ search.close(self.pipe)
+ self.conn.disconnect(self.pipe)
+
+ def test_mdscli_search(self):
+ exp_json_query = r'''{
+ "from": 0, "size": 50, "_source": ["path.real"],
+ "query": {
+ "query_string": {
+ "query": "(samba*) AND path.real.fulltext:\"%BASEPATH%\""
+ }
+ }
+ }'''
+ fake_json_response = '''{
+ "hits" : {
+ "total" : { "value" : 2},
+ "hits" : [
+ {"_source" : {"path" : {"real" : "%BASEPATH%/foo"}}},
+ {"_source" : {"path" : {"real" : "%BASEPATH%/bar"}}}
+ ]
+ }
+ }'''
+ exp_results = ["foo", "bar"]
+ self.run_test('*=="samba*"', exp_results, exp_json_query, fake_json_response)
+
+ def test_mdscli_search_escapes(self):
+ sl_query = (
+ r'kMDItemFSName=="x+x"||'
+ r'kMDItemFSName=="x\*x"||'
+ r'kMDItemFSName=="x=x"||'
+ 'kMDItemFSName=="x\'x"||'
+ r'kMDItemFSName=="x?x"||'
+ r'kMDItemFSName=="x x"||'
+ r'kMDItemFSName=="x(x"||'
+ r'kMDItemFSName=="x\"x"||'
+ r'kMDItemFSName=="x\\x"'
+ )
+ exp_json_query = r'''{
+ "from": 0, "size": 50, "_source": ["path.real"],
+ "query": {
+ "query_string": {
+ "query": "(file.filename:x\\+x OR file.filename:x\\*x OR file.filename:x=x OR file.filename:x'x OR file.filename:x\\?x OR file.filename:x\\ x OR file.filename:x\\(x OR file.filename:x\\\"x OR file.filename:x\\\\x) AND path.real.fulltext:\"%BASEPATH%\""
+ }
+ }
+ }'''
+ fake_json_response = r'''{
+ "hits" : {
+ "total" : {"value" : 9},
+ "hits" : [
+ {"_source" : {"path" : {"real" : "%BASEPATH%/x+x"}}},
+ {"_source" : {"path" : {"real" : "%BASEPATH%/x*x"}}},
+ {"_source" : {"path" : {"real" : "%BASEPATH%/x=x"}}},
+ {"_source" : {"path" : {"real" : "%BASEPATH%/x'x"}}},
+ {"_source" : {"path" : {"real" : "%BASEPATH%/x?x"}}},
+ {"_source" : {"path" : {"real" : "%BASEPATH%/x x"}}},
+ {"_source" : {"path" : {"real" : "%BASEPATH%/x(x"}}},
+ {"_source" : {"path" : {"real" : "%BASEPATH%/x\"x"}}},
+ {"_source" : {"path" : {"real" : "%BASEPATH%/x\\x"}}}
+ ]
+ }
+ }'''
+ exp_results = [
+ r"x+x",
+ r"x*x",
+ r"x=x",
+ r"x'x",
+ r"x?x",
+ r"x x",
+ r"x(x",
+ "x\"x",
+ r"x\x",
+ ]
+ self.run_test(sl_query, exp_results, exp_json_query, fake_json_response)
diff --git a/python/samba/tests/dcerpc/misc.py b/python/samba/tests/dcerpc/misc.py
new file mode 100644
index 0000000..6b58e94
--- /dev/null
+++ b/python/samba/tests/dcerpc/misc.py
@@ -0,0 +1,101 @@
+# Unix SMB/CIFS implementation.
+# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
+#
+# 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/>.
+#
+
+"""Tests for samba.dcerpc.misc."""
+
+from samba.dcerpc import misc
+import samba.tests
+from samba.common import cmp
+
+text1 = "76f53846-a7c2-476a-ae2c-20e2b80d7b34"
+text2 = "344edffa-330a-4b39-b96e-2c34da52e8b1"
+text3 = "00112233-4455-6677-8899-aabbccddeeff"
+
+
+class GUIDTests(samba.tests.TestCase):
+
+ def test_str(self):
+ guid = misc.GUID(text1)
+ self.assertEqual(text1, str(guid))
+
+ def test_repr(self):
+ guid = misc.GUID(text1)
+ self.assertEqual("GUID('%s')" % text1, repr(guid))
+
+ def test_compare_different(self):
+ guid1 = misc.GUID(text1)
+ guid2 = misc.GUID(text2)
+ self.assertFalse(guid1 == guid2)
+ self.assertGreater(guid1, guid2)
+ self.assertTrue(cmp(guid1, guid2) > 0)
+
+ def test_compare_same(self):
+ guid1 = misc.GUID(text1)
+ guid2 = misc.GUID(text1)
+ self.assertTrue(guid1 == guid2)
+ self.assertEqual(guid1, guid2)
+ self.assertEqual(0, cmp(guid1, guid2))
+
+ def test_valid_formats(self):
+ fmts = [
+ "00112233-4455-6677-8899-aabbccddeeff", # 36
+ b"00112233-4455-6677-8899-aabbccddeeff", # 36 as bytes
+ "{00112233-4455-6677-8899-aabbccddeeff}", # 38
+
+ "33221100554477668899aabbccddeeff", # 32
+ b"33221100554477668899aabbccddeeff", # 32 as bytes
+
+ # 16 as hex bytes
+ b"\x33\x22\x11\x00\x55\x44\x77\x66\x88\x99\xaa\xbb\xcc\xdd\xee\xff"
+ ]
+ for fmt in fmts:
+ guid = misc.GUID(fmt)
+ self.assertEqual(text3, str(guid))
+
+ def test_invalid_formats(self):
+ fmts = [
+ "00112233-4455-6677-8899-aabbccddee", # 34
+ "{33221100554477668899aabbccddeeff}",
+ "33221100554477668899aabbccddee", # 30
+ "\\x33\\x22\\x11\\x00\\x55\\x44\\x77\\x66\\x88\\x99\\xaa\\xbb\\xcc\\xdd\\xee\\xff",
+ r"\x33\x22\x11\x00\x55\x44\x77\x66\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
+ ]
+ for fmt in fmts:
+ try:
+ misc.GUID(fmt)
+ except samba.NTSTATUSError:
+ # invalid formats should get this error
+ continue
+ else:
+ # otherwise, test fail
+ self.fail()
+
+
+class PolicyHandleTests(samba.tests.TestCase):
+
+ def test_init(self):
+ x = misc.policy_handle(text1, 1)
+ self.assertEqual(1, x.handle_type)
+ self.assertEqual(text1, str(x.uuid))
+
+ def test_repr(self):
+ x = misc.policy_handle(text1, 42)
+ self.assertEqual("policy_handle(%d, '%s')" % (42, text1), repr(x))
+
+ def test_str(self):
+ x = misc.policy_handle(text1, 42)
+ self.assertEqual("%d, %s" % (42, text1), str(x))
diff --git a/python/samba/tests/dcerpc/raw_protocol.py b/python/samba/tests/dcerpc/raw_protocol.py
new file mode 100755
index 0000000..fa5a042
--- /dev/null
+++ b/python/samba/tests/dcerpc/raw_protocol.py
@@ -0,0 +1,7514 @@
+#!/usr/bin/env python3
+# Unix SMB/CIFS implementation.
+# Copyright (C) Stefan Metzmacher 2014,2015
+#
+# 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/>.
+#
+
+import sys
+import os
+import time
+
+sys.path.insert(0, "bin/python")
+os.environ["PYTHONUNBUFFERED"] = "1"
+
+import samba.dcerpc.dcerpc as dcerpc
+import samba.dcerpc.base as base
+import samba.dcerpc.misc as misc
+import samba.dcerpc.epmapper
+import samba.dcerpc.mgmt
+import samba.dcerpc.netlogon
+import samba.dcerpc.lsa
+import struct
+from samba import gensec
+from samba.tests.dcerpc.raw_testcase import RawDCERPCTest
+from samba.ntstatus import (
+ NT_STATUS_SUCCESS
+)
+
+global_ndr_print = False
+global_hexdump = False
+
+
+class TestDCERPC_BIND(RawDCERPCTest):
+
+ def setUp(self):
+ super().setUp()
+ self.do_ndr_print = global_ndr_print
+ self.do_hexdump = global_hexdump
+
+ def _test_no_auth_request_bind_pfc_flags(self, req_pfc_flags, rep_pfc_flags):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+
+ req = self.generate_bind(call_id=0, pfc_flags=req_pfc_flags, ctx_list=[ctx1])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id,
+ pfc_flags=rep_pfc_flags, auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ # And now try a request
+ req = self.generate_request(call_id=1,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ def _test_no_auth_request_alter_pfc_flags(self, req_pfc_flags, rep_pfc_flags):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+
+ req = self.generate_bind(call_id=0, ctx_list=[ctx1])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ # And now try a alter context
+ req = self.generate_alter(call_id=0, pfc_flags=req_pfc_flags, ctx_list=[ctx1])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id,
+ pfc_flags=rep_pfc_flags, auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 0)
+ self.assertEqual(rep.u.secondary_address, "")
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ # And now try a request
+ req = self.generate_request(call_id=1,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ def test_no_auth_request(self):
+ return self._test_no_auth_request_bind_pfc_flags(
+ req_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ def test_no_auth_request_bind_pfc_00(self):
+ return self._test_no_auth_request_bind_pfc_flags(
+ req_pfc_flags=0 |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ def test_no_auth_request_bind_pfc_FIRST(self):
+ return self._test_no_auth_request_bind_pfc_flags(
+ req_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ def test_no_auth_request_bind_pfc_LAST(self):
+ return self._test_no_auth_request_bind_pfc_flags(
+ req_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_LAST |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ def test_no_auth_request_bind_pfc_HDR_SIGNING(self):
+ return self._test_no_auth_request_bind_pfc_flags(
+ req_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST |
+ dcerpc.DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)
+
+ def test_no_auth_request_bind_pfc_08(self):
+ return self._test_no_auth_request_bind_pfc_flags(
+ req_pfc_flags=0 |
+ 8 |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ def test_no_auth_request_bind_pfc_CONC_MPX(self):
+ return self._test_no_auth_request_bind_pfc_flags(
+ req_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_CONC_MPX |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST |
+ dcerpc.DCERPC_PFC_FLAG_CONC_MPX)
+
+ def test_no_auth_request_bind_pfc_DID_NOT_EXECUTE(self):
+ return self._test_no_auth_request_bind_pfc_flags(
+ req_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ def test_no_auth_request_bind_pfc_MAYBE(self):
+ return self._test_no_auth_request_bind_pfc_flags(
+ req_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_MAYBE |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ def test_no_auth_request_bind_pfc_OBJECT_UUID(self):
+ return self._test_no_auth_request_bind_pfc_flags(
+ req_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_OBJECT_UUID |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ # TODO: doesn't announce DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
+ # without authentication
+ # TODO: doesn't announce DCERPC_PFC_FLAG_CONC_MPX
+ # by default
+ def _test_no_auth_request_bind_pfc_ff(self):
+ return self._test_no_auth_request_bind_pfc_flags(
+ req_pfc_flags=0 |
+ 0xff |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST |
+ dcerpc.DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN |
+ dcerpc.DCERPC_PFC_FLAG_CONC_MPX)
+
+ def test_no_auth_request_alter_pfc_00(self):
+ return self._test_no_auth_request_alter_pfc_flags(
+ req_pfc_flags=0 |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ def test_no_auth_request_alter_pfc_FIRST(self):
+ return self._test_no_auth_request_alter_pfc_flags(
+ req_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ def test_no_auth_request_alter_pfc_LAST(self):
+ return self._test_no_auth_request_alter_pfc_flags(
+ req_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_LAST |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ def test_no_auth_request_alter_pfc_HDR_SIGNING(self):
+ return self._test_no_auth_request_alter_pfc_flags(
+ req_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST |
+ dcerpc.DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)
+
+ def test_no_auth_request_alter_pfc_08(self):
+ return self._test_no_auth_request_alter_pfc_flags(
+ req_pfc_flags=0 |
+ 8 |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ def test_no_auth_request_alter_pfc_CONC_MPX(self):
+ return self._test_no_auth_request_alter_pfc_flags(
+ req_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_CONC_MPX |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ def test_no_auth_request_alter_pfc_DID_NOT_EXECUTE(self):
+ return self._test_no_auth_request_alter_pfc_flags(
+ req_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ def test_no_auth_request_alter_pfc_MAYBE(self):
+ return self._test_no_auth_request_alter_pfc_flags(
+ req_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_MAYBE |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ def test_no_auth_request_alter_pfc_OBJECT_UUID(self):
+ return self._test_no_auth_request_alter_pfc_flags(
+ req_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_OBJECT_UUID |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST)
+
+ def test_no_auth_request_alter_pfc_ff(self):
+ return self._test_no_auth_request_alter_pfc_flags(
+ req_pfc_flags=0 |
+ 0xff |
+ 0,
+ rep_pfc_flags=0 |
+ dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST |
+ dcerpc.DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)
+
+ def test_no_auth_no_ctx(self):
+ # send an useless bind
+ req = self.generate_bind(call_id=0)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_NAK, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.reject_reason,
+ dcerpc.DCERPC_BIND_NAK_REASON_NOT_SPECIFIED)
+ self.assertEqual(rep.u.num_versions, 1)
+ self.assertEqual(rep.u.versions[0].rpc_vers, req.rpc_vers)
+ self.assertEqual(rep.u.versions[0].rpc_vers_minor, req.rpc_vers_minor)
+ self.assertPadding(rep.u._pad, 3)
+
+ def test_invalid_auth_noctx(self):
+ req = self.generate_bind(call_id=0)
+ req.auth_length = dcerpc.DCERPC_AUTH_TRAILER_LENGTH
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_NAK, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.reject_reason,
+ dcerpc.DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED)
+ self.assertEqual(rep.u.num_versions, 1)
+ self.assertEqual(rep.u.versions[0].rpc_vers, req.rpc_vers)
+ self.assertEqual(rep.u.versions[0].rpc_vers_minor, req.rpc_vers_minor)
+ self.assertPadding(rep.u._pad, 3)
+
+ def test_no_auth_valid_valid_request(self):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+
+ req = self.generate_bind(call_id=0, ctx_list=[ctx1])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ # Send a bind again
+ tsf2_list = [ndr32]
+ ctx2 = dcerpc.ctx_list()
+ ctx2.context_id = 2
+ ctx2.num_transfer_syntaxes = len(tsf2_list)
+ ctx2.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx2.transfer_syntaxes = tsf2_list
+
+ req = self.generate_bind(call_id=1, ctx_list=[ctx2])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_NAK, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.reject_reason,
+ dcerpc.DCERPC_BIND_NAK_REASON_NOT_SPECIFIED)
+ self.assertEqual(rep.u.num_versions, 1)
+ self.assertEqual(rep.u.versions[0].rpc_vers, req.rpc_vers)
+ self.assertEqual(rep.u.versions[0].rpc_vers_minor, req.rpc_vers_minor)
+ self.assertPadding(rep.u._pad, 3)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_no_auth_invalid_valid_request(self):
+ # send an useless bind
+ req = self.generate_bind(call_id=0)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_NAK, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.reject_reason,
+ dcerpc.DCERPC_BIND_NAK_REASON_NOT_SPECIFIED)
+ self.assertEqual(rep.u.num_versions, 1)
+ self.assertEqual(rep.u.versions[0].rpc_vers, req.rpc_vers)
+ self.assertEqual(rep.u.versions[0].rpc_vers_minor, req.rpc_vers_minor)
+ self.assertPadding(rep.u._pad, 3)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_alter_no_auth_no_ctx(self):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+
+ req = self.generate_bind(call_id=0, ctx_list=[ctx1])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ # Send a alter
+ req = self.generate_alter(call_id=1, ctx_list=[])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=req.pfc_flags |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, 0)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_no_auth_presentation_ctx_valid1(self):
+ ndr32 = base.transfer_syntax_ndr()
+
+ zero_syntax = misc.ndr_syntax_id()
+
+ tsf1_list = [zero_syntax, ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+
+ req = self.generate_bind(call_id=0, ctx_list=[ctx1])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ # Send a alter
+ req = self.generate_alter(call_id=1, ctx_list=[ctx1])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 0)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ req = self.generate_request(call_id=2,
+ context_id=ctx1.context_id,
+ opnum=0xffff,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=req.pfc_flags |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, ctx1.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, dcerpc.DCERPC_NCA_S_OP_RNG_ERROR)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ def test_no_auth_presentation_ctx_invalid1(self):
+ ndr32 = base.transfer_syntax_ndr()
+
+ zero_syntax = misc.ndr_syntax_id()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = ndr32
+ ctx1.transfer_syntaxes = tsf1_list
+
+ req = self.generate_bind(call_id=0, ctx_list=[ctx1])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_PROVIDER_REJECTION)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, zero_syntax)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ # Send a alter
+ req = self.generate_alter(call_id=1, ctx_list=[ctx1])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 0)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_PROVIDER_REJECTION)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, zero_syntax)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ req = self.generate_request(call_id=2,
+ context_id=12345,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=req.pfc_flags |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, 0)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, dcerpc.DCERPC_NCA_S_UNKNOWN_IF)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ # Send a alter again to prove the connection is still alive
+ req = self.generate_alter(call_id=3, ctx_list=[ctx1])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 0)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_PROVIDER_REJECTION)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, zero_syntax)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ def test_no_auth_presentation_ctx_invalid2(self):
+ ndr32 = base.transfer_syntax_ndr()
+
+ zero_syntax = misc.ndr_syntax_id()
+
+ tsf1a_list = []
+ ctx1a = dcerpc.ctx_list()
+ ctx1a.context_id = 1
+ ctx1a.num_transfer_syntaxes = len(tsf1a_list)
+ ctx1a.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1a.transfer_syntaxes = tsf1a_list
+
+ req = self.generate_bind(call_id=0, ctx_list=[ctx1a])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_NAK, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.reject_reason,
+ dcerpc.DCERPC_BIND_NAK_REASON_NOT_SPECIFIED)
+ self.assertEqual(rep.u.num_versions, 1)
+ self.assertEqual(rep.u.versions[0].rpc_vers, req.rpc_vers)
+ self.assertEqual(rep.u.versions[0].rpc_vers_minor, req.rpc_vers_minor)
+ self.assertPadding(rep.u._pad, 3)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_no_auth_presentation_ctx_invalid3(self):
+ ndr32 = base.transfer_syntax_ndr()
+
+ zero_syntax = misc.ndr_syntax_id()
+
+ tsf1a_list = [zero_syntax, ndr32, ndr32, ndr32]
+ ctx1a = dcerpc.ctx_list()
+ ctx1a.context_id = 1
+ ctx1a.num_transfer_syntaxes = len(tsf1a_list)
+ ctx1a.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1a.transfer_syntaxes = tsf1a_list
+
+ req = self.generate_bind(call_id=0, ctx_list=[ctx1a])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ tsf1b_list = []
+ ctx1b = dcerpc.ctx_list()
+ ctx1b.context_id = 1
+ ctx1b.num_transfer_syntaxes = len(tsf1b_list)
+ ctx1b.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1b.transfer_syntaxes = tsf1b_list
+
+ # Send a alter
+ req = self.generate_alter(call_id=1, ctx_list=[ctx1b])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=req.pfc_flags |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, 0)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_no_auth_presentation_ctx_invalid4(self):
+ ndr32 = base.transfer_syntax_ndr()
+ ndr64 = base.transfer_syntax_ndr64()
+
+ zero_syntax = misc.ndr_syntax_id()
+
+ tsf1a_list = [zero_syntax, ndr32, ndr32, ndr32]
+ ctx1a = dcerpc.ctx_list()
+ ctx1a.context_id = 1
+ ctx1a.num_transfer_syntaxes = len(tsf1a_list)
+ ctx1a.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1a.transfer_syntaxes = tsf1a_list
+
+ req = self.generate_bind(call_id=0, ctx_list=[ctx1a])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ # With a known but wrong syntax we get a protocol error
+ # see test_no_auth_presentation_ctx_valid2
+ tsf1b_list = [zero_syntax, samba.dcerpc.epmapper.abstract_syntax(), ndr64]
+ ctx1b = dcerpc.ctx_list()
+ ctx1b.context_id = 1
+ ctx1b.num_transfer_syntaxes = len(tsf1b_list)
+ ctx1b.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1b.transfer_syntaxes = tsf1b_list
+
+ # Send a alter
+ req = self.generate_alter(call_id=1, ctx_list=[ctx1b])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=req.pfc_flags |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, 0)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_no_auth_presentation_ctx_valid2(self):
+ ndr32 = base.transfer_syntax_ndr()
+
+ zero_syntax = misc.ndr_syntax_id()
+
+ tsf1a_list = [zero_syntax, ndr32, ndr32, ndr32]
+ ctx1a = dcerpc.ctx_list()
+ ctx1a.context_id = 1
+ ctx1a.num_transfer_syntaxes = len(tsf1a_list)
+ ctx1a.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1a.transfer_syntaxes = tsf1a_list
+
+ req = self.generate_bind(call_id=0, ctx_list=[ctx1a])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ # With a unknown but wrong syntaxes we get NO protocol error
+ # see test_no_auth_presentation_ctx_invalid4
+ tsf1b_list = [zero_syntax, samba.dcerpc.epmapper.abstract_syntax()]
+ ctx1b = dcerpc.ctx_list()
+ ctx1b.context_id = 1
+ ctx1b.num_transfer_syntaxes = len(tsf1b_list)
+ ctx1b.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1b.transfer_syntaxes = tsf1b_list
+
+ # Send a alter
+ req = self.generate_alter(call_id=1, ctx_list=[ctx1b])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 0)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_PROVIDER_REJECTION)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, zero_syntax)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ req = self.generate_request(call_id=2,
+ context_id=ctx1a.context_id,
+ opnum=0xffff,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=req.pfc_flags |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, ctx1a.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, dcerpc.DCERPC_NCA_S_OP_RNG_ERROR)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ def test_no_auth_presentation_ctx_no_ndr64(self):
+ ndr32 = base.transfer_syntax_ndr()
+ zero_syntax = misc.ndr_syntax_id()
+
+ tsfZ_list = [zero_syntax]
+ ctxZ = dcerpc.ctx_list()
+ ctxZ.context_id = 54321
+ ctxZ.num_transfer_syntaxes = len(tsfZ_list)
+ ctxZ.abstract_syntax = zero_syntax
+ ctxZ.transfer_syntaxes = tsfZ_list
+
+ req = self.generate_bind(call_id=0, ctx_list=[ctxZ])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_PROVIDER_REJECTION)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, zero_syntax)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ tsf0_list = [ndr32]
+ ctx0 = dcerpc.ctx_list()
+ ctx0.context_id = 0
+ ctx0.num_transfer_syntaxes = len(tsf0_list)
+ ctx0.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx0.transfer_syntaxes = tsf0_list
+
+ req = self.generate_alter(call_id=0, ctx_list=[ctx0])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 0)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ req = self.generate_request(call_id=1,
+ context_id=ctx0.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ tsf1_list = [zero_syntax, ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+
+ req = self.generate_alter(call_id=1, ctx_list=[ctx1])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 0)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ req = self.generate_request(call_id=1,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ tsf2_list = [ndr32, ndr32]
+ ctx2 = dcerpc.ctx_list()
+ ctx2.context_id = 2
+ ctx2.num_transfer_syntaxes = len(tsf2_list)
+ ctx2.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx2.transfer_syntaxes = tsf2_list
+
+ req = self.generate_alter(call_id=2, ctx_list=[ctx2])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 0)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ req = self.generate_request(call_id=1,
+ context_id=ctx2.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ tsf3_list = [ndr32]
+ ctx3 = dcerpc.ctx_list()
+ ctx3.context_id = 3
+ ctx3.num_transfer_syntaxes = len(tsf3_list)
+ ctx3.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx3.transfer_syntaxes = tsf3_list
+
+ tsf4_list = [ndr32]
+ ctx4 = dcerpc.ctx_list()
+ ctx4.context_id = 4
+ ctx4.num_transfer_syntaxes = len(tsf4_list)
+ ctx4.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx4.transfer_syntaxes = tsf4_list
+
+ req = self.generate_alter(call_id=34, ctx_list=[ctx3, ctx4])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 0)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 2)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEqual(rep.u.ctx_list[1].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_PROVIDER_REJECTION)
+ self.assertEqual(rep.u.ctx_list[1].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[1].syntax, zero_syntax)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ req = self.generate_request(call_id=1,
+ context_id=ctx3.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ req = self.generate_alter(call_id=43, ctx_list=[ctx4, ctx3])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 0)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 2)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEqual(rep.u.ctx_list[1].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_PROVIDER_REJECTION)
+ self.assertEqual(rep.u.ctx_list[1].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[1].syntax, zero_syntax)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ req = self.generate_request(call_id=1,
+ context_id=ctx4.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ req = self.generate_request(call_id=1,
+ context_id=ctx3.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ req = self.generate_alter(call_id=44, ctx_list=[ctx4, ctx4])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 0)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 2)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEqual(rep.u.ctx_list[1].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_PROVIDER_REJECTION)
+ self.assertEqual(rep.u.ctx_list[1].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[1].syntax, zero_syntax)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ req = self.generate_request(call_id=1,
+ context_id=ctx4.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ req = self.generate_request(call_id=1,
+ context_id=ctx3.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ tsf5mgmt_list = [ndr32]
+ ctx5mgmt = dcerpc.ctx_list()
+ ctx5mgmt.context_id = 5
+ ctx5mgmt.num_transfer_syntaxes = len(tsf5mgmt_list)
+ ctx5mgmt.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx5mgmt.transfer_syntaxes = tsf5mgmt_list
+
+ tsf5epm_list = [ndr32]
+ ctx5epm = dcerpc.ctx_list()
+ ctx5epm.context_id = 5
+ ctx5epm.num_transfer_syntaxes = len(tsf5epm_list)
+ ctx5epm.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx5epm.transfer_syntaxes = tsf5epm_list
+
+ req = self.generate_alter(call_id=55, ctx_list=[ctx5mgmt, ctx5epm])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 0)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 2)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEqual(rep.u.ctx_list[1].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_PROVIDER_REJECTION)
+ self.assertEqual(rep.u.ctx_list[1].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[1].syntax, zero_syntax)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ req = self.generate_request(call_id=1,
+ context_id=ctx5mgmt.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ req = self.generate_alter(call_id=55, ctx_list=[ctx5mgmt, ctx5epm])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 0)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 2)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEqual(rep.u.ctx_list[1].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_PROVIDER_REJECTION)
+ self.assertEqual(rep.u.ctx_list[1].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[1].syntax, zero_syntax)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ req = self.generate_request(call_id=1,
+ context_id=ctx5mgmt.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ def test_no_auth_bind_time_none_simple(self):
+ features = 0
+ btf = base.bind_time_features_syntax(features)
+
+ zero_syntax = misc.ndr_syntax_id()
+
+ tsf1_list = [btf]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = zero_syntax
+ ctx1.transfer_syntaxes = tsf1_list
+
+ req = self.generate_bind(call_id=0, ctx_list=[ctx1])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK)
+ self.assertEqual(rep.u.ctx_list[0].reason, features)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, zero_syntax)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ def test_no_auth_bind_time_none_ignore_additional(self):
+ features1 = 0
+ btf1 = base.bind_time_features_syntax(features1)
+
+ features2 = dcerpc.DCERPC_BIND_TIME_KEEP_CONNECTION_ON_ORPHAN
+ features2 |= dcerpc.DCERPC_BIND_TIME_SECURITY_CONTEXT_MULTIPLEXING
+ btf2 = base.bind_time_features_syntax(features2)
+
+ zero_syntax = misc.ndr_syntax_id()
+ ndr64 = base.transfer_syntax_ndr64()
+
+ tsf1_list = [btf1, btf2, zero_syntax]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = ndr64
+ ctx1.transfer_syntaxes = tsf1_list
+
+ req = self.generate_bind(call_id=0, ctx_list=[ctx1])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK)
+ self.assertEqual(rep.u.ctx_list[0].reason, features1)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, zero_syntax)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ def test_no_auth_bind_time_only_first(self):
+ features1 = dcerpc.DCERPC_BIND_TIME_KEEP_CONNECTION_ON_ORPHAN
+ btf1 = base.bind_time_features_syntax(features1)
+
+ features2 = dcerpc.DCERPC_BIND_TIME_SECURITY_CONTEXT_MULTIPLEXING
+ btf2 = base.bind_time_features_syntax(features2)
+
+ zero_syntax = misc.ndr_syntax_id()
+
+ tsf1_list = [zero_syntax, btf1, btf2, zero_syntax]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = zero_syntax
+ ctx1.transfer_syntaxes = tsf1_list
+
+ req = self.generate_bind(call_id=0, ctx_list=[ctx1])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_PROVIDER_REJECTION)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, zero_syntax)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ def test_no_auth_bind_time_twice(self):
+ features1 = dcerpc.DCERPC_BIND_TIME_KEEP_CONNECTION_ON_ORPHAN
+ btf1 = base.bind_time_features_syntax(features1)
+
+ features2 = dcerpc.DCERPC_BIND_TIME_SECURITY_CONTEXT_MULTIPLEXING
+ btf2 = base.bind_time_features_syntax(features2)
+
+ zero_syntax = misc.ndr_syntax_id()
+
+ tsf1_list = [btf1]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = zero_syntax
+ ctx1.transfer_syntaxes = tsf1_list
+
+ tsf2_list = [btf2]
+ ctx2 = dcerpc.ctx_list()
+ ctx2.context_id = 2
+ ctx2.num_transfer_syntaxes = len(tsf2_list)
+ ctx2.abstract_syntax = zero_syntax
+ ctx2.transfer_syntaxes = tsf2_list
+
+ req = self.generate_bind(call_id=0, ctx_list=[ctx1, ctx2])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_NAK, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.reject_reason,
+ dcerpc.DCERPC_BIND_NAK_REASON_NOT_SPECIFIED)
+ self.assertEqual(rep.u.num_versions, 1)
+ self.assertEqual(rep.u.versions[0].rpc_vers, req.rpc_vers)
+ self.assertEqual(rep.u.versions[0].rpc_vers_minor, req.rpc_vers_minor)
+ self.assertPadding(rep.u._pad, 3)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_no_auth_bind_time_keep_on_orphan_simple(self):
+ features = dcerpc.DCERPC_BIND_TIME_KEEP_CONNECTION_ON_ORPHAN
+ btf = base.bind_time_features_syntax(features)
+
+ zero_syntax = misc.ndr_syntax_id()
+
+ tsf1_list = [btf]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = zero_syntax
+ ctx1.transfer_syntaxes = tsf1_list
+
+ req = self.generate_bind(call_id=0, ctx_list=[ctx1])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK)
+ self.assertEqual(rep.u.ctx_list[0].reason, features)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, zero_syntax)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ def test_no_auth_bind_time_keep_on_orphan_ignore_additional(self):
+ features1 = dcerpc.DCERPC_BIND_TIME_KEEP_CONNECTION_ON_ORPHAN
+ btf1 = base.bind_time_features_syntax(features1)
+
+ features2 = dcerpc.DCERPC_BIND_TIME_SECURITY_CONTEXT_MULTIPLEXING
+ btf2 = base.bind_time_features_syntax(features2)
+
+ zero_syntax = misc.ndr_syntax_id()
+ ndr64 = base.transfer_syntax_ndr64()
+
+ tsf1_list = [btf1, btf2, zero_syntax]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = ndr64
+ ctx1.transfer_syntaxes = tsf1_list
+
+ req = self.generate_bind(call_id=0, ctx_list=[ctx1])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK)
+ self.assertEqual(rep.u.ctx_list[0].reason, features1)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, zero_syntax)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ def test_no_auth_bind_time_sec_ctx_ignore_additional(self):
+ features1 = dcerpc.DCERPC_BIND_TIME_SECURITY_CONTEXT_MULTIPLEXING
+ btf1 = base.bind_time_features_syntax(features1)
+
+ features2 = dcerpc.DCERPC_BIND_TIME_KEEP_CONNECTION_ON_ORPHAN
+ btf2 = base.bind_time_features_syntax(features2)
+
+ zero_syntax = misc.ndr_syntax_id()
+ ndr64 = base.transfer_syntax_ndr64()
+
+ tsf1_list = [btf1, btf2, zero_syntax]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = ndr64
+ ctx1.transfer_syntaxes = tsf1_list
+
+ req = self.generate_bind(call_id=0, ctx_list=[ctx1])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK)
+ self.assertEqual(rep.u.ctx_list[0].reason, features1)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, zero_syntax)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ def _test_auth_type_level_bind_nak(self, auth_type, auth_level, creds=None,
+ reason=dcerpc.DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+ ctx_list = [ctx1]
+
+ auth_context_id = 0
+
+ if creds is not None:
+ # We always start with DCERPC_AUTH_LEVEL_INTEGRITY
+ auth_context = self.get_auth_context_creds(creds,
+ auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ g_auth_level=dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY)
+ from_server = b""
+ (finished, to_server) = auth_context["gensec"].update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_context["auth_type"],
+ auth_level=auth_context["auth_level"],
+ auth_context_id=auth_context["auth_context_id"],
+ auth_blob=to_server)
+ else:
+ to_server = b"none"
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+
+ req = self.generate_bind(call_id=0,
+ ctx_list=ctx_list,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_NAK, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.reject_reason, reason)
+ self.assertEqual(rep.u.num_versions, 1)
+ self.assertEqual(rep.u.versions[0].rpc_vers, req.rpc_vers)
+ self.assertEqual(rep.u.versions[0].rpc_vers_minor, req.rpc_vers_minor)
+ self.assertPadding(rep.u._pad, 3)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def _test_auth_none_level_bind(self, auth_level,
+ reason=dcerpc.DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE):
+ return self._test_auth_type_level_bind_nak(auth_type=dcerpc.DCERPC_AUTH_LEVEL_NONE,
+ auth_level=auth_level, reason=reason)
+
+ def test_auth_none_none_bind(self):
+ return self._test_auth_none_level_bind(dcerpc.DCERPC_AUTH_LEVEL_NONE,
+ reason=dcerpc.DCERPC_BIND_NAK_REASON_NOT_SPECIFIED)
+
+ def test_auth_none_connect_bind(self):
+ return self._test_auth_none_level_bind(dcerpc.DCERPC_AUTH_LEVEL_CONNECT)
+
+ def test_auth_none_call_bind(self):
+ return self._test_auth_none_level_bind(dcerpc.DCERPC_AUTH_LEVEL_CALL)
+
+ def test_auth_none_packet_bind(self):
+ return self._test_auth_none_level_bind(dcerpc.DCERPC_AUTH_LEVEL_PACKET)
+
+ def test_auth_none_integrity_bind(self):
+ return self._test_auth_none_level_bind(dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY)
+
+ def test_auth_none_privacy_bind(self):
+ return self._test_auth_none_level_bind(dcerpc.DCERPC_AUTH_LEVEL_PRIVACY)
+
+ def test_auth_none_0_bind(self):
+ return self._test_auth_none_level_bind(0,
+ reason=dcerpc.DCERPC_BIND_NAK_REASON_NOT_SPECIFIED)
+
+ def test_auth_none_7_bind(self):
+ return self._test_auth_none_level_bind(7,
+ reason=dcerpc.DCERPC_BIND_NAK_REASON_NOT_SPECIFIED)
+
+ def test_auth_none_255_bind(self):
+ return self._test_auth_none_level_bind(255,
+ reason=dcerpc.DCERPC_BIND_NAK_REASON_NOT_SPECIFIED)
+
+ def _test_auth_none_level_request(self, auth_level):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+ ctx_list = [ctx1]
+
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NONE
+ auth_context_id = 0
+
+ req = self.generate_bind(call_id=0,
+ ctx_list=ctx_list)
+
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEqual(len(rep.u.auth_info), 0)
+
+ # And now try a request without auth_info
+ req = self.generate_request(call_id=2,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=b"none")
+
+ req = self.generate_request(call_id=3,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub=b"",
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ # We get a fault back
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, dcerpc.DCERPC_FAULT_ACCESS_DENIED)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_auth_none_none_request(self):
+ return self._test_auth_none_level_request(dcerpc.DCERPC_AUTH_LEVEL_NONE)
+
+ def test_auth_none_connect_request(self):
+ return self._test_auth_none_level_request(dcerpc.DCERPC_AUTH_LEVEL_CONNECT)
+
+ def test_auth_none_call_request(self):
+ return self._test_auth_none_level_request(dcerpc.DCERPC_AUTH_LEVEL_CALL)
+
+ def test_auth_none_packet_request(self):
+ return self._test_auth_none_level_request(dcerpc.DCERPC_AUTH_LEVEL_PACKET)
+
+ def test_ntlmssp_multi_auth_first1_lastSame2(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_FAULT_SEC_PKG_ERROR
+ auth_context_2nd = 2
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = None
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_last(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_first1_lastNext2(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = 2
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = 4
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_last(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_first1_lastSame111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = None
+ auth_context_2nd = 1
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = None
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = 111
+ forced_auth_type = 111
+ forced_auth_level = 111
+ return self._test_generic_auth_first_last(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_first1_lastNext111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = 1
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = 4
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = 111
+ forced_auth_type = 111
+ forced_auth_level = 111
+ return self._test_generic_auth_first_last(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_MPX_first1_lastNext111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = 1
+ expected_call_id = 4
+ expected_context_id = 0
+ not_executed = False
+ conc_mpx = True
+ forced_call_id = 4
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = 111
+ forced_auth_type = 111
+ forced_auth_level = 111
+ return self._test_generic_auth_first_last(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_first1_lastSameNone(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = None
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_last(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_MPX_first1_lastSameNone(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = True
+ forced_call_id = None
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_last(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_first1_lastNextNone(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = 4
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_last(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_MPX_first1_lastNextNone(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = 4
+ expected_context_id = 0
+ not_executed = False
+ conc_mpx = True
+ forced_call_id = 4
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_last(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_first1_lastSameNone111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = None
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_last(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_MPX_first1_lastSameNone111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = True
+ forced_call_id = None
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_last(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_first1_lastNextNone111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = 4
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_last(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_MPX_first1_lastNextNone111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = 4
+ expected_context_id = 0
+ not_executed = False
+ conc_mpx = True
+ forced_call_id = 4
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_last(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def _test_generic_auth_first_2nd(self,
+ auth_type,
+ pfc_flags_2nd,
+ expected_fault,
+ auth_context_2nd=2,
+ skip_first=False,
+ expected_call_id=None,
+ expected_context_id=None,
+ conc_mpx=False,
+ not_executed=False,
+ forced_call_id=None,
+ forced_context_id=None,
+ forced_opnum=None,
+ forced_auth_context_id=None,
+ forced_auth_type=None,
+ forced_auth_level=None):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ auth_level1 = dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY
+ auth_context_id1=1
+ auth_level2 = dcerpc.DCERPC_AUTH_LEVEL_PACKET
+ auth_context_id2=2
+
+ creds = self.get_user_creds()
+
+ abstract = samba.dcerpc.mgmt.abstract_syntax()
+ transfer = base.transfer_syntax_ndr()
+
+ tsf1_list = [transfer]
+ ctx = samba.dcerpc.dcerpc.ctx_list()
+ ctx.context_id = 1
+ ctx.num_transfer_syntaxes = len(tsf1_list)
+ ctx.abstract_syntax = abstract
+ ctx.transfer_syntaxes = tsf1_list
+
+ auth_context1 = self.get_auth_context_creds(creds=creds,
+ auth_type=auth_type,
+ auth_level=auth_level1,
+ auth_context_id=auth_context_id1,
+ hdr_signing=False)
+ auth_context2 = self.get_auth_context_creds(creds=creds,
+ auth_type=auth_type,
+ auth_level=auth_level2,
+ auth_context_id=auth_context_id2,
+ hdr_signing=False)
+
+ bind_pfc_flags = dcerpc.DCERPC_PFC_FLAG_FIRST | dcerpc.DCERPC_PFC_FLAG_LAST
+ if conc_mpx:
+ bind_pfc_flags |= dcerpc.DCERPC_PFC_FLAG_CONC_MPX
+
+ ack0 = self.do_generic_bind(call_id=0,
+ ctx=ctx,
+ pfc_flags=bind_pfc_flags)
+
+ ack1 = self.do_generic_bind(call_id=1,
+ ctx=ctx,
+ auth_context=auth_context1,
+ assoc_group_id = ack0.u.assoc_group_id,
+ start_with_alter=True)
+ if auth_context_2nd == 2:
+ ack2 = self.do_generic_bind(call_id=2,
+ ctx=ctx,
+ auth_context=auth_context2,
+ assoc_group_id = ack0.u.assoc_group_id,
+ start_with_alter=True)
+
+ ndr_print = self.do_ndr_print
+ hexdump = self.do_hexdump
+ inq_if_ids = samba.dcerpc.mgmt.inq_if_ids()
+ io = inq_if_ids
+ if ndr_print:
+ sys.stderr.write("in: %s" % samba.ndr.ndr_print_in(io))
+ stub_in = samba.ndr.ndr_pack_in(io)
+ stub_in += b'\xfe'*45 # add some padding in order to have some payload
+ if hexdump:
+ sys.stderr.write("stub_in: %d\n%s" % (len(stub_in), self.hexdump(stub_in)))
+
+ call_id = 3
+ context_id = ctx.context_id
+ opnum = io.opnum()
+
+ if not skip_first:
+ pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST
+ stub_in_tmp = stub_in[0:16]
+ req = self.generate_request_auth(call_id=call_id,
+ context_id=context_id,
+ pfc_flags=pfc_flags,
+ opnum=opnum,
+ alloc_hint=len(stub_in),
+ stub=stub_in_tmp,
+ auth_context=auth_context1)
+ self.send_pdu(req, ndr_print=ndr_print, hexdump=hexdump)
+ rep = self.recv_pdu(timeout=0.01)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+
+ # context_id, opnum and auth header values are completely ignored
+ if auth_context_2nd == 1:
+ auth_context_copy = auth_context1.copy()
+ elif auth_context_2nd == 2:
+ auth_context_copy = auth_context2.copy()
+ else:
+ auth_context_copy = None
+
+ expected_pfc_flags = dcerpc.DCERPC_PFC_FLAG_FIRST | dcerpc.DCERPC_PFC_FLAG_LAST
+ if expected_context_id is None:
+ expected_context_id = context_id
+ if expected_call_id is None:
+ expected_call_id = call_id
+ if not_executed:
+ expected_pfc_flags |= dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE
+
+ if forced_call_id is not None:
+ call_id = forced_call_id
+ if forced_context_id is not None:
+ context_id = forced_context_id
+ if forced_opnum is not None:
+ opnum = forced_opnum
+ if forced_auth_context_id is not None:
+ auth_context_copy["auth_context_id"] = forced_auth_context_id
+ if forced_auth_type is not None:
+ auth_context_copy["auth_type"] = forced_auth_type
+ if forced_auth_level is not None:
+ auth_context_copy["auth_level"] = forced_auth_level
+
+ pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST
+ stub_in_tmp = stub_in[16:-1]
+ req = self.generate_request_auth(call_id=call_id,
+ context_id=context_id,
+ pfc_flags=pfc_flags_2nd,
+ opnum=opnum,
+ alloc_hint=len(stub_in_tmp),
+ stub=stub_in_tmp,
+ auth_context=auth_context_copy)
+ self.send_pdu(req, ndr_print=ndr_print, hexdump=hexdump)
+ if expected_fault is None:
+ self.do_single_request(call_id=3, ctx=ctx, io=io, send_req=False, auth_context=auth_context1)
+ return
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, expected_call_id,
+ pfc_flags=expected_pfc_flags,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, expected_context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, expected_fault)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ if not_executed:
+ # still alive
+ rep = self.recv_pdu(timeout=0.01)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+ return
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def _test_generic_auth_first_last(self,
+ auth_type,
+ expected_fault,
+ auth_context_2nd=2,
+ expected_call_id=None,
+ expected_context_id=None,
+ conc_mpx=False,
+ not_executed=False,
+ forced_call_id=None,
+ forced_context_id=None,
+ forced_opnum=None,
+ forced_auth_context_id=None,
+ forced_auth_type=None,
+ forced_auth_level=None):
+ pfc_flags_2nd = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST
+ return self._test_generic_auth_first_2nd(auth_type,
+ pfc_flags_2nd,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def _test_generic_auth_first_first(self,
+ auth_type,
+ expected_fault,
+ auth_context_2nd=2,
+ expected_call_id=None,
+ expected_context_id=None,
+ conc_mpx=False,
+ not_executed=False,
+ forced_call_id=None,
+ forced_context_id=None,
+ forced_opnum=None,
+ forced_auth_context_id=None,
+ forced_auth_type=None,
+ forced_auth_level=None):
+ pfc_flags_2nd = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST
+ return self._test_generic_auth_first_2nd(auth_type,
+ pfc_flags_2nd,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_first1_firstSame2(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_FAULT_SEC_PKG_ERROR
+ auth_context_2nd = 2
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = None
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_first(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_first1_firstNext2(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = 2
+ expected_call_id = 3
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = 4
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_first(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_first1_firstSame111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = 1
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = None
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = 111
+ forced_auth_type = 111
+ forced_auth_level = 111
+ return self._test_generic_auth_first_first(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_MPX_first1_firstSame111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = 1
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = True
+ forced_call_id = None
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = 111
+ forced_auth_type = 111
+ forced_auth_level = 111
+ return self._test_generic_auth_first_first(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_first1_firstNext111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = 1
+ expected_call_id = 3
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = 4
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = 111
+ forced_auth_type = 111
+ forced_auth_level = 111
+ return self._test_generic_auth_first_first(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_MPX_first1_firstNext111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = 1
+ expected_call_id = 4
+ expected_context_id = 0
+ not_executed = False
+ conc_mpx = True
+ forced_call_id = 4
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = 111
+ forced_auth_type = 111
+ forced_auth_level = 111
+ return self._test_generic_auth_first_first(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_first1_firstSameNone(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = None
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_first(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_MPX_first1_firstSameNone(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = True
+ forced_call_id = None
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_first(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_first1_firstNextNone(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = 4
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_first(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_MPX_first1_firstNextNone(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = 4
+ expected_context_id = 0
+ not_executed = False
+ conc_mpx = True
+ forced_call_id = 4
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_first(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_first1_firstSameNone111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = None
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_first(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_MPX_first1_firstSameNone111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = True
+ forced_call_id = None
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_first(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_first1_firstNextNone111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = 4
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_first(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_MPX_first1_firstNextNone111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = 4
+ expected_context_id = 0
+ not_executed = False
+ conc_mpx = True
+ forced_call_id = 4
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_first(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def _test_generic_auth_middle(self,
+ auth_type,
+ expected_fault,
+ expected_context_id=None,
+ not_executed=False,
+ conc_mpx=False,
+ forced_context_id=None,
+ forced_opnum=None,
+ forced_auth_context_id=None,
+ forced_auth_type=None,
+ forced_auth_level=None):
+ auth_context_2nd = 1
+ skip_first = True
+ pfc_flags_2nd = 0
+ expected_call_id = None
+ forced_call_id = None
+ return self._test_generic_auth_first_2nd(auth_type,
+ pfc_flags_2nd,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ skip_first=skip_first,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_auth_middle_alone(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ expected_context_id = 0
+ not_executed = False
+ conc_mpx = False
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_middle(auth_type,
+ expected_fault,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_auth_MPX_middle_alone(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = True
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_middle(auth_type,
+ expected_fault,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_auth_middle_all_111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ expected_context_id = 0
+ not_executed = False
+ conc_mpx = False
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = 111
+ forced_auth_type = 111
+ forced_auth_level = 111
+ return self._test_generic_auth_middle(auth_type,
+ expected_fault,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_auth_MPX_middle_all_111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_UNKNOWN_IF
+ expected_context_id = 0
+ not_executed = True
+ conc_mpx = True
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = 111
+ forced_auth_type = 111
+ forced_auth_level = 111
+ return self._test_generic_auth_middle(auth_type,
+ expected_fault,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_auth_middle_auth_all_111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ expected_context_id = 0
+ not_executed = False
+ conc_mpx = False
+ forced_context_id = None
+ forced_opnum = 111
+ forced_auth_context_id = 111
+ forced_auth_type = 111
+ forced_auth_level = 111
+ return self._test_generic_auth_middle(auth_type,
+ expected_fault,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_auth_MPX_middle_auth_all_111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_FAULT_ACCESS_DENIED
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = True
+ forced_context_id = None
+ forced_opnum = 111
+ forced_auth_context_id = 111
+ forced_auth_type = 111
+ forced_auth_level = 111
+ return self._test_generic_auth_middle(auth_type,
+ expected_fault,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_auth_middle_auth_context_111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ expected_context_id = 0
+ not_executed = False
+ conc_mpx = False
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = 111
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_middle(auth_type,
+ expected_fault,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_auth_MPX_middle_auth_context_111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_FAULT_ACCESS_DENIED
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = True
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = 111
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_middle(auth_type,
+ expected_fault,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_auth_middle_auth_type_111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ expected_context_id = 0
+ not_executed = False
+ conc_mpx = False
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = 111
+ forced_auth_level = None
+ return self._test_generic_auth_middle(auth_type,
+ expected_fault,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_auth_MPX_middle_auth_type_111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_FAULT_ACCESS_DENIED
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = True
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = 111
+ forced_auth_level = None
+ return self._test_generic_auth_middle(auth_type,
+ expected_fault,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_auth_middle_auth_level_111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ expected_context_id = 0
+ not_executed = False
+ conc_mpx = False
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = 111
+ return self._test_generic_auth_middle(auth_type,
+ expected_fault,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_auth_MPX_middle_auth_level_111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_FAULT_ACCESS_DENIED
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = True
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = 111
+ return self._test_generic_auth_middle(auth_type,
+ expected_fault,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def _test_neg_xmit_check_values(self,
+ req_xmit=None,
+ req_recv=None,
+ rep_both=None,
+ alter_xmit=None,
+ alter_recv=None):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+
+ req = self.generate_bind(call_id=0,
+ max_xmit_frag=req_xmit,
+ max_recv_frag=req_recv,
+ ctx_list=[ctx1])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, rep_both)
+ self.assertEqual(rep.u.max_recv_frag, rep_both)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ assoc_group_id = rep.u.assoc_group_id
+ if alter_xmit is None:
+ alter_xmit = rep_both - 8
+ if alter_recv is None:
+ alter_recv = rep_both - 8
+
+ # max_{xmit,recv}_frag and assoc_group_id are completely
+ # ignored in alter_context requests
+ req = self.generate_alter(call_id=1,
+ max_xmit_frag=alter_xmit,
+ max_recv_frag=alter_recv,
+ assoc_group_id=0xffffffff - rep.u.assoc_group_id,
+ ctx_list=[ctx1])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, rep_both)
+ self.assertEqual(rep.u.max_recv_frag, rep_both)
+ self.assertEqual(rep.u.assoc_group_id, rep.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 0)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ chunk_size = rep_both - dcerpc.DCERPC_REQUEST_LENGTH
+ req = self.generate_request(call_id=2,
+ context_id=ctx1.context_id,
+ opnum=0,
+ alloc_hint=0xffffffff,
+ stub=b"\00" * chunk_size)
+ self.send_pdu(req, ndr_print=True, hexdump=True)
+ rep = self.recv_pdu(ndr_print=True, hexdump=True)
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ chunk_size = 5840 - dcerpc.DCERPC_REQUEST_LENGTH
+ req = self.generate_request(call_id=2,
+ context_id=ctx1.context_id,
+ opnum=0,
+ alloc_hint=0xffffffff,
+ stub=b"\00" * chunk_size)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ chunk_size += 1
+ req = self.generate_request(call_id=3,
+ context_id=ctx1.context_id,
+ opnum=0,
+ alloc_hint=0xffffffff,
+ stub=b"\00" * chunk_size)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ # We get a fault
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, 0)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_neg_xmit_ffff_ffff(self):
+ return self._test_neg_xmit_check_values(req_xmit=0xffff,
+ req_recv=0xffff,
+ rep_both=5840)
+
+ def test_neg_xmit_0_ffff(self):
+ return self._test_neg_xmit_check_values(req_xmit=0,
+ req_recv=0xffff,
+ rep_both=2048,
+ alter_xmit=0xffff,
+ alter_recv=0xffff)
+
+ def test_neg_xmit_ffff_0(self):
+ return self._test_neg_xmit_check_values(req_xmit=0xffff,
+ req_recv=0,
+ rep_both=2048)
+
+ def test_neg_xmit_0_0(self):
+ return self._test_neg_xmit_check_values(req_xmit=0,
+ req_recv=0,
+ rep_both=2048,
+ alter_xmit=0xffff,
+ alter_recv=0xffff)
+
+ def test_neg_xmit_3199_0(self):
+ return self._test_neg_xmit_check_values(req_xmit=3199,
+ req_recv=0,
+ rep_both=2048)
+
+ def test_neg_xmit_0_3199(self):
+ return self._test_neg_xmit_check_values(req_xmit=0,
+ req_recv=3199,
+ rep_both=2048)
+
+ def test_neg_xmit_3199_ffff(self):
+ return self._test_neg_xmit_check_values(req_xmit=3199,
+ req_recv=0xffff,
+ rep_both=3192)
+
+ def test_neg_xmit_ffff_3199(self):
+ return self._test_neg_xmit_check_values(req_xmit=0xffff,
+ req_recv=3199,
+ rep_both=3192)
+
+ def test_alloc_hint(self):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx = dcerpc.ctx_list()
+ ctx.context_id = 0
+ ctx.num_transfer_syntaxes = len(tsf1_list)
+ ctx.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx.transfer_syntaxes = tsf1_list
+
+ req = self.generate_bind(call_id=0,
+ ctx_list=[ctx])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertEqual(rep.u.auth_info, b'\0' * 0)
+
+ # And now try a request without auth_info
+ req = self.generate_request(call_id=2,
+ context_id=ctx.context_id,
+ opnum=0,
+ alloc_hint=0xffffffff,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ req = self.generate_request(call_id=3,
+ context_id=ctx.context_id,
+ opnum=1,
+ alloc_hint=0xffffffff,
+ stub=b"\04\00\00\00\00\00\00\00")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ req = self.generate_request(call_id=4,
+ context_id=ctx.context_id,
+ opnum=1,
+ alloc_hint=1,
+ stub=b"\04\00\00\00\00\00\00\00")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ def _get_netlogon_ctx(self):
+ abstract = samba.dcerpc.netlogon.abstract_syntax()
+ ndr32 = base.transfer_syntax_ndr()
+
+ (ctx, ack) = self.prepare_presentation(abstract, ndr32, context_id=0,
+ epmap=True, return_ack=True)
+
+ server = '\\\\' + self.target_hostname
+ if isinstance(server, bytes):
+ server_utf16 = server.decode('utf-8').encode('utf-16-le')
+ else:
+ server_utf16 = server.encode('utf-16-le')
+ computer = 'UNKNOWNCOMPUTER'
+ if isinstance(server, bytes):
+ computer_utf16 = computer.decode('utf-8').encode('utf-16-le')
+ else:
+ computer_utf16 = computer.encode('utf-16-le')
+
+ real_stub = struct.pack('<IIII', 0x00200000,
+ len(server) + 1, 0, len(server) + 1)
+ real_stub += server_utf16 + b'\x00\x00'
+ mod_len = len(real_stub) % 4
+ if mod_len != 0:
+ real_stub += b'\x00' * (4 - mod_len)
+ real_stub += struct.pack('<III',
+ len(computer) + 1, 0, len(computer) + 1)
+ real_stub += computer_utf16 + b'\x00\x00'
+ real_stub += b'\x11\x22\x33\x44\x55\x66\x77\x88'
+
+ return (ctx, ack, real_stub)
+
+ def _test_fragmented_requests(self, remaining=None, alloc_hint=None,
+ fault_first=None, fault_last=None):
+ (ctx, rep, real_stub) = self._get_netlogon_ctx()
+
+ chunk = rep.u.max_recv_frag - dcerpc.DCERPC_REQUEST_LENGTH
+
+ total = 0
+ first = True
+ while remaining > 0:
+ thistime = min(remaining, chunk)
+ remaining -= thistime
+ total += thistime
+
+ pfc_flags = 0
+ if first:
+ pfc_flags |= dcerpc.DCERPC_PFC_FLAG_FIRST
+ first = False
+ stub = real_stub + b'\x00' * (thistime - len(real_stub))
+ else:
+ stub = b"\x00" * thistime
+
+ if remaining == 0:
+ pfc_flags |= dcerpc.DCERPC_PFC_FLAG_LAST
+
+ # And now try a request without auth_info
+ # netr_ServerReqChallenge()
+ req = self.generate_request(call_id=0x21234,
+ pfc_flags=pfc_flags,
+ context_id=ctx.context_id,
+ opnum=4,
+ alloc_hint=alloc_hint,
+ stub=stub)
+ if alloc_hint >= thistime:
+ alloc_hint -= thistime
+ else:
+ alloc_hint = 0
+ self.send_pdu(req, hexdump=False)
+ if fault_first is not None:
+ rep = self.recv_pdu()
+ # We get a fault back
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, fault_first)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+ return
+ if remaining == 0:
+ break
+ if total >= 0x400000 and fault_last is not None:
+ rep = self.recv_pdu()
+ # We get a fault back
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, fault_last)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+ return
+ rep = self.recv_pdu(timeout=0.01)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+
+ if total >= 0x400000 and fault_last is not None:
+ rep = self.recv_pdu()
+ # We get a fault back
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, fault_last)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+ return
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ self.assertEqual(len(rep.u.stub_and_verifier), 12)
+ status = struct.unpack_from("<I", rep.u.stub_and_verifier, len(rep.u.stub_and_verifier) - 4)
+ self.assertEqual(status[0], 0)
+
+ def test_fragmented_requests01(self):
+ return self._test_fragmented_requests(remaining=0x400000,
+ alloc_hint=0x400000)
+
+ def test_fragmented_requests02(self):
+ return self._test_fragmented_requests(remaining=0x400000,
+ alloc_hint=0x100000)
+
+ def test_fragmented_requests03(self):
+ return self._test_fragmented_requests(remaining=0x400000,
+ alloc_hint=0)
+
+ def test_fragmented_requests04(self):
+ return self._test_fragmented_requests(remaining=0x400000,
+ alloc_hint=0x400001,
+ fault_first=dcerpc.DCERPC_FAULT_ACCESS_DENIED)
+
+ def test_fragmented_requests05(self):
+ return self._test_fragmented_requests(remaining=0x500001,
+ alloc_hint=0,
+ fault_last=dcerpc.DCERPC_FAULT_ACCESS_DENIED)
+
+ def _test_same_requests(self, pfc_flags, fault_1st=False, fault_2nd=False):
+ (ctx, rep, real_stub) = self._get_netlogon_ctx()
+
+ # netr_ServerReqChallenge with given flags
+ req = self.generate_request(call_id=2,
+ pfc_flags=pfc_flags,
+ context_id=ctx.context_id,
+ opnum=4,
+ stub=real_stub)
+ self.send_pdu(req)
+ if fault_1st:
+ rep = self.recv_pdu()
+ # We get a fault back
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, 0)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+ return
+ rep = self.recv_pdu(timeout=0.1)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+
+ # netr_ServerReqChallenge without DCERPC_PFC_FLAG_LAST
+ # with the same call_id
+ req = self.generate_request(call_id=2,
+ pfc_flags=pfc_flags,
+ context_id=ctx.context_id,
+ opnum=4,
+ stub=real_stub)
+ self.send_pdu(req)
+ if fault_2nd:
+ rep = self.recv_pdu()
+ # We get a fault back
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+ return
+
+ rep = self.recv_pdu(timeout=0.1)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+
+ def test_first_only_requests(self):
+ return self._test_same_requests(pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST,
+ fault_2nd=True)
+
+ def test_none_only_requests(self):
+ return self._test_same_requests(pfc_flags=0, fault_1st=True)
+
+ def test_last_only_requests(self):
+ return self._test_same_requests(pfc_flags=dcerpc.DCERPC_PFC_FLAG_LAST,
+ fault_1st=True)
+
+ def test_first_maybe_requests(self):
+ return self._test_same_requests(pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_MAYBE,
+ fault_2nd=True)
+
+ def test_first_didnot_requests(self):
+ return self._test_same_requests(pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ fault_2nd=True)
+
+ def test_first_cmpx_requests(self):
+ return self._test_same_requests(pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_CONC_MPX,
+ fault_2nd=True)
+
+ def test_first_08_requests(self):
+ return self._test_same_requests(pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST |
+ 0x08,
+ fault_2nd=True)
+
+ def test_first_cancel_requests(self):
+ (ctx, rep, real_stub) = self._get_netlogon_ctx()
+
+ # netr_ServerReqChallenge with given flags
+ req = self.generate_request(call_id=2,
+ pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_PENDING_CANCEL,
+ context_id=ctx.context_id,
+ opnum=4,
+ stub=real_stub)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ # We get a fault back
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, 0)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, dcerpc.DCERPC_FAULT_NO_CALL_ACTIVE)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_2nd_cancel_requests(self):
+ (ctx, rep, real_stub) = self._get_netlogon_ctx()
+
+ # netr_ServerReqChallenge with given flags
+ req = self.generate_request(call_id=2,
+ pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST,
+ context_id=ctx.context_id,
+ opnum=4,
+ stub=real_stub)
+ self.send_pdu(req)
+ rep = self.recv_pdu(timeout=0.1)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+
+ # netr_ServerReqChallenge with given flags
+ req = self.generate_request(call_id=2,
+ pfc_flags=dcerpc.DCERPC_PFC_FLAG_PENDING_CANCEL,
+ context_id=ctx.context_id,
+ opnum=4,
+ stub=real_stub)
+ self.send_pdu(req)
+ rep = self.recv_pdu(timeout=0.1)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+
+ # netr_ServerReqChallenge with given flags
+ req = self.generate_request(call_id=2,
+ pfc_flags=dcerpc.DCERPC_PFC_FLAG_LAST,
+ context_id=ctx.context_id,
+ opnum=4,
+ stub=real_stub)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ self.assertEqual(len(rep.u.stub_and_verifier), 12)
+ status = struct.unpack_from("<I", rep.u.stub_and_verifier, len(rep.u.stub_and_verifier) - 4)
+ self.assertEqual(status[0], 0)
+
+ def test_last_cancel_requests(self):
+ (ctx, rep, real_stub) = self._get_netlogon_ctx()
+
+ # netr_ServerReqChallenge with given flags
+ req = self.generate_request(call_id=2,
+ pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST,
+ context_id=ctx.context_id,
+ opnum=4,
+ stub=real_stub[:4])
+ self.send_pdu(req)
+ rep = self.recv_pdu(timeout=0.1)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+
+ # netr_ServerReqChallenge with given flags
+ req = self.generate_request(call_id=2,
+ pfc_flags=dcerpc.DCERPC_PFC_FLAG_LAST |
+ dcerpc.DCERPC_PFC_FLAG_PENDING_CANCEL,
+ context_id=ctx.context_id,
+ opnum=4,
+ stub=real_stub[4:])
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ self.assertEqual(len(rep.u.stub_and_verifier), 12)
+ status = struct.unpack_from("<I", rep.u.stub_and_verifier, len(rep.u.stub_and_verifier) - 4)
+ self.assertEqual(status[0], 0)
+
+ def test_mix_requests(self):
+ (ctx, rep, real_stub) = self._get_netlogon_ctx()
+
+ # netr_ServerReqChallenge with given flags
+ req = self.generate_request(call_id=50,
+ pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST,
+ context_id=ctx.context_id,
+ opnum=4,
+ stub=real_stub)
+ self.send_pdu(req)
+ rep = self.recv_pdu(timeout=0.1)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+
+ # netr_ServerReqChallenge with given flags
+ req = self.generate_request(call_id=51,
+ pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST,
+ context_id=ctx.context_id,
+ opnum=4,
+ stub=real_stub)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ # We get a fault back
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, 50,
+ pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ def test_co_cancel_no_request(self):
+ ndr32 = base.transfer_syntax_ndr()
+ abstract = samba.dcerpc.mgmt.abstract_syntax()
+ ctx = self.prepare_presentation(abstract, ndr32, context_id=0xff)
+
+ req = self.generate_co_cancel(call_id=3)
+ self.send_pdu(req)
+ rep = self.recv_pdu(timeout=0.01)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+
+ # And now try a request
+ req = self.generate_request(call_id=1,
+ context_id=ctx.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ def test_co_cancel_request_after_first(self):
+ ndr32 = base.transfer_syntax_ndr()
+ abstract = samba.dcerpc.mgmt.abstract_syntax()
+ ctx = self.prepare_presentation(abstract, ndr32, context_id=0xff)
+
+ req = self.generate_request(call_id=1,
+ pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST,
+ context_id=ctx.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu(timeout=0.01)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+
+ req = self.generate_co_cancel(call_id=1)
+ self.send_pdu(req)
+ rep = self.recv_pdu(timeout=0.01)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+
+ req = self.generate_request(call_id=1,
+ pfc_flags=dcerpc.DCERPC_PFC_FLAG_LAST,
+ context_id=ctx.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ # And now try a request
+ req = self.generate_request(call_id=2,
+ context_id=ctx.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ def test_orphaned_no_request(self):
+ ndr32 = base.transfer_syntax_ndr()
+ abstract = samba.dcerpc.mgmt.abstract_syntax()
+ ctx = self.prepare_presentation(abstract, ndr32)
+
+ req = self.generate_orphaned(call_id=3)
+ self.send_pdu(req)
+ rep = self.recv_pdu(timeout=0.01)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+
+ # And now try a request
+ req = self.generate_request(call_id=1,
+ context_id=ctx.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id & 0xff)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ def test_orphaned_request_after_first_last(self):
+ ndr32 = base.transfer_syntax_ndr()
+ abstract = samba.dcerpc.mgmt.abstract_syntax()
+ ctx = self.prepare_presentation(abstract, ndr32)
+
+ req = self.generate_request(call_id=1,
+ pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST,
+ context_id=ctx.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu(timeout=0.1)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+
+ req = self.generate_orphaned(call_id=1)
+ self.send_pdu(req)
+ rep = self.recv_pdu(timeout=0.1)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+
+ req = self.generate_request(call_id=1,
+ pfc_flags=dcerpc.DCERPC_PFC_FLAG_LAST,
+ context_id=ctx.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id & 0xff)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ # And now try a request
+ req = self.generate_request(call_id=2,
+ context_id=ctx.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id & 0xff)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ def test_orphaned_request_after_first_mpx_last(self):
+ ndr32 = base.transfer_syntax_ndr()
+ abstract = samba.dcerpc.mgmt.abstract_syntax()
+
+ pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST
+ pfc_flags |= samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST
+ pfc_flags |= samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_CONC_MPX
+ ctx = self.prepare_presentation(abstract, ndr32, pfc_flags=pfc_flags)
+
+ req = self.generate_request(call_id=1,
+ pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST,
+ context_id=ctx.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu(timeout=0.1)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+
+ req = self.generate_orphaned(call_id=1)
+ self.send_pdu(req)
+ rep = self.recv_pdu(timeout=0.1)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+
+ req = self.generate_request(call_id=1,
+ pfc_flags=dcerpc.DCERPC_PFC_FLAG_LAST,
+ context_id=ctx.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id & 0xff)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ # And now try a request
+ req = self.generate_request(call_id=2,
+ context_id=ctx.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id & 0xff)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ def test_orphaned_request_after_first_no_last(self):
+ ndr32 = base.transfer_syntax_ndr()
+ abstract = samba.dcerpc.mgmt.abstract_syntax()
+ ctx = self.prepare_presentation(abstract, ndr32)
+
+ req1 = self.generate_request(call_id=1,
+ pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST,
+ context_id=ctx.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req1)
+ rep = self.recv_pdu(timeout=0.1)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+
+ req = self.generate_orphaned(call_id=1)
+ self.send_pdu(req)
+ rep = self.recv_pdu(timeout=0.1)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+
+ # And now try a new request
+ req2 = self.generate_request(call_id=2,
+ context_id=ctx.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req2)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req1.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req1.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_orphaned_request_after_first_mpx_no_last(self):
+ ndr32 = base.transfer_syntax_ndr()
+ abstract = samba.dcerpc.mgmt.abstract_syntax()
+
+ pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST
+ pfc_flags |= samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST
+ pfc_flags |= samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_CONC_MPX
+ ctx = self.prepare_presentation(abstract, ndr32,
+ pfc_flags=pfc_flags)
+
+ req1 = self.generate_request(call_id=1,
+ pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST,
+ context_id=ctx.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req1)
+ rep = self.recv_pdu(timeout=0.1)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+
+ req = self.generate_orphaned(call_id=1)
+ self.send_pdu(req)
+ rep = self.recv_pdu(timeout=0.1)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+
+ # And now try a new request
+ req2 = self.generate_request(call_id=2,
+ context_id=ctx.context_id - 1,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req2)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req2.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, 0)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def _test_spnego_connect_upgrade_request(self, upgrade_auth_level):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+ ctx_list = [ctx1]
+
+ c = self.get_anon_creds()
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_CONNECT
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = b""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+
+ req = self.generate_bind(call_id=0,
+ ctx_list=ctx_list,
+ auth_info=auth_info)
+
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+
+ req = self.generate_alter(call_id=0,
+ ctx_list=ctx_list,
+ assoc_group_id=rep.u.assoc_group_id,
+ auth_info=auth_info)
+
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 0)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertTrue(finished)
+
+ # And now try a request without auth_info
+ req = self.generate_request(call_id=2,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id & 0xff)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ # Now a request with auth_info DCERPC_AUTH_LEVEL_CONNECT
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=b"\x01" +b"\x00" *15)
+ req = self.generate_request(call_id=3,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub=b"",
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ # We don't get an auth_info back
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id & 0xff)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ # Now a request with auth_info upgrade_auth_level
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=upgrade_auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=b"\x01" + b"\x00" * 15)
+ req = self.generate_request(call_id=4,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub=b"",
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ # We get a fault back
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, dcerpc.DCERPC_FAULT_ACCESS_DENIED)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_spnego_connect_packet_upgrade(self):
+ return self._test_spnego_connect_upgrade_request(
+ dcerpc.DCERPC_AUTH_LEVEL_PACKET)
+
+ def test_spnego_connect_integrity_upgrade(self):
+ return self._test_spnego_connect_upgrade_request(
+ dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY)
+
+ def _test_spnego_connect_downgrade_request(self, initial_auth_level):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+ ctx_list = [ctx1]
+
+ c = self.get_anon_creds()
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = initial_auth_level
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = b""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+
+ req = self.generate_bind(call_id=0,
+ ctx_list=ctx_list,
+ auth_info=auth_info)
+
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+
+ req = self.generate_alter(call_id=0,
+ ctx_list=ctx_list,
+ assoc_group_id=rep.u.assoc_group_id,
+ auth_info=auth_info)
+
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 0)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertTrue(finished)
+
+ # Now a request with auth_info DCERPC_AUTH_LEVEL_CONNECT
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=dcerpc.DCERPC_AUTH_LEVEL_CONNECT,
+ auth_context_id=auth_context_id,
+ auth_blob=b"\x01" + b"\x00" * 15)
+ req = self.generate_request(call_id=3,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub=b"",
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ # We get a fault back
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, dcerpc.DCERPC_FAULT_ACCESS_DENIED)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_spnego_packet_downgrade_connect(self):
+ return self._test_spnego_connect_downgrade_request(
+ dcerpc.DCERPC_AUTH_LEVEL_PACKET)
+
+ def test_spnego_integrity_downgrade_connect(self):
+ return self._test_spnego_connect_upgrade_request(
+ dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY)
+
+ def test_spnego_unfinished_request(self):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+ ctx_list = [ctx1]
+
+ c = self.get_anon_creds()
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_CONNECT
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = b""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+
+ req = self.generate_bind(call_id=0,
+ ctx_list=ctx_list,
+ auth_info=auth_info)
+
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ assoc_group_id = rep.u.assoc_group_id
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ # Now a request with auth_info DCERPC_AUTH_LEVEL_CONNECT
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=b"\x01" + b"\x00" * 15)
+ req = self.generate_request(call_id=1,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub=b"",
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ # We get a fault
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=req.pfc_flags |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, 0)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_spnego_auth3(self):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+ ctx_list = [ctx1]
+
+ c = self.get_anon_creds()
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_CONNECT
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = b""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_bind(call_id=0,
+ ctx_list=ctx_list,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_auth3(call_id=0,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu(timeout=0.01)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+
+ # And now try a request without auth_info
+ req = self.generate_request(call_id=2,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ # We get a fault back
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, dcerpc.DCERPC_FAULT_ACCESS_DENIED)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_spnego_connect_reauth_alter(self):
+ ndr32 = base.transfer_syntax_ndr()
+ ndr64 = base.transfer_syntax_ndr64()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+ ctx_list = [ctx1]
+
+ c = self.get_anon_creds()
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_CONNECT
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = b""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+
+ req = self.generate_bind(call_id=0,
+ ctx_list=ctx_list,
+ auth_info=auth_info)
+
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_alter(call_id=0,
+ ctx_list=[ctx1],
+ assoc_group_id=rep.u.assoc_group_id,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 0)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertTrue(finished)
+
+ # And now try a request without auth_info
+ req = self.generate_request(call_id=2,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id & 0xff)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ # Now a request with auth_info DCERPC_AUTH_LEVEL_CONNECT
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=b"\x01" + b"\x00" * 15)
+ req = self.generate_request(call_id=3,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub=b"",
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ # We don't get an auth_info back
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ # Now a reauth
+
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_CONNECT
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = b""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_alter(call_id=0,
+ ctx_list=ctx_list,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ # We get a fault
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=req.pfc_flags |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, 0)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, dcerpc.DCERPC_FAULT_ACCESS_DENIED)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_spnego_connect_reauth_auth3(self):
+ ndr32 = base.transfer_syntax_ndr()
+ ndr64 = base.transfer_syntax_ndr64()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+ ctx_list = [ctx1]
+
+ c = self.get_anon_creds()
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_CONNECT
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = b""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+
+ req = self.generate_bind(call_id=0,
+ ctx_list=ctx_list,
+ auth_info=auth_info)
+
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_alter(call_id=0,
+ ctx_list=[ctx1],
+ assoc_group_id=rep.u.assoc_group_id,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 0)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertTrue(finished)
+
+ # And now try a request without auth_info
+ req = self.generate_request(call_id=2,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ # Now a request with auth_info DCERPC_AUTH_LEVEL_CONNECT
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=b"\x01" + b"\x00" * 15)
+ req = self.generate_request(call_id=3,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub=b"",
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ # We don't get an auth_info back
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ # Now a reauth
+
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_CONNECT
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = b""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_auth3(call_id=0,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ # We get a fault
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=req.pfc_flags |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, 0)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_spnego_change_auth_level(self):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+
+ c = self.get_anon_creds()
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = b""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_bind(call_id=0,
+ ctx_list=[ctx1],
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=dcerpc.DCERPC_AUTH_LEVEL_PRIVACY,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_alter(call_id=0,
+ ctx_list=[ctx1],
+ assoc_group_id=rep.u.assoc_group_id,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=req.pfc_flags |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, 0)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, dcerpc.DCERPC_FAULT_ACCESS_DENIED)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_spnego_change_abstract(self):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+
+ ctx1b = dcerpc.ctx_list()
+ ctx1b.context_id = 1
+ ctx1b.num_transfer_syntaxes = len(tsf1_list)
+ ctx1b.abstract_syntax = samba.dcerpc.epmapper.abstract_syntax()
+ ctx1b.transfer_syntaxes = tsf1_list
+
+ c = self.get_anon_creds()
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = b""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_bind(call_id=0,
+ ctx_list=[ctx1],
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=dcerpc.DCERPC_AUTH_LEVEL_PRIVACY,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_alter(call_id=0,
+ ctx_list=[ctx1b],
+ assoc_group_id=rep.u.assoc_group_id,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=req.pfc_flags |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, 0)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_spnego_change_transfer(self):
+ ndr32 = base.transfer_syntax_ndr()
+ ndr64 = base.transfer_syntax_ndr64()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+
+ tsf1b_list = [ndr32, ndr64]
+ ctx1b = dcerpc.ctx_list()
+ ctx1b.context_id = 1
+ ctx1b.num_transfer_syntaxes = len(tsf1b_list)
+ ctx1b.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1b.transfer_syntaxes = tsf1b_list
+
+ c = self.get_anon_creds()
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = b""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_bind(call_id=0,
+ ctx_list=[ctx1],
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ # We change ctx_list and auth_level
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=dcerpc.DCERPC_AUTH_LEVEL_PRIVACY,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_alter(call_id=0,
+ ctx_list=[ctx1b],
+ assoc_group_id=rep.u.assoc_group_id,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=req.pfc_flags |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, 0)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_spnego_change_auth_type1(self):
+ ndr32 = base.transfer_syntax_ndr()
+ ndr64 = base.transfer_syntax_ndr64()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+
+ c = self.get_anon_creds()
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = b""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_bind(call_id=0,
+ ctx_list=[ctx1],
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ # We change ctx_list and auth_level
+ auth_info = self.generate_auth(auth_type=dcerpc.DCERPC_AUTH_TYPE_KRB5,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_alter(call_id=0,
+ ctx_list=[ctx1],
+ assoc_group_id=rep.u.assoc_group_id,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=req.pfc_flags |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, 0)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, dcerpc.DCERPC_FAULT_SEC_PKG_ERROR)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_spnego_change_auth_type2(self):
+ ndr32 = base.transfer_syntax_ndr()
+ ndr64 = base.transfer_syntax_ndr64()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+
+ tsf1b_list = [ndr32, ndr64]
+ ctx1b = dcerpc.ctx_list()
+ ctx1b.context_id = 1
+ ctx1b.num_transfer_syntaxes = len(tsf1b_list)
+ ctx1b.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1b.transfer_syntaxes = tsf1b_list
+
+ c = self.get_anon_creds()
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = b""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_bind(call_id=0,
+ ctx_list=[ctx1],
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ # We change ctx_list and auth_level
+ auth_info = self.generate_auth(auth_type=dcerpc.DCERPC_AUTH_TYPE_KRB5,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_alter(call_id=0,
+ ctx_list=[ctx1b],
+ assoc_group_id=rep.u.assoc_group_id,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=req.pfc_flags |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, 0)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_spnego_change_auth_type3(self):
+ ndr32 = base.transfer_syntax_ndr()
+ ndr64 = base.transfer_syntax_ndr64()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+
+ tsf1b_list = [ndr32, ndr64]
+ ctx1b = dcerpc.ctx_list()
+ ctx1b.context_id = 1
+ ctx1b.num_transfer_syntaxes = len(tsf1b_list)
+ ctx1b.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1b.transfer_syntaxes = tsf1b_list
+
+ c = self.get_anon_creds()
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = b""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_bind(call_id=0,
+ ctx_list=[ctx1],
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ # We change ctx_list and auth_level
+ auth_info = self.generate_auth(auth_type=dcerpc.DCERPC_AUTH_TYPE_NONE,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_alter(call_id=0,
+ ctx_list=[ctx1b],
+ assoc_group_id=rep.u.assoc_group_id,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=req.pfc_flags |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, 0)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, dcerpc.DCERPC_FAULT_ACCESS_DENIED)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_spnego_auth_pad_ok(self):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+ ctx_list = [ctx1]
+
+ c = self.get_anon_creds()
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_CONNECT
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = b""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+
+ req = self.generate_bind(call_id=0,
+ ctx_list=ctx_list,
+ auth_info=auth_info)
+ req_pdu = samba.ndr.ndr_pack(req)
+
+ auth_pad_ok = len(req_pdu)
+ auth_pad_ok -= dcerpc.DCERPC_REQUEST_LENGTH
+ auth_pad_ok -= dcerpc.DCERPC_AUTH_TRAILER_LENGTH
+ auth_pad_ok -= len(to_server)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_pad_length=auth_pad_ok,
+ auth_blob=to_server)
+
+ req = self.generate_bind(call_id=0,
+ ctx_list=ctx_list,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_alter(call_id=0,
+ ctx_list=ctx_list,
+ assoc_group_id=rep.u.assoc_group_id,
+ auth_info=auth_info)
+ req_pdu = samba.ndr.ndr_pack(req)
+
+ auth_pad_ok = len(req_pdu)
+ auth_pad_ok -= dcerpc.DCERPC_REQUEST_LENGTH
+ auth_pad_ok -= dcerpc.DCERPC_AUTH_TRAILER_LENGTH
+ auth_pad_ok -= len(to_server)
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_pad_length=auth_pad_ok,
+ auth_blob=to_server)
+ req = self.generate_alter(call_id=0,
+ ctx_list=ctx_list,
+ assoc_group_id=rep.u.assoc_group_id,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 0)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertTrue(finished)
+
+ # And now try a request without auth_info
+ req = self.generate_request(call_id=2,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ # Now a request with auth_info DCERPC_AUTH_LEVEL_CONNECT
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=b"\x01" + b"\x00" * 15)
+ req = self.generate_request(call_id=3,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub=b"",
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ # We don't get an auth_info back
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ self._disconnect("disconnect")
+ self.assertNotConnected()
+
+ def test_spnego_auth_pad_fail_bind(self):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+ ctx_list = [ctx1]
+
+ c = self.get_anon_creds()
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_CONNECT
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = b""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+
+ req = self.generate_bind(call_id=0,
+ ctx_list=ctx_list,
+ auth_info=auth_info)
+ req_pdu = samba.ndr.ndr_pack(req)
+
+ auth_pad_ok = len(req_pdu)
+ auth_pad_ok -= dcerpc.DCERPC_REQUEST_LENGTH
+ auth_pad_ok -= dcerpc.DCERPC_AUTH_TRAILER_LENGTH
+ auth_pad_ok -= len(to_server)
+ auth_pad_bad = auth_pad_ok + 1
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_pad_length=auth_pad_bad,
+ auth_blob=to_server)
+
+ req = self.generate_bind(call_id=0,
+ ctx_list=ctx_list,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_NAK, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.reject_reason,
+ dcerpc.DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED)
+ self.assertEqual(rep.u.num_versions, 1)
+ self.assertEqual(rep.u.versions[0].rpc_vers, req.rpc_vers)
+ self.assertEqual(rep.u.versions[0].rpc_vers_minor, req.rpc_vers_minor)
+ self.assertEqual(len(rep.u._pad), 3)
+ self.assertEqual(rep.u._pad, b'\0' * 3)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_spnego_auth_pad_fail_alter(self):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+ ctx_list = [ctx1]
+
+ c = self.get_anon_creds()
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_CONNECT
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = b""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+
+ req = self.generate_bind(call_id=0,
+ ctx_list=ctx_list,
+ auth_info=auth_info)
+ req_pdu = samba.ndr.ndr_pack(req)
+
+ auth_pad_ok = len(req_pdu)
+ auth_pad_ok -= dcerpc.DCERPC_REQUEST_LENGTH
+ auth_pad_ok -= dcerpc.DCERPC_AUTH_TRAILER_LENGTH
+ auth_pad_ok -= len(to_server)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_pad_length=auth_pad_ok,
+ auth_blob=to_server)
+
+ req = self.generate_bind(call_id=0,
+ ctx_list=ctx_list,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+ req = self.generate_alter(call_id=0,
+ ctx_list=ctx_list,
+ assoc_group_id=rep.u.assoc_group_id,
+ auth_info=auth_info)
+ req_pdu = samba.ndr.ndr_pack(req)
+
+ auth_pad_ok = len(req_pdu)
+ auth_pad_ok -= dcerpc.DCERPC_REQUEST_LENGTH
+ auth_pad_ok -= dcerpc.DCERPC_AUTH_TRAILER_LENGTH
+ auth_pad_ok -= len(to_server)
+ auth_pad_bad = auth_pad_ok + 1
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_pad_length=auth_pad_bad,
+ auth_blob=to_server)
+ req = self.generate_alter(call_id=0,
+ ctx_list=ctx_list,
+ assoc_group_id=rep.u.assoc_group_id,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=req.pfc_flags |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, 0)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, dcerpc.DCERPC_NCA_S_PROTO_ERROR)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_ntlmssp_auth_pad_ok(self):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+ ctx_list = [ctx1]
+
+ c = self.get_anon_creds()
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_CONNECT
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = b""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+
+ req = self.generate_bind(call_id=0,
+ ctx_list=ctx_list,
+ auth_info=auth_info)
+ req_pdu = samba.ndr.ndr_pack(req)
+
+ auth_pad_ok = len(req_pdu)
+ auth_pad_ok -= dcerpc.DCERPC_REQUEST_LENGTH
+ auth_pad_ok -= dcerpc.DCERPC_AUTH_TRAILER_LENGTH
+ auth_pad_ok -= len(to_server)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_pad_length=auth_pad_ok,
+ auth_blob=to_server)
+
+ req = self.generate_bind(call_id=0,
+ ctx_list=ctx_list,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertTrue(finished)
+
+ auth_pad_ok = 0
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_pad_length=auth_pad_ok,
+ auth_blob=to_server)
+ req = self.generate_auth3(call_id=0,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu(timeout=0.01)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+
+ # And now try a request without auth_info
+ req = self.generate_request(call_id=2,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub=b"")
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ # Now a request with auth_info DCERPC_AUTH_LEVEL_CONNECT
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=b"\x01" + b"\x00" * 15)
+ req = self.generate_request(call_id=3,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub=b"",
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ # We don't get an auth_info back
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+
+ self._disconnect("disconnect")
+ self.assertNotConnected()
+
+ def test_ntlmssp_auth_pad_fail_auth3(self):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+ ctx_list = [ctx1]
+
+ c = self.get_anon_creds()
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(c)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_CONNECT
+ auth_context_id = 2
+ g.start_mech_by_authtype(auth_type, auth_level)
+ from_server = b""
+ (finished, to_server) = g.update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_blob=to_server)
+
+ req = self.generate_bind(call_id=0,
+ ctx_list=ctx_list,
+ auth_info=auth_info)
+ req_pdu = samba.ndr.ndr_pack(req)
+
+ auth_pad_ok = len(req_pdu)
+ auth_pad_ok -= dcerpc.DCERPC_REQUEST_LENGTH
+ auth_pad_ok -= dcerpc.DCERPC_AUTH_TRAILER_LENGTH
+ auth_pad_ok -= len(to_server)
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_pad_length=auth_pad_ok,
+ auth_blob=to_server)
+
+ req = self.generate_bind(call_id=0,
+ ctx_list=ctx_list,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 4)
+ self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
+ a = self.parse_auth(rep.u.auth_info)
+
+ from_server = a.credentials
+ (finished, to_server) = g.update(from_server)
+ self.assertTrue(finished)
+
+ auth_pad_bad = 1
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ auth_pad_length=auth_pad_bad,
+ auth_blob=to_server)
+ req = self.generate_auth3(call_id=0,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=req.pfc_flags |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, 0)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, dcerpc.DCERPC_NCA_S_FAULT_REMOTE_NO_MEMORY)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def _test_auth_bind_auth_level(self, auth_type, auth_level, auth_context_id, ctx,
+ g_auth_level=dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY,
+ hdr_signing=False,
+ alter_fault=None):
+ creds = self.get_user_creds()
+ auth_context = self.get_auth_context_creds(creds=creds,
+ auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ g_auth_level=g_auth_level,
+ hdr_signing=hdr_signing)
+ if auth_context is None:
+ return None
+ ack = self.do_generic_bind(ctx=ctx,
+ auth_context=auth_context,
+ alter_fault=alter_fault)
+ if ack is None:
+ return None
+ return auth_context
+
+ def _test_spnego_level_bind_nak(self, auth_level,
+ reason=dcerpc.DCERPC_BIND_NAK_REASON_INVALID_CHECKSUM):
+ c = self.get_user_creds()
+ return self._test_auth_type_level_bind_nak(auth_type=dcerpc.DCERPC_AUTH_TYPE_SPNEGO,
+ auth_level=auth_level, creds=c, reason=reason)
+
+ def _test_spnego_level_bind(self, auth_level,
+ g_auth_level=dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY,
+ alter_fault=None,
+ request_fault=None,
+ response_fault_flags=0):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 0x1001
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_context_id = 2
+
+ auth_context = self._test_auth_bind_auth_level(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ ctx=ctx1,
+ g_auth_level=g_auth_level,
+ alter_fault=alter_fault)
+ if request_fault is None:
+ return
+
+ self.assertIsNotNone(auth_context)
+ g = auth_context["gensec"]
+ self.assertIsNotNone(g)
+
+ stub_bin = b'\x00' * 17
+ mod_len = len(stub_bin) % dcerpc.DCERPC_AUTH_PAD_ALIGNMENT
+ auth_pad_length = 0
+ if mod_len > 0:
+ auth_pad_length = dcerpc.DCERPC_AUTH_PAD_ALIGNMENT - mod_len
+ stub_bin += b'\x00' * auth_pad_length
+
+ if g_auth_level >= dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY:
+ sig_size = g.sig_size(len(stub_bin))
+ else:
+ sig_size = 16
+ zero_sig = b"\x00" * sig_size
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_pad_length=auth_pad_length,
+ auth_context_id=auth_context_id,
+ auth_blob=zero_sig)
+ req = self.generate_request(call_id=4,
+ context_id=ctx1.context_id,
+ opnum=0xffff,
+ stub=stub_bin,
+ auth_info=auth_info)
+ if g_auth_level >= dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY:
+ req_blob = samba.ndr.ndr_pack(req)
+ ofs_stub = dcerpc.DCERPC_REQUEST_LENGTH
+ ofs_sig = len(req_blob) - req.auth_length
+ ofs_trailer = ofs_sig - dcerpc.DCERPC_AUTH_TRAILER_LENGTH
+ req_data = req_blob[ofs_stub:ofs_trailer]
+ req_whole = req_blob[0:ofs_sig]
+ sig = g.sign_packet(req_data, req_whole)
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_pad_length=auth_pad_length,
+ auth_context_id=auth_context_id,
+ auth_blob=sig)
+ req = self.generate_request(call_id=4,
+ context_id=ctx1.context_id,
+ opnum=0xffff,
+ stub=stub_bin,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=req.pfc_flags | response_fault_flags,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, ctx1.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, request_fault)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ if response_fault_flags & dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE:
+ return
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_spnego_none_bind(self):
+ return self._test_spnego_level_bind_nak(dcerpc.DCERPC_AUTH_LEVEL_NONE,
+ reason=dcerpc.DCERPC_BIND_NAK_REASON_NOT_SPECIFIED)
+
+ def test_spnego_call_bind(self):
+ return self._test_spnego_level_bind_nak(dcerpc.DCERPC_AUTH_LEVEL_CALL,
+ reason=dcerpc.DCERPC_BIND_NAK_REASON_INVALID_CHECKSUM)
+
+ def test_spnego_0_bind(self):
+ return self._test_spnego_level_bind_nak(0,
+ reason=dcerpc.DCERPC_BIND_NAK_REASON_NOT_SPECIFIED)
+
+ def test_spnego_7_bind(self):
+ return self._test_spnego_level_bind_nak(7,
+ reason=dcerpc.DCERPC_BIND_NAK_REASON_NOT_SPECIFIED)
+
+ def test_spnego_255_bind(self):
+ return self._test_spnego_level_bind_nak(255,
+ reason=dcerpc.DCERPC_BIND_NAK_REASON_NOT_SPECIFIED)
+
+ def test_spnego_connect_bind_none(self):
+ return self._test_spnego_level_bind(auth_level=dcerpc.DCERPC_AUTH_LEVEL_CONNECT,
+ g_auth_level=dcerpc.DCERPC_AUTH_LEVEL_CONNECT)
+
+ def test_spnego_connect_bind_sign(self):
+ return self._test_spnego_level_bind(auth_level=dcerpc.DCERPC_AUTH_LEVEL_CONNECT,
+ g_auth_level=dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY)
+
+ def test_spnego_connect_bind_seal(self):
+ return self._test_spnego_level_bind(auth_level=dcerpc.DCERPC_AUTH_LEVEL_CONNECT,
+ g_auth_level=dcerpc.DCERPC_AUTH_LEVEL_PRIVACY)
+
+ def test_spnego_packet_bind_none(self):
+ # DCERPC_AUTH_LEVEL_PACKET is handled as alias of
+ # DCERPC_AUTH_LEVEL_INTEGRITY
+ return self._test_spnego_level_bind(auth_level=dcerpc.DCERPC_AUTH_LEVEL_PACKET,
+ g_auth_level=dcerpc.DCERPC_AUTH_LEVEL_CONNECT,
+ request_fault=dcerpc.DCERPC_FAULT_SEC_PKG_ERROR)
+
+ def test_spnego_packet_bind_sign(self):
+ # DCERPC_AUTH_LEVEL_PACKET is handled as alias of
+ # DCERPC_AUTH_LEVEL_INTEGRITY
+ return self._test_spnego_level_bind(auth_level=dcerpc.DCERPC_AUTH_LEVEL_PACKET,
+ g_auth_level=dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY,
+ request_fault=dcerpc.DCERPC_NCA_S_OP_RNG_ERROR,
+ response_fault_flags=dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE)
+
+ def test_spnego_packet_bind_seal(self):
+ # DCERPC_AUTH_LEVEL_PACKET is handled as alias of
+ # DCERPC_AUTH_LEVEL_INTEGRITY
+ return self._test_spnego_level_bind(auth_level=dcerpc.DCERPC_AUTH_LEVEL_PACKET,
+ g_auth_level=dcerpc.DCERPC_AUTH_LEVEL_PRIVACY,
+ request_fault=dcerpc.DCERPC_NCA_S_OP_RNG_ERROR,
+ response_fault_flags=dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE)
+
+ def test_spnego_integrity_bind_none(self):
+ return self._test_spnego_level_bind(auth_level=dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY,
+ g_auth_level=dcerpc.DCERPC_AUTH_LEVEL_CONNECT,
+ request_fault=dcerpc.DCERPC_FAULT_SEC_PKG_ERROR)
+
+ def test_spnego_integrity_bind_sign(self):
+ return self._test_spnego_level_bind(auth_level=dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY,
+ g_auth_level=dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY,
+ request_fault=dcerpc.DCERPC_NCA_S_OP_RNG_ERROR,
+ response_fault_flags=dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE)
+
+ def test_spnego_integrity_bind_seal(self):
+ return self._test_spnego_level_bind(auth_level=dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY,
+ g_auth_level=dcerpc.DCERPC_AUTH_LEVEL_PRIVACY,
+ request_fault=dcerpc.DCERPC_NCA_S_OP_RNG_ERROR,
+ response_fault_flags=dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE)
+
+ def test_spnego_privacy_bind_none(self):
+ # This fails...
+ return self._test_spnego_level_bind(auth_level=dcerpc.DCERPC_AUTH_LEVEL_PRIVACY,
+ g_auth_level=dcerpc.DCERPC_AUTH_LEVEL_CONNECT,
+ alter_fault=dcerpc.DCERPC_FAULT_SEC_PKG_ERROR)
+
+ def test_spnego_privacy_bind_sign(self):
+ # This fails...
+ return self._test_spnego_level_bind(auth_level=dcerpc.DCERPC_AUTH_LEVEL_PRIVACY,
+ g_auth_level=dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY,
+ alter_fault=dcerpc.DCERPC_FAULT_SEC_PKG_ERROR)
+
+ def test_spnego_privacy_bind_seal(self):
+ return self._test_spnego_level_bind(auth_level=dcerpc.DCERPC_AUTH_LEVEL_PRIVACY,
+ g_auth_level=dcerpc.DCERPC_AUTH_LEVEL_PRIVACY)
+
+ def _test_auth_signing_auth_level_request(self, auth_type, auth_level, hdr_sign=False):
+ ndr32 = base.transfer_syntax_ndr()
+
+ tsf1_list = [ndr32]
+ ctx1 = dcerpc.ctx_list()
+ ctx1.context_id = 0x1001
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = samba.dcerpc.mgmt.abstract_syntax()
+ ctx1.transfer_syntaxes = tsf1_list
+ ctx_list = [ctx1]
+
+ auth_context_id = 2
+
+ auth_context = self._test_auth_bind_auth_level(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ hdr_signing=hdr_sign,
+ ctx=ctx1)
+ self.assertIsNotNone(auth_context)
+ g = auth_context["gensec"]
+ self.assertIsNotNone(g)
+
+ stub_bin = b'\x00' * 0
+ mod_len = len(stub_bin) % dcerpc.DCERPC_AUTH_PAD_ALIGNMENT
+ auth_pad_length = 0
+ if mod_len > 0:
+ auth_pad_length = dcerpc.DCERPC_AUTH_PAD_ALIGNMENT - mod_len
+ stub_bin += b'\x00' * auth_pad_length
+
+ sig_size = g.sig_size(len(stub_bin))
+ zero_sig = b"\x00" * sig_size
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_pad_length=auth_pad_length,
+ auth_context_id=auth_context_id,
+ auth_blob=zero_sig)
+ req = self.generate_request(call_id=3,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub=stub_bin,
+ auth_info=auth_info)
+ req_blob = samba.ndr.ndr_pack(req)
+ ofs_stub = dcerpc.DCERPC_REQUEST_LENGTH
+ ofs_sig = len(req_blob) - req.auth_length
+ ofs_trailer = ofs_sig - dcerpc.DCERPC_AUTH_TRAILER_LENGTH
+ req_data = req_blob[ofs_stub:ofs_trailer]
+ req_whole = req_blob[0:ofs_sig]
+ sig = g.sign_packet(req_data, req_whole)
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_pad_length=auth_pad_length,
+ auth_context_id=auth_context_id,
+ auth_blob=sig)
+ req = self.generate_request(call_id=3,
+ context_id=ctx1.context_id,
+ opnum=0,
+ stub=stub_bin,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ (rep, rep_blob) = self.recv_pdu_raw()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=sig_size)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id & 0xff)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+ self.assertEqual(rep.auth_length, sig_size)
+
+ ofs_stub = dcerpc.DCERPC_REQUEST_LENGTH
+ ofs_sig = rep.frag_length - rep.auth_length
+ ofs_trailer = ofs_sig - dcerpc.DCERPC_AUTH_TRAILER_LENGTH
+ rep_data = rep_blob[ofs_stub:ofs_trailer]
+ rep_whole = rep_blob[0:ofs_sig]
+ rep_sig = rep_blob[ofs_sig:]
+ rep_auth_info_blob = rep_blob[ofs_trailer:]
+
+ rep_auth_info = self.parse_auth(rep_auth_info_blob)
+ self.assertEqual(rep_auth_info.auth_type, auth_type)
+ self.assertEqual(rep_auth_info.auth_level, auth_level)
+ # mgmt_inq_if_ids() returns no fixed size results
+ #self.assertEqual(rep_auth_info.auth_pad_length, 0)
+ self.assertEqual(rep_auth_info.auth_reserved, 0)
+ self.assertEqual(rep_auth_info.auth_context_id, auth_context_id)
+ self.assertEqual(rep_auth_info.credentials, rep_sig)
+
+ g.check_packet(rep_data, rep_whole, rep_sig)
+
+ stub_bin = b'\x00' * 17
+ mod_len = len(stub_bin) % dcerpc.DCERPC_AUTH_PAD_ALIGNMENT
+ auth_pad_length = 0
+ if mod_len > 0:
+ auth_pad_length = dcerpc.DCERPC_AUTH_PAD_ALIGNMENT - mod_len
+ stub_bin += b'\x00' * auth_pad_length
+
+ sig_size = g.sig_size(len(stub_bin))
+ zero_sig = b"\x00" * sig_size
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_pad_length=auth_pad_length,
+ auth_context_id=auth_context_id,
+ auth_blob=zero_sig)
+ req = self.generate_request(call_id=4,
+ context_id=ctx1.context_id,
+ opnum=0xffff,
+ stub=stub_bin,
+ auth_info=auth_info)
+ req_blob = samba.ndr.ndr_pack(req)
+ ofs_stub = dcerpc.DCERPC_REQUEST_LENGTH
+ ofs_sig = len(req_blob) - req.auth_length
+ ofs_trailer = ofs_sig - dcerpc.DCERPC_AUTH_TRAILER_LENGTH
+ req_data = req_blob[ofs_stub:ofs_trailer]
+ req_whole = req_blob[0:ofs_sig]
+ sig = g.sign_packet(req_data, req_whole)
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_pad_length=auth_pad_length,
+ auth_context_id=auth_context_id,
+ auth_blob=sig)
+ req = self.generate_request(call_id=4,
+ context_id=ctx1.context_id,
+ opnum=0xffff,
+ stub=stub_bin,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=req.pfc_flags |
+ dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, ctx1.context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, dcerpc.DCERPC_NCA_S_OP_RNG_ERROR)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ stub_bin = b'\x00' * 8
+ mod_len = len(stub_bin) % dcerpc.DCERPC_AUTH_PAD_ALIGNMENT
+ auth_pad_length = 0
+ if mod_len > 0:
+ auth_pad_length = dcerpc.DCERPC_AUTH_PAD_ALIGNMENT - mod_len
+ stub_bin += b'\x00' * auth_pad_length
+
+ sig_size = g.sig_size(len(stub_bin))
+ zero_sig = b"\x00" * sig_size
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_pad_length=auth_pad_length,
+ auth_context_id=auth_context_id,
+ auth_blob=zero_sig)
+ req = self.generate_request(call_id=5,
+ context_id=ctx1.context_id,
+ opnum=1,
+ stub=stub_bin,
+ auth_info=auth_info)
+ req_blob = samba.ndr.ndr_pack(req)
+ ofs_stub = dcerpc.DCERPC_REQUEST_LENGTH
+ ofs_sig = len(req_blob) - req.auth_length
+ ofs_trailer = ofs_sig - dcerpc.DCERPC_AUTH_TRAILER_LENGTH
+ req_data = req_blob[ofs_stub:ofs_trailer]
+ req_whole = req_blob[0:ofs_sig]
+ sig = g.sign_packet(req_data, req_whole)
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_pad_length=auth_pad_length,
+ auth_context_id=auth_context_id,
+ auth_blob=sig)
+ req = self.generate_request(call_id=5,
+ context_id=ctx1.context_id,
+ opnum=1,
+ stub=stub_bin,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ (rep, rep_blob) = self.recv_pdu_raw()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=sig_size)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id & 0xff)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+ self.assertEqual(rep.auth_length, sig_size)
+
+ ofs_stub = dcerpc.DCERPC_REQUEST_LENGTH
+ ofs_sig = rep.frag_length - rep.auth_length
+ ofs_trailer = ofs_sig - dcerpc.DCERPC_AUTH_TRAILER_LENGTH
+ rep_data = rep_blob[ofs_stub:ofs_trailer]
+ rep_whole = rep_blob[0:ofs_sig]
+ rep_sig = rep_blob[ofs_sig:]
+ rep_auth_info_blob = rep_blob[ofs_trailer:]
+
+ rep_auth_info = self.parse_auth(rep_auth_info_blob)
+ self.assertEqual(rep_auth_info.auth_type, auth_type)
+ self.assertEqual(rep_auth_info.auth_level, auth_level)
+ self.assertEqual(rep_auth_info.auth_pad_length, 4)
+ self.assertEqual(rep_auth_info.auth_reserved, 0)
+ self.assertEqual(rep_auth_info.auth_context_id, auth_context_id)
+ self.assertEqual(rep_auth_info.credentials, rep_sig)
+
+ g.check_packet(rep_data, rep_whole, rep_sig)
+
+ stub_bin = b'\x00' * 8
+ mod_len = len(stub_bin) % dcerpc.DCERPC_AUTH_PAD_ALIGNMENT
+ auth_pad_length = 0
+ if mod_len > 0:
+ auth_pad_length = dcerpc.DCERPC_AUTH_PAD_ALIGNMENT - mod_len
+ stub_bin += b'\x00' * auth_pad_length
+
+ sig_size = g.sig_size(len(stub_bin))
+ zero_sig = b"\x00" * sig_size
+
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_pad_length=auth_pad_length,
+ auth_context_id=auth_context_id,
+ auth_blob=zero_sig)
+ req = self.generate_request(call_id=6,
+ context_id=ctx1.context_id,
+ opnum=3,
+ stub=stub_bin,
+ auth_info=auth_info)
+ req_blob = samba.ndr.ndr_pack(req)
+ ofs_stub = dcerpc.DCERPC_REQUEST_LENGTH
+ ofs_sig = len(req_blob) - req.auth_length
+ ofs_trailer = ofs_sig - dcerpc.DCERPC_AUTH_TRAILER_LENGTH
+ req_data = req_blob[ofs_stub:ofs_trailer]
+ req_whole = req_blob[0:ofs_sig]
+ sig = g.sign_packet(req_data, req_whole)
+ auth_info = self.generate_auth(auth_type=auth_type,
+ auth_level=auth_level,
+ auth_pad_length=auth_pad_length,
+ auth_context_id=auth_context_id,
+ auth_blob=sig)
+ req = self.generate_request(call_id=6,
+ context_id=ctx1.context_id,
+ opnum=3,
+ stub=stub_bin,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ (rep, rep_blob) = self.recv_pdu_raw()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ auth_length=sig_size)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, req.u.context_id & 0xff)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+ self.assertEqual(rep.auth_length, sig_size)
+
+ ofs_stub = dcerpc.DCERPC_REQUEST_LENGTH
+ ofs_sig = rep.frag_length - rep.auth_length
+ ofs_trailer = ofs_sig - dcerpc.DCERPC_AUTH_TRAILER_LENGTH
+ rep_data = rep_blob[ofs_stub:ofs_trailer]
+ rep_whole = rep_blob[0:ofs_sig]
+ rep_sig = rep_blob[ofs_sig:]
+ rep_auth_info_blob = rep_blob[ofs_trailer:]
+
+ rep_auth_info = self.parse_auth(rep_auth_info_blob)
+ self.assertEqual(rep_auth_info.auth_type, auth_type)
+ self.assertEqual(rep_auth_info.auth_level, auth_level)
+ self.assertEqual(rep_auth_info.auth_pad_length, 12)
+ self.assertEqual(rep_auth_info.auth_reserved, 0)
+ self.assertEqual(rep_auth_info.auth_context_id, auth_context_id)
+ self.assertEqual(rep_auth_info.credentials, rep_sig)
+
+ g.check_packet(rep_data, rep_whole, rep_sig)
+
+ def test_spnego_signing_packet(self):
+ # DCERPC_AUTH_LEVEL_PACKET is handled as alias of
+ # DCERPC_AUTH_LEVEL_INTEGRITY
+ return self._test_auth_signing_auth_level_request(dcerpc.DCERPC_AUTH_TYPE_SPNEGO,
+ dcerpc.DCERPC_AUTH_LEVEL_PACKET)
+
+ def test_spnego_hdr_signing_packet(self):
+ # DCERPC_AUTH_LEVEL_PACKET is handled as alias of
+ # DCERPC_AUTH_LEVEL_INTEGRITY
+ return self._test_auth_signing_auth_level_request(dcerpc.DCERPC_AUTH_TYPE_SPNEGO,
+ dcerpc.DCERPC_AUTH_LEVEL_PACKET,
+ hdr_sign=True)
+
+ def test_spnego_signing_integrity(self):
+ return self._test_auth_signing_auth_level_request(dcerpc.DCERPC_AUTH_TYPE_SPNEGO,
+ dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY)
+
+ def test_spnego_hdr_signing_integrity(self):
+ return self._test_auth_signing_auth_level_request(dcerpc.DCERPC_AUTH_TYPE_SPNEGO,
+ dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY,
+ hdr_sign=True)
+
+ def test_ntlm_signing_packet(self):
+ # DCERPC_AUTH_LEVEL_PACKET is handled as alias of
+ # DCERPC_AUTH_LEVEL_INTEGRITY
+ return self._test_auth_signing_auth_level_request(dcerpc.DCERPC_AUTH_TYPE_NTLMSSP,
+ dcerpc.DCERPC_AUTH_LEVEL_PACKET)
+
+ def test_ntlm_hdr_signing_packet(self):
+ # DCERPC_AUTH_LEVEL_PACKET is handled as alias of
+ # DCERPC_AUTH_LEVEL_INTEGRITY
+ return self._test_auth_signing_auth_level_request(dcerpc.DCERPC_AUTH_TYPE_NTLMSSP,
+ dcerpc.DCERPC_AUTH_LEVEL_PACKET,
+ hdr_sign=True)
+
+ def test_ntlm_signing_integrity(self):
+ return self._test_auth_signing_auth_level_request(dcerpc.DCERPC_AUTH_TYPE_NTLMSSP,
+ dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY)
+
+ def test_ntlm_hdr_signing_integrity(self):
+ return self._test_auth_signing_auth_level_request(dcerpc.DCERPC_AUTH_TYPE_NTLMSSP,
+ dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY,
+ hdr_sign=True)
+
+ def test_krb5_signing_packet(self):
+ # DCERPC_AUTH_LEVEL_PACKET is handled as alias of
+ # DCERPC_AUTH_LEVEL_INTEGRITY
+ return self._test_auth_signing_auth_level_request(dcerpc.DCERPC_AUTH_TYPE_KRB5,
+ dcerpc.DCERPC_AUTH_LEVEL_PACKET)
+
+ def test_krb5_hdr_signing_packet(self):
+ # DCERPC_AUTH_LEVEL_PACKET is handled as alias of
+ # DCERPC_AUTH_LEVEL_INTEGRITY
+ return self._test_auth_signing_auth_level_request(dcerpc.DCERPC_AUTH_TYPE_KRB5,
+ dcerpc.DCERPC_AUTH_LEVEL_PACKET,
+ hdr_sign=True)
+
+ def test_krb5_signing_integrity(self):
+ return self._test_auth_signing_auth_level_request(dcerpc.DCERPC_AUTH_TYPE_KRB5,
+ dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY)
+
+ def test_krb5_hdr_signing_integrity(self):
+ return self._test_auth_signing_auth_level_request(dcerpc.DCERPC_AUTH_TYPE_KRB5,
+ dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY,
+ hdr_sign=True)
+
+ def test_assoc_group_fail1(self):
+ abstract = samba.dcerpc.mgmt.abstract_syntax()
+ transfer = base.transfer_syntax_ndr()
+
+ tsf1_list = [transfer]
+ ctx = samba.dcerpc.dcerpc.ctx_list()
+ ctx.context_id = 1
+ ctx.num_transfer_syntaxes = len(tsf1_list)
+ ctx.abstract_syntax = abstract
+ ctx.transfer_syntaxes = tsf1_list
+
+ ack = self.do_generic_bind(ctx=ctx, assoc_group_id=1,
+ nak_reason=dcerpc.DCERPC_BIND_NAK_REASON_NOT_SPECIFIED)
+ return
+
+ def test_assoc_group_fail2(self):
+ abstract = samba.dcerpc.mgmt.abstract_syntax()
+ transfer = base.transfer_syntax_ndr()
+
+ tsf1_list = [transfer]
+ ctx = samba.dcerpc.dcerpc.ctx_list()
+ ctx.context_id = 1
+ ctx.num_transfer_syntaxes = len(tsf1_list)
+ ctx.abstract_syntax = abstract
+ ctx.transfer_syntaxes = tsf1_list
+
+ ack = self.do_generic_bind(ctx=ctx)
+
+ self._disconnect("test_assoc_group_fail2")
+ self.assertNotConnected()
+ time.sleep(0.5)
+ self.connect()
+
+ ack2 = self.do_generic_bind(ctx=ctx, assoc_group_id=ack.u.assoc_group_id,
+ nak_reason=dcerpc.DCERPC_BIND_NAK_REASON_NOT_SPECIFIED)
+ return
+
+ def test_assoc_group_diff1(self):
+ abstract = samba.dcerpc.mgmt.abstract_syntax()
+ transfer = base.transfer_syntax_ndr()
+
+ (ctx1, ack1) = self.prepare_presentation(abstract, transfer,
+ context_id=1, return_ack=True)
+
+ conn2 = self.second_connection()
+ (ctx2, ack2) = conn2.prepare_presentation(abstract, transfer,
+ context_id=2, return_ack=True)
+ self.assertNotEqual(ack2.u.assoc_group_id, ack1.u.assoc_group_id)
+
+ conn2._disconnect("End of Test")
+ return
+
+ def test_assoc_group_ok1(self):
+ abstract = samba.dcerpc.mgmt.abstract_syntax()
+ transfer = base.transfer_syntax_ndr()
+
+ (ctx1, ack1) = self.prepare_presentation(abstract, transfer,
+ context_id=1, return_ack=True)
+
+ conn2 = self.second_connection()
+ (ctx2, ack2) = conn2.prepare_presentation(abstract, transfer,
+ assoc_group_id=ack1.u.assoc_group_id,
+ context_id=2, return_ack=True)
+
+ inq_if_ids = samba.dcerpc.mgmt.inq_if_ids()
+ self.do_single_request(call_id=1, ctx=ctx1, io=inq_if_ids)
+ conn2.do_single_request(call_id=1, ctx=ctx2, io=inq_if_ids)
+
+ conn2.do_single_request(call_id=1, ctx=ctx1, io=inq_if_ids,
+ fault_pfc_flags=(
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST |
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE),
+ fault_status=dcerpc.DCERPC_NCA_S_UNKNOWN_IF,
+ fault_context_id=0)
+
+ self.do_single_request(call_id=1, ctx=ctx1, io=inq_if_ids)
+ conn2.do_single_request(call_id=1, ctx=ctx2, io=inq_if_ids)
+ conn2._disconnect("End of Test")
+ return
+
+ def test_assoc_group_ok2(self):
+ abstract = samba.dcerpc.mgmt.abstract_syntax()
+ transfer = base.transfer_syntax_ndr()
+
+ self.reconnect_smb_pipe(primary_address='\\pipe\\lsarpc',
+ secondary_address='\\pipe\\lsass',
+ transport_creds=self.get_user_creds())
+ (ctx1, ack1) = self.prepare_presentation(abstract, transfer,
+ context_id=1, return_ack=True)
+
+ conn2 = self.second_connection()
+ (ctx2, ack2) = conn2.prepare_presentation(abstract, transfer,
+ assoc_group_id=ack1.u.assoc_group_id,
+ context_id=2, return_ack=True)
+
+ inq_if_ids = samba.dcerpc.mgmt.inq_if_ids()
+ self.do_single_request(call_id=1, ctx=ctx1, io=inq_if_ids)
+ conn2.do_single_request(call_id=1, ctx=ctx2, io=inq_if_ids)
+
+ conn2.do_single_request(call_id=1, ctx=ctx1, io=inq_if_ids,
+ fault_pfc_flags=(
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST |
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE),
+ fault_status=dcerpc.DCERPC_NCA_S_UNKNOWN_IF,
+ fault_context_id=0)
+
+ self.do_single_request(call_id=1, ctx=ctx1, io=inq_if_ids)
+ conn2.do_single_request(call_id=1, ctx=ctx2, io=inq_if_ids)
+ conn2._disconnect("End of Test")
+ return
+
+ def test_assoc_group_fail3(self):
+ abstract = samba.dcerpc.mgmt.abstract_syntax()
+ transfer = base.transfer_syntax_ndr()
+
+ (ctx1, ack1) = self.prepare_presentation(abstract, transfer,
+ context_id=1, return_ack=True)
+
+ # assoc groups are per transport
+ connF = self.second_connection(primary_address="\\pipe\\lsarpc",
+ secondary_address="\\pipe\\lsass",
+ transport_creds=self.get_user_creds())
+ tsfF_list = [transfer]
+ ctxF = samba.dcerpc.dcerpc.ctx_list()
+ ctxF.context_id = 0xF
+ ctxF.num_transfer_syntaxes = len(tsfF_list)
+ ctxF.abstract_syntax = abstract
+ ctxF.transfer_syntaxes = tsfF_list
+ ack = connF.do_generic_bind(ctx=ctxF, assoc_group_id=ack1.u.assoc_group_id,
+ nak_reason=dcerpc.DCERPC_BIND_NAK_REASON_NOT_SPECIFIED)
+ # wait for a disconnect
+ rep = connF.recv_pdu()
+ self.assertIsNone(rep)
+ connF.assertNotConnected()
+
+ conn2 = self.second_connection()
+ (ctx2, ack2) = conn2.prepare_presentation(abstract, transfer,
+ assoc_group_id=ack1.u.assoc_group_id,
+ context_id=2, return_ack=True)
+
+ inq_if_ids = samba.dcerpc.mgmt.inq_if_ids()
+ self.do_single_request(call_id=1, ctx=ctx1, io=inq_if_ids)
+ conn2.do_single_request(call_id=1, ctx=ctx2, io=inq_if_ids)
+
+ conn2.do_single_request(call_id=1, ctx=ctx1, io=inq_if_ids,
+ fault_pfc_flags=(
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST |
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE),
+ fault_status=dcerpc.DCERPC_NCA_S_UNKNOWN_IF,
+ fault_context_id=0)
+
+ self.do_single_request(call_id=1, ctx=ctx1, io=inq_if_ids)
+ conn2.do_single_request(call_id=1, ctx=ctx2, io=inq_if_ids)
+ conn2._disconnect("End of Test")
+ return
+
+ def _test_krb5_hdr_sign_delayed1(self, do_upgrade):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_KRB5
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY
+ auth_context_id = 1
+
+ creds = self.get_user_creds()
+
+ abstract = samba.dcerpc.mgmt.abstract_syntax()
+ transfer = base.transfer_syntax_ndr()
+
+ tsf1_list = [transfer]
+ ctx = samba.dcerpc.dcerpc.ctx_list()
+ ctx.context_id = 1
+ ctx.num_transfer_syntaxes = len(tsf1_list)
+ ctx.abstract_syntax = abstract
+ ctx.transfer_syntaxes = tsf1_list
+
+ auth_context = self.get_auth_context_creds(creds=creds,
+ auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ hdr_signing=False)
+
+ ack = self.do_generic_bind(call_id=1,
+ ctx=ctx,
+ auth_context=auth_context)
+
+ inq_if_ids = samba.dcerpc.mgmt.inq_if_ids()
+ self.do_single_request(call_id=2, ctx=ctx, io=inq_if_ids,
+ auth_context=auth_context)
+
+ #
+ # This is just an alter context without authentication
+ # But it can turn on header signing for the whole connection
+ #
+ ack2 = self.do_generic_bind(call_id=3, ctx=ctx,
+ pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST |
+ dcerpc.DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN,
+ assoc_group_id = ack.u.assoc_group_id,
+ start_with_alter=True)
+
+ self.assertFalse(auth_context['hdr_signing'])
+ if do_upgrade:
+ auth_context['hdr_signing'] = True
+ auth_context["gensec"].want_feature(gensec.FEATURE_SIGN_PKT_HEADER)
+ fault_status=None
+ else:
+ fault_status=dcerpc.DCERPC_FAULT_SEC_PKG_ERROR
+
+ self.do_single_request(call_id=4, ctx=ctx, io=inq_if_ids,
+ auth_context=auth_context,
+ fault_status=fault_status)
+
+ if fault_status is not None:
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+ return
+
+ self.do_single_request(call_id=5, ctx=ctx, io=inq_if_ids,
+ auth_context=auth_context)
+ return
+
+ def test_krb5_hdr_sign_delayed1_ok1(self):
+ return self._test_krb5_hdr_sign_delayed1(do_upgrade=True)
+
+ def test_krb5_hdr_sign_delayed1_fail1(self):
+ return self._test_krb5_hdr_sign_delayed1(do_upgrade=False)
+
+ def _test_krb5_hdr_sign_delayed2(self, do_upgrade):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_KRB5
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY
+ auth_context_id = 1
+
+ creds = self.get_user_creds()
+
+ abstract = samba.dcerpc.mgmt.abstract_syntax()
+ transfer = base.transfer_syntax_ndr()
+
+ tsf1_list = [transfer]
+ ctx = samba.dcerpc.dcerpc.ctx_list()
+ ctx.context_id = 1
+ ctx.num_transfer_syntaxes = len(tsf1_list)
+ ctx.abstract_syntax = abstract
+ ctx.transfer_syntaxes = tsf1_list
+
+ auth_context = self.get_auth_context_creds(creds=creds,
+ auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ hdr_signing=False)
+
+ #
+ # SUPPORT_HEADER_SIGN on alter context activates header signing
+ #
+ ack = self.do_generic_bind(call_id=1,
+ ctx=ctx,
+ auth_context=auth_context,
+ pfc_flags_2nd=dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST |
+ dcerpc.DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)
+
+ self.assertFalse(auth_context['hdr_signing'])
+ if do_upgrade:
+ auth_context['hdr_signing'] = True
+ auth_context["gensec"].want_feature(gensec.FEATURE_SIGN_PKT_HEADER)
+ fault_status=None
+ else:
+ fault_status=dcerpc.DCERPC_FAULT_SEC_PKG_ERROR
+
+ inq_if_ids = samba.dcerpc.mgmt.inq_if_ids()
+ self.do_single_request(call_id=4, ctx=ctx, io=inq_if_ids,
+ auth_context=auth_context,
+ fault_status=fault_status)
+
+ if fault_status is not None:
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+ return
+
+ self.do_single_request(call_id=5, ctx=ctx, io=inq_if_ids,
+ auth_context=auth_context)
+ return
+
+ def test_krb5_hdr_sign_delayed2_ok1(self):
+ return self._test_krb5_hdr_sign_delayed2(do_upgrade=True)
+
+ def test_krb5_hdr_sign_delayed2_fail1(self):
+ return self._test_krb5_hdr_sign_delayed2(do_upgrade=False)
+
+ def test_krb5_hdr_sign_delayed3_fail1(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_KRB5
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY
+ auth_context_id = 1
+
+ creds = self.get_user_creds()
+
+ abstract = samba.dcerpc.mgmt.abstract_syntax()
+ transfer = base.transfer_syntax_ndr()
+
+ tsf1_list = [transfer]
+ ctx = samba.dcerpc.dcerpc.ctx_list()
+ ctx.context_id = 1
+ ctx.num_transfer_syntaxes = len(tsf1_list)
+ ctx.abstract_syntax = abstract
+ ctx.transfer_syntaxes = tsf1_list
+
+ auth_context = self.get_auth_context_creds(creds=creds,
+ auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ hdr_signing=False)
+
+ #
+ # SUPPORT_HEADER_SIGN on auth3 doesn't activate header signing
+ #
+ ack = self.do_generic_bind(call_id=1,
+ ctx=ctx,
+ auth_context=auth_context,
+ pfc_flags_2nd=dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST |
+ dcerpc.DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN,
+ use_auth3=True)
+
+ inq_if_ids = samba.dcerpc.mgmt.inq_if_ids()
+ self.do_single_request(call_id=2, ctx=ctx, io=inq_if_ids,
+ auth_context=auth_context)
+
+ self.assertFalse(auth_context['hdr_signing'])
+ auth_context['hdr_signing'] = True
+ auth_context["gensec"].want_feature(gensec.FEATURE_SIGN_PKT_HEADER)
+ fault_status=dcerpc.DCERPC_FAULT_SEC_PKG_ERROR
+
+ self.do_single_request(call_id=4, ctx=ctx, io=inq_if_ids,
+ auth_context=auth_context,
+ fault_status=fault_status)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+ return
+
+ def _test_lsa_multi_auth_connect1(self, smb_creds,
+ account_name0, authority_name0):
+ creds1 = self.get_anon_creds()
+ account_name1 = "ANONYMOUS LOGON"
+ authority_name1 = "NT AUTHORITY"
+ auth_type1 = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ auth_level1 = dcerpc.DCERPC_AUTH_LEVEL_CONNECT
+ auth_context_id1 = 1
+
+ creds2 = self.get_user_creds()
+ account_name2 = creds2.get_username()
+ authority_name2 = creds2.get_domain()
+ auth_type2 = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ auth_level2 = dcerpc.DCERPC_AUTH_LEVEL_CONNECT
+ auth_context_id2 = 2
+
+ abstract = samba.dcerpc.lsa.abstract_syntax()
+ transfer = base.transfer_syntax_ndr()
+
+ self.reconnect_smb_pipe(primary_address='\\pipe\\lsarpc',
+ secondary_address='\\pipe\\lsass',
+ transport_creds=smb_creds)
+ self.assertIsConnected()
+
+ tsf1_list = [transfer]
+ ctx1 = samba.dcerpc.dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = abstract
+ ctx1.transfer_syntaxes = tsf1_list
+
+ auth_context1 = self.get_auth_context_creds(creds=creds1,
+ auth_type=auth_type1,
+ auth_level=auth_level1,
+ auth_context_id=auth_context_id1,
+ hdr_signing=False)
+ auth_context2 = self.get_auth_context_creds(creds=creds2,
+ auth_type=auth_type2,
+ auth_level=auth_level2,
+ auth_context_id=auth_context_id2,
+ hdr_signing=False)
+
+ get_user_name = samba.dcerpc.lsa.GetUserName()
+ get_user_name.in_system_name = self.target_hostname
+ get_user_name.in_account_name = None
+ get_user_name.in_authority_name = base.ndr_pointer(None)
+
+ ack1 = self.do_generic_bind(call_id=0,
+ ctx=ctx1,
+ auth_context=auth_context1)
+
+ #
+ # With just one explicit auth context and that
+ # uses AUTH_LEVEL_CONNECT context.
+ #
+ # We always get that by default instead of the one default one
+ # inherited from the transport
+ #
+ self.do_single_request(call_id=1, ctx=ctx1, io=get_user_name)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name1)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name1)
+
+ self.do_single_request(call_id=2, ctx=ctx1, io=get_user_name,
+ auth_context=auth_context1)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name1)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name1)
+
+ ack2 = self.do_generic_bind(call_id=3,
+ ctx=ctx1,
+ auth_context=auth_context2,
+ assoc_group_id = ack1.u.assoc_group_id,
+ start_with_alter=True)
+
+ #
+ # Now we have two explicit auth contexts
+ #
+ # If we don't specify one of them we get the default one
+ # inherited from the transport
+ #
+ self.do_single_request(call_id=4, ctx=ctx1, io=get_user_name)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name0)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name0)
+
+ self.do_single_request(call_id=5, ctx=ctx1, io=get_user_name,
+ auth_context=auth_context1)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name1)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name1)
+
+ self.do_single_request(call_id=6, ctx=ctx1, io=get_user_name,
+ auth_context=auth_context2)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name2)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name2)
+
+ self.do_single_request(call_id=7, ctx=ctx1, io=get_user_name)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name0)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name0)
+
+ return
+
+ def test_lsa_multi_auth_connect1u(self):
+ smb_auth_creds = self.get_user_creds()
+ account_name0 = smb_auth_creds.get_username()
+ authority_name0 = smb_auth_creds.get_domain()
+ return self._test_lsa_multi_auth_connect1(smb_auth_creds,
+ account_name0,
+ authority_name0)
+
+ def test_lsa_multi_auth_connect1a(self):
+ smb_auth_creds = self.get_anon_creds()
+ account_name0 = "ANONYMOUS LOGON"
+ authority_name0 = "NT AUTHORITY"
+ return self._test_lsa_multi_auth_connect1(smb_auth_creds,
+ account_name0,
+ authority_name0)
+
+ def _test_lsa_multi_auth_connect2(self, smb_creds,
+ account_name0, authority_name0):
+ creds1 = self.get_anon_creds()
+ account_name1 = "ANONYMOUS LOGON"
+ authority_name1 = "NT AUTHORITY"
+ auth_type1 = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ auth_level1 = dcerpc.DCERPC_AUTH_LEVEL_CONNECT
+ auth_context_id1 = 1
+
+ creds2 = self.get_user_creds()
+ account_name2 = creds2.get_username()
+ authority_name2 = creds2.get_domain()
+ auth_type2 = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ auth_level2 = dcerpc.DCERPC_AUTH_LEVEL_CONNECT
+ auth_context_id2 = 2
+
+ abstract = samba.dcerpc.lsa.abstract_syntax()
+ transfer = base.transfer_syntax_ndr()
+
+ self.reconnect_smb_pipe(primary_address='\\pipe\\lsarpc',
+ secondary_address='\\pipe\\lsass',
+ transport_creds=smb_creds)
+ self.assertIsConnected()
+
+ tsf1_list = [transfer]
+ ctx1 = samba.dcerpc.dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = abstract
+ ctx1.transfer_syntaxes = tsf1_list
+
+ auth_context1 = self.get_auth_context_creds(creds=creds1,
+ auth_type=auth_type1,
+ auth_level=auth_level1,
+ auth_context_id=auth_context_id1,
+ hdr_signing=False)
+ auth_context2 = self.get_auth_context_creds(creds=creds2,
+ auth_type=auth_type2,
+ auth_level=auth_level2,
+ auth_context_id=auth_context_id2,
+ hdr_signing=False)
+
+ get_user_name = samba.dcerpc.lsa.GetUserName()
+ get_user_name.in_system_name = self.target_hostname
+ get_user_name.in_account_name = None
+ get_user_name.in_authority_name = base.ndr_pointer(None)
+
+ ack0 = self.do_generic_bind(call_id=0, ctx=ctx1)
+
+ #
+ # We use the default auth context
+ # inherited from the transport
+ #
+ self.do_single_request(call_id=1, ctx=ctx1, io=get_user_name)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name0)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name0)
+
+ ack1 = self.do_generic_bind(call_id=2,
+ ctx=ctx1,
+ auth_context=auth_context1,
+ assoc_group_id = ack0.u.assoc_group_id,
+ start_with_alter=True)
+
+ #
+ # With just one explicit auth context and that
+ # uses AUTH_LEVEL_CONNECT context.
+ #
+ # We always get that by default instead of the one default one
+ # inherited from the transport
+ #
+ self.do_single_request(call_id=3, ctx=ctx1, io=get_user_name)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name1)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name1)
+
+ self.do_single_request(call_id=4, ctx=ctx1, io=get_user_name,
+ auth_context=auth_context1)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name1)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name1)
+
+ ack2 = self.do_generic_bind(call_id=5,
+ ctx=ctx1,
+ auth_context=auth_context2,
+ assoc_group_id = ack0.u.assoc_group_id,
+ start_with_alter=True)
+
+ #
+ # Now we have two explicit auth contexts
+ #
+ # If we don't specify one of them we get the default one
+ # inherited from the transport (again)
+ #
+ self.do_single_request(call_id=6, ctx=ctx1, io=get_user_name)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name0)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name0)
+
+ self.do_single_request(call_id=7, ctx=ctx1, io=get_user_name,
+ auth_context=auth_context1)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name1)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name1)
+
+ self.do_single_request(call_id=8, ctx=ctx1, io=get_user_name,
+ auth_context=auth_context2)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name2)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name2)
+
+ self.do_single_request(call_id=9, ctx=ctx1, io=get_user_name)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name0)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name0)
+
+ return
+
+ def test_lsa_multi_auth_connect2u(self):
+ smb_auth_creds = self.get_user_creds()
+ account_name0 = smb_auth_creds.get_username()
+ authority_name0 = smb_auth_creds.get_domain()
+ return self._test_lsa_multi_auth_connect2(smb_auth_creds,
+ account_name0,
+ authority_name0)
+
+ def test_lsa_multi_auth_connect2a(self):
+ smb_auth_creds = self.get_anon_creds()
+ account_name0 = "ANONYMOUS LOGON"
+ authority_name0 = "NT AUTHORITY"
+ return self._test_lsa_multi_auth_connect2(smb_auth_creds,
+ account_name0,
+ authority_name0)
+
+ def _test_lsa_multi_auth_connect3(self, smb_creds,
+ account_name0, authority_name0):
+ creds1 = self.get_anon_creds()
+ account_name1 = "ANONYMOUS LOGON"
+ authority_name1 = "NT AUTHORITY"
+ auth_type1 = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ auth_level1 = dcerpc.DCERPC_AUTH_LEVEL_CONNECT
+ auth_context_id1 = 1
+
+ creds2 = self.get_user_creds()
+ account_name2 = creds2.get_username()
+ authority_name2 = creds2.get_domain()
+ auth_type2 = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ auth_level2 = dcerpc.DCERPC_AUTH_LEVEL_CONNECT
+ auth_context_id2 = 2
+
+ abstract = samba.dcerpc.lsa.abstract_syntax()
+ transfer = base.transfer_syntax_ndr()
+
+ self.reconnect_smb_pipe(primary_address='\\pipe\\lsarpc',
+ secondary_address='\\pipe\\lsass',
+ transport_creds=smb_creds)
+ self.assertIsConnected()
+
+ tsf1_list = [transfer]
+ ctx1 = samba.dcerpc.dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = abstract
+ ctx1.transfer_syntaxes = tsf1_list
+
+ auth_context1 = self.get_auth_context_creds(creds=creds1,
+ auth_type=auth_type1,
+ auth_level=auth_level1,
+ auth_context_id=auth_context_id1,
+ hdr_signing=False)
+ auth_context2 = self.get_auth_context_creds(creds=creds2,
+ auth_type=auth_type2,
+ auth_level=auth_level2,
+ auth_context_id=auth_context_id2,
+ hdr_signing=False)
+
+ get_user_name = samba.dcerpc.lsa.GetUserName()
+ get_user_name.in_system_name = self.target_hostname
+ get_user_name.in_account_name = None
+ get_user_name.in_authority_name = base.ndr_pointer(None)
+
+ ack0 = self.do_generic_bind(call_id=0, ctx=ctx1)
+
+ #
+ # We use the default auth context
+ # inherited from the transport
+ #
+ self.do_single_request(call_id=1, ctx=ctx1, io=get_user_name)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name0)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name0)
+
+ ack1 = self.do_generic_bind(call_id=2,
+ ctx=ctx1,
+ auth_context=auth_context1,
+ assoc_group_id = ack0.u.assoc_group_id,
+ start_with_alter=True)
+
+ #
+ # With just one explicit auth context and that
+ # uses AUTH_LEVEL_CONNECT context.
+ #
+ # We always get that by default instead of the one default one
+ # inherited from the transport
+ #
+ # Until an explicit usage resets that mode
+ #
+ self.do_single_request(call_id=3, ctx=ctx1, io=get_user_name)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name1)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name1)
+
+ self.do_single_request(call_id=4, ctx=ctx1, io=get_user_name)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name1)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name1)
+
+ self.do_single_request(call_id=5, ctx=ctx1, io=get_user_name,
+ auth_context=auth_context1)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name1)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name1)
+
+ self.do_single_request(call_id=6, ctx=ctx1, io=get_user_name)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name0)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name0)
+
+ ack2 = self.do_generic_bind(call_id=7,
+ ctx=ctx1,
+ auth_context=auth_context2,
+ assoc_group_id = ack0.u.assoc_group_id,
+ start_with_alter=True)
+ #
+ # A new auth context won't change that mode again.
+ #
+ self.do_single_request(call_id=8, ctx=ctx1, io=get_user_name)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name0)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name0)
+
+ self.do_single_request(call_id=9, ctx=ctx1, io=get_user_name,
+ auth_context=auth_context1)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name1)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name1)
+
+ self.do_single_request(call_id=10, ctx=ctx1, io=get_user_name,
+ auth_context=auth_context2)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name2)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name2)
+
+ self.do_single_request(call_id=11, ctx=ctx1, io=get_user_name)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name0)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name0)
+
+ return
+
+ def test_lsa_multi_auth_connect3u(self):
+ smb_auth_creds = self.get_user_creds()
+ account_name0 = smb_auth_creds.get_username()
+ authority_name0 = smb_auth_creds.get_domain()
+ return self._test_lsa_multi_auth_connect3(smb_auth_creds,
+ account_name0,
+ authority_name0)
+
+ def test_lsa_multi_auth_connect3a(self):
+ smb_auth_creds = self.get_anon_creds()
+ account_name0 = "ANONYMOUS LOGON"
+ authority_name0 = "NT AUTHORITY"
+ return self._test_lsa_multi_auth_connect3(smb_auth_creds,
+ account_name0,
+ authority_name0)
+
+ def _test_lsa_multi_auth_connect4(self, smb_creds,
+ account_name0, authority_name0):
+ creds1 = self.get_anon_creds()
+ account_name1 = "ANONYMOUS LOGON"
+ authority_name1 = "NT AUTHORITY"
+ auth_type1 = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ auth_level1 = dcerpc.DCERPC_AUTH_LEVEL_CONNECT
+ auth_context_id1 = 1
+
+ creds2 = self.get_user_creds()
+ account_name2 = creds2.get_username()
+ authority_name2 = creds2.get_domain()
+ auth_type2 = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ auth_level2 = dcerpc.DCERPC_AUTH_LEVEL_CONNECT
+ auth_context_id2 = 2
+
+ creds3 = self.get_anon_creds()
+ account_name3 = "ANONYMOUS LOGON"
+ authority_name3 = "NT AUTHORITY"
+ auth_type3 = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ auth_level3 = dcerpc.DCERPC_AUTH_LEVEL_CONNECT
+ auth_context_id3 = 3
+
+ creds4 = self.get_user_creds()
+ account_name4 = creds4.get_username()
+ authority_name4 = creds4.get_domain()
+ auth_type4 = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ auth_level4 = dcerpc.DCERPC_AUTH_LEVEL_CONNECT
+ auth_context_id4 = 4
+
+ abstract = samba.dcerpc.lsa.abstract_syntax()
+ transfer = base.transfer_syntax_ndr()
+
+ self.reconnect_smb_pipe(primary_address='\\pipe\\lsarpc',
+ secondary_address='\\pipe\\lsass',
+ transport_creds=smb_creds)
+ self.assertIsConnected()
+
+ tsf1_list = [transfer]
+ ctx1 = samba.dcerpc.dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = abstract
+ ctx1.transfer_syntaxes = tsf1_list
+
+ auth_context1 = self.get_auth_context_creds(creds=creds1,
+ auth_type=auth_type1,
+ auth_level=auth_level1,
+ auth_context_id=auth_context_id1,
+ hdr_signing=False)
+ auth_context2 = self.get_auth_context_creds(creds=creds2,
+ auth_type=auth_type2,
+ auth_level=auth_level2,
+ auth_context_id=auth_context_id2,
+ hdr_signing=False)
+ auth_context3 = self.get_auth_context_creds(creds=creds3,
+ auth_type=auth_type3,
+ auth_level=auth_level3,
+ auth_context_id=auth_context_id3,
+ hdr_signing=False)
+ auth_context4 = self.get_auth_context_creds(creds=creds4,
+ auth_type=auth_type4,
+ auth_level=auth_level4,
+ auth_context_id=auth_context_id4,
+ hdr_signing=False)
+
+ get_user_name = samba.dcerpc.lsa.GetUserName()
+ get_user_name.in_system_name = self.target_hostname
+ get_user_name.in_account_name = None
+ get_user_name.in_authority_name = base.ndr_pointer(None)
+
+ ack0 = self.do_generic_bind(call_id=0, ctx=ctx1)
+
+ #
+ # We use the default auth context
+ # inherited from the transport
+ #
+ self.do_single_request(call_id=1, ctx=ctx1, io=get_user_name)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name0)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name0)
+
+ ack1 = self.do_generic_bind(call_id=2,
+ ctx=ctx1,
+ auth_context=auth_context1,
+ assoc_group_id = ack0.u.assoc_group_id,
+ start_with_alter=True)
+
+ #
+ # With just one explicit auth context and that
+ # uses AUTH_LEVEL_CONNECT context.
+ #
+ # We always get that by default instead of the one default one
+ # inherited from the transport
+ #
+ # Until a new explicit context resets the mode
+ #
+ self.do_single_request(call_id=3, ctx=ctx1, io=get_user_name)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name1)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name1)
+
+ self.do_single_request(call_id=4, ctx=ctx1, io=get_user_name)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name1)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name1)
+
+ ack2 = self.do_generic_bind(call_id=5,
+ ctx=ctx1,
+ auth_context=auth_context2,
+ assoc_group_id = ack0.u.assoc_group_id,
+ start_with_alter=True)
+
+ #
+ # A new auth context with LEVEL_CONNECT resets the default.
+ #
+ self.do_single_request(call_id=6, ctx=ctx1, io=get_user_name)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name2)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name2)
+
+ self.do_single_request(call_id=7, ctx=ctx1, io=get_user_name)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name2)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name2)
+
+ ack3 = self.do_generic_bind(call_id=8,
+ ctx=ctx1,
+ auth_context=auth_context3,
+ assoc_group_id = ack0.u.assoc_group_id,
+ start_with_alter=True)
+
+ #
+ # A new auth context with LEVEL_CONNECT resets the default.
+ #
+ self.do_single_request(call_id=9, ctx=ctx1, io=get_user_name)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name3)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name3)
+
+ self.do_single_request(call_id=10, ctx=ctx1, io=get_user_name)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name3)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name3)
+
+ ack4 = self.do_generic_bind(call_id=11,
+ ctx=ctx1,
+ auth_context=auth_context4,
+ assoc_group_id = ack0.u.assoc_group_id,
+ start_with_alter=True)
+
+ #
+ # A new auth context with LEVEL_CONNECT resets the default.
+ #
+ self.do_single_request(call_id=12, ctx=ctx1, io=get_user_name)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name4)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name4)
+
+ self.do_single_request(call_id=13, ctx=ctx1, io=get_user_name)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name4)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name4)
+
+ #
+ # Only the explicit usage of any context reset that mode
+ #
+ self.do_single_request(call_id=14, ctx=ctx1, io=get_user_name,
+ auth_context=auth_context1)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name1)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name1)
+
+ self.do_single_request(call_id=15, ctx=ctx1, io=get_user_name)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name0)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name0)
+
+ self.do_single_request(call_id=16, ctx=ctx1, io=get_user_name,
+ auth_context=auth_context1)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name1)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name1)
+
+ self.do_single_request(call_id=17, ctx=ctx1, io=get_user_name,
+ auth_context=auth_context2)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name2)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name2)
+
+ self.do_single_request(call_id=18, ctx=ctx1, io=get_user_name,
+ auth_context=auth_context3)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name3)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name3)
+
+ self.do_single_request(call_id=19, ctx=ctx1, io=get_user_name,
+ auth_context=auth_context4)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name4)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name4)
+
+ self.do_single_request(call_id=20, ctx=ctx1, io=get_user_name)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name0)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name0)
+
+ return
+
+ def test_lsa_multi_auth_connect4u(self):
+ smb_auth_creds = self.get_user_creds()
+ account_name0 = smb_auth_creds.get_username()
+ authority_name0 = smb_auth_creds.get_domain()
+ return self._test_lsa_multi_auth_connect4(smb_auth_creds,
+ account_name0,
+ authority_name0)
+
+ def test_lsa_multi_auth_connect4a(self):
+ smb_auth_creds = self.get_anon_creds()
+ account_name0 = "ANONYMOUS LOGON"
+ authority_name0 = "NT AUTHORITY"
+ return self._test_lsa_multi_auth_connect4(smb_auth_creds,
+ account_name0,
+ authority_name0)
+
+ def _test_lsa_multi_auth_sign_connect1(self, smb_creds,
+ account_name0, authority_name0):
+
+ creds1 = self.get_user_creds()
+ account_name1 = creds1.get_username()
+ authority_name1 = creds1.get_domain()
+ auth_type1 = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ auth_level1 = dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY
+ auth_context_id1 = 1
+
+ creds2 = self.get_user_creds()
+ account_name2 = creds2.get_username()
+ authority_name2 = creds2.get_domain()
+ auth_type2 = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ auth_level2 = dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY
+ auth_context_id2 = 2
+
+ creds3 = self.get_anon_creds()
+ account_name3 = "ANONYMOUS LOGON"
+ authority_name3 = "NT AUTHORITY"
+ auth_type3 = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ auth_level3 = dcerpc.DCERPC_AUTH_LEVEL_CONNECT
+ auth_context_id3 = 3
+
+ abstract = samba.dcerpc.lsa.abstract_syntax()
+ transfer = base.transfer_syntax_ndr()
+
+ self.reconnect_smb_pipe(primary_address='\\pipe\\lsarpc',
+ secondary_address='\\pipe\\lsass',
+ transport_creds=smb_creds)
+ self.assertIsConnected()
+
+ tsf1_list = [transfer]
+ ctx1 = samba.dcerpc.dcerpc.ctx_list()
+ ctx1.context_id = 1
+ ctx1.num_transfer_syntaxes = len(tsf1_list)
+ ctx1.abstract_syntax = abstract
+ ctx1.transfer_syntaxes = tsf1_list
+
+ auth_context1 = self.get_auth_context_creds(creds=creds1,
+ auth_type=auth_type1,
+ auth_level=auth_level1,
+ auth_context_id=auth_context_id1,
+ hdr_signing=False)
+ auth_context2 = self.get_auth_context_creds(creds=creds2,
+ auth_type=auth_type2,
+ auth_level=auth_level2,
+ auth_context_id=auth_context_id2,
+ hdr_signing=False)
+ auth_context3 = self.get_auth_context_creds(creds=creds3,
+ auth_type=auth_type3,
+ auth_level=auth_level3,
+ auth_context_id=auth_context_id3,
+ hdr_signing=False)
+
+ get_user_name = samba.dcerpc.lsa.GetUserName()
+ get_user_name.in_system_name = self.target_hostname
+ get_user_name.in_account_name = None
+ get_user_name.in_authority_name = base.ndr_pointer(None)
+
+ ack1 = self.do_generic_bind(call_id=0,
+ ctx=ctx1,
+ auth_context=auth_context1)
+
+ #
+ # With just one explicit auth context and that
+ # *not* uses AUTH_LEVEL_CONNECT context.
+ #
+ # We don't get the by default (auth_context1)
+ #
+ self.do_single_request(call_id=1, ctx=ctx1, io=get_user_name)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name0)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name0)
+
+ self.do_single_request(call_id=2, ctx=ctx1, io=get_user_name,
+ auth_context=auth_context1)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name1)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name1)
+
+ self.do_single_request(call_id=3, ctx=ctx1, io=get_user_name)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name0)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name0)
+
+ ack2 = self.do_generic_bind(call_id=4,
+ ctx=ctx1,
+ auth_context=auth_context2,
+ assoc_group_id = ack1.u.assoc_group_id,
+ start_with_alter=True)
+
+ #
+ # With just two explicit auth context and
+ # *none* uses AUTH_LEVEL_CONNECT context.
+ #
+ # We don't get auth_context1 or auth_context2 by default
+ #
+ self.do_single_request(call_id=5, ctx=ctx1, io=get_user_name)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name0)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name0)
+
+ self.do_single_request(call_id=6, ctx=ctx1, io=get_user_name,
+ auth_context=auth_context1)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name1)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name1)
+
+ self.do_single_request(call_id=7, ctx=ctx1, io=get_user_name,
+ auth_context=auth_context2)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name2)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name2)
+
+ self.do_single_request(call_id=8, ctx=ctx1, io=get_user_name)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name0)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name0)
+
+ ack3 = self.do_generic_bind(call_id=9,
+ ctx=ctx1,
+ auth_context=auth_context3,
+ assoc_group_id = ack1.u.assoc_group_id,
+ start_with_alter=True)
+
+ #
+ # Now we have tree explicit auth contexts,
+ # but just one with AUTH_LEVEL_CONNECT
+ #
+ # If we don't specify one of them we get
+ # that one auth_level_connect context.
+ #
+ # Until an explicit usage of any auth context reset that mode.
+ #
+ self.do_single_request(call_id=10, ctx=ctx1, io=get_user_name)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name3)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name3)
+
+ self.do_single_request(call_id=11, ctx=ctx1, io=get_user_name)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name3)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name3)
+
+ self.do_single_request(call_id=12, ctx=ctx1, io=get_user_name,
+ auth_context=auth_context1)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name1)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name1)
+
+ self.do_single_request(call_id=13, ctx=ctx1, io=get_user_name)
+ self.assertEqual(get_user_name.result[0], NT_STATUS_SUCCESS)
+ self.assertEqualsStrLower(get_user_name.out_account_name, account_name0)
+ self.assertEqualsStrLower(get_user_name.out_authority_name.value, authority_name0)
+
+ return
+
+ def test_lsa_multi_auth_sign_connect1u(self):
+ smb_auth_creds = self.get_user_creds()
+ account_name0 = smb_auth_creds.get_username()
+ authority_name0 = smb_auth_creds.get_domain()
+ return self._test_lsa_multi_auth_sign_connect1(smb_auth_creds,
+ account_name0,
+ authority_name0)
+ def test_lsa_multi_auth_sign_connect1a(self):
+ smb_auth_creds = self.get_anon_creds()
+ account_name0 = "ANONYMOUS LOGON"
+ authority_name0 = "NT AUTHORITY"
+ return self._test_lsa_multi_auth_sign_connect1(smb_auth_creds,
+ account_name0,
+ authority_name0)
+
+ def test_spnego_multiple_auth_hdr_signing(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level1 = dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY
+ auth_context_id1=1
+ auth_level2 = dcerpc.DCERPC_AUTH_LEVEL_PACKET
+ auth_context_id2=2
+
+ creds = self.get_user_creds()
+
+ abstract = samba.dcerpc.mgmt.abstract_syntax()
+ transfer = base.transfer_syntax_ndr()
+
+ tsf1_list = [transfer]
+ ctx = samba.dcerpc.dcerpc.ctx_list()
+ ctx.context_id = 1
+ ctx.num_transfer_syntaxes = len(tsf1_list)
+ ctx.abstract_syntax = abstract
+ ctx.transfer_syntaxes = tsf1_list
+
+ auth_context1 = self.get_auth_context_creds(creds=creds,
+ auth_type=auth_type,
+ auth_level=auth_level1,
+ auth_context_id=auth_context_id1,
+ hdr_signing=False)
+ auth_context2 = self.get_auth_context_creds(creds=creds,
+ auth_type=auth_type,
+ auth_level=auth_level2,
+ auth_context_id=auth_context_id2,
+ hdr_signing=False)
+
+ ack0 = self.do_generic_bind(call_id=1, ctx=ctx)
+
+ ack1 = self.do_generic_bind(call_id=2,
+ ctx=ctx,
+ auth_context=auth_context1,
+ assoc_group_id = ack0.u.assoc_group_id,
+ start_with_alter=True)
+ ack2 = self.do_generic_bind(call_id=3,
+ ctx=ctx,
+ auth_context=auth_context2,
+ assoc_group_id = ack0.u.assoc_group_id,
+ start_with_alter=True)
+
+ inq_if_ids = samba.dcerpc.mgmt.inq_if_ids()
+ self.do_single_request(call_id=4, ctx=ctx, io=inq_if_ids)
+ self.do_single_request(call_id=5, ctx=ctx, io=inq_if_ids,
+ auth_context=auth_context1)
+ self.do_single_request(call_id=6, ctx=ctx, io=inq_if_ids,
+ auth_context=auth_context2)
+
+ ack3 = self.do_generic_bind(call_id=7, ctx=ctx,
+ pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST |
+ dcerpc.DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN,
+ assoc_group_id = ack0.u.assoc_group_id,
+ start_with_alter=True)
+
+ self.assertFalse(auth_context1['hdr_signing'])
+ auth_context1['hdr_signing'] = True
+ auth_context1["gensec"].want_feature(gensec.FEATURE_SIGN_PKT_HEADER)
+
+ self.do_single_request(call_id=8, ctx=ctx, io=inq_if_ids)
+ self.do_single_request(call_id=9, ctx=ctx, io=inq_if_ids,
+ auth_context=auth_context1)
+ self.do_single_request(call_id=10, ctx=ctx, io=inq_if_ids,
+ auth_context=auth_context2,
+ fault_status=dcerpc.DCERPC_FAULT_SEC_PKG_ERROR)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def test_multiple_auth_limit(self):
+ creds = self.get_user_creds()
+
+ abstract = samba.dcerpc.mgmt.abstract_syntax()
+ transfer = base.transfer_syntax_ndr()
+
+ tsf1_list = [transfer]
+ ctx = samba.dcerpc.dcerpc.ctx_list()
+ ctx.context_id = 1
+ ctx.num_transfer_syntaxes = len(tsf1_list)
+ ctx.abstract_syntax = abstract
+ ctx.transfer_syntaxes = tsf1_list
+
+ ack0 = self.do_generic_bind(call_id=0, ctx=ctx)
+
+ is_server_listening = samba.dcerpc.mgmt.is_server_listening()
+
+ max_num_auth_str = samba.tests.env_get_var_value('MAX_NUM_AUTH', allow_missing=True)
+ if max_num_auth_str is not None:
+ max_num_auth = int(max_num_auth_str)
+ else:
+ max_num_auth = 2049
+
+ for i in range(1, max_num_auth+2):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_SPNEGO
+ auth_level = dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY
+ auth_context_id = i
+
+ auth_context = self.get_auth_context_creds(creds=creds,
+ auth_type=auth_type,
+ auth_level=auth_level,
+ auth_context_id=auth_context_id,
+ hdr_signing=False)
+
+ alter_fault = None
+ if i > max_num_auth:
+ alter_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+
+ ack = self.do_generic_bind(call_id=auth_context_id,
+ ctx=ctx,
+ auth_context=auth_context,
+ assoc_group_id = ack0.u.assoc_group_id,
+ alter_fault=alter_fault,
+ start_with_alter=True,
+ )
+ if alter_fault is not None:
+ break
+
+
+ self.do_single_request(call_id=auth_context_id,
+ ctx=ctx, io=is_server_listening,
+ auth_context=auth_context)
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+ return
+
+
+if __name__ == "__main__":
+ global_ndr_print = True
+ global_hexdump = True
+ import unittest
+ unittest.main()
diff --git a/python/samba/tests/dcerpc/raw_testcase.py b/python/samba/tests/dcerpc/raw_testcase.py
new file mode 100644
index 0000000..743fa0f
--- /dev/null
+++ b/python/samba/tests/dcerpc/raw_testcase.py
@@ -0,0 +1,1177 @@
+# Unix SMB/CIFS implementation.
+# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2010
+# Copyright (C) Stefan Metzmacher 2014,2015
+#
+# 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/>.
+#
+
+import sys
+import socket
+import samba.dcerpc.dcerpc as dcerpc
+import samba.dcerpc.base
+import samba.dcerpc.epmapper
+import samba.dcerpc.security as security
+import samba.tests
+from samba import gensec
+from samba.credentials import Credentials
+from samba.tests import TestCase
+from samba.ndr import ndr_pack, ndr_unpack, ndr_unpack_out
+from samba.ntstatus import (
+ NT_STATUS_CONNECTION_DISCONNECTED,
+ NT_STATUS_PIPE_DISCONNECTED,
+ NT_STATUS_IO_TIMEOUT
+)
+from samba import NTSTATUSError
+from samba.samba3 import param as s3param
+from samba.samba3 import libsmb_samba_internal as libsmb
+from samba.credentials import SMB_SIGNING_REQUIRED
+
+class smb_pipe_socket(object):
+
+ def __init__(self, target_hostname, pipename, creds, impersonation_level, lp):
+ lp3 = s3param.get_context()
+ lp3.load(lp.configfile)
+ saved_signing_state = creds.get_smb_ipc_signing()
+ creds.set_smb_ipc_signing(SMB_SIGNING_REQUIRED)
+ self.smbconn = libsmb.Conn(target_hostname, 'IPC$', lp3,
+ creds=creds, ipc=True)
+ creds.set_smb_ipc_signing(saved_signing_state)
+ self.smbfid = self.smbconn.create(pipename,
+ DesiredAccess=0x12019f,
+ ShareAccess=0x7,
+ CreateDisposition=1,
+ CreateOptions=0x400040,
+ ImpersonationLevel=impersonation_level)
+ return
+
+ def close(self):
+ self.smbconn.close(self.smbfid)
+ del self.smbconn
+
+ def settimeout(self, timeo):
+ # The socket module we simulate there
+ # specifies the timeo as seconds as float.
+ msecs = int(timeo * 1000)
+ assert msecs >= 0
+ self.smbconn.settimeout(msecs)
+ return
+
+ def send(self, buf, flags=0):
+ return self.smbconn.write(self.smbfid, buffer=buf, offset=0, mode=8)
+
+ def recv(self, len, flags=0):
+ try:
+ return self.smbconn.read(self.smbfid, offset=0, size=len)
+ except NTSTATUSError as e:
+ if e.args[0] == NT_STATUS_CONNECTION_DISCONNECTED:
+ return b'\0' * 0
+ if e.args[0] == NT_STATUS_PIPE_DISCONNECTED:
+ return b'\0' * 0
+ if e.args[0] == NT_STATUS_IO_TIMEOUT:
+ raise socket.timeout(str(e))
+ raise e
+
+class RawDCERPCTest(TestCase):
+ """A raw DCE/RPC Test case."""
+
+ def _disconnect(self, reason):
+ if self.s is None:
+ return
+ self.s.close()
+ self.s = None
+ if self.do_hexdump:
+ sys.stderr.write("disconnect[%s]\n" % reason)
+
+ def _connect_tcp(self):
+ tcp_port = int(self.primary_address)
+ try:
+ self.a = socket.getaddrinfo(self.host, tcp_port, socket.AF_UNSPEC,
+ socket.SOCK_STREAM, socket.SOL_TCP,
+ 0)
+ self.s = socket.socket(self.a[0][0], self.a[0][1], self.a[0][2])
+ self.s.settimeout(10)
+ self.s.connect(self.a[0][4])
+ except socket.error as e:
+ self.s.close()
+ raise
+ except IOError as e:
+ self.s.close()
+ raise
+ except Exception as e:
+ raise
+ finally:
+ pass
+ self.max_xmit_frag = 5840
+ self.max_recv_frag = 5840
+ if self.secondary_address is None:
+ self.secondary_address = self.primary_address
+ # compat for older tests
+ self.tcp_port = tcp_port
+
+ def _connect_smb(self):
+ a = self.primary_address.split('\\')
+ self.assertEqual(len(a), 3)
+ self.assertEqual(a[0], "")
+ self.assertEqual(a[1], "pipe")
+ pipename = a[2]
+ self.s = smb_pipe_socket(self.target_hostname,
+ pipename,
+ self.transport_creds,
+ self.transport_impersonation,
+ self.lp_ctx)
+ self.max_xmit_frag = 4280
+ self.max_recv_frag = 4280
+ if self.secondary_address is None:
+ self.secondary_address = self.primary_address
+
+ def connect(self):
+ self.assertNotConnected()
+ if self.primary_address.startswith("\\pipe\\"):
+ self._connect_smb()
+ else:
+ self._connect_tcp()
+ if self.secondary_address is None:
+ self.secondary_address = self.primary_address
+ return
+
+ def setUp(self):
+ super().setUp()
+ self.do_ndr_print = False
+ self.do_hexdump = False
+
+ self.ignore_random_pad = samba.tests.env_get_var_value('IGNORE_RANDOM_PAD',
+ allow_missing=True)
+ self.host = samba.tests.env_get_var_value('SERVER')
+ self.target_hostname = samba.tests.env_get_var_value('TARGET_HOSTNAME', allow_missing=True)
+ if self.target_hostname is None:
+ self.target_hostname = self.host
+ self.primary_address = "135"
+ self.secondary_address = None
+ self.transport_creds = self.get_anon_creds()
+ self.transport_impersonation = 0x2
+
+ self.settings = {}
+ self.settings["lp_ctx"] = self.lp_ctx = samba.tests.env_loadparm()
+ self.settings["target_hostname"] = self.target_hostname
+
+ self.s = None
+ self.connect()
+
+ def tearDown(self):
+ self._disconnect("tearDown")
+ super().tearDown()
+
+ def noop(self):
+ return
+
+ def reconnect_smb_pipe(self, primary_address, secondary_address=None,
+ transport_creds=None, transport_impersonation=None):
+ self._disconnect("reconnect_smb_pipe")
+ self.assertIsNotNone(primary_address)
+ self.primary_address = primary_address
+ if secondary_address is not None:
+ self.secondary_address = secondary_address
+ else:
+ self.secondary_address = None
+
+ if transport_creds is not None:
+ self.transport_creds = transport_creds
+
+ if transport_impersonation is not None:
+ self.transport_impersonation = transport_impersonation
+
+ self.connect()
+ return
+
+ def second_connection(self, primary_address=None, secondary_address=None,
+ transport_creds=None, transport_impersonation=None):
+ c = RawDCERPCTest(methodName='noop')
+ c.do_ndr_print = self.do_ndr_print
+ c.do_hexdump = self.do_hexdump
+ c.ignore_random_pad = self.ignore_random_pad
+
+ c.host = self.host
+ c.target_hostname = self.target_hostname
+ if primary_address is not None:
+ c.primary_address = primary_address
+ if secondary_address is not None:
+ c.secondary_address = secondary_address
+ else:
+ c.secondary_address = None
+ else:
+ self.assertIsNone(secondary_address)
+ c.primary_address = self.primary_address
+ c.secondary_address = self.secondary_address
+
+ if transport_creds is not None:
+ c.transport_creds = transport_creds
+ else:
+ c.transport_creds = self.transport_creds
+
+ if transport_impersonation is not None:
+ c.transport_impersonation = transport_impersonation
+ else:
+ c.transport_impersonation = self.transport_impersonation
+
+ c.lp_ctx = self.lp_ctx
+ c.settings = self.settings
+
+ c.s = None
+ c.connect()
+ return c
+
+ def get_user_creds(self):
+ c = Credentials()
+ c.guess()
+ domain = samba.tests.env_get_var_value('DOMAIN')
+ realm = samba.tests.env_get_var_value('REALM')
+ username = samba.tests.env_get_var_value('USERNAME')
+ password = samba.tests.env_get_var_value('PASSWORD')
+ c.set_domain(domain)
+ c.set_realm(realm)
+ c.set_username(username)
+ c.set_password(password)
+ return c
+
+ def get_anon_creds(self):
+ c = Credentials()
+ c.set_anonymous()
+ return c
+
+ def get_auth_context_creds(self, creds, auth_type, auth_level,
+ auth_context_id,
+ g_auth_level=None,
+ hdr_signing=False):
+
+ if g_auth_level is None:
+ g_auth_level = auth_level
+
+ g = gensec.Security.start_client(self.settings)
+ g.set_credentials(creds)
+ g.want_feature(gensec.FEATURE_DCE_STYLE)
+ g.start_mech_by_authtype(auth_type, g_auth_level)
+
+ if auth_type == dcerpc.DCERPC_AUTH_TYPE_KRB5:
+ expect_3legs = True
+ elif auth_type == dcerpc.DCERPC_AUTH_TYPE_NTLMSSP:
+ expect_3legs = True
+ else:
+ expect_3legs = False
+
+ auth_context = {}
+ auth_context["auth_type"] = auth_type
+ auth_context["auth_level"] = auth_level
+ auth_context["auth_context_id"] = auth_context_id
+ auth_context["g_auth_level"] = g_auth_level
+ auth_context["gensec"] = g
+ auth_context["hdr_signing"] = hdr_signing
+ auth_context["expect_3legs"] = expect_3legs
+
+ return auth_context
+
+ def do_generic_bind(self, ctx, auth_context=None,
+ pfc_flags=samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST,
+ assoc_group_id=0, call_id=0,
+ nak_reason=None, alter_fault=None,
+ start_with_alter=False,
+ pfc_flags_2nd=samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST,
+ use_auth3=False):
+ ctx_list = [ctx]
+
+ if auth_context is not None:
+ if auth_context['hdr_signing']:
+ pfc_flags |= dcerpc.DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
+
+ expect_3legs = auth_context["expect_3legs"]
+
+ from_server = b""
+ (finished, to_server) = auth_context["gensec"].update(from_server)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_context["auth_type"],
+ auth_level=auth_context["auth_level"],
+ auth_context_id=auth_context["auth_context_id"],
+ auth_blob=to_server)
+ else:
+ auth_info = b""
+
+ if start_with_alter:
+ req = self.generate_alter(call_id=call_id,
+ pfc_flags=pfc_flags,
+ ctx_list=ctx_list,
+ assoc_group_id=0xffffffff - assoc_group_id,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ if alter_fault is not None:
+ self.verify_pdu(rep, samba.dcerpc.dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=req.pfc_flags |
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, 0)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, alter_fault)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+ return None
+ self.verify_pdu(rep, samba.dcerpc.dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id,
+ pfc_flags=req.pfc_flags)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertEqual(rep.u.assoc_group_id, assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 0)
+ self.assertEqual(rep.u.secondary_address, '')
+ self.assertPadding(rep.u._pad1, 2)
+ else:
+ req = self.generate_bind(call_id=call_id,
+ pfc_flags=pfc_flags,
+ ctx_list=ctx_list,
+ assoc_group_id=assoc_group_id,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ if nak_reason is not None:
+ self.verify_pdu(rep, samba.dcerpc.dcerpc.DCERPC_PKT_BIND_NAK, req.call_id,
+ auth_length=0)
+ self.assertEqual(rep.u.reject_reason, nak_reason)
+ self.assertEqual(rep.u.num_versions, 1)
+ self.assertEqual(rep.u.versions[0].rpc_vers, req.rpc_vers)
+ self.assertEqual(rep.u.versions[0].rpc_vers_minor, req.rpc_vers_minor)
+ self.assertPadding(rep.u._pad, 3)
+ return
+ self.verify_pdu(rep, samba.dcerpc.dcerpc.DCERPC_PKT_BIND_ACK, req.call_id,
+ pfc_flags=pfc_flags)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ if assoc_group_id != 0:
+ self.assertEqual(rep.u.assoc_group_id, assoc_group_id)
+ else:
+ self.assertNotEqual(rep.u.assoc_group_id, 0)
+ assoc_group_id = rep.u.assoc_group_id
+ sda_str = self.secondary_address
+ sda_len = len(sda_str) + 1
+ mod_len = (2 + sda_len) % 4
+ if mod_len != 0:
+ sda_pad = 4 - mod_len
+ else:
+ sda_pad = 0
+ self.assertEqual(rep.u.secondary_address_size, sda_len)
+ self.assertEqual(rep.u.secondary_address, sda_str)
+ self.assertPadding(rep.u._pad1, sda_pad)
+
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ samba.dcerpc.dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ samba.dcerpc.dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ctx.transfer_syntaxes[0])
+ ack = rep
+ if auth_context is None:
+ self.assertEqual(rep.auth_length, 0)
+ self.assertEqual(len(rep.u.auth_info), 0)
+ return ack
+ self.assertNotEqual(rep.auth_length, 0)
+ self.assertGreater(len(rep.u.auth_info), samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH)
+ self.assertEqual(rep.auth_length, len(rep.u.auth_info) - samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH)
+
+ a = self.parse_auth(rep.u.auth_info, auth_context=auth_context)
+
+ from_server = a.credentials
+ (finished, to_server) = auth_context["gensec"].update(from_server)
+ if expect_3legs:
+ self.assertTrue(finished)
+ if auth_context['hdr_signing']:
+ auth_context["gensec"].want_feature(gensec.FEATURE_SIGN_PKT_HEADER)
+ else:
+ self.assertFalse(use_auth3)
+ self.assertFalse(finished)
+
+ auth_info = self.generate_auth(auth_type=auth_context["auth_type"],
+ auth_level=auth_context["auth_level"],
+ auth_context_id=auth_context["auth_context_id"],
+ auth_blob=to_server)
+ if use_auth3:
+ req = self.generate_auth3(call_id=call_id,
+ pfc_flags=pfc_flags_2nd,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu(timeout=0.01)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+ return ack
+ req = self.generate_alter(call_id=call_id,
+ ctx_list=ctx_list,
+ pfc_flags=pfc_flags_2nd,
+ assoc_group_id=0xffffffff - assoc_group_id,
+ auth_info=auth_info)
+ self.send_pdu(req)
+ rep = self.recv_pdu()
+ if alter_fault is not None:
+ self.verify_pdu(rep, samba.dcerpc.dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ pfc_flags=req.pfc_flags |
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, 0)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, alter_fault)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+ return None
+ self.verify_pdu(rep, samba.dcerpc.dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id,
+ pfc_flags=req.pfc_flags)
+ self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
+ self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
+ self.assertEqual(rep.u.assoc_group_id, assoc_group_id)
+ self.assertEqual(rep.u.secondary_address_size, 0)
+ self.assertEqual(rep.u.secondary_address, '')
+ self.assertPadding(rep.u._pad1, 2)
+ self.assertEqual(rep.u.num_results, 1)
+ self.assertEqual(rep.u.ctx_list[0].result,
+ samba.dcerpc.dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
+ self.assertEqual(rep.u.ctx_list[0].reason,
+ samba.dcerpc.dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
+ self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ctx.transfer_syntaxes[0])
+ if finished:
+ self.assertEqual(rep.auth_length, 0)
+ else:
+ self.assertNotEqual(rep.auth_length, 0)
+ self.assertGreaterEqual(len(rep.u.auth_info), samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH)
+ self.assertEqual(rep.auth_length, len(rep.u.auth_info) - samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH)
+
+ a = self.parse_auth(rep.u.auth_info, auth_context=auth_context)
+
+ if finished:
+ return ack
+
+ from_server = a.credentials
+ (finished, to_server) = auth_context["gensec"].update(from_server)
+ self.assertTrue(finished)
+ if auth_context['hdr_signing']:
+ auth_context["gensec"].want_feature(gensec.FEATURE_SIGN_PKT_HEADER)
+
+ return ack
+
+ def prepare_presentation(self, abstract, transfer, object=None,
+ context_id=0xffff, epmap=False, auth_context=None,
+ pfc_flags=samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST,
+ assoc_group_id=0,
+ return_ack=False):
+ if epmap:
+ self.epmap_reconnect(abstract, transfer=transfer, object=object)
+
+ tsf1_list = [transfer]
+ ctx = samba.dcerpc.dcerpc.ctx_list()
+ ctx.context_id = context_id
+ ctx.num_transfer_syntaxes = len(tsf1_list)
+ ctx.abstract_syntax = abstract
+ ctx.transfer_syntaxes = tsf1_list
+
+ ack = self.do_generic_bind(ctx=ctx,
+ auth_context=auth_context,
+ pfc_flags=pfc_flags,
+ assoc_group_id=assoc_group_id)
+ if ack is None:
+ ctx = None
+
+ if return_ack:
+ return (ctx, ack)
+ return ctx
+
+ def do_single_request(self, call_id, ctx, io,
+ auth_context=None,
+ object=None,
+ bigendian=False, ndr64=False,
+ allow_remaining=False,
+ send_req=True,
+ recv_rep=True,
+ fault_pfc_flags=(
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST),
+ fault_status=None,
+ fault_context_id=None,
+ timeout=None,
+ ndr_print=None,
+ hexdump=None):
+
+ if fault_context_id is None:
+ fault_context_id = ctx.context_id
+
+ if ndr_print is None:
+ ndr_print = self.do_ndr_print
+ if hexdump is None:
+ hexdump = self.do_hexdump
+
+ if send_req:
+ if ndr_print:
+ sys.stderr.write("in: %s" % samba.ndr.ndr_print_in(io))
+ stub_in = samba.ndr.ndr_pack_in(io, bigendian=bigendian, ndr64=ndr64)
+ if hexdump:
+ sys.stderr.write("stub_in: %d\n%s" % (len(stub_in), self.hexdump(stub_in)))
+
+ pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST
+ pfc_flags |= samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST
+ if object is not None:
+ pfc_flags |= samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_OBJECT_UUID
+
+ req = self.generate_request_auth(call_id=call_id,
+ context_id=ctx.context_id,
+ pfc_flags=pfc_flags,
+ object=object,
+ opnum=io.opnum(),
+ stub=stub_in,
+ auth_context=auth_context)
+ self.send_pdu(req, ndr_print=ndr_print, hexdump=hexdump)
+ if recv_rep:
+ (rep, rep_blob) = self.recv_pdu_raw(timeout=timeout,
+ ndr_print=ndr_print,
+ hexdump=hexdump)
+ if fault_status:
+ self.verify_pdu(rep, samba.dcerpc.dcerpc.DCERPC_PKT_FAULT, call_id,
+ pfc_flags=fault_pfc_flags, auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, fault_context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, fault_status)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+ return
+
+ expected_auth_length = 0
+ if auth_context is not None and \
+ auth_context["auth_level"] >= dcerpc.DCERPC_AUTH_LEVEL_PACKET:
+ if send_req:
+ expected_auth_length = req.auth_length
+ else:
+ expected_auth_length = rep.auth_length
+
+
+ self.verify_pdu(rep, samba.dcerpc.dcerpc.DCERPC_PKT_RESPONSE, call_id,
+ auth_length=expected_auth_length)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, ctx.context_id & 0xff)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
+ stub_out = self.check_response_auth(rep, rep_blob, auth_context)
+ self.assertEqual(len(stub_out), rep.u.alloc_hint)
+
+ if hexdump:
+ sys.stderr.write("stub_out: %d\n%s" % (len(stub_out), self.hexdump(stub_out)))
+ ndr_unpack_out(io, stub_out, bigendian=bigendian, ndr64=ndr64,
+ allow_remaining=allow_remaining)
+ if ndr_print:
+ sys.stderr.write("out: %s" % samba.ndr.ndr_print_out(io))
+
+ def epmap_reconnect(self, abstract, transfer=None, object=None):
+ ndr32 = samba.dcerpc.base.transfer_syntax_ndr()
+
+ if transfer is None:
+ transfer = ndr32
+
+ if object is None:
+ object = samba.dcerpc.misc.GUID()
+
+ ctx = self.prepare_presentation(samba.dcerpc.epmapper.abstract_syntax(),
+ transfer, context_id=0)
+
+ data1 = ndr_pack(abstract)
+ lhs1 = samba.dcerpc.epmapper.epm_lhs()
+ lhs1.protocol = samba.dcerpc.epmapper.EPM_PROTOCOL_UUID
+ lhs1.lhs_data = data1[:18]
+ rhs1 = samba.dcerpc.epmapper.epm_rhs_uuid()
+ rhs1.unknown = data1[18:]
+ floor1 = samba.dcerpc.epmapper.epm_floor()
+ floor1.lhs = lhs1
+ floor1.rhs = rhs1
+ data2 = ndr_pack(transfer)
+ lhs2 = samba.dcerpc.epmapper.epm_lhs()
+ lhs2.protocol = samba.dcerpc.epmapper.EPM_PROTOCOL_UUID
+ lhs2.lhs_data = data2[:18]
+ rhs2 = samba.dcerpc.epmapper.epm_rhs_uuid()
+ rhs2.unknown = data1[18:]
+ floor2 = samba.dcerpc.epmapper.epm_floor()
+ floor2.lhs = lhs2
+ floor2.rhs = rhs2
+ lhs3 = samba.dcerpc.epmapper.epm_lhs()
+ lhs3.protocol = samba.dcerpc.epmapper.EPM_PROTOCOL_NCACN
+ lhs3.lhs_data = b""
+ floor3 = samba.dcerpc.epmapper.epm_floor()
+ floor3.lhs = lhs3
+ floor3.rhs.minor_version = 0
+ lhs4 = samba.dcerpc.epmapper.epm_lhs()
+ lhs4.protocol = samba.dcerpc.epmapper.EPM_PROTOCOL_TCP
+ lhs4.lhs_data = b""
+ floor4 = samba.dcerpc.epmapper.epm_floor()
+ floor4.lhs = lhs4
+ floor4.rhs.port = int(self.primary_address)
+ lhs5 = samba.dcerpc.epmapper.epm_lhs()
+ lhs5.protocol = samba.dcerpc.epmapper.EPM_PROTOCOL_IP
+ lhs5.lhs_data = b""
+ floor5 = samba.dcerpc.epmapper.epm_floor()
+ floor5.lhs = lhs5
+ floor5.rhs.ipaddr = "0.0.0.0"
+
+ floors = [floor1, floor2, floor3, floor4, floor5]
+ req_tower = samba.dcerpc.epmapper.epm_tower()
+ req_tower.num_floors = len(floors)
+ req_tower.floors = floors
+ req_twr = samba.dcerpc.epmapper.epm_twr_t()
+ req_twr.tower = req_tower
+
+ epm_map = samba.dcerpc.epmapper.epm_Map()
+ epm_map.in_object = object
+ epm_map.in_map_tower = req_twr
+ epm_map.in_entry_handle = samba.dcerpc.misc.policy_handle()
+ epm_map.in_max_towers = 4
+
+ self.do_single_request(call_id=2, ctx=ctx, io=epm_map)
+
+ self.assertGreaterEqual(epm_map.out_num_towers, 1)
+ rep_twr = epm_map.out_towers[0].twr
+ self.assertIsNotNone(rep_twr)
+ self.assertEqual(rep_twr.tower_length, 75)
+ self.assertEqual(rep_twr.tower.num_floors, 5)
+ self.assertEqual(len(rep_twr.tower.floors), 5)
+ self.assertEqual(rep_twr.tower.floors[3].lhs.protocol,
+ samba.dcerpc.epmapper.EPM_PROTOCOL_TCP)
+ self.assertEqual(rep_twr.tower.floors[3].lhs.protocol,
+ samba.dcerpc.epmapper.EPM_PROTOCOL_TCP)
+
+ # reconnect to the given port
+ self._disconnect("epmap_reconnect")
+ self.primary_address = "%d" % rep_twr.tower.floors[3].rhs.port
+ self.secondary_address = None
+ self.connect()
+
+ def send_pdu(self, req, ndr_print=None, hexdump=None):
+ if ndr_print is None:
+ ndr_print = self.do_ndr_print
+ if hexdump is None:
+ hexdump = self.do_hexdump
+ try:
+ req_pdu = ndr_pack(req)
+ if ndr_print:
+ sys.stderr.write("send_pdu: %s" % samba.ndr.ndr_print(req))
+ if hexdump:
+ sys.stderr.write("send_pdu: %d\n%s" % (len(req_pdu), self.hexdump(req_pdu)))
+ while True:
+ sent = self.s.send(req_pdu, 0)
+ if sent == len(req_pdu):
+ break
+ req_pdu = req_pdu[sent:]
+ except socket.error as e:
+ self._disconnect("send_pdu: %s" % e)
+ raise
+ except IOError as e:
+ self._disconnect("send_pdu: %s" % e)
+ raise
+ except NTSTATUSError as e:
+ self._disconnect("send_pdu: %s" % e)
+ raise
+ finally:
+ pass
+
+ def recv_raw(self, hexdump=None, timeout=None):
+ rep_pdu = None
+ if hexdump is None:
+ hexdump = self.do_hexdump
+ try:
+ if timeout is not None:
+ self.s.settimeout(timeout)
+ rep_pdu = self.s.recv(0xffff, 0)
+ self.s.settimeout(10)
+ if len(rep_pdu) == 0:
+ self._disconnect("recv_raw: EOF")
+ return None
+ if hexdump:
+ sys.stderr.write("recv_raw: %d\n%s" % (len(rep_pdu), self.hexdump(rep_pdu)))
+ except socket.timeout as e:
+ self.s.settimeout(10)
+ sys.stderr.write("recv_raw: TIMEOUT\n")
+ pass
+ except socket.error as e:
+ self._disconnect("recv_raw: %s" % e)
+ raise
+ except IOError as e:
+ self._disconnect("recv_raw: %s" % e)
+ raise
+ finally:
+ pass
+ return rep_pdu
+
+ def recv_pdu_raw(self, ndr_print=None, hexdump=None, timeout=None):
+ rep_pdu = None
+ rep = None
+ if ndr_print is None:
+ ndr_print = self.do_ndr_print
+ if hexdump is None:
+ hexdump = self.do_hexdump
+ try:
+ rep_pdu = self.recv_raw(hexdump=hexdump, timeout=timeout)
+ if rep_pdu is None:
+ return (None, None)
+ rep = ndr_unpack(samba.dcerpc.dcerpc.ncacn_packet, rep_pdu, allow_remaining=True)
+ if ndr_print:
+ sys.stderr.write("recv_pdu: %s" % samba.ndr.ndr_print(rep))
+ self.assertEqual(rep.frag_length, len(rep_pdu))
+ finally:
+ pass
+ return (rep, rep_pdu)
+
+ def recv_pdu(self, ndr_print=None, hexdump=None, timeout=None):
+ (rep, rep_pdu) = self.recv_pdu_raw(ndr_print=ndr_print,
+ hexdump=hexdump,
+ timeout=timeout)
+ return rep
+
+ def generate_auth(self,
+ auth_type=None,
+ auth_level=None,
+ auth_pad_length=0,
+ auth_context_id=None,
+ auth_blob=None,
+ ndr_print=None, hexdump=None):
+ if ndr_print is None:
+ ndr_print = self.do_ndr_print
+ if hexdump is None:
+ hexdump = self.do_hexdump
+
+ if auth_type is not None:
+ a = samba.dcerpc.dcerpc.auth()
+ a.auth_type = auth_type
+ a.auth_level = auth_level
+ a.auth_pad_length = auth_pad_length
+ a.auth_context_id = auth_context_id
+ a.credentials = auth_blob
+
+ ai = ndr_pack(a)
+ if ndr_print:
+ sys.stderr.write("generate_auth: %s" % samba.ndr.ndr_print(a))
+ if hexdump:
+ sys.stderr.write("generate_auth: %d\n%s" % (len(ai), self.hexdump(ai)))
+ else:
+ ai = b""
+
+ return ai
+
+ def parse_auth(self, auth_info, ndr_print=None, hexdump=None,
+ auth_context=None, stub_len=0):
+ if ndr_print is None:
+ ndr_print = self.do_ndr_print
+ if hexdump is None:
+ hexdump = self.do_hexdump
+
+ if (len(auth_info) <= samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH):
+ return None
+
+ if hexdump:
+ sys.stderr.write("parse_auth: %d\n%s" % (len(auth_info), self.hexdump(auth_info)))
+ a = ndr_unpack(samba.dcerpc.dcerpc.auth, auth_info, allow_remaining=True)
+ if ndr_print:
+ sys.stderr.write("parse_auth: %s" % samba.ndr.ndr_print(a))
+
+ if auth_context is not None:
+ self.assertEqual(a.auth_type, auth_context["auth_type"])
+ self.assertEqual(a.auth_level, auth_context["auth_level"])
+ self.assertEqual(a.auth_reserved, 0)
+ self.assertEqual(a.auth_context_id, auth_context["auth_context_id"])
+
+ self.assertLessEqual(a.auth_pad_length, dcerpc.DCERPC_AUTH_PAD_ALIGNMENT)
+ self.assertLessEqual(a.auth_pad_length, stub_len)
+
+ return a
+
+ def check_response_auth(self, rep, rep_blob, auth_context=None,
+ auth_pad_length=None):
+
+ if auth_context is None:
+ self.assertEqual(rep.auth_length, 0)
+ return rep.u.stub_and_verifier
+
+ if auth_context["auth_level"] == dcerpc.DCERPC_AUTH_LEVEL_CONNECT:
+ self.assertEqual(rep.auth_length, 0)
+ return rep.u.stub_and_verifier
+
+ self.assertGreater(rep.auth_length, 0)
+
+ ofs_stub = dcerpc.DCERPC_REQUEST_LENGTH
+ ofs_sig = rep.frag_length - rep.auth_length
+ ofs_trailer = ofs_sig - dcerpc.DCERPC_AUTH_TRAILER_LENGTH
+ rep_data = rep_blob[ofs_stub:ofs_trailer]
+ rep_whole = rep_blob[0:ofs_sig]
+ rep_sig = rep_blob[ofs_sig:]
+ rep_auth_info_blob = rep_blob[ofs_trailer:]
+
+ rep_auth_info = self.parse_auth(rep_auth_info_blob,
+ auth_context=auth_context,
+ stub_len=len(rep_data))
+ if auth_pad_length is not None:
+ self.assertEqual(rep_auth_info.auth_pad_length, auth_pad_length)
+ self.assertEqual(rep_auth_info.credentials, rep_sig)
+
+ if auth_context["auth_level"] >= dcerpc.DCERPC_AUTH_LEVEL_PRIVACY:
+ # TODO: not yet supported here
+ self.assertTrue(False)
+ elif auth_context["auth_level"] >= dcerpc.DCERPC_AUTH_LEVEL_PACKET:
+ auth_context["gensec"].check_packet(rep_data, rep_whole, rep_sig)
+
+ stub_out = rep_data[0:len(rep_data)-rep_auth_info.auth_pad_length]
+
+ return stub_out
+
+ def generate_pdu(self, ptype, call_id, payload,
+ rpc_vers=5,
+ rpc_vers_minor=0,
+ pfc_flags=(samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST),
+ drep=None,
+ ndr_print=None, hexdump=None):
+
+ if drep is None:
+ drep = [samba.dcerpc.dcerpc.DCERPC_DREP_LE, 0, 0, 0]
+ if getattr(payload, 'auth_info', None):
+ ai = payload.auth_info
+ else:
+ ai = b""
+
+ p = samba.dcerpc.dcerpc.ncacn_packet()
+ p.rpc_vers = rpc_vers
+ p.rpc_vers_minor = rpc_vers_minor
+ p.ptype = ptype
+ p.pfc_flags = pfc_flags
+ p.drep = drep
+ p.frag_length = 0
+ if len(ai) > samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH:
+ p.auth_length = len(ai) - samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH
+ else:
+ p.auth_length = 0
+ p.call_id = call_id
+ p.u = payload
+
+ pdu = ndr_pack(p)
+ p.frag_length = len(pdu)
+
+ return p
+
+ def generate_request_auth(self, call_id,
+ pfc_flags=(dcerpc.DCERPC_PFC_FLAG_FIRST |
+ dcerpc.DCERPC_PFC_FLAG_LAST),
+ alloc_hint=None,
+ context_id=None,
+ opnum=None,
+ object=None,
+ stub=None,
+ auth_context=None,
+ ndr_print=None, hexdump=None):
+
+ if stub is None:
+ stub = b""
+
+ sig_size = 0
+ if auth_context is not None:
+ mod_len = len(stub) % dcerpc.DCERPC_AUTH_PAD_ALIGNMENT
+ auth_pad_length = 0
+ if mod_len > 0:
+ auth_pad_length = dcerpc.DCERPC_AUTH_PAD_ALIGNMENT - mod_len
+ stub += b'\x00' * auth_pad_length
+
+ if auth_context["g_auth_level"] >= samba.dcerpc.dcerpc.DCERPC_AUTH_LEVEL_PACKET:
+ sig_size = auth_context["gensec"].sig_size(len(stub))
+ else:
+ sig_size = 16
+
+ zero_sig = b"\x00" * sig_size
+ auth_info = self.generate_auth(auth_type=auth_context["auth_type"],
+ auth_level=auth_context["auth_level"],
+ auth_pad_length=auth_pad_length,
+ auth_context_id=auth_context["auth_context_id"],
+ auth_blob=zero_sig)
+ else:
+ auth_info = b""
+
+ req = self.generate_request(call_id=call_id,
+ pfc_flags=pfc_flags,
+ alloc_hint=alloc_hint,
+ context_id=context_id,
+ opnum=opnum,
+ object=object,
+ stub=stub,
+ auth_info=auth_info,
+ ndr_print=ndr_print,
+ hexdump=hexdump)
+ if auth_context is None:
+ return req
+
+ req_blob = samba.ndr.ndr_pack(req)
+ ofs_stub = dcerpc.DCERPC_REQUEST_LENGTH
+ ofs_sig = len(req_blob) - req.auth_length
+ ofs_trailer = ofs_sig - dcerpc.DCERPC_AUTH_TRAILER_LENGTH
+ req_data = req_blob[ofs_stub:ofs_trailer]
+ req_whole = req_blob[0:ofs_sig]
+
+ if auth_context["g_auth_level"] >= dcerpc.DCERPC_AUTH_LEVEL_PRIVACY:
+ # TODO: not yet supported here
+ self.assertTrue(False)
+ elif auth_context["g_auth_level"] >= dcerpc.DCERPC_AUTH_LEVEL_PACKET:
+ req_sig = auth_context["gensec"].sign_packet(req_data, req_whole)
+ elif auth_context["g_auth_level"] >= dcerpc.DCERPC_AUTH_LEVEL_CONNECT:
+ self.assertEqual(auth_context["auth_type"],
+ dcerpc.DCERPC_AUTH_TYPE_NTLMSSP)
+ req_sig = b"\x01" +b"\x00" *15
+ else:
+ return req
+ self.assertEqual(len(req_sig), req.auth_length)
+ self.assertEqual(len(req_sig), sig_size)
+
+ stub_sig_ofs = len(req.u.stub_and_verifier) - sig_size
+ stub = req.u.stub_and_verifier[0:stub_sig_ofs] + req_sig
+ req.u.stub_and_verifier = stub
+
+ return req
+
+ def verify_pdu(self, p, ptype, call_id,
+ rpc_vers=5,
+ rpc_vers_minor=0,
+ pfc_flags=(samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST),
+ drep=None,
+ auth_length=None):
+
+ if drep is None:
+ drep = [samba.dcerpc.dcerpc.DCERPC_DREP_LE, 0, 0, 0]
+ self.assertIsNotNone(p, "No valid pdu")
+
+ if getattr(p.u, 'auth_info', None):
+ ai = p.u.auth_info
+ else:
+ ai = b""
+
+ self.assertEqual(p.rpc_vers, rpc_vers)
+ self.assertEqual(p.rpc_vers_minor, rpc_vers_minor)
+ self.assertEqual(p.ptype, ptype)
+ self.assertEqual(p.pfc_flags, pfc_flags)
+ self.assertEqual(p.drep, drep)
+ self.assertGreaterEqual(p.frag_length,
+ samba.dcerpc.dcerpc.DCERPC_NCACN_PAYLOAD_OFFSET)
+ if len(ai) > samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH:
+ self.assertEqual(p.auth_length,
+ len(ai) - samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH)
+ elif auth_length is not None:
+ self.assertEqual(p.auth_length, auth_length)
+ else:
+ self.assertEqual(p.auth_length, 0)
+ self.assertEqual(p.call_id, call_id)
+
+ return
+
+ def generate_bind(self, call_id,
+ pfc_flags=(samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST),
+ max_xmit_frag=None,
+ max_recv_frag=None,
+ assoc_group_id=0,
+ ctx_list=None,
+ auth_info=b"",
+ ndr_print=None, hexdump=None):
+
+ if ctx_list is None:
+ ctx_list = []
+ if max_xmit_frag is None:
+ max_xmit_frag=self.max_xmit_frag
+ if max_recv_frag is None:
+ max_recv_frag=self.max_recv_frag
+
+ b = samba.dcerpc.dcerpc.bind()
+ b.max_xmit_frag = max_xmit_frag
+ b.max_recv_frag = max_recv_frag
+ b.assoc_group_id = assoc_group_id
+ b.num_contexts = len(ctx_list)
+ b.ctx_list = ctx_list
+ b.auth_info = auth_info
+
+ p = self.generate_pdu(ptype=samba.dcerpc.dcerpc.DCERPC_PKT_BIND,
+ pfc_flags=pfc_flags,
+ call_id=call_id,
+ payload=b,
+ ndr_print=ndr_print, hexdump=hexdump)
+
+ return p
+
+ def generate_alter(self, call_id,
+ pfc_flags=(samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST),
+ max_xmit_frag=None,
+ max_recv_frag=None,
+ assoc_group_id=0,
+ ctx_list=None,
+ auth_info=b"",
+ ndr_print=None, hexdump=None):
+
+ if ctx_list is None:
+ ctx_list = []
+ if max_xmit_frag is None:
+ max_xmit_frag=self.max_xmit_frag
+ if max_recv_frag is None:
+ max_recv_frag=self.max_recv_frag
+
+ a = samba.dcerpc.dcerpc.bind()
+ a.max_xmit_frag = max_xmit_frag
+ a.max_recv_frag = max_recv_frag
+ a.assoc_group_id = assoc_group_id
+ a.num_contexts = len(ctx_list)
+ a.ctx_list = ctx_list
+ a.auth_info = auth_info
+
+ p = self.generate_pdu(ptype=samba.dcerpc.dcerpc.DCERPC_PKT_ALTER,
+ pfc_flags=pfc_flags,
+ call_id=call_id,
+ payload=a,
+ ndr_print=ndr_print, hexdump=hexdump)
+
+ return p
+
+ def generate_auth3(self, call_id,
+ pfc_flags=(samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST),
+ auth_info=b"",
+ ndr_print=None, hexdump=None):
+
+ a = samba.dcerpc.dcerpc.auth3()
+ a.auth_info = auth_info
+
+ p = self.generate_pdu(ptype=samba.dcerpc.dcerpc.DCERPC_PKT_AUTH3,
+ pfc_flags=pfc_flags,
+ call_id=call_id,
+ payload=a,
+ ndr_print=ndr_print, hexdump=hexdump)
+
+ return p
+
+ def generate_request(self, call_id,
+ pfc_flags=(samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST),
+ alloc_hint=None,
+ context_id=None,
+ opnum=None,
+ object=None,
+ stub=None,
+ auth_info=b"",
+ ndr_print=None, hexdump=None):
+
+ if alloc_hint is None:
+ alloc_hint = len(stub)
+
+ r = samba.dcerpc.dcerpc.request()
+ r.alloc_hint = alloc_hint
+ r.context_id = context_id
+ r.opnum = opnum
+ if object is not None:
+ r.object = object
+ r.stub_and_verifier = stub + auth_info
+
+ p = self.generate_pdu(ptype=samba.dcerpc.dcerpc.DCERPC_PKT_REQUEST,
+ pfc_flags=pfc_flags,
+ call_id=call_id,
+ payload=r,
+ ndr_print=ndr_print, hexdump=hexdump)
+
+ if len(auth_info) > samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH:
+ p.auth_length = len(auth_info) - samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH
+
+ return p
+
+ def generate_co_cancel(self, call_id,
+ pfc_flags=(samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST),
+ auth_info=b"",
+ ndr_print=None, hexdump=None):
+
+ c = samba.dcerpc.dcerpc.co_cancel()
+ c.auth_info = auth_info
+
+ p = self.generate_pdu(ptype=samba.dcerpc.dcerpc.DCERPC_PKT_CO_CANCEL,
+ pfc_flags=pfc_flags,
+ call_id=call_id,
+ payload=c,
+ ndr_print=ndr_print, hexdump=hexdump)
+
+ return p
+
+ def generate_orphaned(self, call_id,
+ pfc_flags=(samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST),
+ auth_info=b"",
+ ndr_print=None, hexdump=None):
+
+ o = samba.dcerpc.dcerpc.orphaned()
+ o.auth_info = auth_info
+
+ p = self.generate_pdu(ptype=samba.dcerpc.dcerpc.DCERPC_PKT_ORPHANED,
+ pfc_flags=pfc_flags,
+ call_id=call_id,
+ payload=o,
+ ndr_print=ndr_print, hexdump=hexdump)
+
+ return p
+
+ def generate_shutdown(self, call_id,
+ pfc_flags=(samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
+ samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST),
+ ndr_print=None, hexdump=None):
+
+ s = samba.dcerpc.dcerpc.shutdown()
+
+ p = self.generate_pdu(ptype=samba.dcerpc.dcerpc.DCERPC_PKT_SHUTDOWN,
+ pfc_flags=pfc_flags,
+ call_id=call_id,
+ payload=s,
+ ndr_print=ndr_print, hexdump=hexdump)
+
+ return p
+
+ def assertIsConnected(self):
+ self.assertIsNotNone(self.s, msg="Not connected")
+ return
+
+ def assertNotConnected(self):
+ self.assertIsNone(self.s, msg="Is connected")
+ return
+
+ def assertNDRSyntaxEquals(self, s1, s2):
+ self.assertEqual(s1.uuid, s2.uuid)
+ self.assertEqual(s1.if_version, s2.if_version)
+ return
+
+ def assertPadding(self, pad, length):
+ self.assertEqual(len(pad), length)
+ #
+ # sometimes windows sends random bytes
+ #
+ # we have IGNORE_RANDOM_PAD=1 to
+ # disable the check
+ #
+ if self.ignore_random_pad:
+ return
+ zero_pad = b'\0' * length
+ self.assertEqual(pad, zero_pad)
+
+ def assertEqualsStrLower(self, s1, s2):
+ self.assertEqual(str(s1).lower(), str(s2).lower())
diff --git a/python/samba/tests/dcerpc/registry.py b/python/samba/tests/dcerpc/registry.py
new file mode 100644
index 0000000..be9e484
--- /dev/null
+++ b/python/samba/tests/dcerpc/registry.py
@@ -0,0 +1,51 @@
+# Unix SMB/CIFS implementation.
+# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
+#
+# 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/>.
+#
+
+"""Tests for samba.dcerpc.registry."""
+
+from samba.dcerpc import winreg
+from samba.tests import RpcInterfaceTestCase
+
+
+class WinregTests(RpcInterfaceTestCase):
+
+ def setUp(self):
+ super().setUp()
+ self.conn = winreg.winreg("ncalrpc:", self.get_loadparm(),
+ self.get_credentials())
+
+ def get_hklm(self):
+ return self.conn.OpenHKLM(None,
+ winreg.KEY_QUERY_VALUE | winreg.KEY_ENUMERATE_SUB_KEYS)
+
+ def test_hklm(self):
+ handle = self.conn.OpenHKLM(None,
+ winreg.KEY_QUERY_VALUE | winreg.KEY_ENUMERATE_SUB_KEYS)
+ self.conn.CloseKey(handle)
+
+ def test_getversion(self):
+ handle = self.get_hklm()
+ version = self.conn.GetVersion(handle)
+ self.assertEqual(int, version.__class__)
+ self.conn.CloseKey(handle)
+
+ def test_getkeyinfo(self):
+ handle = self.conn.OpenHKLM(None,
+ winreg.KEY_QUERY_VALUE | winreg.KEY_ENUMERATE_SUB_KEYS)
+ x = self.conn.QueryInfoKey(handle, winreg.String())
+ self.assertEqual(9, len(x)) # should return a 9-tuple
+ self.conn.CloseKey(handle)
diff --git a/python/samba/tests/dcerpc/rpc_talloc.py b/python/samba/tests/dcerpc/rpc_talloc.py
new file mode 100644
index 0000000..4ad86a6
--- /dev/null
+++ b/python/samba/tests/dcerpc/rpc_talloc.py
@@ -0,0 +1,86 @@
+# test generated python code from pidl
+# Copyright (C) Andrew Tridgell August 2010
+#
+# 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/>.
+#
+#
+# to run this test, use one of these:
+#
+# python -m unittest samba.tests.dcerpc.rpc_talloc
+#
+# or if you have trial installed (from twisted), use
+#
+# trial samba.tests.dcerpc.rpc_talloc
+
+"""Tests for the talloc handling in the generated Python DCE/RPC bindings."""
+
+import sys
+
+sys.path.insert(0, "bin/python")
+
+import samba
+import samba.tests
+from samba.dcerpc import drsuapi
+import talloc
+
+talloc.enable_null_tracking()
+
+
+class TallocTests(samba.tests.TestCase):
+ """test talloc behaviour of pidl generated python code"""
+
+ def check_blocks(self, object, num_expected):
+ """check that the number of allocated blocks is correct"""
+ nblocks = talloc.total_blocks(object)
+ if object is None:
+ nblocks -= self.initial_blocks
+ self.assertEqual(nblocks, num_expected)
+
+ def get_rodc_partial_attribute_set(self):
+ """get a list of attributes for RODC replication"""
+ partial_attribute_set = drsuapi.DsPartialAttributeSet()
+
+ # we expect one block for the object
+ self.check_blocks(partial_attribute_set, 1)
+
+ attids = [1, 2, 3]
+ partial_attribute_set.version = 1
+ partial_attribute_set.attids = attids
+ partial_attribute_set.num_attids = len(attids)
+
+ # we expect one block for the object, a structure, and a
+ # reference to the array
+ self.check_blocks(partial_attribute_set, 2)
+
+ return partial_attribute_set
+
+ def pas_test(self):
+ pas = self.get_rodc_partial_attribute_set()
+ self.check_blocks(pas, 2)
+ req8 = drsuapi.DsGetNCChangesRequest8()
+ self.check_blocks(req8, 1)
+
+ # We expect the pas and req8, plus one block for each python object
+ self.check_blocks(None, 5)
+ req8.partial_attribute_set = pas
+ if req8.partial_attribute_set.attids[1] != 2:
+ raise Exception("Wrong value in attids[2]")
+ # we now get an additional reference
+ self.check_blocks(None, 6)
+
+ def test_run(self):
+ self.initial_blocks = talloc.total_blocks(None)
+ self.check_blocks(None, 0)
+ self.pas_test()
+ self.check_blocks(None, 0)
diff --git a/python/samba/tests/dcerpc/rpcecho.py b/python/samba/tests/dcerpc/rpcecho.py
new file mode 100644
index 0000000..949e4e2
--- /dev/null
+++ b/python/samba/tests/dcerpc/rpcecho.py
@@ -0,0 +1,71 @@
+# Unix SMB/CIFS implementation.
+# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
+#
+# 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/>.
+#
+
+"""Tests for samba.dceprc.rpcecho."""
+
+from samba.dcerpc import echo
+from samba.ndr import ndr_pack, ndr_unpack
+from samba.tests import RpcInterfaceTestCase, TestCase
+
+
+class RpcEchoTests(RpcInterfaceTestCase):
+
+ def setUp(self):
+ super().setUp()
+ self.conn = echo.rpcecho("ncalrpc:", self.get_loadparm())
+
+ def test_two_contexts(self):
+ self.conn2 = echo.rpcecho("ncalrpc:", self.get_loadparm(), basis_connection=self.conn)
+ self.assertEqual(3, self.conn2.AddOne(2))
+
+ def test_abstract_syntax(self):
+ self.assertEqual(("60a15ec5-4de8-11d7-a637-005056a20182", 1),
+ self.conn.abstract_syntax)
+
+ def test_addone(self):
+ self.assertEqual(2, self.conn.AddOne(1))
+
+ def test_echodata(self):
+ self.assertEqual([1, 2, 3], self.conn.EchoData([1, 2, 3]))
+
+ def test_call(self):
+ self.assertEqual(u"foobar", self.conn.TestCall(u"foobar"))
+
+ def test_surrounding(self):
+ surrounding_struct = echo.Surrounding()
+ surrounding_struct.x = 4
+ surrounding_struct.surrounding = [1, 2, 3, 4]
+ y = self.conn.TestSurrounding(surrounding_struct)
+ self.assertEqual(8 * [0], y.surrounding)
+
+ def test_manual_request(self):
+ self.assertEqual(b"\x01\x00\x00\x00", self.conn.request(0, chr(0) * 4))
+
+ def test_server_name(self):
+ self.assertEqual(None, self.conn.server_name)
+
+
+class NdrEchoTests(TestCase):
+
+ def test_info1_push(self):
+ x = echo.info1()
+ x.v = 42
+ self.assertEqual(b"\x2a", ndr_pack(x))
+
+ def test_info1_pull(self):
+ x = ndr_unpack(echo.info1, b"\x42")
+ self.assertEqual(x.v, 66)
diff --git a/python/samba/tests/dcerpc/sam.py b/python/samba/tests/dcerpc/sam.py
new file mode 100644
index 0000000..9029cce
--- /dev/null
+++ b/python/samba/tests/dcerpc/sam.py
@@ -0,0 +1,783 @@
+# -*- coding: utf-8 -*-
+#
+# Unix SMB/CIFS implementation.
+# Copyright © Jelmer Vernooij <jelmer@samba.org> 2008
+#
+# 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/>.
+#
+
+"""Tests for samba.dcerpc.sam."""
+
+from samba.dcerpc import samr, security, lsa
+from samba.dcerpc.samr import DomainGeneralInformation
+from samba.tests import RpcInterfaceTestCase
+from samba.tests import env_loadparm, delete_force
+
+from samba.credentials import Credentials
+from samba.auth import system_session
+from samba.samdb import SamDB
+from samba.dsdb import (
+ ATYPE_NORMAL_ACCOUNT,
+ ATYPE_WORKSTATION_TRUST,
+ GTYPE_SECURITY_UNIVERSAL_GROUP,
+ GTYPE_SECURITY_GLOBAL_GROUP)
+from samba import generate_random_password
+from samba.ndr import ndr_unpack
+import os
+
+
+# FIXME: Pidl should be doing this for us
+def toArray(handle, array, num_entries):
+ return [(entry.idx, entry.name) for entry in array.entries[:num_entries]]
+
+
+# Extract the rid from an ldb message, assumes that the message has a
+# objectSID attribute
+#
+def rid(msg):
+ sid = ndr_unpack(security.dom_sid, msg["objectSID"][0])
+ (_, rid) = sid.split()
+ return rid
+
+
+# Calculate the request size for EnumDomainUsers and EnumDomainGroups calls
+# to hold the specified number of entries.
+# We use the w2k3 element size value of 54, code under test
+# rounds this up i.e. (1+(max_size/SAMR_ENUM_USERS_MULTIPLIER))
+#
+def calc_max_size(num_entries):
+ return (num_entries - 1) * 54
+
+
+class SamrTests(RpcInterfaceTestCase):
+
+ def setUp(self):
+ super().setUp()
+ self.conn = samr.samr("ncalrpc:", self.get_loadparm())
+ self.open_samdb()
+ self.open_domain_handle()
+
+ #
+ # Open the samba database
+ #
+ def open_samdb(self):
+ self.lp = env_loadparm()
+ self.domain = os.environ["DOMAIN"]
+ self.creds = Credentials()
+ self.creds.guess(self.lp)
+ self.session = system_session()
+ self.samdb = SamDB(
+ session_info=self.session, credentials=self.creds, lp=self.lp)
+
+ #
+ # Open a SAMR Domain handle
+ def open_domain_handle(self):
+ self.handle = self.conn.Connect2(
+ None, security.SEC_FLAG_MAXIMUM_ALLOWED)
+
+ self.domain_sid = self.conn.LookupDomain(
+ self.handle, lsa.String(self.domain))
+
+ self.domain_handle = self.conn.OpenDomain(
+ self.handle, security.SEC_FLAG_MAXIMUM_ALLOWED, self.domain_sid)
+
+ # Filter a list of records, removing those that are not part of the
+ # current domain.
+ #
+ def filter_domain(self, unfiltered):
+ def sid(msg):
+ sid = ndr_unpack(security.dom_sid, msg["objectSID"][0])
+ (x, _) = sid.split()
+ return x
+
+ dom_sid = security.dom_sid(self.samdb.get_domain_sid())
+ return [x for x in unfiltered if sid(x) == dom_sid]
+
+ def test_connect5(self):
+ (level, info, handle) =\
+ self.conn.Connect5(None, 0, 1, samr.ConnectInfo1())
+
+ def test_connect2(self):
+ handle = self.conn.Connect2(None, security.SEC_FLAG_MAXIMUM_ALLOWED)
+ self.assertTrue(handle is not None)
+
+ def test_EnumDomains(self):
+ handle = self.conn.Connect2(None, security.SEC_FLAG_MAXIMUM_ALLOWED)
+ toArray(*self.conn.EnumDomains(handle, 0, 4294967295))
+ self.conn.Close(handle)
+
+ # Create groups based on the id list supplied, the id is used to
+ # form a unique name and description.
+ #
+ # returns a list of the created dn's, which can be passed to delete_dns
+ # to clean up after the test has run.
+ def create_groups(self, ids):
+ dns = []
+ for i in ids:
+ name = "SAMR_GRP%d" % i
+ dn = "cn=%s,cn=Users,%s" % (name, self.samdb.domain_dn())
+ delete_force(self.samdb, dn)
+
+ self.samdb.newgroup(name)
+ dns.append(dn)
+ return dns
+
+ # Create user accounts based on the id list supplied, the id is used to
+ # form a unique name and description.
+ #
+ # returns a list of the created dn's, which can be passed to delete_dns
+ # to clean up after the test has run.
+ def create_users(self, ids):
+ dns = []
+ for i in ids:
+ name = "SAMR_USER%d" % i
+ dn = "cn=%s,CN=USERS,%s" % (name, self.samdb.domain_dn())
+ delete_force(self.samdb, dn)
+
+ # We only need the user to exist, we don't need a password
+ self.samdb.newuser(
+ name,
+ password=None,
+ setpassword=False,
+ description="Description for " + name,
+ givenname="given%dname" % i,
+ surname="surname%d" % i)
+ dns.append(dn)
+ return dns
+
+ # Create computer accounts based on the id list supplied, the id is used to
+ # form a unique name and description.
+ #
+ # returns a list of the created dn's, which can be passed to delete_dns
+ # to clean up after the test has run.
+ def create_computers(self, ids):
+ dns = []
+ for i in ids:
+ name = "SAMR_CMP%d" % i
+ dn = "cn=%s,cn=COMPUTERS,%s" % (name, self.samdb.domain_dn())
+ delete_force(self.samdb, dn)
+
+ self.samdb.newcomputer(name, description="Description of " + name)
+ dns.append(dn)
+ return dns
+
+ # Delete the specified dn's.
+ #
+ # Used to clean up entries created by individual tests.
+ #
+ def delete_dns(self, dns):
+ for dn in dns:
+ delete_force(self.samdb, dn)
+
+ # Common tests for QueryDisplayInfo
+ #
+ def _test_QueryDisplayInfo(
+ self, level, check_results, select, attributes, add_elements):
+ #
+ # Get the expected results by querying the samdb database directly.
+ # We do this rather than use a list of expected results as this runs
+ # with other tests so we do not have a known fixed list of elements
+ expected = self.samdb.search(expression=select, attrs=attributes)
+ self.assertTrue(len(expected) > 0)
+
+ #
+ # Perform QueryDisplayInfo with max results greater than the expected
+ # number of results.
+ (ts, rs, actual) = self.conn.QueryDisplayInfo(
+ self.domain_handle, level, 0, 1024, 4294967295)
+
+ self.assertEqual(len(expected), ts)
+ self.assertEqual(len(expected), rs)
+ check_results(expected, actual.entries)
+
+ #
+ # Perform QueryDisplayInfo with max results set to the number of
+ # results returned from the first query, should return the same results
+ (ts1, rs1, actual1) = self.conn.QueryDisplayInfo(
+ self.domain_handle, level, 0, rs, 4294967295)
+ self.assertEqual(ts, ts1)
+ self.assertEqual(rs, rs1)
+ check_results(expected, actual1.entries)
+
+ #
+ # Perform QueryDisplayInfo and get the last two results.
+ # Note: We are assuming there are at least three entries
+ self.assertTrue(ts > 2)
+ (ts2, rs2, actual2) = self.conn.QueryDisplayInfo(
+ self.domain_handle, level, (ts - 2), 2, 4294967295)
+ self.assertEqual(ts, ts2)
+ self.assertEqual(2, rs2)
+ check_results(list(expected)[-2:], actual2.entries)
+
+ #
+ # Perform QueryDisplayInfo and get the first two results.
+ # Note: We are assuming there are at least three entries
+ self.assertTrue(ts > 2)
+ (ts2, rs2, actual2) = self.conn.QueryDisplayInfo(
+ self.domain_handle, level, 0, 2, 4294967295)
+ self.assertEqual(ts, ts2)
+ self.assertEqual(2, rs2)
+ check_results(list(expected)[:2], actual2.entries)
+
+ #
+ # Perform QueryDisplayInfo and get two results in the middle of the
+ # list i.e. not the first or the last entry.
+ # Note: We are assuming there are at least four entries
+ self.assertTrue(ts > 3)
+ (ts2, rs2, actual2) = self.conn.QueryDisplayInfo(
+ self.domain_handle, level, 1, 2, 4294967295)
+ self.assertEqual(ts, ts2)
+ self.assertEqual(2, rs2)
+ check_results(list(expected)[1:2], actual2.entries)
+
+ #
+ # To check that cached values are being returned rather than the
+ # results being re-read from disk we add elements, and request all
+ # but the first result.
+ #
+ dns = add_elements([1000, 1002, 1003, 1004])
+
+ #
+ # Perform QueryDisplayInfo and get all but the first result.
+ # We should be using the cached results so the entries we just added
+ # should not be present
+ (ts3, rs3, actual3) = self.conn.QueryDisplayInfo(
+ self.domain_handle, level, 1, 1024, 4294967295)
+ self.assertEqual(ts, ts3)
+ self.assertEqual(len(expected) - 1, rs3)
+ check_results(list(expected)[1:], actual3.entries)
+
+ #
+ # Perform QueryDisplayInfo and get all the results.
+ # As the start index is zero we should reread the data from disk and
+ # the added entries should be there
+ new = self.samdb.search(expression=select, attrs=attributes)
+ (ts4, rs4, actual4) = self.conn.QueryDisplayInfo(
+ self.domain_handle, level, 0, 1024, 4294967295)
+ self.assertEqual(len(expected) + len(dns), ts4)
+ self.assertEqual(len(expected) + len(dns), rs4)
+ check_results(new, actual4.entries)
+
+ # Delete the added DN's and query all but the first entry.
+ # This should ensure the cached results are used and that the
+ # missing entry code is triggered.
+ self.delete_dns(dns)
+ (ts5, rs5, actual5) = self.conn.QueryDisplayInfo(
+ self.domain_handle, level, 1, 1024, 4294967295)
+ self.assertEqual(len(expected) + len(dns), ts5)
+ # The deleted results will be filtered from the result set so should
+ # be missing from the returned results.
+ # Note: depending on the GUID order, the first result in the cache may
+ # be a deleted entry, in which case the results will contain all
+ # the expected elements, otherwise the first expected result will
+ # be missing.
+ if rs5 == len(expected):
+ check_results(expected, actual5.entries)
+ elif rs5 == (len(expected) - 1):
+ check_results(list(expected)[1:], actual5.entries)
+ else:
+ self.fail("Incorrect number of entries {0}".format(rs5))
+
+ #
+ # Perform QueryDisplayInfo specifying an index past the end of the
+ # available data.
+ # Should return no data.
+ (ts6, rs6, actual6) = self.conn.QueryDisplayInfo(
+ self.domain_handle, level, ts5, 1, 4294967295)
+ self.assertEqual(ts5, ts6)
+ self.assertEqual(0, rs6)
+
+ self.conn.Close(self.handle)
+
+ # Test for QueryDisplayInfo, Level 1
+ # Returns the sAMAccountName, displayName and description for all
+ # the user accounts.
+ #
+ def test_QueryDisplayInfo_level_1(self):
+ def check_results(expected, actual):
+ # Assume the QueryDisplayInfo and ldb.search return their results
+ # in the same order
+ for (e, a) in zip(expected, actual):
+ self.assertTrue(isinstance(a, samr.DispEntryGeneral))
+ self.assertEqual(str(e["sAMAccountName"]),
+ str(a.account_name))
+
+ # The displayName and description are optional.
+ # In the expected results they will be missing, in
+ # samr.DispEntryGeneral the corresponding attribute will have a
+ # length of zero.
+ #
+ if a.full_name.length == 0:
+ self.assertFalse("displayName" in e)
+ else:
+ self.assertEqual(str(e["displayName"]), str(a.full_name))
+
+ if a.description.length == 0:
+ self.assertFalse("description" in e)
+ else:
+ self.assertEqual(str(e["description"]),
+ str(a.description))
+ # Create four user accounts
+ # to ensure that we have the minimum needed for the tests.
+ dns = self.create_users([1, 2, 3, 4])
+
+ select = "(&(objectclass=user)(sAMAccountType={0}))".format(
+ ATYPE_NORMAL_ACCOUNT)
+ attributes = ["sAMAccountName", "displayName", "description"]
+ self._test_QueryDisplayInfo(
+ 1, check_results, select, attributes, self.create_users)
+
+ self.delete_dns(dns)
+
+ # Test for QueryDisplayInfo, Level 2
+ # Returns the sAMAccountName and description for all
+ # the computer accounts.
+ #
+ def test_QueryDisplayInfo_level_2(self):
+ def check_results(expected, actual):
+ # Assume the QueryDisplayInfo and ldb.search return their results
+ # in the same order
+ for (e, a) in zip(expected, actual):
+ self.assertTrue(isinstance(a, samr.DispEntryFull))
+ self.assertEqual(str(e["sAMAccountName"]),
+ str(a.account_name))
+
+ # The description is optional.
+ # In the expected results they will be missing, in
+ # samr.DispEntryGeneral the corresponding attribute will have a
+ # length of zero.
+ #
+ if a.description.length == 0:
+ self.assertFalse("description" in e)
+ else:
+ self.assertEqual(str(e["description"]),
+ str(a.description))
+
+ # Create four computer accounts
+ # to ensure that we have the minimum needed for the tests.
+ dns = self.create_computers([1, 2, 3, 4])
+
+ select = "(&(objectclass=user)(sAMAccountType={0}))".format(
+ ATYPE_WORKSTATION_TRUST)
+ attributes = ["sAMAccountName", "description"]
+ self._test_QueryDisplayInfo(
+ 2, check_results, select, attributes, self.create_computers)
+
+ self.delete_dns(dns)
+
+ # Test for QueryDisplayInfo, Level 3
+ # Returns the sAMAccountName and description for all
+ # the groups.
+ #
+ def test_QueryDisplayInfo_level_3(self):
+ def check_results(expected, actual):
+ # Assume the QueryDisplayInfo and ldb.search return their results
+ # in the same order
+ for (e, a) in zip(expected, actual):
+ self.assertTrue(isinstance(a, samr.DispEntryFullGroup))
+ self.assertEqual(str(e["sAMAccountName"]),
+ str(a.account_name))
+
+ # The description is optional.
+ # In the expected results they will be missing, in
+ # samr.DispEntryGeneral the corresponding attribute will have a
+ # length of zero.
+ #
+ if a.description.length == 0:
+ self.assertFalse("description" in e)
+ else:
+ self.assertEqual(str(e["description"]),
+ str(a.description))
+
+ # Create four groups
+ # to ensure that we have the minimum needed for the tests.
+ dns = self.create_groups([1, 2, 3, 4])
+
+ select = "(&(|(groupType=%d)(groupType=%d))(objectClass=group))" % (
+ GTYPE_SECURITY_UNIVERSAL_GROUP,
+ GTYPE_SECURITY_GLOBAL_GROUP)
+ attributes = ["sAMAccountName", "description"]
+ self._test_QueryDisplayInfo(
+ 3, check_results, select, attributes, self.create_groups)
+
+ self.delete_dns(dns)
+
+ # Test for QueryDisplayInfo, Level 4
+ # Returns the sAMAccountName (as an ASCII string)
+ # for all the user accounts.
+ #
+ def test_QueryDisplayInfo_level_4(self):
+ def check_results(expected, actual):
+ # Assume the QueryDisplayInfo and ldb.search return their results
+ # in the same order
+ for (e, a) in zip(expected, actual):
+ self.assertTrue(isinstance(a, samr.DispEntryAscii))
+ self.assertTrue(
+ isinstance(a.account_name, lsa.AsciiStringLarge))
+ self.assertEqual(
+ str(e["sAMAccountName"]), str(a.account_name.string))
+
+ # Create four user accounts
+ # to ensure that we have the minimum needed for the tests.
+ dns = self.create_users([1, 2, 3, 4])
+
+ select = "(&(objectclass=user)(sAMAccountType={0}))".format(
+ ATYPE_NORMAL_ACCOUNT)
+ attributes = ["sAMAccountName", "displayName", "description"]
+ self._test_QueryDisplayInfo(
+ 4, check_results, select, attributes, self.create_users)
+
+ self.delete_dns(dns)
+
+ # Test for QueryDisplayInfo, Level 5
+ # Returns the sAMAccountName (as an ASCII string)
+ # for all the groups.
+ #
+ def test_QueryDisplayInfo_level_5(self):
+ def check_results(expected, actual):
+ # Assume the QueryDisplayInfo and ldb.search return their results
+ # in the same order
+ for (e, a) in zip(expected, actual):
+ self.assertTrue(isinstance(a, samr.DispEntryAscii))
+ self.assertTrue(
+ isinstance(a.account_name, lsa.AsciiStringLarge))
+ self.assertEqual(
+ str(e["sAMAccountName"]), str(a.account_name.string))
+
+ # Create four groups
+ # to ensure that we have the minimum needed for the tests.
+ dns = self.create_groups([1, 2, 3, 4])
+
+ select = "(&(|(groupType=%d)(groupType=%d))(objectClass=group))" % (
+ GTYPE_SECURITY_UNIVERSAL_GROUP,
+ GTYPE_SECURITY_GLOBAL_GROUP)
+ attributes = ["sAMAccountName", "description"]
+ self._test_QueryDisplayInfo(
+ 5, check_results, select, attributes, self.create_groups)
+
+ self.delete_dns(dns)
+
+ def test_EnumDomainGroups(self):
+ def check_results(expected, actual):
+ for (e, a) in zip(expected, actual):
+ self.assertTrue(isinstance(a, samr.SamEntry))
+ self.assertEqual(
+ str(e["sAMAccountName"]), str(a.name.string))
+
+ # Create four groups
+ # to ensure that we have the minimum needed for the tests.
+ dns = self.create_groups([1, 2, 3, 4])
+
+ #
+ # Get the expected results by querying the samdb database directly.
+ # We do this rather than use a list of expected results as this runs
+ # with other tests so we do not have a known fixed list of elements
+ select = "(&(|(groupType=%d)(groupType=%d))(objectClass=group))" % (
+ GTYPE_SECURITY_UNIVERSAL_GROUP,
+ GTYPE_SECURITY_GLOBAL_GROUP)
+ attributes = ["sAMAccountName", "objectSID"]
+ unfiltered = self.samdb.search(expression=select, attrs=attributes)
+ filtered = self.filter_domain(unfiltered)
+ self.assertTrue(len(filtered) > 4)
+
+ # Sort the expected results by rid
+ expected = sorted(list(filtered), key=rid)
+
+ #
+ # Perform EnumDomainGroups with max size greater than the expected
+ # number of results. Allow for an extra 10 entries
+ #
+ max_size = calc_max_size(len(expected) + 10)
+ (resume_handle, actual, num_entries) = self.conn.EnumDomainGroups(
+ self.domain_handle, 0, max_size)
+ self.assertEqual(len(expected), num_entries)
+ check_results(expected, actual.entries)
+
+ #
+ # Perform EnumDomainGroups with size set to so that it contains
+ # 4 entries.
+ #
+ max_size = calc_max_size(4)
+ (resume_handle, actual, num_entries) = self.conn.EnumDomainGroups(
+ self.domain_handle, 0, max_size)
+ self.assertEqual(4, num_entries)
+ check_results(expected[:4], actual.entries)
+
+ #
+ # Try calling with resume_handle greater than number of entries
+ # Should return no results and a resume handle of 0
+ max_size = calc_max_size(1)
+ rh = len(expected)
+ self.conn.Close(self.handle)
+ (resume_handle, a, num_entries) = self.conn.EnumDomainGroups(
+ self.domain_handle, rh, max_size)
+
+ self.assertEqual(0, num_entries)
+ self.assertEqual(0, resume_handle)
+
+ #
+ # Enumerate through the domain groups one element at a time.
+ #
+ max_size = calc_max_size(1)
+ actual = []
+ (resume_handle, a, num_entries) = self.conn.EnumDomainGroups(
+ self.domain_handle, 0, max_size)
+ while resume_handle:
+ self.assertEqual(1, num_entries)
+ actual.append(a.entries[0])
+ (resume_handle, a, num_entries) = self.conn.EnumDomainGroups(
+ self.domain_handle, resume_handle, max_size)
+ if num_entries:
+ actual.append(a.entries[0])
+
+ #
+ # Check that the cached results are being returned.
+ # Obtain a new resume_handle and insert new entries into the
+ # into the DB
+ #
+ actual = []
+ max_size = calc_max_size(1)
+ (resume_handle, a, num_entries) = self.conn.EnumDomainGroups(
+ self.domain_handle, 0, max_size)
+ extra_dns = self.create_groups([1000, 1002, 1003, 1004])
+ while resume_handle:
+ self.assertEqual(1, num_entries)
+ actual.append(a.entries[0])
+ (resume_handle, a, num_entries) = self.conn.EnumDomainGroups(
+ self.domain_handle, resume_handle, max_size)
+ if num_entries:
+ actual.append(a.entries[0])
+
+ self.assertEqual(len(expected), len(actual))
+ check_results(expected, actual)
+
+ #
+ # Perform EnumDomainGroups, we should read the newly added domains
+ #
+ max_size = calc_max_size(len(expected) + len(extra_dns) + 10)
+ (resume_handle, actual, num_entries) = self.conn.EnumDomainGroups(
+ self.domain_handle, 0, max_size)
+ self.assertEqual(len(expected) + len(extra_dns), num_entries)
+
+ #
+ # Get a new expected result set by querying the database directly
+ unfiltered01 = self.samdb.search(expression=select, attrs=attributes)
+ filtered01 = self.filter_domain(unfiltered01)
+ self.assertTrue(len(filtered01) > len(expected))
+
+ # Sort the expected results by rid
+ expected01 = sorted(list(filtered01), key=rid)
+
+ #
+ # Now check that we read the new entries.
+ #
+ check_results(expected01, actual.entries)
+
+ #
+ # Check that deleted results are handled correctly.
+ # Obtain a new resume_handle and delete entries from the DB.
+ #
+ actual = []
+ max_size = calc_max_size(1)
+ (resume_handle, a, num_entries) = self.conn.EnumDomainGroups(
+ self.domain_handle, 0, max_size)
+ self.delete_dns(extra_dns)
+ while resume_handle and num_entries:
+ self.assertEqual(1, num_entries)
+ actual.append(a.entries[0])
+ (resume_handle, a, num_entries) = self.conn.EnumDomainGroups(
+ self.domain_handle, resume_handle, max_size)
+ if num_entries:
+ actual.append(a.entries[0])
+
+ self.assertEqual(len(expected), len(actual))
+ check_results(expected, actual)
+
+ self.delete_dns(dns)
+
+ def test_EnumDomainUsers(self):
+ def check_results(expected, actual):
+ for (e, a) in zip(expected, actual):
+ self.assertTrue(isinstance(a, samr.SamEntry))
+ self.assertEqual(
+ str(e["sAMAccountName"]), str(a.name.string))
+
+ # Create four users
+ # to ensure that we have the minimum needed for the tests.
+ dns = self.create_users([1, 2, 3, 4])
+
+ #
+ # Get the expected results by querying the samdb database directly.
+ # We do this rather than use a list of expected results as this runs
+ # with other tests so we do not have a known fixed list of elements
+ select = "(objectClass=user)"
+ attributes = ["sAMAccountName", "objectSID", "userAccountConrol"]
+ unfiltered = self.samdb.search(expression=select, attrs=attributes)
+ filtered = self.filter_domain(unfiltered)
+ self.assertTrue(len(filtered) > 4)
+
+ # Sort the expected results by rid
+ expected = sorted(list(filtered), key=rid)
+
+ #
+ # Perform EnumDomainUsers with max_size greater than required for the
+ # expected number of results. We should get all the results.
+ #
+ max_size = calc_max_size(len(expected) + 10)
+ (resume_handle, actual, num_entries) = self.conn.EnumDomainUsers(
+ self.domain_handle, 0, 0, max_size)
+ self.assertEqual(len(expected), num_entries)
+ check_results(expected, actual.entries)
+
+ #
+ # Perform EnumDomainUsers with size set to so that it contains
+ # 4 entries.
+ max_size = calc_max_size(4)
+ (resume_handle, actual, num_entries) = self.conn.EnumDomainUsers(
+ self.domain_handle, 0, 0, max_size)
+ self.assertEqual(4, num_entries)
+ check_results(expected[:4], actual.entries)
+
+ #
+ # Try calling with resume_handle greater than number of entries
+ # Should return no results and a resume handle of 0
+ rh = len(expected)
+ max_size = calc_max_size(1)
+ self.conn.Close(self.handle)
+ (resume_handle, a, num_entries) = self.conn.EnumDomainUsers(
+ self.domain_handle, rh, 0, max_size)
+
+ self.assertEqual(0, num_entries)
+ self.assertEqual(0, resume_handle)
+
+ #
+ # Enumerate through the domain users one element at a time.
+ # We should get all the results.
+ #
+ actual = []
+ max_size = calc_max_size(1)
+ (resume_handle, a, num_entries) = self.conn.EnumDomainUsers(
+ self.domain_handle, 0, 0, max_size)
+ while resume_handle:
+ self.assertEqual(1, num_entries)
+ actual.append(a.entries[0])
+ (resume_handle, a, num_entries) = self.conn.EnumDomainUsers(
+ self.domain_handle, resume_handle, 0, max_size)
+ if num_entries:
+ actual.append(a.entries[0])
+
+ self.assertEqual(len(expected), len(actual))
+ check_results(expected, actual)
+
+ #
+ # Check that the cached results are being returned.
+ # Obtain a new resume_handle and insert new entries into the
+ # into the DB. As the entries were added after the results were cached
+ # they should not show up in the returned results.
+ #
+ actual = []
+ max_size = calc_max_size(1)
+ (resume_handle, a, num_entries) = self.conn.EnumDomainUsers(
+ self.domain_handle, 0, 0, max_size)
+ extra_dns = self.create_users([1000, 1002, 1003, 1004])
+ while resume_handle:
+ self.assertEqual(1, num_entries)
+ actual.append(a.entries[0])
+ (resume_handle, a, num_entries) = self.conn.EnumDomainUsers(
+ self.domain_handle, resume_handle, 0, max_size)
+ if num_entries:
+ actual.append(a.entries[0])
+
+ self.assertEqual(len(expected), len(actual))
+ check_results(expected, actual)
+
+ #
+ # Perform EnumDomainUsers, we should read the newly added groups
+ # As resume_handle is zero, the results will be read from disk.
+ #
+ max_size = calc_max_size(len(expected) + len(extra_dns) + 10)
+ (resume_handle, actual, num_entries) = self.conn.EnumDomainUsers(
+ self.domain_handle, 0, 0, max_size)
+ self.assertEqual(len(expected) + len(extra_dns), num_entries)
+
+ #
+ # Get a new expected result set by querying the database directly
+ unfiltered01 = self.samdb.search(expression=select, attrs=attributes)
+ filtered01 = self.filter_domain(unfiltered01)
+ self.assertTrue(len(filtered01) > len(expected))
+
+ # Sort the expected results by rid
+ expected01 = sorted(list(filtered01), key=rid)
+
+ #
+ # Now check that we read the new entries.
+ #
+ self.assertEqual(len(expected01), num_entries)
+ check_results(expected01, actual.entries)
+
+ self.delete_dns(dns + extra_dns)
+
+ def test_DomGeneralInformation_num_users(self):
+ info = self.conn.QueryDomainInfo(
+ self.domain_handle, DomainGeneralInformation)
+ #
+ # Enumerate through all the domain users and compare the number
+ # returned against QueryDomainInfo they should be the same
+ max_size = calc_max_size(1)
+ (resume_handle, a, num_entries) = self.conn.EnumDomainUsers(
+ self.domain_handle, 0, 0, max_size)
+ count = num_entries
+ while resume_handle:
+ self.assertEqual(1, num_entries)
+ (resume_handle, a, num_entries) = self.conn.EnumDomainUsers(
+ self.domain_handle, resume_handle, 0, max_size)
+ count += num_entries
+
+ self.assertEqual(count, info.num_users)
+
+ def test_DomGeneralInformation_num_groups(self):
+ info = self.conn.QueryDomainInfo(
+ self.domain_handle, DomainGeneralInformation)
+ #
+ # Enumerate through all the domain groups and compare the number
+ # returned against QueryDomainInfo they should be the same
+ max_size = calc_max_size(1)
+ (resume_handle, a, num_entries) = self.conn.EnumDomainGroups(
+ self.domain_handle, 0, max_size)
+ count = num_entries
+ while resume_handle:
+ self.assertEqual(1, num_entries)
+ (resume_handle, a, num_entries) = self.conn.EnumDomainGroups(
+ self.domain_handle, resume_handle, max_size)
+ count += num_entries
+
+ self.assertEqual(count, info.num_groups)
+
+ def test_DomGeneralInformation_num_aliases(self):
+ info = self.conn.QueryDomainInfo(
+ self.domain_handle, DomainGeneralInformation)
+ #
+ # Enumerate through all the domain aliases and compare the number
+ # returned against QueryDomainInfo they should be the same
+ max_size = calc_max_size(1)
+ (resume_handle, a, num_entries) = self.conn.EnumDomainAliases(
+ self.domain_handle, 0, max_size)
+ count = num_entries
+ while resume_handle:
+ self.assertEqual(1, num_entries)
+ (resume_handle, a, num_entries) = self.conn.EnumDomainAliases(
+ self.domain_handle, resume_handle, max_size)
+ count += num_entries
+
+ self.assertEqual(count, info.num_aliases)
diff --git a/python/samba/tests/dcerpc/samr_change_password.py b/python/samba/tests/dcerpc/samr_change_password.py
new file mode 100644
index 0000000..f872bba
--- /dev/null
+++ b/python/samba/tests/dcerpc/samr_change_password.py
@@ -0,0 +1,187 @@
+# Unix SMB/CIFS implementation.
+#
+# Copyright © 2020 Andreas Schneider <asn@samba.org>
+#
+# 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/>.
+#
+
+"""Tests for samba.dcerpc.samr.password"""
+
+import ctypes
+import samba.tests
+
+from samba import crypto, generate_random_password, generate_random_bytes, ntstatus
+from samba.auth import system_session
+from samba.credentials import Credentials
+from samba.credentials import SMB_ENCRYPTION_REQUIRED
+from samba.dcerpc import samr, security, lsa
+from samba.samdb import SamDB
+from samba.tests import RpcInterfaceTestCase
+
+
+class SamrPasswordTests(RpcInterfaceTestCase):
+ def setUp(self):
+ super().setUp()
+ self.open_samdb()
+
+ self.create_user_account(10000)
+
+ self.remote_server = samba.tests.env_get_var_value('SERVER')
+ self.remote_domain = samba.tests.env_get_var_value('DOMAIN')
+ self.remote_user = samba.tests.env_get_var_value('USERNAME')
+ self.remote_password = samba.tests.env_get_var_value('PASSWORD')
+ self.remote_binding_string = "ncacn_np:%s[krb5]" % (self.remote_server)
+
+ self.remote_creds = Credentials()
+ self.remote_creds.guess(self.lp)
+ self.remote_creds.set_username(self.remote_user)
+ self.remote_creds.set_password(self.remote_password)
+
+ def tearDown(self):
+ super().tearDown()
+
+ samr.Close(self.user_handle)
+ samr.Close(self.domain_handle)
+ samr.Close(self.handle)
+
+ samba.tests.delete_force(self.samdb, self.user_dn)
+
+ #
+ # Open the samba database
+ #
+ def open_samdb(self):
+ self.lp = samba.tests.env_loadparm()
+
+ self.local_creds = Credentials()
+ self.local_creds.guess(self.lp)
+ self.session = system_session()
+ self.samdb = SamDB(session_info=self.session,
+ credentials=self.local_creds,
+ lp=self.lp)
+
+ #
+ # Open a SAMR Domain handle
+ #
+ def open_domain_handle(self):
+ self.handle = self.conn.Connect2(None,
+ security.SEC_FLAG_MAXIMUM_ALLOWED)
+
+ self.domain_sid = self.conn.LookupDomain(self.handle,
+ lsa.String(self.remote_domain))
+
+ self.domain_handle = self.conn.OpenDomain(self.handle,
+ security.SEC_FLAG_MAXIMUM_ALLOWED,
+ self.domain_sid)
+
+ def open_user_handle(self):
+ name = lsa.String(self.user_name)
+
+ rids = self.conn.LookupNames(self.domain_handle, [name])
+
+ self.user_handle = self.conn.OpenUser(self.domain_handle,
+ security.SEC_FLAG_MAXIMUM_ALLOWED,
+ rids[0].ids[0])
+ #
+ # Create a test user account
+ #
+ def create_user_account(self, user_id):
+ self.user_name = ("SAMR_USER_%d" % user_id)
+ self.user_pass = generate_random_password(32, 32)
+ self.user_dn = "cn=%s,cn=users,%s" % (self.user_name, self.samdb.domain_dn())
+
+ samba.tests.delete_force(self.samdb, self.user_dn)
+
+ self.samdb.newuser(self.user_name,
+ self.user_pass,
+ description="Password for " + self.user_name + " is " + self.user_pass,
+ givenname=self.user_name,
+ surname=self.user_name)
+
+
+ def init_samr_CryptPassword(self, password, session_key):
+
+ def encode_pw_buffer(password):
+ data = bytearray([0] * 516)
+
+ p = samba.string_to_byte_array(password.encode('utf-16-le'))
+ plen = len(p)
+
+ b = generate_random_bytes(512 - plen)
+
+ i = 512 - plen
+ data[0:i] = b
+ data[i:i+plen] = p
+ data[512:516] = plen.to_bytes(4, byteorder='little')
+
+ return bytes(data)
+
+ # This is a test, so always allow to encrypt using RC4
+ try:
+ crypto.set_relax_mode()
+ encrypted_blob = samba.arcfour_encrypt(session_key, encode_pw_buffer(password))
+ finally:
+ crypto.set_strict_mode()
+
+ out_blob = samr.CryptPassword()
+ out_blob.data = list(encrypted_blob)
+
+ return out_blob
+
+
+ def test_setUserInfo2_Password(self, password='P@ssw0rd'):
+ self.conn = samr.samr(self.remote_binding_string,
+ self.get_loadparm(),
+ self.remote_creds)
+ self.open_domain_handle()
+ self.open_user_handle()
+
+ password='P@ssw0rd'
+
+ level = 24
+ info = samr.UserInfo24()
+
+ info.password_expired = 0
+ info.password = self.init_samr_CryptPassword(password, self.conn.session_key)
+
+ # If the server is in FIPS mode, it should reject the password change!
+ try:
+ self.conn.SetUserInfo2(self.user_handle, level, info)
+ except samba.NTSTATUSError as e:
+ code = ctypes.c_uint32(e.args[0]).value
+ print(code)
+ if ((code == ntstatus.NT_STATUS_ACCESS_DENIED) and
+ (self.lp.weak_crypto == 'disallowed')):
+ pass
+ else:
+ raise
+
+
+ def test_setUserInfo2_Password_Encrypted(self, password='P@ssw0rd'):
+ self.remote_creds.set_smb_encryption(SMB_ENCRYPTION_REQUIRED)
+
+ self.conn = samr.samr(self.remote_binding_string,
+ self.get_loadparm(),
+ self.remote_creds)
+ self.open_domain_handle()
+ self.open_user_handle()
+
+ password='P@ssw0rd'
+
+ level = 24
+ info = samr.UserInfo24()
+
+ info.password_expired = 0
+ info.password = self.init_samr_CryptPassword(password, self.conn.session_key)
+
+ self.conn.SetUserInfo2(self.user_handle, level, info)
diff --git a/python/samba/tests/dcerpc/srvsvc.py b/python/samba/tests/dcerpc/srvsvc.py
new file mode 100644
index 0000000..4baaec3
--- /dev/null
+++ b/python/samba/tests/dcerpc/srvsvc.py
@@ -0,0 +1,68 @@
+# -*- coding: utf-8 -*-
+#
+# Unix SMB/CIFS implementation.
+# Copyright © Dhananjay Sathe <dhanajaysathe@gmail.com> 2011
+# Copyright © Jelmer Vernooij <jelmer@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/>.
+#
+
+"""Tests for samba.dcerpc.srvsvc."""
+
+from samba.dcerpc import srvsvc
+from samba.tests import RpcInterfaceTestCase
+
+
+class SrvsvcTests(RpcInterfaceTestCase):
+
+ def setUp(self):
+ super().setUp()
+ self.conn = srvsvc.srvsvc("ncalrpc:", self.get_loadparm())
+ self.server_unc = "\\\\."
+
+ def getDummyShareObject(self):
+ share = srvsvc.NetShareInfo2()
+
+ share.name = u'test'
+ share.comment = u'test share'
+ share.type = srvsvc.STYPE_DISKTREE
+ share.current_users = 0x00000000
+ share.max_users = -1
+ share.password = None
+ share.path = u'C:\\tmp' # some random path
+ share.permissions = 123434566
+ return share
+
+ def test_NetShareAdd(self):
+ self.skipTest("Dangerous test")
+ share = self.getDummyShareObject()
+ self.conn.NetShareAdd(self.server_unc, 2, share, None)
+
+ def test_NetShareSetInfo(self):
+ self.skipTest("Dangerous test")
+ share = self.getDummyShareObject()
+ parm_error = 0x00000000
+ self.conn.NetShareAdd(self.server_unc, 502, share, parm_error)
+ name = share.name
+ share.comment = "now successfully modified "
+ parm_error = self.pipe.NetShareSetInfo(self.server_unc, name,
+ 502, share, parm_error)
+
+ def test_NetShareDel(self):
+ self.skipTest("Dangerous test")
+ share = self.getDummyShareObject()
+ parm_error = 0x00000000
+ self.expectFailure("NetShareAdd doesn't work properly from Python",
+ self.conn.NetShareAdd, self.server_unc, 502, share, parm_error)
+ self.conn.NetShareDel(self.server_unc, share.name, 0)
diff --git a/python/samba/tests/dcerpc/string_tests.py b/python/samba/tests/dcerpc/string_tests.py
new file mode 100644
index 0000000..a3426bb
--- /dev/null
+++ b/python/samba/tests/dcerpc/string_tests.py
@@ -0,0 +1,132 @@
+# Unix SMB/CIFS implementation.
+# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2016
+#
+# 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/>.
+#
+
+"""Tests for string and unicode handling in PIDL generated bindings
+samba.dcerpc.*"""
+
+from samba.dcerpc import drsblobs
+import samba.tests
+from samba.ndr import ndr_unpack, ndr_pack
+import talloc
+import gc
+
+
+class TestException(Exception):
+ pass
+
+
+class StringTests(samba.tests.TestCase):
+
+ def setUp(self):
+ super().setUp()
+ talloc.enable_null_tracking()
+ self.startup_blocks = talloc.total_blocks()
+
+ def tearDown(self):
+ super().tearDown()
+ gc.collect()
+ if talloc.total_blocks() != self.startup_blocks:
+ talloc.report_full()
+ self.fail("it appears we are leaking memory")
+
+ def test_string_from_python(self):
+ info = drsblobs.repsFromTo2OtherInfo()
+ info.dns_name1 = "hello.example.com"
+ info.dns_name2 = "goodbye.example.com"
+ gc.collect()
+ self.assertIsNotNone(info)
+ self.assertEqual(info.dns_name1, "hello.example.com")
+ self.assertEqual(info.dns_name2, "goodbye.example.com")
+
+ info.dns_name1 = ""
+ info.dns_name2 = "goodbye.example.com"
+
+ self.assertEqual(info.dns_name1, "")
+ self.assertEqual(info.dns_name2, "goodbye.example.com")
+
+ info.dns_name2 = None
+
+ self.assertEqual(info.dns_name1, "")
+ self.assertIsNone(info.dns_name2)
+
+ def test_string_with_exception(self):
+ try:
+ self.test_string_from_python()
+ raise TestException()
+ except TestException:
+ pass
+
+ def test_string_from_python_function(self):
+ def get_info():
+ info = drsblobs.repsFromTo2OtherInfo()
+ info.dns_name1 = "1.example.com"
+ info.dns_name2 = "2.example.com"
+ return info
+
+ info = get_info()
+ gc.collect()
+ self.assertIsNotNone(info)
+ self.assertEqual(info.dns_name1, "1.example.com")
+ self.assertEqual(info.dns_name2, "2.example.com")
+
+ def test_string_modify_in_place(self):
+ info = drsblobs.repsFromTo2OtherInfo()
+ info.dns_name1 = "1.example.com"
+ info.dns_name2 = "%s.example.com"
+ gc.collect()
+ self.assertIsNotNone(info)
+ self.assertEqual(info.dns_name1, "1.example.com")
+ self.assertEqual(info.dns_name2, "%s.example.com")
+ info.dns_name1 += ".co.nz"
+ info.dns_name2 %= 2
+ self.assertEqual(info.dns_name1, "1.example.com.co.nz")
+ self.assertEqual(info.dns_name2, "2.example.com")
+ del info
+
+ def test_string_delete(self):
+ gc.collect()
+ info = drsblobs.repsFromTo2OtherInfo()
+ info.dns_name1 = "1.example.com"
+ info.dns_name2 = "2.example.com"
+ info.dns_name1 = None
+ try:
+ del info.dns_name2
+ except AttributeError:
+ pass
+
+ self.assertIsNotNone(info)
+ self.assertIsNone(info.dns_name1)
+ self.assertIsNotNone(info.dns_name2)
+
+
+class StringTestsWithoutLeakCheck(samba.tests.TestCase):
+ """We know that the ndr unpacking test leaves stuff in the
+ autofree_context, and we don't want to worry about that. So for
+ this test we don't make memory leak assertions."""
+
+ def test_string_from_ndr(self):
+ info = drsblobs.repsFromTo2OtherInfo()
+ info.dns_name1 = "1.example.com"
+ info.dns_name2 = "2.example.com"
+ packed = ndr_pack(info)
+ gc.collect()
+
+ info_unpacked = ndr_unpack(drsblobs.repsFromTo2OtherInfo, packed)
+
+ self.assertIsNotNone(info_unpacked)
+ self.assertEqual(info_unpacked.dns_name1, "1.example.com")
+ self.assertEqual(info_unpacked.dns_name2, "2.example.com")
diff --git a/python/samba/tests/dcerpc/testrpc.py b/python/samba/tests/dcerpc/testrpc.py
new file mode 100644
index 0000000..789ea9a
--- /dev/null
+++ b/python/samba/tests/dcerpc/testrpc.py
@@ -0,0 +1,143 @@
+# test generated python code from pidl
+# Copyright (C) Andrew Tridgell August 2010
+#
+# 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/>.
+#
+import sys
+
+sys.path.insert(0, "bin/python")
+
+import samba
+import samba.tests
+from samba.dcerpc import drsuapi
+import talloc
+
+talloc.enable_null_tracking()
+
+
+class RpcTests(object):
+ """test type behaviour of pidl generated python RPC code"""
+
+ def check_blocks(self, object, num_expected):
+ """check that the number of allocated blocks is correct"""
+ nblocks = talloc.total_blocks(object)
+ if object is None:
+ nblocks -= self.initial_blocks
+ leaked_blocks = (nblocks - num_expected)
+ if leaked_blocks != 0:
+ print("Leaked %d blocks" % leaked_blocks)
+
+ def check_type(self, interface, typename, type):
+ print("Checking type %s" % typename)
+ v = type()
+ for n in dir(v):
+ if n[0] == '_':
+ continue
+ try:
+ value = getattr(v, n)
+ except TypeError as errstr:
+ if str(errstr) == "unknown union level":
+ print("ERROR: Unknown union level in %s.%s" % (typename, n))
+ self.errcount += 1
+ continue
+ print(str(errstr)[1:21])
+ if str(errstr)[0:21] == "Can not convert C Type":
+ print("ERROR: Unknown C type for %s.%s" % (typename, n))
+ self.errcount += 1
+ continue
+ else:
+ print("ERROR: Failed to instantiate %s.%s" % (typename, n))
+ self.errcount += 1
+ continue
+ except Exception:
+ print("ERROR: Failed to instantiate %s.%s" % (typename, n))
+ self.errcount += 1
+ continue
+
+ # now try setting the value back
+ try:
+ print("Setting %s.%s" % (typename, n))
+ setattr(v, n, value)
+ except Exception as e:
+ if isinstance(e, AttributeError) and str(e).endswith("is read-only"):
+ # readonly, ignore
+ continue
+ else:
+ print("ERROR: Failed to set %s.%s: %r: %s" % (typename, n, e.__class__, e))
+ self.errcount += 1
+ continue
+
+ # and try a comparison
+ try:
+ if value != getattr(v, n):
+ print("ERROR: Comparison failed for %s.%s: %r != %r" % (typename, n, value, getattr(v, n)))
+ continue
+ except Exception as e:
+ print("ERROR: compare exception for %s.%s: %r: %s" % (typename, n, e.__class__, e))
+ continue
+
+ def check_interface(self, interface, iname):
+ errcount = self.errcount
+ for n in dir(interface):
+ if n[0] == '_' or n == iname:
+ # skip the special ones
+ continue
+ value = getattr(interface, n)
+ if isinstance(value, str):
+ # print "%s=\"%s\"" % (n, value)
+ pass
+ elif isinstance(value, int):
+ # print "%s=%d" % (n, value)
+ pass
+ elif isinstance(value, type):
+ try:
+ initial_blocks = talloc.total_blocks(None)
+ self.check_type(interface, n, value)
+ self.check_blocks(None, initial_blocks)
+ except Exception as e:
+ print("ERROR: Failed to check_type %s.%s: %r: %s" % (iname, n, e.__class__, e))
+ self.errcount += 1
+ elif callable(value):
+ pass # Method
+ else:
+ print("UNKNOWN: %s=%s" % (n, value))
+ if self.errcount - errcount != 0:
+ print("Found %d errors in %s" % (self.errcount - errcount, iname))
+
+ def check_all_interfaces(self):
+ for iname in dir(samba.dcerpc):
+ if iname[0] == '_':
+ continue
+ if iname == 'ClientConnection' or iname == 'base':
+ continue
+ print("Checking interface %s" % iname)
+ iface = getattr(samba.dcerpc, iname)
+ initial_blocks = talloc.total_blocks(None)
+ self.check_interface(iface, iname)
+ self.check_blocks(None, initial_blocks)
+
+ def run(self):
+ self.initial_blocks = talloc.total_blocks(None)
+ self.errcount = 0
+ self.check_all_interfaces()
+ return self.errcount
+
+
+tests = RpcTests()
+errcount = tests.run()
+if errcount == 0:
+ sys.exit(0)
+else:
+ print("%d failures" % errcount)
+ sys.exit(1)
diff --git a/python/samba/tests/dcerpc/unix.py b/python/samba/tests/dcerpc/unix.py
new file mode 100644
index 0000000..b7fa1f3
--- /dev/null
+++ b/python/samba/tests/dcerpc/unix.py
@@ -0,0 +1,43 @@
+# Unix SMB/CIFS implementation.
+# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
+#
+# 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/>.
+#
+
+"""Tests for samba.dcerpc.unixinfo."""
+
+
+from samba.dcerpc import unixinfo
+from samba.tests import RpcInterfaceTestCase
+
+class UnixinfoTests(RpcInterfaceTestCase):
+
+ def setUp(self):
+ super().setUp()
+ self.conn = unixinfo.unixinfo("ncalrpc:", self.get_loadparm())
+
+ def test_getpwuid_int(self):
+ infos = self.conn.GetPWUid(range(512))
+ self.assertEqual(512, len(infos))
+ self.assertEqual("/bin/false", infos[0].shell)
+ self.assertTrue(isinstance(infos[0].homedir, str))
+
+ def test_gidtosid(self):
+ self.conn.GidToSid(1000)
+
+ def test_uidtosid(self):
+ self.conn.UidToSid(1000)
+
+ def test_uidtosid_fail(self):
+ self.assertRaises(TypeError, self.conn.UidToSid, "100")