diff --git a/pike/test/__init__.py b/pike/test/__init__.py index 74c40aa6..806d1b96 100644 --- a/pike/test/__init__.py +++ b/pike/test/__init__.py @@ -62,6 +62,7 @@ class CapabilityMissing(TestRequirementNotMet): class ShareCapabilityMissing(TestRequirementNotMet): pass + class Options(enum.Enum): PIKE_LOGLEVEL = "PIKE_LOGLEVEL" PIKE_TRACE = "PIKE_TRACE" @@ -83,22 +84,23 @@ def option(cls, name, default=None): if value is _NotSet or len(value) == 0: if default is _Required: raise MissingArgument( - "Environment variable {!r} must be set".format(name)) + "Environment variable {!r} must be set".format(name) + ) value = default return value @classmethod - def booloption(cls, name, default='no'): - table = {'yes': True, 'true': True, 'no': False, 'false': False, '': False} + def booloption(cls, name, default="no"): + table = {"yes": True, "true": True, "no": False, "false": False, "": False} return table[cls.option(name, default=default).lower()] @classmethod def smb2constoption(cls, name, default=None): - return getattr(smb2, cls.option(name, '').upper(), default) + return getattr(smb2, cls.option(name, "").upper(), default) @classmethod def loglevel(cls): - return getattr(logging, cls.option(cls.PIKE_LOGLEVEL, default='NOTSET').upper()) + return getattr(logging, cls.option(cls.PIKE_LOGLEVEL, default="NOTSET").upper()) @classmethod def trace(cls): @@ -110,7 +112,7 @@ def server(cls): @classmethod def port(cls): - return int(cls.option(cls.PIKE_PORT, default='445')) + return int(cls.option(cls.PIKE_PORT, default="445")) @classmethod def creds(cls): @@ -134,7 +136,7 @@ def min_dialect(cls): @classmethod def max_dialect(cls): - return cls.smb2constoption(cls.PIKE_MAX_DIALECT, default=float('inf')) + return cls.smb2constoption(cls.PIKE_MAX_DIALECT, default=float("inf")) def default_client(signing=None): @@ -145,8 +147,9 @@ def default_client(signing=None): if signing is None: signing = Options.signing() if signing: - client.security_mode = (smb2.SMB2_NEGOTIATE_SIGNING_ENABLED | - smb2.SMB2_NEGOTIATE_SIGNING_REQUIRED) + client.security_mode = ( + smb2.SMB2_NEGOTIATE_SIGNING_ENABLED | smb2.SMB2_NEGOTIATE_SIGNING_REQUIRED + ) return client @@ -155,6 +158,7 @@ class TreeConnect(object): """ Combines a Client, Connection, Channel, and Tree for simple access to an SMB share. """ + _client = attr.ib(default=None) server = attr.ib(factory=Options.server) port = attr.ib(factory=Options.port) @@ -193,21 +197,29 @@ def connect(self): :return: connected pike.model.Connection """ if self.conn and self.conn.connected: - raise SequenceError("Already connected: {!r}. Must call close() before reconnecting".format(self.conn)) + raise SequenceError( + "Already connected: {!r}. Must call close() before reconnecting".format( + self.conn + ) + ) self.conn = self.client.connect(server=self.server, port=self.port).negotiate() negotiated_dialect = self.conn.negotiate_response.dialect_revision - if (self.require_dialect and - (negotiated_dialect < self.require_dialect[0] or - negotiated_dialect > self.require_dialect[1])): + if self.require_dialect and ( + negotiated_dialect < self.require_dialect[0] + or negotiated_dialect > self.require_dialect[1] + ): self.close() raise DialectMissing("Dialect required: {}".format(self.require_dialect)) capabilities = self.conn.negotiate_response.capabilities - if (self.require_capabilities and - (capabilities & self.require_capabilities != self.require_capabilities)): + if self.require_capabilities and ( + capabilities & self.require_capabilities != self.require_capabilities + ): self.close() - raise CapabilityMissing("Server does not support: %s " % - str(self.require_capabilities & ~capabilities)) + raise CapabilityMissing( + "Server does not support: %s " + % str(self.require_capabilities & ~capabilities) + ) return self.conn def session_setup(self): @@ -225,7 +237,11 @@ def session_setup(self): if not self.conn or not self.conn.connected: raise SequenceError("Not connected. Must call connect() first") if self.chan: - raise SequenceError("Channel already established: {!r}. Must call close() before reconnecting".format(self.chan)) + raise SequenceError( + "Channel already established: {!r}. Must call close() before reconnecting".format( + self.chan + ) + ) self.chan = self.conn.session_setup(self.creds, resume=self.resume) if self.encryption: self.chan.session.encrypt_data = True @@ -242,17 +258,25 @@ def tree_connect(self): :return: pike.model.Tree """ if not self.chan: - raise SequenceError("Channel not established. Must call session_setup() first") + raise SequenceError( + "Channel not established. Must call session_setup() first" + ) if self.tree: - raise SequenceError("Tree already connected: {!r}. Must call close() before reconnecting".format(self.tree)) + raise SequenceError( + "Tree already connected: {!r}. Must call close() before reconnecting".format( + self.tree + ) + ) self.tree = self.chan.tree_connect(self.share) capabilities = self.tree.tree_connect_response.capabilities - if (self.require_share_capabilities and - (capabilities & self.require_share_capabilities != self.require_share_capabilities)): + if self.require_share_capabilities and ( + capabilities & self.require_share_capabilities + != self.require_share_capabilities + ): self.close() raise ShareCapabilityMissing( - "Share does not support: %s" % - str(self.require_share_capabilities & ~capabilities) + "Share does not support: %s" + % str(self.require_share_capabilities & ~capabilities) ) return self.tree @@ -355,8 +379,10 @@ def init_once(): PikeTest.loglevel = Options.loglevel() PikeTest.handler = logging.StreamHandler() PikeTest.handler.setLevel(PikeTest.loglevel) - PikeTest.handler.setFormatter(logging.Formatter('%(asctime)s:%(name)s:%(levelname)s: %(message)s')) - PikeTest.logger = logging.getLogger('pike') + PikeTest.handler.setFormatter( + logging.Formatter("%(asctime)s:%(name)s:%(levelname)s: %(message)s") + ) + PikeTest.logger = logging.getLogger("pike") PikeTest.logger.addHandler(PikeTest.handler) PikeTest.logger.setLevel(PikeTest.loglevel) model.trace = PikeTest.trace = Options.trace() @@ -391,8 +417,7 @@ def error(self, *args, **kwargs): def critical(self, *args, **kwargs): self.logger.critical(*args, **kwargs) - def set_client_dialect(self, min_dialect=None, max_dialect=None, - client=None): + def set_client_dialect(self, min_dialect=None, max_dialect=None, client=None): if client is None: client = self.default_client client.restrict_dialects(min_dialect, max_dialect) @@ -434,20 +459,21 @@ def assert_error(self, status): if err.response.status != status: raise_from( self.failureException( - '"%s" raised when "%s" expected' % (err.response.status, status), + '"%s" raised when "%s" expected' + % (err.response.status, status), ), - err + err, ) def setUp(self): if self.loglevel != logging.NOTSET: print(file=sys.stderr) - if hasattr(self, 'setup'): + if hasattr(self, "setup"): self.setup() def tearDown(self): - if hasattr(self, 'teardown'): + if hasattr(self, "teardown"): self.teardown() for conn in self._connections: @@ -457,7 +483,7 @@ def tearDown(self): gc.collect() def _get_decorator_attr(self, name, default): - name = '__pike_test_' + name + name = "__pike_test_" + name test_method = getattr(self, self._testMethodName) if hasattr(test_method, name): @@ -468,13 +494,13 @@ def _get_decorator_attr(self, name, default): return default def required_dialect(self): - return self._get_decorator_attr('RequireDialect', (0, float('inf'))) + return self._get_decorator_attr("RequireDialect", (0, float("inf"))) def required_capabilities(self): - return self._get_decorator_attr('RequireCapabilities', 0) + return self._get_decorator_attr("RequireCapabilities", 0) def required_share_capabilities(self): - return self._get_decorator_attr('RequireShareCapabilities', 0) + return self._get_decorator_attr("RequireShareCapabilities", 0) def assertBufferEqual(self, buf1, buf2): """ @@ -489,39 +515,52 @@ def assertBufferEqual(self, buf1, buf2): # XXX: consider usage of stdlib bisect module chunk_1 = (low, low + ((high - low) // 2)) chunk_2 = (chunk_1[1], high) - if buf1[chunk_1[0]:chunk_1[1]] != buf2[chunk_1[0]:chunk_1[1]]: + if buf1[chunk_1[0] : chunk_1[1]] != buf2[chunk_1[0] : chunk_1[1]]: low, high = chunk_1 - elif buf1[chunk_2[0]:chunk_2[1]] != buf2[chunk_2[0]:chunk_2[1]]: + elif buf1[chunk_2[0] : chunk_2[1]] != buf2[chunk_2[0] : chunk_2[1]]: low, high = chunk_2 else: break if high - low <= 1: - raise AssertionError("Block mismatch at byte {0}: " - "{1} != {2}".format(low, buf1[low], buf2[low])) + raise AssertionError( + "Block mismatch at byte {0}: " + "{1} != {2}".format(low, buf1[low], buf2[low]) + ) + class _Decorator(object): def __init__(self, value): self.value = value def __call__(self, thing): - setattr(thing, '__pike_test_' + self.__class__.__name__, self.value) + setattr(thing, "__pike_test_" + self.__class__.__name__, self.value) return thing class _RangeDecorator(object): - def __init__(self, minvalue=0, maxvalue=float('inf')): + def __init__(self, minvalue=0, maxvalue=float("inf")): self.minvalue = minvalue self.maxvalue = maxvalue def __call__(self, thing): - setattr(thing, '__pike_test_' + self.__class__.__name__, - (self.minvalue, self.maxvalue)) + setattr( + thing, + "__pike_test_" + self.__class__.__name__, + (self.minvalue, self.maxvalue), + ) return thing -class RequireDialect(_RangeDecorator): pass -class RequireCapabilities(_Decorator): pass -class RequireShareCapabilities(_Decorator): pass +class RequireDialect(_RangeDecorator): + pass + + +class RequireCapabilities(_Decorator): + pass + + +class RequireShareCapabilities(_Decorator): + pass class PikeTestSuite(unittest.TestSuite): @@ -529,24 +568,26 @@ class PikeTestSuite(unittest.TestSuite): Custom test suite for easily patching in skip tests in downstream distributions of these test cases """ + skip_tests_reasons = { - "test_to_be_skipped": "This test should be skipped", + "test_to_be_skipped": "This test should be skipped", } @staticmethod def _raise_skip(reason): def inner(*args, **kwds): raise unittest.SkipTest(reason) + return inner def addTest(self, test): testMethodName = getattr(test, "_testMethodName", None) if testMethodName in self.skip_tests_reasons: setattr( - test, - testMethodName, - self._raise_skip( - self.skip_tests_reasons[testMethodName])) + test, + testMethodName, + self._raise_skip(self.skip_tests_reasons[testMethodName]), + ) super(PikeTestSuite, self).addTest(test) @@ -611,8 +652,8 @@ def suite(clz=PikeTestSuite): test_loader = unittest.TestLoader() test_loader.suiteClass = clz test_suite = test_loader.discover( - os.path.abspath(os.path.dirname(__file__)), - "*.py") + os.path.abspath(os.path.dirname(__file__)), "*.py" + ) return test_suite @@ -620,6 +661,6 @@ def samba_suite(): return suite(SambaPikeTestSuite) -if __name__ == '__main__': +if __name__ == "__main__": test_runner = unittest.TextTestRunner() test_runner.run(suite()) diff --git a/pike/test/acl.py b/pike/test/acl.py index b76509e9..f1316ddb 100644 --- a/pike/test/acl.py +++ b/pike/test/acl.py @@ -22,14 +22,15 @@ class SecTest(pike.test.PikeTest): - def __init__(self, *args, **kwargs): super(SecTest, self).__init__(*args, **kwargs) self.chan = None self.tree = None - self.sec_info = (pike.smb2.OWNER_SECURITY_INFORMATION | - pike.smb2.GROUP_SECURITY_INFORMATION | - pike.smb2.DACL_SECURITY_INFORMATION) + self.sec_info = ( + pike.smb2.OWNER_SECURITY_INFORMATION + | pike.smb2.GROUP_SECURITY_INFORMATION + | pike.smb2.DACL_SECURITY_INFORMATION + ) self.sec_info_owner = pike.smb2.OWNER_SECURITY_INFORMATION self.sec_info_group = pike.smb2.GROUP_SECURITY_INFORMATION self.sec_info_dacl = pike.smb2.DACL_SECURITY_INFORMATION @@ -37,76 +38,96 @@ def __init__(self, *args, **kwargs): def open_file(self): """Helper to open basic file""" self.chan, self.tree = self.tree_connect() - return self.chan.create(self.tree, "test_sec.txt", - options=pike.smb2.FILE_DELETE_ON_CLOSE, - access=(pike.smb2.READ_CONTROL | - pike.smb2.WRITE_OWNER | - pike.smb2.DELETE | - pike.smb2.WRITE_DAC), - disposition=pike.smb2.FILE_SUPERSEDE).result() + return self.chan.create( + self.tree, + "test_sec.txt", + options=pike.smb2.FILE_DELETE_ON_CLOSE, + access=( + pike.smb2.READ_CONTROL + | pike.smb2.WRITE_OWNER + | pike.smb2.DELETE + | pike.smb2.WRITE_DAC + ), + disposition=pike.smb2.FILE_SUPERSEDE, + ).result() def test_set_sec_same(self): handle = self.open_file() info = self.chan.query_file_info( - handle, pike.smb2.FILE_SECURITY_INFORMATION, + handle, + pike.smb2.FILE_SECURITY_INFORMATION, info_type=pike.smb2.SMB2_0_INFO_SECURITY, - additional_information=self.sec_info) + additional_information=self.sec_info, + ) with self.chan.set_file_info( - handle, - pike.smb2.FileSecurityInformation, - additional_information=self.sec_info) as file_info: + handle, + pike.smb2.FileSecurityInformation, + additional_information=self.sec_info, + ) as file_info: file_info.clone_from(info) self.chan.close(handle) def test_set_sec_owner(self): handle = self.open_file() info = self.chan.query_file_info( - handle, pike.smb2.FILE_SECURITY_INFORMATION, + handle, + pike.smb2.FILE_SECURITY_INFORMATION, info_type=pike.smb2.SMB2_0_INFO_SECURITY, - additional_information=self.sec_info) + additional_information=self.sec_info, + ) with self.chan.set_file_info( - handle, - pike.smb2.FileSecurityInformation, - additional_information=self.sec_info_owner) as file_info: + handle, + pike.smb2.FileSecurityInformation, + additional_information=self.sec_info_owner, + ) as file_info: file_info.clone_from(info, ["owner_sid"]) self.chan.close(handle) def test_set_sec_group(self): handle = self.open_file() info = self.chan.query_file_info( - handle, pike.smb2.FILE_SECURITY_INFORMATION, + handle, + pike.smb2.FILE_SECURITY_INFORMATION, info_type=pike.smb2.SMB2_0_INFO_SECURITY, - additional_information=self.sec_info) + additional_information=self.sec_info, + ) with self.chan.set_file_info( - handle, - pike.smb2.FileSecurityInformation, - additional_information=self.sec_info_group) as file_info: + handle, + pike.smb2.FileSecurityInformation, + additional_information=self.sec_info_group, + ) as file_info: file_info.clone_from(info, ["group_sid"]) self.chan.close(handle) def test_set_sec_dacl(self): handle = self.open_file() info = self.chan.query_file_info( - handle, pike.smb2.FILE_SECURITY_INFORMATION, + handle, + pike.smb2.FILE_SECURITY_INFORMATION, info_type=pike.smb2.SMB2_0_INFO_SECURITY, - additional_information=self.sec_info) + additional_information=self.sec_info, + ) with self.chan.set_file_info( - handle, - pike.smb2.FileSecurityInformation, - additional_information=self.sec_info_dacl) as file_info: + handle, + pike.smb2.FileSecurityInformation, + additional_information=self.sec_info_dacl, + ) as file_info: file_info.clone_from(info, ["dacl"]) self.chan.close(handle) def test_set_sec_dacl_partial_copy(self): handle = self.open_file() info = self.chan.query_file_info( - handle, pike.smb2.FILE_SECURITY_INFORMATION, + handle, + pike.smb2.FILE_SECURITY_INFORMATION, info_type=pike.smb2.SMB2_0_INFO_SECURITY, - additional_information=self.sec_info) + additional_information=self.sec_info, + ) with self.chan.set_file_info( - handle, - pike.smb2.FileSecurityInformation, - additional_information=self.sec_info_dacl) as file_info: + handle, + pike.smb2.FileSecurityInformation, + additional_information=self.sec_info_dacl, + ) as file_info: file_info.clone_from(info, []) aces = info.dacl.children new_dacl = pike.smb2.NT_ACL() @@ -118,13 +139,16 @@ def test_set_sec_dacl_partial_copy(self): def test_set_sec_dacl_append_ace(self): handle = self.open_file() info = self.chan.query_file_info( - handle, pike.smb2.FILE_SECURITY_INFORMATION, + handle, + pike.smb2.FILE_SECURITY_INFORMATION, info_type=pike.smb2.SMB2_0_INFO_SECURITY, - additional_information=self.sec_info) + additional_information=self.sec_info, + ) with self.chan.set_file_info( - handle, - pike.smb2.FileSecurityInformation, - additional_information=self.sec_info_dacl) as file_info: + handle, + pike.smb2.FileSecurityInformation, + additional_information=self.sec_info_dacl, + ) as file_info: file_info.clone_from(info, []) aces = info.dacl.children new_dacl = info.dacl.clone() @@ -139,19 +163,22 @@ def test_set_sec_dacl_append_ace(self): def test_set_sec_dacl_new(self): handle = self.open_file() info = self.chan.query_file_info( - handle, pike.smb2.FILE_SECURITY_INFORMATION, + handle, + pike.smb2.FILE_SECURITY_INFORMATION, info_type=pike.smb2.SMB2_0_INFO_SECURITY, - additional_information=self.sec_info) + additional_information=self.sec_info, + ) with self.chan.set_file_info( - handle, - pike.smb2.FileSecurityInformation, - additional_information=self.sec_info_dacl) as file_info: + handle, + pike.smb2.FileSecurityInformation, + additional_information=self.sec_info_dacl, + ) as file_info: file_info.clone_from(info, []) aces = info.dacl.children - #generate a new NT_ACL object + # generate a new NT_ACL object new_dacl = pike.smb2.NT_ACL() new_dacl.acl_revision = pike.smb2.ACL_REVISION - #keep the original aces + # keep the original aces new_dacl._entries = aces # append a cloned ace then modify it template_ace = aces[0].clone(new_parent=new_dacl) diff --git a/pike/test/appinstanceid.py b/pike/test/appinstanceid.py index e4c1914b..39422d53 100644 --- a/pike/test/appinstanceid.py +++ b/pike/test/appinstanceid.py @@ -29,10 +29,15 @@ class AppInstanceIdTest(pike.test.PikeTest): def __init__(self, *args, **kwargs): super(AppInstanceIdTest, self).__init__(*args, **kwargs) - self.share_all = pike.smb2.FILE_SHARE_READ | pike.smb2.FILE_SHARE_WRITE | pike.smb2.FILE_SHARE_DELETE - self.lease1 = array.array('B', map(random.randint, [0] * 16, [255] * 16)) - self.app_instance_id1 = array.array('B', - map(random.randint, [0] * 16, [255] * 16)) + self.share_all = ( + pike.smb2.FILE_SHARE_READ + | pike.smb2.FILE_SHARE_WRITE + | pike.smb2.FILE_SHARE_DELETE + ) + self.lease1 = array.array("B", map(random.randint, [0] * 16, [255] * 16)) + self.app_instance_id1 = array.array( + "B", map(random.randint, [0] * 16, [255] * 16) + ) self.r = pike.smb2.SMB2_LEASE_READ_CACHING self.rw = self.r | pike.smb2.SMB2_LEASE_WRITE_CACHING self.rh = self.r | pike.smb2.SMB2_LEASE_HANDLE_CACHING @@ -41,41 +46,47 @@ def __init__(self, *args, **kwargs): # Perform create with AppInstanceId def test_appinstanceid(self): chan, tree = self.tree_connect() - + # Request rwh lease - handle1 = chan.create(tree, - 'appinstanceid.txt', - access=pike.smb2.FILE_READ_DATA | pike.smb2.FILE_WRITE_DATA | pike.smb2.DELETE, - share=self.share_all, - disposition=pike.smb2.FILE_OPEN_IF, - options=pike.smb2.FILE_DELETE_ON_CLOSE, - oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, - lease_key = self.lease1, - lease_state = self.rwh, - durable=0, - persistent=True, - app_instance_id=self.app_instance_id1).result() - + handle1 = chan.create( + tree, + "appinstanceid.txt", + access=pike.smb2.FILE_READ_DATA + | pike.smb2.FILE_WRITE_DATA + | pike.smb2.DELETE, + share=self.share_all, + disposition=pike.smb2.FILE_OPEN_IF, + options=pike.smb2.FILE_DELETE_ON_CLOSE, + oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, + lease_key=self.lease1, + lease_state=self.rwh, + durable=0, + persistent=True, + app_instance_id=self.app_instance_id1, + ).result() + self.assertEqual(handle1.durable_flags, pike.smb2.SMB2_DHANDLE_FLAG_PERSISTENT) self.assertEqual(handle1.lease.lease_state, self.rwh) chan.close(handle1) - + # Invalidate disconnected persistent handle via AppInstanceId def test_appinstanceid_persistent_with_disconnect(self): chan, tree = self.tree_connect() # Request rwh lease - handle1 = chan.create(tree, - 'appinstanceid.txt', - share=self.share_all, - disposition=pike.smb2.FILE_OPEN_IF, - oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, - lease_key = self.lease1, - lease_state = self.rwh, - durable=0, - persistent=True, - app_instance_id=self.app_instance_id1).result() + handle1 = chan.create( + tree, + "appinstanceid.txt", + share=self.share_all, + disposition=pike.smb2.FILE_OPEN_IF, + oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, + lease_key=self.lease1, + lease_state=self.rwh, + durable=0, + persistent=True, + app_instance_id=self.app_instance_id1, + ).result() self.assertEqual(handle1.durable_flags, pike.smb2.SMB2_DHANDLE_FLAG_PERSISTENT) self.assertEqual(handle1.lease.lease_state, self.rwh) @@ -86,19 +97,23 @@ def test_appinstanceid_persistent_with_disconnect(self): chan2, tree2 = self.tree_connect(client=pike.model.Client()) # Request reconnect - handle2 = chan2.create(tree, - 'appinstanceid.txt', - access=pike.smb2.FILE_READ_DATA | pike.smb2.FILE_WRITE_DATA | pike.smb2.DELETE, - share=self.share_all, - disposition=pike.smb2.FILE_OPEN_IF, - options=pike.smb2.FILE_DELETE_ON_CLOSE, - oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, - lease_key = self.lease1, - lease_state = self.rwh, - durable=0, - persistent=True, - app_instance_id=self.app_instance_id1).result() - + handle2 = chan2.create( + tree, + "appinstanceid.txt", + access=pike.smb2.FILE_READ_DATA + | pike.smb2.FILE_WRITE_DATA + | pike.smb2.DELETE, + share=self.share_all, + disposition=pike.smb2.FILE_OPEN_IF, + options=pike.smb2.FILE_DELETE_ON_CLOSE, + oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, + lease_key=self.lease1, + lease_state=self.rwh, + durable=0, + persistent=True, + app_instance_id=self.app_instance_id1, + ).result() + self.assertEqual(handle2.durable_flags, pike.smb2.SMB2_DHANDLE_FLAG_PERSISTENT) self.assertEqual(handle2.lease.lease_state, self.rwh) @@ -110,16 +125,18 @@ def test_appinstanceid_reconnect_same_clientguid(self): chan, tree = self.tree_connect() # Request rwh lease - handle1 = chan.create(tree, - 'appinstanceid.txt', - share=self.share_all, - disposition=pike.smb2.FILE_OPEN_IF, - oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, - lease_key = self.lease1, - lease_state = self.rwh, - durable=0, - persistent=True, - app_instance_id=self.app_instance_id1).result() + handle1 = chan.create( + tree, + "appinstanceid.txt", + share=self.share_all, + disposition=pike.smb2.FILE_OPEN_IF, + oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, + lease_key=self.lease1, + lease_state=self.rwh, + durable=0, + persistent=True, + app_instance_id=self.app_instance_id1, + ).result() self.assertEqual(handle1.durable_flags, pike.smb2.SMB2_DHANDLE_FLAG_PERSISTENT) self.assertEqual(handle1.lease.lease_state, self.rwh) @@ -131,18 +148,22 @@ def test_appinstanceid_reconnect_same_clientguid(self): # Request reconnect with self.assert_error(pike.ntstatus.STATUS_FILE_NOT_AVAILABLE): - handle2 = chan2.create(tree, - 'appinstanceid.txt', - access=pike.smb2.FILE_READ_DATA | pike.smb2.FILE_WRITE_DATA | pike.smb2.DELETE, - share=self.share_all, - disposition=pike.smb2.FILE_OPEN_IF, - options=pike.smb2.FILE_DELETE_ON_CLOSE, - oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, - lease_key = self.lease1, - lease_state = self.rwh, - durable=0, - persistent=True, - app_instance_id=self.app_instance_id1).result() + handle2 = chan2.create( + tree, + "appinstanceid.txt", + access=pike.smb2.FILE_READ_DATA + | pike.smb2.FILE_WRITE_DATA + | pike.smb2.DELETE, + share=self.share_all, + disposition=pike.smb2.FILE_OPEN_IF, + options=pike.smb2.FILE_DELETE_ON_CLOSE, + oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, + lease_key=self.lease1, + lease_state=self.rwh, + durable=0, + persistent=True, + app_instance_id=self.app_instance_id1, + ).result() # Close the connection chan2.connection.close() @@ -150,19 +171,23 @@ def test_appinstanceid_reconnect_same_clientguid(self): chan3, tree3 = self.tree_connect(client=pike.model.Client()) # Request reconnect - handle3 = chan3.create(tree, - 'appinstanceid.txt', - access=pike.smb2.FILE_READ_DATA | pike.smb2.FILE_WRITE_DATA | pike.smb2.DELETE, - share=self.share_all, - disposition=pike.smb2.FILE_OPEN_IF, - options=pike.smb2.FILE_DELETE_ON_CLOSE, - oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, - lease_key = self.lease1, - lease_state = self.rwh, - durable=0, - persistent=True, - app_instance_id=self.app_instance_id1).result() - + handle3 = chan3.create( + tree, + "appinstanceid.txt", + access=pike.smb2.FILE_READ_DATA + | pike.smb2.FILE_WRITE_DATA + | pike.smb2.DELETE, + share=self.share_all, + disposition=pike.smb2.FILE_OPEN_IF, + options=pike.smb2.FILE_DELETE_ON_CLOSE, + oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, + lease_key=self.lease1, + lease_state=self.rwh, + durable=0, + persistent=True, + app_instance_id=self.app_instance_id1, + ).result() + self.assertEqual(handle3.durable_flags, pike.smb2.SMB2_DHANDLE_FLAG_PERSISTENT) self.assertEqual(handle3.lease.lease_state, self.rwh) diff --git a/pike/test/changenotify.py b/pike/test/changenotify.py index 607234e4..16549a54 100644 --- a/pike/test/changenotify.py +++ b/pike/test/changenotify.py @@ -26,11 +26,13 @@ def test_change_notify_file_name(self): chan, tree = self.tree_connect() # connect to the root of the share - root = chan.create(tree, - '', - access=pike.smb2.GENERIC_READ, - options=pike.smb2.FILE_DIRECTORY_FILE, - share=pike.smb2.FILE_SHARE_READ).result() + root = chan.create( + tree, + "", + access=pike.smb2.GENERIC_READ, + options=pike.smb2.FILE_DIRECTORY_FILE, + share=pike.smb2.FILE_SHARE_READ, + ).result() # build a change notify request smb_req = chan.request(obj=root) @@ -41,15 +43,21 @@ def test_change_notify_file_name(self): futures = chan.connection.submit(smb_req.parent) # create a file on the share to trigger the notification - file = chan.create(tree, - filename, - access=pike.smb2.FILE_READ_DATA | pike.smb2.FILE_WRITE_DATA | pike.smb2.DELETE, - share=pike.smb2.FILE_SHARE_READ | pike.smb2.FILE_SHARE_WRITE | pike.smb2.FILE_SHARE_DELETE, - options=pike.smb2.FILE_DELETE_ON_CLOSE, - disposition=pike.smb2.FILE_SUPERSEDE).result() - + file = chan.create( + tree, + filename, + access=pike.smb2.FILE_READ_DATA + | pike.smb2.FILE_WRITE_DATA + | pike.smb2.DELETE, + share=pike.smb2.FILE_SHARE_READ + | pike.smb2.FILE_SHARE_WRITE + | pike.smb2.FILE_SHARE_DELETE, + options=pike.smb2.FILE_DELETE_ON_CLOSE, + disposition=pike.smb2.FILE_SUPERSEDE, + ).result() + chan.close(file) - + # collect the change notify response result = futures[0].result()[0] @@ -57,17 +65,19 @@ def test_change_notify_file_name(self): self.assertEqual(len(result.notifications), 1) self.assertEqual(result.notifications[0].filename, filename) self.assertEqual(result.notifications[0].action, pike.smb2.SMB2_ACTION_ADDED) - + chan.close(root) def test_change_notify_cancel(self): chan, tree = self.tree_connect() - root = chan.create(tree, - '', - access=pike.smb2.GENERIC_READ, - options=pike.smb2.FILE_DIRECTORY_FILE, - share=pike.smb2.FILE_SHARE_READ).result() + root = chan.create( + tree, + "", + access=pike.smb2.GENERIC_READ, + options=pike.smb2.FILE_DIRECTORY_FILE, + share=pike.smb2.FILE_SHARE_READ, + ).result() cn_future = chan.change_notify(root) # close the handle for the outstanding notify chan.close(root) diff --git a/pike/test/compound.py b/pike/test/compound.py index 0a3f6bf7..106c8535 100644 --- a/pike/test/compound.py +++ b/pike/test/compound.py @@ -36,7 +36,7 @@ def test_create_close(self): create_req = pike.smb2.CreateRequest(smb_req1) close_req = pike.smb2.CloseRequest(smb_req2) - create_req.name = 'hello.txt' + create_req.name = "hello.txt" create_req.desired_access = pike.smb2.GENERIC_READ | pike.smb2.GENERIC_WRITE create_req.file_attributes = pike.smb2.FILE_ATTRIBUTE_NORMAL create_req.create_disposition = pike.smb2.FILE_OPEN_IF @@ -53,12 +53,13 @@ def test_create_query_close(self): chan, tree = self.tree_connect() create_req = chan.create_request( - tree, - "create_query_close", - access=(pike.smb2.GENERIC_READ | - pike.smb2.GENERIC_WRITE | - pike.smb2.DELETE), - options=pike.smb2.FILE_DELETE_ON_CLOSE) + tree, + "create_query_close", + access=( + pike.smb2.GENERIC_READ | pike.smb2.GENERIC_WRITE | pike.smb2.DELETE + ), + options=pike.smb2.FILE_DELETE_ON_CLOSE, + ) nb_req = create_req.parent.parent query_req = chan.query_file_info_request(RelatedOpen(tree)) nb_req.adopt(query_req.parent) @@ -66,19 +67,19 @@ def test_create_query_close(self): close_req = chan.close_request(RelatedOpen(tree)) nb_req.adopt(close_req.parent) - (create_res, - query_res, - close_res) = chan.connection.transceive(nb_req) + (create_res, query_res, close_res) = chan.connection.transceive(nb_req) compare_attributes = [ - "creation_time", - "change_time", - "last_access_time", - "last_write_time", - "file_attributes"] + "creation_time", + "change_time", + "last_access_time", + "last_write_time", + "file_attributes", + ] for attr in compare_attributes: - self.assertEqual(getattr(create_res[0], attr), - getattr(query_res[0][0], attr)) + self.assertEqual( + getattr(create_res[0], attr), getattr(query_res[0][0], attr) + ) # Compound create/write/close & create/read/close def test_create_write_close(self): @@ -88,9 +89,8 @@ def test_create_write_close(self): chan, tree = self.tree_connect() create_req1 = chan.create_request( - tree, - filename, - access=pike.smb2.GENERIC_WRITE) + tree, filename, access=pike.smb2.GENERIC_WRITE + ) nb_req = create_req1.parent.parent write_req = chan.write_request(RelatedOpen(tree), 0, buf) nb_req.adopt(write_req.parent) @@ -98,16 +98,14 @@ def test_create_write_close(self): close_req = chan.close_request(RelatedOpen(tree)) nb_req.adopt(close_req.parent) - (create_res1, - write_res, - close_res) = chan.connection.transceive(nb_req) + (create_res1, write_res, close_res) = chan.connection.transceive(nb_req) create_req2 = chan.create_request( - tree, - filename, - access=(pike.smb2.GENERIC_READ | - pike.smb2.DELETE), - options=pike.smb2.FILE_DELETE_ON_CLOSE) + tree, + filename, + access=(pike.smb2.GENERIC_READ | pike.smb2.DELETE), + options=pike.smb2.FILE_DELETE_ON_CLOSE, + ) nb_req = create_req2.parent.parent read_req = chan.read_request(RelatedOpen(tree), 1024, 0) nb_req.adopt(read_req.parent) @@ -115,9 +113,7 @@ def test_create_write_close(self): close_req = chan.close_request(RelatedOpen(tree)) nb_req.adopt(close_req.parent) - (create_res2, - read_res, - close_res) = chan.connection.transceive(nb_req) + (create_res2, read_res, close_res) = chan.connection.transceive(nb_req) self.assertEqual(buf, read_res[0].data.tobytes()) @@ -128,11 +124,11 @@ def test_create_write_close_access_denied(self): chan, tree = self.tree_connect() create_req1 = chan.create_request( - tree, - filename, - access=(pike.smb2.GENERIC_READ | - pike.smb2.DELETE), - options=pike.smb2.FILE_DELETE_ON_CLOSE) + tree, + filename, + access=(pike.smb2.GENERIC_READ | pike.smb2.DELETE), + options=pike.smb2.FILE_DELETE_ON_CLOSE, + ) nb_req = create_req1.parent.parent write_req = chan.write_request(RelatedOpen(tree), 0, "Expect fail") nb_req.adopt(write_req.parent) @@ -141,24 +137,25 @@ def test_create_write_close_access_denied(self): nb_req.adopt(close_req.parent) with self.assert_error(pike.ntstatus.STATUS_ACCESS_DENIED): - (create_res1, - write_res, - close_res) = chan.connection.transceive(nb_req) + (create_res1, write_res, close_res) = chan.connection.transceive(nb_req) def test_create_failed_and_query(self): chan, tree = self.tree_connect() name = "create_query_failed" - test_dir = chan.create(tree, - name, - access=pike.smb2.GENERIC_READ, - options=pike.smb2.FILE_DIRECTORY_FILE).result() + test_dir = chan.create( + tree, + name, + access=pike.smb2.GENERIC_READ, + options=pike.smb2.FILE_DIRECTORY_FILE, + ).result() create_req = chan.create_request( - tree, - name, - access=pike.smb2.GENERIC_READ, - disposition=pike.smb2.FILE_CREATE, - options=pike.smb2.FILE_DIRECTORY_FILE) + tree, + name, + access=pike.smb2.GENERIC_READ, + disposition=pike.smb2.FILE_CREATE, + options=pike.smb2.FILE_DIRECTORY_FILE, + ) nb_req = create_req.parent.parent query_req = chan.query_directory_request(RelatedOpen(tree)) diff --git a/pike/test/copychunk.py b/pike/test/copychunk.py index ed34a071..60fb6d11 100644 --- a/pike/test/copychunk.py +++ b/pike/test/copychunk.py @@ -28,44 +28,47 @@ import pike.smb2 import pike.test -share_all = pike.smb2.FILE_SHARE_READ | \ - pike.smb2.FILE_SHARE_WRITE | \ - pike.smb2.FILE_SHARE_DELETE -access_rwd = pike.smb2.FILE_READ_DATA | \ - pike.smb2.FILE_WRITE_DATA | \ - pike.smb2.DELETE -access_wd = pike.smb2.FILE_WRITE_DATA | \ - pike.smb2.DELETE +share_all = ( + pike.smb2.FILE_SHARE_READ | pike.smb2.FILE_SHARE_WRITE | pike.smb2.FILE_SHARE_DELETE +) +access_rwd = pike.smb2.FILE_READ_DATA | pike.smb2.FILE_WRITE_DATA | pike.smb2.DELETE +access_wd = pike.smb2.FILE_WRITE_DATA | pike.smb2.DELETE SIMPLE_CONTENT = "Hello" -SIMPLE_5_CHUNKS = [(0, 0, 4000), (4000, 4000, 4000), (8000, 8000, 4000), - (12000, 12000, 4000), (16000, 16000, 4000)] +SIMPLE_5_CHUNKS = [ + (0, 0, 4000), + (4000, 4000, 4000), + (8000, 8000, 4000), + (12000, 12000, 4000), + (16000, 16000, 4000), +] SIMPLE_5_CHUNKS_LEN = 20000 def _gen_test_buffer(length): # XXX: refactor and push up into helper/util module - pattern = "".join([chr(x) for x in range(ord(' '), ord('~'))]) + pattern = "".join([chr(x) for x in range(ord(" "), ord("~"))]) buf = (pattern * ((length // len(pattern)) + 1))[:length] return buf.encode("ascii") def _gen_random_test_buffer(length): # XXX: refactor and push up into helper/util module - buf = '' - random_str_seq = "0123456789" + \ - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + buf = "" + random_str_seq = "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" for i in range(0, length): if i % length == 0 and i != 0: - buf += '-' + buf += "-" # XXX: accidentally quadratic str concat buf += str(random_str_seq[random.randint(0, len(random_str_seq) - 1)]) return buf.encode("ascii") + ### # Main test ### + class TestServerSideCopy(pike.test.PikeTest): # these values are valid for Windows -- other servers may need to adjust bad_resume_key_error = pike.ntstatus.STATUS_OBJECT_NAME_NOT_FOUND @@ -84,14 +87,17 @@ def tearDown(self): def _create_and_write(self, filename, content): """ create / overwrite filename with content """ - fh1 = self.chan.create(self.tree, - filename, - access=access_rwd, - share=share_all, - disposition=pike.smb2.FILE_SUPERSEDE).result() + fh1 = self.chan.create( + self.tree, + filename, + access=access_rwd, + share=share_all, + disposition=pike.smb2.FILE_SUPERSEDE, + ).result() # get the max size of write per request - max_write_size = min(self.chan.connection.negotiate_response.max_write_size, - self.max_chunk_size) + max_write_size = min( + self.chan.connection.negotiate_response.max_write_size, self.max_chunk_size + ) total_len = len(content) this_offset = 0 writes = [] @@ -106,17 +112,22 @@ def _create_and_write(self, filename, content): num_of_writes = len(writes) bytes_written = 0 for the_offset, the_length in writes: - bytes_written += self.chan.write(fh1, the_offset, - content[the_offset:(the_offset + the_length)]) + bytes_written += self.chan.write( + fh1, the_offset, content[the_offset : (the_offset + the_length)] + ) self.chan.close(fh1) - def _open_src_dst(self, src_filename, dst_filename, - src_access=None, - src_disp=None, - src_options=None, - dst_access=None, - dst_disp=None, - dst_options=None): + def _open_src_dst( + self, + src_filename, + dst_filename, + src_access=None, + src_disp=None, + src_options=None, + dst_access=None, + dst_disp=None, + dst_options=None, + ): if src_access is None: src_access = pike.smb2.FILE_READ_DATA | pike.smb2.DELETE if dst_access is None: @@ -131,28 +142,34 @@ def _open_src_dst(self, src_filename, dst_filename, dst_options = pike.smb2.FILE_DELETE_ON_CLOSE if src_filename == dst_filename: - src_options = 0 # if we're opening the same file, only delete one - fh_src = self.chan.create(self.tree, - src_filename, - access=src_access, - share=share_all, - disposition=src_disp, - options=src_options).result() - - fh_dst = self.chan.create(self.tree, - dst_filename, - access=dst_access, - share=share_all, - disposition=dst_disp, - options=dst_options).result() + src_options = 0 # if we're opening the same file, only delete one + fh_src = self.chan.create( + self.tree, + src_filename, + access=src_access, + share=share_all, + disposition=src_disp, + options=src_options, + ).result() + + fh_dst = self.chan.create( + self.tree, + dst_filename, + access=dst_access, + share=share_all, + disposition=dst_disp, + options=dst_options, + ).result() return (fh_src, fh_dst) def _get_readable_handler(self, filename): - fh_read = self.chan.create(self.tree, - filename, - access=pike.smb2.FILE_READ_DATA, - share=share_all, - options=0).result() + fh_read = self.chan.create( + self.tree, + filename, + access=pike.smb2.FILE_READ_DATA, + share=share_all, + options=0, + ).result() return fh_read def _clean_up_other_channels(self): @@ -190,8 +207,11 @@ def _read_big_file(self, file_handle, total_len, add_offset=0): num_of_reads = len(reads) read_list = [] for the_offset, the_length in reads: - read_list.append(self.chan.read( - file_handle, the_length, the_offset + add_offset).tobytes()) + read_list.append( + self.chan.read( + file_handle, the_length, the_offset + add_offset + ).tobytes() + ) return b"".join(read_list) def _gen_16mega_file(self, filename): @@ -206,24 +226,30 @@ def _gen_16mega_file(self, filename): chunks_64k_1m = list(zip([0] * 16, list_offset_64k, [65536] * 16)) list_offset_1m = [i * 1048576 for i in range(16)] chunks_1m_16m = list(zip([0] * 16, list_offset_1m, [1048576] * 16)) - fh_64k = self.chan.create(self.tree, - file_64k, - access=access_rwd, - share=share_all, - disposition=pike.smb2.FILE_OPEN, - options=pike.smb2.FILE_DELETE_ON_CLOSE).result() - fh_1m = self.chan.create(self.tree, - file_1m, - access=access_rwd, - share=share_all, - disposition=pike.smb2.FILE_SUPERSEDE, - options=pike.smb2.FILE_DELETE_ON_CLOSE).result() - fh_16m = self.chan.create(self.tree, - filename, - access=access_rwd, - share=share_all, - disposition=pike.smb2.FILE_SUPERSEDE, - options=0).result() + fh_64k = self.chan.create( + self.tree, + file_64k, + access=access_rwd, + share=share_all, + disposition=pike.smb2.FILE_OPEN, + options=pike.smb2.FILE_DELETE_ON_CLOSE, + ).result() + fh_1m = self.chan.create( + self.tree, + file_1m, + access=access_rwd, + share=share_all, + disposition=pike.smb2.FILE_SUPERSEDE, + options=pike.smb2.FILE_DELETE_ON_CLOSE, + ).result() + fh_16m = self.chan.create( + self.tree, + filename, + access=access_rwd, + share=share_all, + disposition=pike.smb2.FILE_SUPERSEDE, + options=0, + ).result() self.chan.copychunk(fh_64k, fh_1m, chunks_64k_1m) self.chan.copychunk(fh_1m, fh_16m, chunks_1m_16m) self.chan.close(fh_64k) @@ -255,8 +281,10 @@ def _gen_random_chunks_on_para(self, random_chunk_size=False, random_offset=Fals length = total_len - this_offset chunks.append((offset, offset + dst_offset, length)) this_offset += chunk_sz - self.logger.info("chunks generated, total_length is %d, chunk_size is %d, dst_offset is %lu" % ( - total_len, chunk_sz, dst_offset)) + self.logger.info( + "chunks generated, total_length is %d, chunk_size is %d, dst_offset is %lu" + % (total_len, chunk_sz, dst_offset) + ) return chunks def _prepare_before_ssc_copy(self, filepair, write_thru=False): @@ -267,19 +295,26 @@ def _prepare_before_ssc_copy(self, filepair, write_thru=False): num_sess = len(filepair) for i in range(0, num_sess): chan, tree = self.tree_connect() - fh_src = chan.create(tree, - filepair[i][0], - access=access_rwd, - share=share_all).result() - - fh_dst = chan.create(tree, - filepair[i][1], - access=access_rwd, - share=share_all, - options=my_options).result() + fh_src = chan.create( + tree, filepair[i][0], access=access_rwd, share=share_all + ).result() + + fh_dst = chan.create( + tree, + filepair[i][1], + access=access_rwd, + share=share_all, + options=my_options, + ).result() resume_key = chan.resume_key(fh_src)[0][0].resume_key self.other_chan_list.append( - {"channel": chan, "tree": tree, "filehandles": [fh_src, fh_dst], "resume_key": resume_key}) + { + "channel": chan, + "tree": tree, + "filehandles": [fh_src, fh_dst], + "resume_key": resume_key, + } + ) def _submit_ssc_async_request(self, chan, file_handle, resume_key, chunks): """ @@ -312,7 +347,9 @@ def _submit_ssc_async_request_in_other_channels(self, index, chunks): return self._submit_ssc_async_request(chan, fh_dst, resume_key, chunks) - def generic_ssc_test_case(self, block, number_of_chunks, total_offset=0, write_flag=False): + def generic_ssc_test_case( + self, block, number_of_chunks, total_offset=0, write_flag=False + ): """ copy block in number_of_chunks, offset the destination copy by total_offset """ @@ -339,8 +376,9 @@ def generic_ssc_test_case(self, block, number_of_chunks, total_offset=0, write_f else: dst_access = access_rwd - fh_src, fh_dst = self._open_src_dst(src_filename, dst_filename, - dst_access=dst_access) + fh_src, fh_dst = self._open_src_dst( + src_filename, dst_filename, dst_access=dst_access + ) result = self.chan.copychunk(fh_src, fh_dst, chunks, write_flag=write_flag) @@ -351,8 +389,7 @@ def generic_ssc_test_case(self, block, number_of_chunks, total_offset=0, write_f src_buf = self.chan.read(fh_src, total_len, 0).tobytes() self.assertBufferEqual(src_buf, block) fh_dst_read = self._get_readable_handler(dst_filename) - dst_buf = self.chan.read( - fh_dst_read, total_len, total_offset).tobytes() + dst_buf = self.chan.read(fh_dst_read, total_len, total_offset).tobytes() self.assertBufferEqual(dst_buf, block) self.chan.close(fh_dst_read) @@ -431,11 +468,12 @@ def generic_ssc_same_file_test_case(self, block, number_of_chunks, total_offset= length = chunk_sz else: length = total_len - this_offset - chunks.append((offset, offset+total_len+total_offset, length)) + chunks.append((offset, offset + total_len + total_offset, length)) this_offset += chunk_sz - fh_src, fh_dst = self._open_src_dst(filename, filename, - dst_disp=pike.smb2.FILE_OPEN_IF) + fh_src, fh_dst = self._open_src_dst( + filename, filename, dst_disp=pike.smb2.FILE_OPEN_IF + ) result = self.chan.copychunk(fh_src, fh_dst, chunks) self.assertEqual(result[0][0].chunks_written, number_of_chunks) @@ -447,7 +485,7 @@ def generic_ssc_same_file_test_case(self, block, number_of_chunks, total_offset= if total_offset > 0: offs_buf = self.chan.read(fh_src, total_offset, total_len).tobytes() self.assertBufferEqual(offs_buf, b"\x00" * total_offset) - dst_buf = self.chan.read(fh_src, total_len, total_len+total_offset).tobytes() + dst_buf = self.chan.read(fh_src, total_len, total_len + total_offset).tobytes() self.assertBufferEqual(dst_buf, block) self.chan.close(fh_src) @@ -486,7 +524,9 @@ def test_same_offset_multiple_chunks(self): offset = 64 self.generic_ssc_same_file_test_case(block, num_of_chunks, offset) - def generic_ssc_overlap_test_case(self, block, number_of_chunks, overlap_each_block=0): + def generic_ssc_overlap_test_case( + self, block, number_of_chunks, overlap_each_block=0 + ): """ copy block in number_of_chunks, each destination block offset will be overlapped over the previous block by overlap_each_block bytes @@ -500,8 +540,8 @@ def generic_ssc_overlap_test_case(self, block, number_of_chunks, overlap_each_bl this_offset = 0 chunks = [] - src_block = array.array('B', block) - dst_block = array.array('B', block) + src_block = array.array("B", block) + dst_block = array.array("B", block) while this_offset < total_len: offset = dst_offset = this_offset if offset - overlap_each_block > 0: @@ -511,8 +551,9 @@ def generic_ssc_overlap_test_case(self, block, number_of_chunks, overlap_each_bl else: length = total_len - this_offset chunks.append((offset, dst_offset, length)) - dst_block[dst_offset:dst_offset + length] = \ - src_block[offset:offset+length] + dst_block[dst_offset : dst_offset + length] = src_block[ + offset : offset + length + ] this_offset += chunk_sz dst_len = dst_offset + length dst_block = dst_block[:dst_len].tobytes() @@ -550,48 +591,58 @@ def test_overlap_15_chunks_4096_overlap(self): overlap = 4096 self.generic_ssc_overlap_test_case(block, num_of_chunks, overlap) - def generic_ssc_negative_test_case(self, src_access=None, dst_access=None, - src_disp=None, dst_disp=None, - src_options=None, dst_options=None, - src_brl=None, dst_brl=None, - exp_error=None): + def generic_ssc_negative_test_case( + self, + src_access=None, + dst_access=None, + src_disp=None, + dst_disp=None, + src_options=None, + dst_options=None, + src_brl=None, + dst_brl=None, + exp_error=None, + ): block = b"Hello" total_len = len(block) src_filename = "src_negative.txt" dst_filename = "dst_negative.txt" self._create_and_write(src_filename, block) - fh_src, fh_dst = self._open_src_dst(src_filename, dst_filename, - src_access=src_access, - src_disp=src_disp, - src_options=src_options, - dst_access=dst_access, - dst_disp=dst_disp, - dst_options=dst_options) + fh_src, fh_dst = self._open_src_dst( + src_filename, + dst_filename, + src_access=src_access, + src_disp=src_disp, + src_options=src_options, + dst_access=dst_access, + dst_disp=dst_disp, + dst_options=dst_options, + ) close_handles = [] if src_brl or dst_brl: chan2, tree2 = self.tree_connect() if src_brl: - fh_src_other = chan2.create(tree2, - src_filename, - access=access_rwd, - share=share_all).result() - chan2.lock(fh_src_other, - [( 0, 2, pike.smb2.SMB2_LOCKFLAG_EXCLUSIVE_LOCK )]).result() + fh_src_other = chan2.create( + tree2, src_filename, access=access_rwd, share=share_all + ).result() + chan2.lock( + fh_src_other, [(0, 2, pike.smb2.SMB2_LOCKFLAG_EXCLUSIVE_LOCK)] + ).result() close_handles.append((chan2, fh_src_other)) if dst_brl: - fh_dst_other = chan2.create(tree2, - dst_filename, - access=access_rwd, - share=share_all).result() - chan2.lock(fh_dst_other, - [( 3, 2, pike.smb2.SMB2_LOCKFLAG_EXCLUSIVE_LOCK )]).result() + fh_dst_other = chan2.create( + tree2, dst_filename, access=access_rwd, share=share_all + ).result() + chan2.lock( + fh_dst_other, [(3, 2, pike.smb2.SMB2_LOCKFLAG_EXCLUSIVE_LOCK)] + ).result() close_handles.append((chan2, fh_dst_other)) if exp_error is None: exp_error = pike.ntstatus.STATUS_SUCCESS try: with self.assert_error(exp_error): - result = self.chan.copychunk(fh_src, fh_dst, [(0,0,5)]) + result = self.chan.copychunk(fh_src, fh_dst, [(0, 0, 5)]) finally: for chan, fh in close_handles: chan.close(fh) @@ -604,8 +655,9 @@ def test_neg_src_exc_brl(self): Initiate copychunk when another handle has an exclusive BRL on the source file (win 8 / 2012) """ - self.generic_ssc_negative_test_case(src_brl=True, - exp_error=pike.ntstatus.STATUS_FILE_LOCK_CONFLICT) + self.generic_ssc_negative_test_case( + src_brl=True, exp_error=pike.ntstatus.STATUS_FILE_LOCK_CONFLICT + ) @pike.test.RequireDialect(pike.smb2.DIALECT_SMB3_0) def test_neg_dst_exc_brl(self): @@ -613,41 +665,46 @@ def test_neg_dst_exc_brl(self): Initiate copychunk when another handle has an exclusive BRL on the destination file (win 8 / 2012) """ - self.generic_ssc_negative_test_case(dst_brl=True, - exp_error=pike.ntstatus.STATUS_FILE_LOCK_CONFLICT) + self.generic_ssc_negative_test_case( + dst_brl=True, exp_error=pike.ntstatus.STATUS_FILE_LOCK_CONFLICT + ) def test_neg_src_no_read(self): """ Try to copychunk with no read access on the source file """ - self.generic_ssc_negative_test_case(src_access=pike.smb2.FILE_WRITE_DATA | \ - pike.smb2.DELETE, - exp_error=pike.ntstatus.STATUS_ACCESS_DENIED) + self.generic_ssc_negative_test_case( + src_access=pike.smb2.FILE_WRITE_DATA | pike.smb2.DELETE, + exp_error=pike.ntstatus.STATUS_ACCESS_DENIED, + ) def test_neg_dst_no_read(self): """ Try to copychunk with no read access on the destination file """ - self.generic_ssc_negative_test_case(dst_access=pike.smb2.FILE_WRITE_DATA | \ - pike.smb2.DELETE, - exp_error=pike.ntstatus.STATUS_ACCESS_DENIED) + self.generic_ssc_negative_test_case( + dst_access=pike.smb2.FILE_WRITE_DATA | pike.smb2.DELETE, + exp_error=pike.ntstatus.STATUS_ACCESS_DENIED, + ) def test_neg_dst_no_write(self): """ Try to copychunk with no write access on the destination file """ - self.generic_ssc_negative_test_case(dst_access=pike.smb2.FILE_READ_DATA | \ - pike.smb2.DELETE, - exp_error=pike.ntstatus.STATUS_ACCESS_DENIED) + self.generic_ssc_negative_test_case( + dst_access=pike.smb2.FILE_READ_DATA | pike.smb2.DELETE, + exp_error=pike.ntstatus.STATUS_ACCESS_DENIED, + ) def test_neg_dst_is_a_dir(self): """ Try to copychunk with destination file being a directory """ - self.generic_ssc_negative_test_case(dst_options=pike.smb2.FILE_DIRECTORY_FILE | \ - pike.smb2.FILE_DELETE_ON_CLOSE, - dst_disp=pike.smb2.FILE_OPEN_IF, - exp_error=pike.ntstatus.STATUS_INVALID_DEVICE_REQUEST) + self.generic_ssc_negative_test_case( + dst_options=pike.smb2.FILE_DIRECTORY_FILE | pike.smb2.FILE_DELETE_ON_CLOSE, + dst_disp=pike.smb2.FILE_OPEN_IF, + exp_error=pike.ntstatus.STATUS_INVALID_DEVICE_REQUEST, + ) def generic_multiple_resume_key_test_case(self, sess_num): """ @@ -659,21 +716,20 @@ def generic_multiple_resume_key_test_case(self, sess_num): for i in range(sess_num): chan, tree = self.tree_connect() - fh_1 = chan.create(tree, - src_filename, - access=access_rwd, - share=share_all).result() + fh_1 = chan.create( + tree, src_filename, access=access_rwd, share=share_all + ).result() chan.write(fh_1, 0, content) resume_key_1_1 = chan.resume_key(fh_1)[0][0].resume_key resume_key_1_2 = chan.resume_key(fh_1)[0][0].resume_key - fh_2 = chan.create(tree, - src_filename, - access=access_rwd, - share=share_all).result() + fh_2 = chan.create( + tree, src_filename, access=access_rwd, share=share_all + ).result() resume_key_2_1 = chan.resume_key(fh_2)[0][0].resume_key resume_key_2_2 = chan.resume_key(fh_2)[0][0].resume_key self.other_chan_list.append( - {"channel": chan, "tree": tree, "filehandles": [fh_1, fh_2]}) + {"channel": chan, "tree": tree, "filehandles": [fh_1, fh_2]} + ) try: # for same file handler, resume_key should be same self.assertEqual(resume_key_1_1, resume_key_1_2) @@ -684,8 +740,10 @@ def generic_multiple_resume_key_test_case(self, sess_num): self.assertNotIn(resume_key_1_1, rk_list) self.assertNotIn(resume_key_2_1, rk_list) except AssertionError: - self.error("resume key check failed on session index {0}".format( - i), exc_info=True) + self.error( + "resume key check failed on session index {0}".format(i), + exc_info=True, + ) raise else: rk_list += [resume_key_1_1, resume_key_2_1] @@ -706,15 +764,13 @@ def generic_negative_resume_key_test_case(self, resume_key, exp_error=None): dst_filename = "dst_copy_chunk_rk.txt" chunks = [(0, 0, len(SIMPLE_CONTENT))] - fh_src, fh_dst = self._open_src_dst( - src_filename, dst_filename) + fh_src, fh_dst = self._open_src_dst(src_filename, dst_filename) if exp_error is None: exp_error = pike.ntstatus.STATUS_SUCCESS try: with self.assert_error(exp_error): - result = self.chan.copychunk( - fh_src, fh_dst, chunks, resume_key) + result = self.chan.copychunk(fh_src, fh_dst, chunks, resume_key) finally: self.chan.close(fh_src) self.chan.close(fh_dst) @@ -728,16 +784,17 @@ def test_other_resume_key(self): self._prepare_source_file() chan_2, tree_2 = self.tree_connect() src_filename = "src_copy_chunk_rk.txt" - fh_src_2 = chan_2.create(tree_2, - src_filename, - access=access_rwd, - share=share_all).result() + fh_src_2 = chan_2.create( + tree_2, src_filename, access=access_rwd, share=share_all + ).result() self.other_chan_list.append( - {"channel": chan_2, "tree": tree_2, "filehandles": [fh_src_2]}) + {"channel": chan_2, "tree": tree_2, "filehandles": [fh_src_2]} + ) other_key = chan_2.resume_key(fh_src_2)[0][0].resume_key self.generic_negative_resume_key_test_case( - other_key, exp_error=self.bad_resume_key_error) + other_key, exp_error=self.bad_resume_key_error + ) def test_bogus_resume_key(self): """ @@ -746,13 +803,13 @@ def test_bogus_resume_key(self): """ self._prepare_source_file() import array - bogus_key = array.array('B', [255] * 24) + + bogus_key = array.array("B", [255] * 24) self.generic_negative_resume_key_test_case( - bogus_key, exp_error=self.bad_resume_key_error) + bogus_key, exp_error=self.bad_resume_key_error + ) - def basic_ssc_random_test_case(self, - chunks, - src_options=0): + def basic_ssc_random_test_case(self, chunks, src_options=0): """ given chunks, perform server side copy accordingly """ @@ -760,7 +817,8 @@ def basic_ssc_random_test_case(self, dst_filename = "dst_copy_chunk_random.txt" fh_src, fh_dst = self._open_src_dst( - src_filename, dst_filename, src_options=src_options) + src_filename, dst_filename, src_options=src_options + ) result = self.chan.copychunk(fh_src, fh_dst, chunks) copy_len = chunks[-1][0] + chunks[-1][2] @@ -770,8 +828,7 @@ def basic_ssc_random_test_case(self, # read each file and verify the result src_buf = self._read_big_file(fh_src, copy_len) - dst_buf = self._read_big_file( - fh_dst, copy_len, add_offset=dst_offset) + dst_buf = self._read_big_file(fh_dst, copy_len, add_offset=dst_offset) self.assertBufferEqual(dst_buf, src_buf) self.chan.close(fh_src) @@ -785,8 +842,7 @@ def generic_ssc_random_test_case_loop(self, **kwargs): self._gen_16mega_file(src_filename) iter_num = 3 for i in range(iter_num): - self.logger.info( - "iter %d, parameters flags are %s" % (i, kwargs)) + self.logger.info("iter %d, parameters flags are %s" % (i, kwargs)) chunks = self._gen_random_chunks_on_para(**kwargs) if i == (iter_num - 1): src_options = pike.smb2.FILE_DELETE_ON_CLOSE @@ -802,11 +858,13 @@ def test_random_chunk_size(self): def test_random_file_offset(self): self.generic_ssc_random_test_case_loop( - random_chunk_size=False, random_offset=True) + random_chunk_size=False, random_offset=True + ) def test_random_all(self): self.generic_ssc_random_test_case_loop( - random_chunk_size=True, random_offset=True) + random_chunk_size=True, random_offset=True + ) def generic_ssc_compound_test_case(self): """ @@ -821,26 +879,27 @@ def generic_ssc_compound_test_case(self): block = _gen_test_buffer(SIMPLE_5_CHUNKS_LEN) self._create_and_write(src_filename, block) fh_src, fh_dst = self._open_src_dst(src_filename, dst_filename) - ioctl_req = self.chan.copychunk_request( - fh_src, fh_dst, SIMPLE_5_CHUNKS) + ioctl_req = self.chan.copychunk_request(fh_src, fh_dst, SIMPLE_5_CHUNKS) nb_req = ioctl_req.parent.parent read_req1 = self.chan.read_request( - pike.model.RelatedOpen(self.tree), SIMPLE_5_CHUNKS_LEN // 2, 0) + pike.model.RelatedOpen(self.tree), SIMPLE_5_CHUNKS_LEN // 2, 0 + ) nb_req.adopt(read_req1.parent) - read_req2 = self.chan.read_request(pike.model.RelatedOpen( - self.tree), SIMPLE_5_CHUNKS_LEN // 2, SIMPLE_5_CHUNKS_LEN // 2) + read_req2 = self.chan.read_request( + pike.model.RelatedOpen(self.tree), + SIMPLE_5_CHUNKS_LEN // 2, + SIMPLE_5_CHUNKS_LEN // 2, + ) nb_req.adopt(read_req2.parent) close_req = self.chan.close_request(pike.model.RelatedOpen(self.tree)) nb_req.adopt(close_req.parent) - (ssc_res, - read1_res, - read2_res, - close_res) = self.chan.connection.transceive(nb_req) + (ssc_res, read1_res, read2_res, close_res) = self.chan.connection.transceive( + nb_req + ) self.assertEqual(ssc_res[0][0].chunks_written, len(SIMPLE_5_CHUNKS)) - self.assertEqual( - ssc_res[0][0].total_bytes_written, SIMPLE_5_CHUNKS_LEN) + self.assertEqual(ssc_res[0][0].total_bytes_written, SIMPLE_5_CHUNKS_LEN) dst_buf = read1_res[0].data.tobytes() + read2_res[0].data.tobytes() self.assertBufferEqual(dst_buf, block) self.chan.close(fh_src) @@ -858,8 +917,11 @@ def generic_mchan_ssc_test_case(self): dst_filename = "dst_copy_chunk_mc.txt" block = _gen_test_buffer(SIMPLE_5_CHUNKS_LEN) self._create_and_write(src_filename, block) - chan2 = self.chan.connection.client.connect(self.server).\ - negotiate().session_setup(self.creds, bind=self.chan.session) + chan2 = ( + self.chan.connection.client.connect(self.server) + .negotiate() + .session_setup(self.creds, bind=self.chan.session) + ) fh_src, fh_dst = self._open_src_dst(src_filename, dst_filename) resume_key = self.chan.resume_key(fh_src)[0][0].resume_key @@ -882,8 +944,9 @@ def generic_mchan_ssc_test_case(self): def test_ssc_in_multchannel(self): self.generic_mchan_ssc_test_case() - def generic_multiple_ssc_test_case(self, filepair, chunks, blocks, - write_thru=False, num_iter=1): + def generic_multiple_ssc_test_case( + self, filepair, chunks, blocks, write_thru=False, num_iter=1 + ): """ server side copy in multiple sessions, multiple iterations with filepair, chunks, blocks, write_through flag as input @@ -901,8 +964,9 @@ def generic_multiple_ssc_test_case(self, filepair, chunks, blocks, chunk_break = list(zip(*chunks)) dst_list = [x + filepair[i][2] for x in chunk_break[1]] newchunks = list(zip(chunk_break[0], dst_list, chunk_break[2])) - ssc_futures[it * num_sess + - i] = self._submit_ssc_async_request_in_other_channels(i, newchunks) + ssc_futures[ + it * num_sess + i + ] = self._submit_ssc_async_request_in_other_channels(i, newchunks) # collect asychronized results for i in range(num_sess * num_iter): @@ -911,8 +975,15 @@ def generic_multiple_ssc_test_case(self, filepair, chunks, blocks, self.assertEqual(results[i][0][0].chunks_written, len(chunks)) self.assertEqual(results[i][0][0].total_bytes_written, copy_len) if i < num_sess: - dst_buf = self.other_chan_list[i]["channel"].read( - self.other_chan_list[i]["filehandles"][1], copy_len, filepair[i][2]).tobytes() + dst_buf = ( + self.other_chan_list[i]["channel"] + .read( + self.other_chan_list[i]["filehandles"][1], + copy_len, + filepair[i][2], + ) + .tobytes() + ) self.assertBufferEqual(dst_buf, blocks[i]) def test_multiple_ssc_file(self): @@ -932,10 +1003,13 @@ def test_multiple_ssc_file(self): block = _gen_random_test_buffer(SIMPLE_5_CHUNKS_LEN) self._create_and_write(src_filename, block) blocks.append(block) - self.logger.info("start multiple session test, session number is %d iteration number is %d" % ( - num_sess, num_iter)) + self.logger.info( + "start multiple session test, session number is %d iteration number is %d" + % (num_sess, num_iter) + ) self.generic_multiple_ssc_test_case( - filepair, SIMPLE_5_CHUNKS, blocks, num_iter=num_iter) + filepair, SIMPLE_5_CHUNKS, blocks, num_iter=num_iter + ) def test_multiple_ssc_same_source_file(self): """ @@ -955,10 +1029,13 @@ def test_multiple_ssc_same_source_file(self): block = _gen_random_test_buffer(SIMPLE_5_CHUNKS_LEN) self._create_and_write(src_filename, block) blocks = [block] * num_sess - self.logger.info("ssc same source multiple session test, session number is %d iteration number is %d" % ( - num_sess, num_iter)) + self.logger.info( + "ssc same source multiple session test, session number is %d iteration number is %d" + % (num_sess, num_iter) + ) self.generic_multiple_ssc_test_case( - filepair, SIMPLE_5_CHUNKS, blocks, num_iter=num_iter) + filepair, SIMPLE_5_CHUNKS, blocks, num_iter=num_iter + ) def test_multiple_ssc_same_dest_file(self): """ @@ -973,15 +1050,17 @@ def test_multiple_ssc_same_dest_file(self): for i in range(0, num_sess): src_filename = "src_multiple_session" + str(i) + ".txt" dst_filename = "dst_multiple_session_same_dest.txt" - filepair.append((src_filename, dst_filename, - 0 + i * SIMPLE_5_CHUNKS_LEN)) + filepair.append((src_filename, dst_filename, 0 + i * SIMPLE_5_CHUNKS_LEN)) block = _gen_random_test_buffer(SIMPLE_5_CHUNKS_LEN) self._create_and_write(src_filename, block) blocks.append(block) - self.logger.info("ssc same dest multiple session test, session number is %d iteration number is %d" % ( - num_sess, num_iter)) + self.logger.info( + "ssc same dest multiple session test, session number is %d iteration number is %d" + % (num_sess, num_iter) + ) self.generic_multiple_ssc_test_case( - filepair, SIMPLE_5_CHUNKS, blocks, num_iter=num_iter) + filepair, SIMPLE_5_CHUNKS, blocks, num_iter=num_iter + ) def test_multiple_ssc_file_with_writethrough_flag(self): """ @@ -1000,13 +1079,17 @@ def test_multiple_ssc_file_with_writethrough_flag(self): block = _gen_random_test_buffer(SIMPLE_5_CHUNKS_LEN) self._create_and_write(src_filename, block) blocks.append(block) - self.logger.info("ssc test with write_through set, session number is %d iteration number is %d" % ( - num_sess, num_iter)) + self.logger.info( + "ssc test with write_through set, session number is %d iteration number is %d" + % (num_sess, num_iter) + ) self.generic_multiple_ssc_test_case( - filepair, SIMPLE_5_CHUNKS, blocks, write_thru=True, num_iter=num_iter) + filepair, SIMPLE_5_CHUNKS, blocks, write_thru=True, num_iter=num_iter + ) - def generic_ssc_boundary_test_case(self, block, chunks, - exp_error=None, ssc_res=[0, 0, 0]): + def generic_ssc_boundary_test_case( + self, block, chunks, exp_error=None, ssc_res=[0, 0, 0] + ): """ check situation that one of the chunks which contain numbers cross the value of end of file or maximum values system can support @@ -1017,8 +1100,7 @@ def generic_ssc_boundary_test_case(self, block, chunks, fh_src, fh_dst = self._open_src_dst(src_filename, dst_filename) resume_key = self.chan.resume_key(fh_src)[0][0].resume_key - future = self._submit_ssc_async_request( - self.chan, fh_dst, resume_key, chunks) + future = self._submit_ssc_async_request(self.chan, fh_dst, resume_key, chunks) if exp_error is None: exp_error = pike.ntstatus.STATUS_SUCCESS @@ -1030,8 +1112,7 @@ def generic_ssc_boundary_test_case(self, block, chunks, self.chan.close(fh_dst) ioctl_resp = future[0].response.response.children[0] - self.assertIsInstance( - ioctl_resp.ioctl_output, pike.smb2.CopyChunkCopyResponse) + self.assertIsInstance(ioctl_resp.ioctl_output, pike.smb2.CopyChunkCopyResponse) chunks_written = ioctl_resp.children[0].chunks_written chunk_bytes_written = ioctl_resp.children[0].chunk_bytes_written total_bytes_written = ioctl_resp.children[0].total_bytes_written @@ -1042,25 +1123,37 @@ def generic_ssc_boundary_test_case(self, block, chunks, def test_neg_cross_offset_basic(self): block = _gen_test_buffer(4096) chunks = [(10, 0, 4096)] - self.generic_ssc_boundary_test_case(block, chunks, - exp_error=pike.ntstatus.STATUS_INVALID_VIEW_SIZE) + self.generic_ssc_boundary_test_case( + block, chunks, exp_error=pike.ntstatus.STATUS_INVALID_VIEW_SIZE + ) def test_neg_cross_offset_second_chunk(self): block = _gen_test_buffer(8192) chunks = [(0, 0, 4096), (4097, 4096, 4096)] exp_res = [1, 0, 4096] - self.generic_ssc_boundary_test_case(block, chunks, - exp_error=pike.ntstatus.STATUS_INVALID_VIEW_SIZE, - ssc_res=exp_res) + self.generic_ssc_boundary_test_case( + block, + chunks, + exp_error=pike.ntstatus.STATUS_INVALID_VIEW_SIZE, + ssc_res=exp_res, + ) def test_neg_cross_offset_fifth_chunk(self): block = _gen_test_buffer(20480) - chunks = [(0, 0, 4096), (4096, 4096, 4096), (8192, 8192, 4096), - (12288, 12288, 4096), (16386, 16384, 4096)] + chunks = [ + (0, 0, 4096), + (4096, 4096, 4096), + (8192, 8192, 4096), + (12288, 12288, 4096), + (16386, 16384, 4096), + ] exp_res = [4, 0, 16384] - self.generic_ssc_boundary_test_case(block, chunks, - exp_error=pike.ntstatus.STATUS_INVALID_VIEW_SIZE, - ssc_res=exp_res) + self.generic_ssc_boundary_test_case( + block, + chunks, + exp_error=pike.ntstatus.STATUS_INVALID_VIEW_SIZE, + ssc_res=exp_res, + ) def test_neg_cross_max_chunks(self): """ @@ -1068,12 +1161,13 @@ def test_neg_cross_max_chunks(self): """ block = _gen_test_buffer(30000) chunks = [(0, 0, 100)] * 300 - exp_res = [self.max_number_of_chunks, - self.max_chunk_size, - self.max_data_size] - self.generic_ssc_boundary_test_case(block, chunks, - exp_error=pike.ntstatus.STATUS_INVALID_PARAMETER, - ssc_res=exp_res) + exp_res = [self.max_number_of_chunks, self.max_chunk_size, self.max_data_size] + self.generic_ssc_boundary_test_case( + block, + chunks, + exp_error=pike.ntstatus.STATUS_INVALID_PARAMETER, + ssc_res=exp_res, + ) def test_neg_cross_chunk_size(self): """ @@ -1082,12 +1176,13 @@ def test_neg_cross_chunk_size(self): """ block = _gen_test_buffer(1048577) chunks = [(0, 0, 1048577)] - exp_res = [self.max_number_of_chunks, - self.max_chunk_size, - self.max_data_size] - self.generic_ssc_boundary_test_case(block, chunks, - exp_error=pike.ntstatus.STATUS_INVALID_PARAMETER, - ssc_res=exp_res) + exp_res = [self.max_number_of_chunks, self.max_chunk_size, self.max_data_size] + self.generic_ssc_boundary_test_case( + block, + chunks, + exp_error=pike.ntstatus.STATUS_INVALID_PARAMETER, + ssc_res=exp_res, + ) def test_neg_cross_second_chunk_size(self): """ @@ -1096,12 +1191,13 @@ def test_neg_cross_second_chunk_size(self): """ block = _gen_test_buffer(2097153) chunks = [(0, 0, 1048576), (1048576, 1048576, 1048577)] - exp_res = [self.max_number_of_chunks, - self.max_chunk_size, - self.max_data_size] - self.generic_ssc_boundary_test_case(block, chunks, - exp_error=pike.ntstatus.STATUS_INVALID_PARAMETER, - ssc_res=exp_res) + exp_res = [self.max_number_of_chunks, self.max_chunk_size, self.max_data_size] + self.generic_ssc_boundary_test_case( + block, + chunks, + exp_error=pike.ntstatus.STATUS_INVALID_PARAMETER, + ssc_res=exp_res, + ) def test_neg_cross_chunk_size_allf(self): """ @@ -1109,9 +1205,10 @@ def test_neg_cross_chunk_size_allf(self): """ block = _gen_test_buffer(1048577) chunks = [(0, 0, 4294967295)] - exp_res = [self.max_number_of_chunks, - self.max_chunk_size, - self.max_data_size] - self.generic_ssc_boundary_test_case(block, chunks, - exp_error=pike.ntstatus.STATUS_INVALID_PARAMETER, - ssc_res=exp_res) + exp_res = [self.max_number_of_chunks, self.max_chunk_size, self.max_data_size] + self.generic_ssc_boundary_test_case( + block, + chunks, + exp_error=pike.ntstatus.STATUS_INVALID_PARAMETER, + ssc_res=exp_res, + ) diff --git a/pike/test/credit.py b/pike/test/credit.py index f13a84c0..b878e595 100644 --- a/pike/test/credit.py +++ b/pike/test/credit.py @@ -29,39 +29,47 @@ import pike.test # common size constants -size_64k = 2**16 -size_128k = 2**17 +size_64k = 2 ** 16 +size_128k = 2 ** 17 size_192k = size_64k + size_128k -size_512k = 2**19 +size_512k = 2 ** 19 size_960k = size_192k * 5 -size_1m = 2**20 -size_2m = 2**21 -size_4m = 2**22 -size_8m = 2**23 - -share_all = pike.smb2.FILE_SHARE_READ | pike.smb2.FILE_SHARE_WRITE | pike.smb2.FILE_SHARE_DELETE +size_1m = 2 ** 20 +size_2m = 2 ** 21 +size_4m = 2 ** 22 +size_8m = 2 ** 23 + +share_all = ( + pike.smb2.FILE_SHARE_READ | pike.smb2.FILE_SHARE_WRITE | pike.smb2.FILE_SHARE_DELETE +) lease_rh = pike.smb2.SMB2_LEASE_READ_CACHING | pike.smb2.SMB2_LEASE_HANDLE_CACHING # debugging callback functions which are registered if debug logging is enabled def post_serialize_credit_assessment(nb): smb_res = nb[0] - print("{0} ({1}) ___ Charge: {2} / Request: {3} / Total: {4}".format( - smb_res.command, - smb_res.message_id, - smb_res.credit_charge, - smb_res.credit_request, - nb.conn.credits)) + print( + "{0} ({1}) ___ Charge: {2} / Request: {3} / Total: {4}".format( + smb_res.command, + smb_res.message_id, + smb_res.credit_charge, + smb_res.credit_request, + nb.conn.credits, + ) + ) def post_deserialize_credit_assessment(nb): smb_res = nb[0] - print("{0} ({1}) ___ Charge: {2} / Response: {3} / Total: {4}".format( - smb_res.command, - smb_res.message_id, - smb_res.credit_charge, - smb_res.credit_response, - nb.conn.credits + smb_res.credit_response - smb_res.credit_charge)) + print( + "{0} ({1}) ___ Charge: {2} / Response: {3} / Total: {4}".format( + smb_res.command, + smb_res.message_id, + smb_res.credit_charge, + smb_res.credit_response, + nb.conn.credits + smb_res.credit_response - smb_res.credit_charge, + ) + ) def post_serialize_credit_assert(exp_credit_charge, future): @@ -69,10 +77,12 @@ def cb(nb): with future: if nb[0].credit_charge != exp_credit_charge: raise AssertionError( - "Expected credit_charge {0}. Actual {1}".format( - exp_credit_charge, - nb[0].credit_charge)) + "Expected credit_charge {0}. Actual {1}".format( + exp_credit_charge, nb[0].credit_charge + ) + ) future.complete(True) + return cb @@ -82,11 +92,11 @@ def __init__(self, *args, **kwargs): super(CreditTest, self).__init__(*args, **kwargs) if self.loglevel == pike.test.logging.DEBUG: self.default_client.register_callback( - pike.model.EV_REQ_POST_SERIALIZE, - post_serialize_credit_assessment) + pike.model.EV_REQ_POST_SERIALIZE, post_serialize_credit_assessment + ) self.default_client.register_callback( - pike.model.EV_RES_POST_DESERIALIZE, - post_deserialize_credit_assessment) + pike.model.EV_RES_POST_DESERIALIZE, post_deserialize_credit_assessment + ) # set the default credit request to 1 to make things more predictable def setUp(self): @@ -117,25 +127,29 @@ def generic_mc_write_mc_read(self, file_size, write_size, read_size): with chan.let(credit_request=16): fh = chan.create(tree, fname).result() - self.info("writing {0} chunks of {1} bytes; {2} credits per op".format( - write_chunks, - write_size, - write_credits_per_op)) + self.info( + "writing {0} chunks of {1} bytes; {2} credits per op".format( + write_chunks, write_size, write_credits_per_op + ) + ) for ix in range(write_chunks): credit_assert_future = pike.model.Future() with chan.connection.callback( - pike.model.EV_REQ_POST_SERIALIZE, - post_serialize_credit_assert( - write_credits_per_op, - credit_assert_future)): - result = chan.write(fh, write_size*ix, write_buf) + pike.model.EV_REQ_POST_SERIALIZE, + post_serialize_credit_assert( + write_credits_per_op, credit_assert_future + ), + ): + result = chan.write(fh, write_size * ix, write_buf) self.assertEqual(result, write_size) self.assertTrue(credit_assert_future.result()) chan.close(fh) # calculate a reasonable expected number of credits # from negotiate, session_setup (x2), tree_connect, create (+16), close - exp_credits = starting_credits + ((pike.model.default_credit_request - 1) * 4) + 15 + exp_credits = ( + starting_credits + ((pike.model.default_credit_request - 1) * 4) + 15 + ) credit_request_per_op = pike.model.default_credit_request # from the series of write requests if write_credits_per_op > credit_request_per_op: @@ -144,37 +158,40 @@ def generic_mc_write_mc_read(self, file_size, write_size, read_size): # windows seems to have a credit wall of 128 if exp_credits > 128: exp_credits = 128 - self.info("Expect the server to have granted at least " - "{0} credits".format(exp_credits)) + self.info( + "Expect the server to have granted at least " + "{0} credits".format(exp_credits) + ) self.assertGreaterEqual(chan.connection.credits, exp_credits) read_chunks = file_size // read_size read_buf = buf * (file_chunks // read_chunks) read_credits_per_op = read_size // size_64k - self.info("reading {0} chunks of {1} bytes; {2} credits per op".format( - read_chunks, - read_size, - read_credits_per_op)) + self.info( + "reading {0} chunks of {1} bytes; {2} credits per op".format( + read_chunks, read_size, read_credits_per_op + ) + ) fh = chan.create( tree, fname, access=pike.smb2.GENERIC_READ | pike.smb2.DELETE, disposition=pike.smb2.FILE_OPEN, - options=pike.smb2.FILE_DELETE_ON_CLOSE).result() + options=pike.smb2.FILE_DELETE_ON_CLOSE, + ).result() file_buffer = array.array("B") for ix in range(read_chunks): credit_assert_future = pike.model.Future() with chan.connection.callback( - pike.model.EV_REQ_POST_SERIALIZE, - post_serialize_credit_assert( - read_credits_per_op, - credit_assert_future)): - result = chan.read(fh, read_size, read_size*ix) + pike.model.EV_REQ_POST_SERIALIZE, + post_serialize_credit_assert(read_credits_per_op, credit_assert_future), + ): + result = chan.read(fh, read_size, read_size * ix) file_buffer.extend(result) self.assertEqual(len(result), read_size) self.assertTrue(credit_assert_future.result()) chan.close(fh) - self.assertEqual(file_buffer.tobytes(), buf*file_chunks) + self.assertEqual(file_buffer.tobytes(), buf * file_chunks) def generic_arbitrary_mc_write_mc_read(self, file_size, write_size, read_size): """ @@ -185,7 +202,7 @@ def generic_arbitrary_mc_write_mc_read(self, file_size, write_size, read_size): this version of the function works with arbitrary sizes """ fname = self.id().rpartition(".")[-1] - buf = b"\0\1\2\3\4\5\6\7"*8192 + buf = b"\0\1\2\3\4\5\6\7" * 8192 buflen = len(buf) file_chunks, file_remainder = divmod(file_size, buflen) file_buf = buf * file_chunks + buf[:file_remainder] @@ -211,10 +228,11 @@ def generic_arbitrary_mc_write_mc_read(self, file_size, write_size, read_size): with chan.let(credit_request=16): fh = chan.create(tree, fname).result() - self.info("writing {0} chunks of {1} bytes; {2} credits per op".format( - write_chunks, - write_size, - write_credits_per_op)) + self.info( + "writing {0} chunks of {1} bytes; {2} credits per op".format( + write_chunks, write_size, write_credits_per_op + ) + ) ix = None # TODO: consolidate chunks to a list of tuples (file_offset, local_buffer_offset, length) # this would simplify the loop, instead of having the extra chunk @@ -222,43 +240,44 @@ def generic_arbitrary_mc_write_mc_read(self, file_size, write_size, read_size): for ix in range(write_chunks): credit_assert_future = pike.model.Future() with chan.connection.callback( - pike.model.EV_REQ_POST_SERIALIZE, - post_serialize_credit_assert( - write_credits_per_op, - credit_assert_future)): + pike.model.EV_REQ_POST_SERIALIZE, + post_serialize_credit_assert( + write_credits_per_op, credit_assert_future + ), + ): result = chan.write( - fh, - write_size*ix, - file_buf[write_size*ix:write_size*(ix+1)]) + fh, + write_size * ix, + file_buf[write_size * ix : write_size * (ix + 1)], + ) self.assertEqual(result, write_size) self.assertTrue(credit_assert_future.result()) if extra_write is not None: if ix is None: extra_write_offset = 0 else: - extra_write_offset = write_size*(ix+1) + extra_write_offset = write_size * (ix + 1) ix = None - self.info("writing extra chunk of {0} bytes @ {1}; {2} credits".format( - extra_write[0], - extra_write_offset, - extra_write[1])) + self.info( + "writing extra chunk of {0} bytes @ {1}; {2} credits".format( + extra_write[0], extra_write_offset, extra_write[1] + ) + ) credit_assert_future = pike.model.Future() with chan.connection.callback( - pike.model.EV_REQ_POST_SERIALIZE, - post_serialize_credit_assert( - extra_write[1], - credit_assert_future)): - result = chan.write( - fh, - extra_write_offset, - file_buf[-extra_write[0]:]) + pike.model.EV_REQ_POST_SERIALIZE, + post_serialize_credit_assert(extra_write[1], credit_assert_future), + ): + result = chan.write(fh, extra_write_offset, file_buf[-extra_write[0] :]) self.assertEqual(result, extra_write[0]) self.assertTrue(credit_assert_future.result()) chan.close(fh) # calculate a reasonable expected number of credits # from negotiate, session_setup (x2), tree_connect, create (+16), close - exp_credits = starting_credits + ((pike.model.default_credit_request - 1) * 4) + 15 + exp_credits = ( + starting_credits + ((pike.model.default_credit_request - 1) * 4) + 15 + ) credit_request_per_op = pike.model.default_credit_request # from the series of write requests if write_credits_per_op > credit_request_per_op: @@ -269,12 +288,14 @@ def generic_arbitrary_mc_write_mc_read(self, file_size, write_size, read_size): credit_request_per_op = pike.model.default_credit_request if extra_write[1] > credit_request_per_op: credit_request_per_op = extra_write[1] - exp_credits += (credit_request_per_op - extra_write[1]) + exp_credits += credit_request_per_op - extra_write[1] # windows seems to have a credit wall of 128 if exp_credits > 128: exp_credits = 128 - self.info("Expect the server to have granted at least " - "{0} credits".format(exp_credits)) + self.info( + "Expect the server to have granted at least " + "{0} credits".format(exp_credits) + ) self.assertGreaterEqual(chan.connection.credits, exp_credits) read_chunks, read_remainder = divmod(file_size, read_size) @@ -290,25 +311,26 @@ def generic_arbitrary_mc_write_mc_read(self, file_size, write_size, read_size): c += 1 extra_read = (read_remainder, c) - self.info("reading {0} chunks of {1} bytes; {2} credits per op".format( - read_chunks, - read_size, - read_credits_per_op)) + self.info( + "reading {0} chunks of {1} bytes; {2} credits per op".format( + read_chunks, read_size, read_credits_per_op + ) + ) fh = chan.create( - tree, - fname, - access=pike.smb2.GENERIC_READ | pike.smb2.DELETE, - disposition=pike.smb2.FILE_OPEN, - options=pike.smb2.FILE_DELETE_ON_CLOSE).result() + tree, + fname, + access=pike.smb2.GENERIC_READ | pike.smb2.DELETE, + disposition=pike.smb2.FILE_OPEN, + options=pike.smb2.FILE_DELETE_ON_CLOSE, + ).result() read_buffer = array.array("B") for ix in range(read_chunks): credit_assert_future = pike.model.Future() with chan.connection.callback( - pike.model.EV_REQ_POST_SERIALIZE, - post_serialize_credit_assert( - read_credits_per_op, - credit_assert_future)): - result = chan.read(fh, read_size, read_size*ix) + pike.model.EV_REQ_POST_SERIALIZE, + post_serialize_credit_assert(read_credits_per_op, credit_assert_future), + ): + result = chan.read(fh, read_size, read_size * ix) read_buffer.extend(result) self.assertEqual(len(result), read_size) self.assertTrue(credit_assert_future.result()) @@ -316,17 +338,17 @@ def generic_arbitrary_mc_write_mc_read(self, file_size, write_size, read_size): if ix is None: extra_read_offset = 0 else: - extra_read_offset = read_size*(ix+1) - self.info("reading extra chunk of {0} bytes @ {1}; {2} credits".format( - extra_read[0], - extra_read_offset, - extra_read[1])) + extra_read_offset = read_size * (ix + 1) + self.info( + "reading extra chunk of {0} bytes @ {1}; {2} credits".format( + extra_read[0], extra_read_offset, extra_read[1] + ) + ) credit_assert_future = pike.model.Future() with chan.connection.callback( - pike.model.EV_REQ_POST_SERIALIZE, - post_serialize_credit_assert( - extra_read[1], - credit_assert_future)): + pike.model.EV_REQ_POST_SERIALIZE, + post_serialize_credit_assert(extra_read[1], credit_assert_future), + ): result = chan.read(fh, extra_read[0], extra_read_offset) read_buffer.extend(result) self.assertEqual(len(result), extra_read[0]) @@ -337,7 +359,6 @@ def generic_arbitrary_mc_write_mc_read(self, file_size, write_size, read_size): class PowerOf2CreditTest(CreditTest): - def test_1_1m_write_1_1m_read(self): self.generic_mc_write_mc_read(size_1m, size_1m, size_1m) @@ -381,21 +402,20 @@ def test_sequence_number_wrap(self): self.assertEqual(chan1.connection.credits, starting_credits) with chan1.let(credit_request=credits_per_req): - fh1 = chan1.create( - tree1, - fname).result() + fh1 = chan1.create(tree1, fname).result() exp_credits = starting_credits + credits_per_req - 1 self.assertEqual(chan1.connection.credits, exp_credits) # build up the sequence number to the target while chan1.connection._next_mid < sequence_number_target: - smb_req = chan1.write_request(fh1, 0, buf*credits_per_req).parent + smb_req = chan1.write_request(fh1, 0, buf * credits_per_req).parent smb_future = chan1.connection.submit(smb_req.parent)[0] smb_resp = smb_future.result() if smb_future.interim_response: # if server granted credits on interim - self.assertEqual(smb_future.interim_response.credit_response, - credits_per_req) + self.assertEqual( + smb_future.interim_response.credit_response, credits_per_req + ) # then server should grant 0 credits on final resp self.assertEqual(smb_resp.credit_response, 0) else: @@ -422,24 +442,21 @@ def test_async_lock(self): """ chan1, tree1 = self.tree_connect() chan2, tree2 = self.tree_connect() - chan2_starting_credits = chan2.connection.negotiate_response.parent.credit_response + chan2_starting_credits = ( + chan2.connection.negotiate_response.parent.credit_response + ) fname = "test_async_lock" buf = b"\0\1\2\3\4\5\6\7" lock1 = (0, 8, pike.smb2.SMB2_LOCKFLAG_EXCLUSIVE_LOCK) contend_locks = [ - (0, 2, pike.smb2.SMB2_LOCKFLAG_EXCLUSIVE_LOCK), - (2, 2, pike.smb2.SMB2_LOCKFLAG_EXCLUSIVE_LOCK), - (4, 4, pike.smb2.SMB2_LOCKFLAG_EXCLUSIVE_LOCK)] + (0, 2, pike.smb2.SMB2_LOCKFLAG_EXCLUSIVE_LOCK), + (2, 2, pike.smb2.SMB2_LOCKFLAG_EXCLUSIVE_LOCK), + (4, 4, pike.smb2.SMB2_LOCKFLAG_EXCLUSIVE_LOCK), + ] credit_req = 3 - fh1 = chan1.create( - tree1, - fname, - share=share_all).result() - fh2 = chan2.create( - tree2, - fname, - share=share_all).result() + fh1 = chan1.create(tree1, fname, share=share_all).result() + fh2 = chan2.create(tree2, fname, share=share_all).result() self.assertEqual(chan2.connection.credits, chan2_starting_credits) chan1.lock(fh1, [lock1]).result() @@ -470,14 +487,17 @@ def test_async_lock(self): buf = b"\0\1\2\3\4\5\6\7" * 8192 # send a request for all of our credits - chan2.write(fh2, 0, buf*exp_credits) + chan2.write(fh2, 0, buf * exp_credits) self.assertEqual(chan2.connection.credits, exp_credits) # send a request for all of our credits + 1 (this should disconnect the client) with self.assertRaises(EOFError): - chan2.write(fh2, 0, buf*(exp_credits + 1)) - self.fail("We should have {0} credits, but an {1} credit request succeeds".format( - exp_credits, exp_credits + 1)) + chan2.write(fh2, 0, buf * (exp_credits + 1)) + self.fail( + "We should have {0} credits, but an {1} credit request succeeds".format( + exp_credits, exp_credits + 1 + ) + ) def test_async_write(self): """ @@ -490,30 +510,32 @@ def test_async_write(self): """ chan1, tree1 = self.tree_connect() chan2, tree2 = self.tree_connect() - chan2_starting_credits = chan2.connection.negotiate_response.parent.credit_response + chan2_starting_credits = ( + chan2.connection.negotiate_response.parent.credit_response + ) fname = "test_async_write" - lkey = array.array('B', map(random.randint, [0] * 16, [255] * 16)) + lkey = array.array("B", map(random.randint, [0] * 16, [255] * 16)) # buf is 64k buf = b"\0\1\2\3\4\5\6\7" * 8192 write_request_multiples = [1, 2, 3, 4] credit_req = 16 fh1 = chan1.create( - tree1, - fname, - share=share_all, - oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, - lease_key=lkey, - lease_state=lease_rh).result() - fh2 = chan2.create( - tree2, - fname, - share=share_all).result() + tree1, + fname, + share=share_all, + oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, + lease_key=lkey, + lease_state=lease_rh, + ).result() + fh2 = chan2.create(tree2, fname, share=share_all).result() self.assertEqual(chan2.connection.credits, chan2_starting_credits) write_futures = [] for n_credits in write_request_multiples: with chan2.let(credit_request=credit_req): - f = chan2.connection.submit(chan2.write_request(fh2, 0, buf*n_credits).parent.parent)[0] + f = chan2.connection.submit( + chan2.write_request(fh2, 0, buf * n_credits).parent.parent + )[0] f.wait_interim() if f.interim_response is not None: self.assertEqual(f.interim_response.credit_response, credit_req) @@ -546,18 +568,27 @@ def test_{name}_{tag}_{ix}(self): self.generic_arbitrary_mc_write_mc_read({file_size}, {write_size}, {read_size})""" @classmethod - def generate_multiple_64k_test_cases(cls, tag, n_cases, size_range_multiple, write_range_multiple, read_range_multiple): + def generate_multiple_64k_test_cases( + cls, + tag, + n_cases, + size_range_multiple, + write_range_multiple, + read_range_multiple, + ): name = "Mult64k" print(cls.header.format(**locals())) for ix in range(n_cases): - file_size = 2**16 * random.randint(*size_range_multiple) - write_size = 2**16 * random.randint(*write_range_multiple) - read_size = 2**16 * random.randint(*read_range_multiple) + file_size = 2 ** 16 * random.randint(*size_range_multiple) + write_size = 2 ** 16 * random.randint(*write_range_multiple) + read_size = 2 ** 16 * random.randint(*read_range_multiple) print(cls.template.format(**locals())) print(cls.footer.format(**locals())) @classmethod - def generate_arbitrary_test_cases(cls, tag, n_cases, size_range, write_range, read_range): + def generate_arbitrary_test_cases( + cls, tag, n_cases, size_range, write_range, read_range + ): name = "Arb" print(cls.header.format(**locals())) for ix in range(n_cases): @@ -570,8 +601,13 @@ def generate_arbitrary_test_cases(cls, tag, n_cases, size_range, write_range, re if __name__ == "__main__": import argparse + parser = argparse.ArgumentParser() if len(sys.argv) > 1 and sys.argv[1].startswith("64"): - TestCaseGenerator.generate_multiple_64k_test_cases("gen1", 8, (1, 128), (1, 16), (1, 16)) + TestCaseGenerator.generate_multiple_64k_test_cases( + "gen1", 8, (1, 128), (1, 16), (1, 16) + ) else: - TestCaseGenerator.generate_arbitrary_test_cases("iter1", 32, (45*1024, 2**23), (2**15, 2**20), (2**15, 2**20)) + TestCaseGenerator.generate_arbitrary_test_cases( + "iter1", 32, (45 * 1024, 2 ** 23), (2 ** 15, 2 ** 20), (2 ** 15, 2 ** 20) + ) diff --git a/pike/test/durable.py b/pike/test/durable.py index 346bef64..fe447f0c 100644 --- a/pike/test/durable.py +++ b/pike/test/durable.py @@ -28,33 +28,48 @@ # for buffer too small class InvalidNetworkResiliencyRequestRequest(pike.smb2.NetworkResiliencyRequestRequest): - def _encode(self, cur): + def _encode(self, cur): cur.encode_uint32le(self.timeout) cur.encode_uint16le(self.reserved) @pike.test.RequireCapabilities(pike.smb2.SMB2_GLOBAL_CAP_LEASING) class DurableHandleTest(pike.test.PikeTest): - share_all = pike.smb2.FILE_SHARE_READ | pike.smb2.FILE_SHARE_WRITE | pike.smb2.FILE_SHARE_DELETE - lease1 = array.array('B', map(random.randint, [0] * 16, [255] * 16)) - lease2 = array.array('B', map(random.randint, [0] * 16, [255] * 16)) + share_all = ( + pike.smb2.FILE_SHARE_READ + | pike.smb2.FILE_SHARE_WRITE + | pike.smb2.FILE_SHARE_DELETE + ) + lease1 = array.array("B", map(random.randint, [0] * 16, [255] * 16)) + lease2 = array.array("B", map(random.randint, [0] * 16, [255] * 16)) r = pike.smb2.SMB2_LEASE_READ_CACHING rw = r | pike.smb2.SMB2_LEASE_WRITE_CACHING rh = r | pike.smb2.SMB2_LEASE_HANDLE_CACHING rwh = rw | rh buffer_too_small_error = pike.ntstatus.STATUS_INVALID_PARAMETER - def create(self, chan, tree, durable, lease=rwh, lease_key=lease1, - disposition=pike.smb2.FILE_SUPERSEDE): - return chan.create(tree, - 'durable.txt', - access=pike.smb2.FILE_READ_DATA | pike.smb2.FILE_WRITE_DATA | pike.smb2.DELETE, - share=self.share_all, - disposition=disposition, - oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, - lease_key = lease_key, - lease_state = lease, - durable=durable).result() + def create( + self, + chan, + tree, + durable, + lease=rwh, + lease_key=lease1, + disposition=pike.smb2.FILE_SUPERSEDE, + ): + return chan.create( + tree, + "durable.txt", + access=pike.smb2.FILE_READ_DATA + | pike.smb2.FILE_WRITE_DATA + | pike.smb2.DELETE, + share=self.share_all, + disposition=disposition, + oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, + lease_key=lease_key, + lease_state=lease, + durable=durable, + ).result() def durable_test(self, durable): chan, tree = self.tree_connect() @@ -123,12 +138,14 @@ def durable_invalidate_test(self, durable): chan2, tree2 = self.tree_connect(client=pike.model.Client()) # Invalidate handle from separate client - handle2 = self.create(chan2, - tree2, - durable=durable, - lease=self.rw, - lease_key=self.lease2, - disposition=pike.smb2.FILE_OPEN) + handle2 = self.create( + chan2, + tree2, + durable=durable, + lease=self.rw, + lease_key=self.lease2, + disposition=pike.smb2.FILE_OPEN, + ) self.assertEqual(handle2.lease.lease_state, self.rw) chan2.close(handle2) @@ -157,12 +174,14 @@ def test_resiliency_reconnect_before_timeout(self, durable=True): chan2, tree2 = self.tree_connect(client=pike.model.Client()) - handle2 = self.create(chan2, - tree2, - durable=durable, - lease=self.rw, - lease_key=self.lease2, - disposition=pike.smb2.FILE_OPEN) + handle2 = self.create( + chan2, + tree2, + durable=durable, + lease=self.rw, + lease_key=self.lease2, + disposition=pike.smb2.FILE_OPEN, + ) # resiliency interact handle2's lease_status(before rw, now r) self.assertEqual(handle2.lease.lease_state, self.r) chan2.close(handle2) @@ -191,19 +210,20 @@ def test_resiliency_reconnect_after_timeout(self, durable=True): chan2, tree2 = self.tree_connect(client=pike.model.Client()) # Invalidate handle from separate client - handle2 = self.create(chan2, - tree2, - durable=durable, - lease=self.rw, - lease_key=self.lease2, - disposition=pike.smb2.FILE_OPEN) + handle2 = self.create( + chan2, + tree2, + durable=durable, + lease=self.rw, + lease_key=self.lease2, + disposition=pike.smb2.FILE_OPEN, + ) self.assertEqual(handle2.lease.lease_state, self.rw) chan2.close(handle2) chan2.connection.close() chan3, tree3 = self.tree_connect() - # Reconnect should fail(resiliency timeout) with self.assert_error(pike.ntstatus.STATUS_OBJECT_NAME_NOT_FOUND): handle3 = self.create(chan3, tree3, durable=handle1) @@ -211,9 +231,7 @@ def test_resiliency_reconnect_after_timeout(self, durable=True): @pike.test.RequireDialect(pike.smb2.DIALECT_SMB2_1) def test_resiliency_buffer_too_small(self, durable=True): chan, tree = self.tree_connect() - handle1 = self.create(chan, - tree, - durable=durable) + handle1 = self.create(chan, tree, durable=durable) self.assertEqual(handle1.is_durable, durable) timeout = 5 @@ -232,12 +250,14 @@ def test_resiliency_buffer_too_small(self, durable=True): chan.connection.close() chan2, tree2 = self.tree_connect(client=pike.model.Client()) - handle2 = self.create(chan2, - tree2, - durable=durable, - lease=self.rw, - lease_key=self.lease2, - disposition=pike.smb2.FILE_OPEN) + handle2 = self.create( + chan2, + tree2, + durable=durable, + lease=self.rw, + lease_key=self.lease2, + disposition=pike.smb2.FILE_OPEN, + ) self.assertEqual(handle2.lease.lease_state, self.rw) chan2.close(handle2) diff --git a/pike/test/encryption.py b/pike/test/encryption.py index c5c8178f..1c2793a3 100644 --- a/pike/test/encryption.py +++ b/pike/test/encryption.py @@ -25,15 +25,14 @@ def test_smb_3_0_encryption(self): client = model.Client(dialects=[smb2.DIALECT_SMB3_0]) conn = client.connect(self.server) conn.negotiate() - self.assertEqual(conn.negotiate_response.dialect_revision, - smb2.DIALECT_SMB3_0) - self.assertTrue(conn.negotiate_response.capabilities & - smb2.SMB2_GLOBAL_CAP_ENCRYPTION) + self.assertEqual(conn.negotiate_response.dialect_revision, smb2.DIALECT_SMB3_0) + self.assertTrue( + conn.negotiate_response.capabilities & smb2.SMB2_GLOBAL_CAP_ENCRYPTION + ) chan = conn.session_setup(self.creds) chan.session.encrypt_data = True self.assertIsNotNone(chan.session.encryption_context) - self.assertEqual(chan.session.encryption_context.aes_mode, - crypto.AES.MODE_CCM) + self.assertEqual(chan.session.encryption_context.aes_mode, crypto.AES.MODE_CCM) tree = chan.tree_connect(self.share) self.assertIsNotNone(tree.tree_connect_response.parent.parent.transform) @@ -41,66 +40,67 @@ def test_smb_3_0_2_encryption(self): client = model.Client(dialects=[smb2.DIALECT_SMB3_0_2]) conn = client.connect(self.server) conn.negotiate() - self.assertEqual(conn.negotiate_response.dialect_revision, - smb2.DIALECT_SMB3_0_2) - self.assertTrue(conn.negotiate_response.capabilities & - smb2.SMB2_GLOBAL_CAP_ENCRYPTION) + self.assertEqual( + conn.negotiate_response.dialect_revision, smb2.DIALECT_SMB3_0_2 + ) + self.assertTrue( + conn.negotiate_response.capabilities & smb2.SMB2_GLOBAL_CAP_ENCRYPTION + ) chan = conn.session_setup(self.creds) chan.session.encrypt_data = True self.assertIsNotNone(chan.session.encryption_context) - self.assertEqual(chan.session.encryption_context.aes_mode, - crypto.AES.MODE_CCM) + self.assertEqual(chan.session.encryption_context.aes_mode, crypto.AES.MODE_CCM) tree = chan.tree_connect(self.share) self.assertIsNotNone(tree.tree_connect_response.parent.parent.transform) def test_smb_3_1_1_encryption_gcm(self): - client = model.Client(dialects=[smb2.DIALECT_SMB3_0, - smb2.DIALECT_SMB3_1_1]) + client = model.Client(dialects=[smb2.DIALECT_SMB3_0, smb2.DIALECT_SMB3_1_1]) conn = client.connect(self.server) conn.negotiate(ciphers=[crypto.SMB2_AES_128_GCM]) - self.assertEqual(conn.negotiate_response.dialect_revision, - smb2.DIALECT_SMB3_1_1) - self.assertFalse(conn.negotiate_response.capabilities & - smb2.SMB2_GLOBAL_CAP_ENCRYPTION) + self.assertEqual( + conn.negotiate_response.dialect_revision, smb2.DIALECT_SMB3_1_1 + ) + self.assertFalse( + conn.negotiate_response.capabilities & smb2.SMB2_GLOBAL_CAP_ENCRYPTION + ) chan = conn.session_setup(self.creds) chan.session.encrypt_data = True self.assertIsNotNone(chan.session.encryption_context) - self.assertEqual(chan.session.encryption_context.aes_mode, - crypto.AES.MODE_GCM) + self.assertEqual(chan.session.encryption_context.aes_mode, crypto.AES.MODE_GCM) tree = chan.tree_connect(self.share) self.assertIsNotNone(tree.tree_connect_response.parent.parent.transform) def test_smb_3_1_1_encryption_ccm(self): - client = model.Client(dialects=[smb2.DIALECT_SMB3_0, - smb2.DIALECT_SMB3_1_1]) + client = model.Client(dialects=[smb2.DIALECT_SMB3_0, smb2.DIALECT_SMB3_1_1]) conn = client.connect(self.server) conn.negotiate(ciphers=[crypto.SMB2_AES_128_CCM]) - self.assertEqual(conn.negotiate_response.dialect_revision, - smb2.DIALECT_SMB3_1_1) - self.assertFalse(conn.negotiate_response.capabilities & - smb2.SMB2_GLOBAL_CAP_ENCRYPTION) + self.assertEqual( + conn.negotiate_response.dialect_revision, smb2.DIALECT_SMB3_1_1 + ) + self.assertFalse( + conn.negotiate_response.capabilities & smb2.SMB2_GLOBAL_CAP_ENCRYPTION + ) chan = conn.session_setup(self.creds) chan.session.encrypt_data = True self.assertIsNotNone(chan.session.encryption_context) - self.assertEqual(chan.session.encryption_context.aes_mode, - crypto.AES.MODE_CCM) + self.assertEqual(chan.session.encryption_context.aes_mode, crypto.AES.MODE_CCM) tree = chan.tree_connect(self.share) self.assertIsNotNone(tree.tree_connect_response.parent.parent.transform) def test_smb_3_1_1_compound(self): - client = model.Client(dialects=[smb2.DIALECT_SMB3_0, - smb2.DIALECT_SMB3_1_1]) + client = model.Client(dialects=[smb2.DIALECT_SMB3_0, smb2.DIALECT_SMB3_1_1]) conn = client.connect(self.server) conn.negotiate(ciphers=[crypto.SMB2_AES_128_GCM]) - self.assertEqual(conn.negotiate_response.dialect_revision, - smb2.DIALECT_SMB3_1_1) - self.assertFalse(conn.negotiate_response.capabilities & - smb2.SMB2_GLOBAL_CAP_ENCRYPTION) + self.assertEqual( + conn.negotiate_response.dialect_revision, smb2.DIALECT_SMB3_1_1 + ) + self.assertFalse( + conn.negotiate_response.capabilities & smb2.SMB2_GLOBAL_CAP_ENCRYPTION + ) chan = conn.session_setup(self.creds) chan.session.encrypt_data = True self.assertIsNotNone(chan.session.encryption_context) - self.assertEqual(chan.session.encryption_context.aes_mode, - crypto.AES.MODE_GCM) + self.assertEqual(chan.session.encryption_context.aes_mode, crypto.AES.MODE_GCM) chan.session.encrypt_data = True tree = chan.tree_connect(self.share) self.assertIsNotNone(tree.tree_connect_response.parent.parent.transform) @@ -111,7 +111,7 @@ def test_smb_3_1_1_compound(self): create_req = smb2.CreateRequest(smb_req1) close_req = smb2.CloseRequest(smb_req2) - create_req.name = 'hello.txt' + create_req.name = "hello.txt" create_req.desired_access = pike.smb2.GENERIC_READ | pike.smb2.GENERIC_WRITE create_req.file_attributes = pike.smb2.FILE_ATTRIBUTE_NORMAL create_req.create_disposition = pike.smb2.FILE_OPEN_IF diff --git a/pike/test/invalid_session.py b/pike/test/invalid_session.py index adb3b732..ab8fb5a7 100644 --- a/pike/test/invalid_session.py +++ b/pike/test/invalid_session.py @@ -28,7 +28,7 @@ def test_logoff(self): logoff_req = smb2.LogoffRequest(req) # Set invalid session id - req.session_id = 0xffffffffffffffff + req.session_id = 0xFFFFFFFFFFFFFFFF with self.assert_error(nt.STATUS_USER_SESSION_DELETED): conn.transceive(req.parent)[0] @@ -38,9 +38,8 @@ def test_logoff(self): def open_file(self, filename): self.chan, self.tree = self.tree_connect() fh = self.chan.create( - self.tree, - filename, - disposition=smb2.FILE_SUPERSEDE).result() + self.tree, filename, disposition=smb2.FILE_SUPERSEDE + ).result() return fh def test_treeconnect(self): @@ -52,7 +51,7 @@ def test_treeconnect(self): tree_con_req1.path = tree.path # Set invalid session id - req1.session_id = 0xffffffffffffffff + req1.session_id = 0xFFFFFFFFFFFFFFFF with self.assert_error(nt.STATUS_USER_SESSION_DELETED): chan.connection.transceive(req1.parent)[0] @@ -75,7 +74,7 @@ def test_ioctl(self): val_req1.dialects = self.chan.session.client.dialects # Set invalid session - req1.session_id = 0xffffffffffffffff + req1.session_id = 0xFFFFFFFFFFFFFFFF with self.assert_error(nt.STATUS_USER_SESSION_DELETED): self.chan.connection.transceive(req1.parent) @@ -91,7 +90,7 @@ def test_oplock_break_ack(self): oplock_ack_req1.file_id = fh.file_id # Set invalid session and tree id - req1.session_id = 0xffffffffffffffff + req1.session_id = 0xFFFFFFFFFFFFFFFF with self.assert_error(nt.STATUS_USER_SESSION_DELETED): self.chan.connection.transceive(req1.parent) diff --git a/pike/test/invalid_tree.py b/pike/test/invalid_tree.py index e6c65140..575ee64d 100644 --- a/pike/test/invalid_tree.py +++ b/pike/test/invalid_tree.py @@ -24,9 +24,8 @@ class InvalidTreeTest(pike.test.PikeTest): def open_file(self, filename): self.chan, self.tree = self.tree_connect() fh = self.chan.create( - self.tree, - filename, - disposition=smb2.FILE_SUPERSEDE).result() + self.tree, filename, disposition=smb2.FILE_SUPERSEDE + ).result() return fh def test_treeconnect(self): @@ -38,7 +37,7 @@ def test_treeconnect(self): tree_con_req1.path = tree.path # Set invalid tree id - req1.tree_id = 0xffffffff + req1.tree_id = 0xFFFFFFFF res1 = chan.connection.transceive(req1.parent)[0] # New tree id has to be new and unique @@ -74,7 +73,7 @@ def test_ioctl(self): val_req1.dialects = self.chan.session.client.dialects # Set invalid tree id - req1.tree_id = 0xffffffff + req1.tree_id = 0xFFFFFFFF with self.assert_error(nt.STATUS_NETWORK_NAME_DELETED): self.chan.connection.transceive(req1.parent) @@ -90,7 +89,7 @@ def test_oplock_break_ack(self): oplock_ack_req1.file_id = fh.file_id # Set invalid tree id - req1.tree_id = 0xffffffff + req1.tree_id = 0xFFFFFFFF with self.assert_error(nt.STATUS_NETWORK_NAME_DELETED): self.chan.connection.transceive(req1.parent) diff --git a/pike/test/lease.py b/pike/test/lease.py index 48987d61..001b1cf2 100644 --- a/pike/test/lease.py +++ b/pike/test/lease.py @@ -27,9 +27,13 @@ @pike.test.RequireDialect(0x210) @pike.test.RequireCapabilities(pike.smb2.SMB2_GLOBAL_CAP_LEASING) class LeaseTest(pike.test.PikeTest): - share_all = pike.smb2.FILE_SHARE_READ | pike.smb2.FILE_SHARE_WRITE | pike.smb2.FILE_SHARE_DELETE - lease1 = array.array('B', map(random.randint, [0] * 16, [255] * 16)) - lease2 = array.array('B', map(random.randint, [0] * 16, [255] * 16)) + share_all = ( + pike.smb2.FILE_SHARE_READ + | pike.smb2.FILE_SHARE_WRITE + | pike.smb2.FILE_SHARE_DELETE + ) + lease1 = array.array("B", map(random.randint, [0] * 16, [255] * 16)) + lease2 = array.array("B", map(random.randint, [0] * 16, [255] * 16)) r = pike.smb2.SMB2_LEASE_READ_CACHING rw = r | pike.smb2.SMB2_LEASE_WRITE_CACHING rh = r | pike.smb2.SMB2_LEASE_HANDLE_CACHING @@ -40,35 +44,43 @@ def test_lease_upgrade_break(self): chan, tree = self.tree_connect() # Request rw lease - handle1 = chan.create(tree, - 'lease.txt', - share=self.share_all, - oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, - lease_key = self.lease1, - lease_state = self.rw).result() + handle1 = chan.create( + tree, + "lease.txt", + share=self.share_all, + oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, + lease_key=self.lease1, + lease_state=self.rw, + ).result() self.assertEqual(handle1.lease.lease_state, self.rw) - handle2 = chan.create(tree, - 'lease.txt', - share=self.share_all, - oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, - lease_key = self.lease1, - lease_state = self.rwh).result() + handle2 = chan.create( + tree, + "lease.txt", + share=self.share_all, + oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, + lease_key=self.lease1, + lease_state=self.rwh, + ).result() self.assertIs(handle2.lease, handle1.lease) self.assertEqual(handle2.lease.lease_state, self.rwh) # On break, voluntarily give up handle caching - handle2.lease.on_break(lambda state: state & ~pike.smb2.SMB2_LEASE_HANDLE_CACHING) + handle2.lease.on_break( + lambda state: state & ~pike.smb2.SMB2_LEASE_HANDLE_CACHING + ) # Break our lease - handle3 = chan.create(tree, - 'lease.txt', - share=self.share_all, - oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, - lease_key = self.lease2, - lease_state = self.rwh).result() + handle3 = chan.create( + tree, + "lease.txt", + share=self.share_all, + oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, + lease_key=self.lease2, + lease_state=self.rwh, + ).result() # First lease should have broken to r self.assertEqual(handle2.lease.lease_state, self.r) @@ -83,28 +95,34 @@ def test_lease_upgrade_break(self): def test_lease_break_close_ack(self): chan, tree = self.tree_connect() # Request rw lease - handle1 = chan.create(tree, - 'lease.txt', - share=self.share_all, - oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, - lease_key = self.lease1, - lease_state = self.rw).result() + handle1 = chan.create( + tree, + "lease.txt", + share=self.share_all, + oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, + lease_key=self.lease1, + lease_state=self.rw, + ).result() # Upgrade to rwh - handle2 = chan.create(tree, - 'lease.txt', - share=self.share_all, - oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, - lease_key = self.lease1, - lease_state = self.rwh).result() + handle2 = chan.create( + tree, + "lease.txt", + share=self.share_all, + oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, + lease_key=self.lease1, + lease_state=self.rwh, + ).result() # Break our lease - handle3_future = chan.create(tree, - 'lease.txt', - share=self.share_all, - oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, - lease_key = self.lease2, - lease_state = self.rwh) + handle3_future = chan.create( + tree, + "lease.txt", + share=self.share_all, + oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, + lease_key=self.lease2, + lease_state=self.rwh, + ) # Wait for break handle1.lease.future.wait() @@ -126,24 +144,28 @@ def test_lease_multiple_connections(self): chan, tree = self.tree_connect() # Request rwh lease - handle1 = chan.create(tree, - 'lease.txt', - share=self.share_all, - oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, - lease_key = self.lease1, - lease_state = self.rwh).result() + handle1 = chan.create( + tree, + "lease.txt", + share=self.share_all, + oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, + lease_key=self.lease1, + lease_state=self.rwh, + ).result() self.assertEqual(handle1.lease.lease_state, self.rwh) chan2, tree2 = self.tree_connect() # Request rwh lease to same file on separate connection, # which we should get - handle2 = chan2.create(tree2, - 'lease.txt', - share=self.share_all, - oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, - lease_key = self.lease1, - lease_state = self.rwh).result() + handle2 = chan2.create( + tree2, + "lease.txt", + share=self.share_all, + oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, + lease_key=self.lease1, + lease_state=self.rwh, + ).result() self.assertEqual(handle2.lease.lease_state, self.rwh) # Leases should be the same object diff --git a/pike/test/lock.py b/pike/test/lock.py index 1a7db38f..6b111ccb 100644 --- a/pike/test/lock.py +++ b/pike/test/lock.py @@ -26,24 +26,37 @@ class LockTest(pike.test.PikeTest): def test_lock(self): chan, tree = self.tree_connect() buffer = "0123456789012345678901" - locks = [(8, 8, pike.smb2.SMB2_LOCKFLAG_EXCLUSIVE_LOCK | pike.smb2.SMB2_LOCKFLAG_FAIL_IMMEDIATELY)] - - share_all = pike.smb2.FILE_SHARE_READ | pike.smb2.FILE_SHARE_WRITE | pike.smb2.FILE_SHARE_DELETE - - file = chan.create(tree, - 'lock.txt', - access=pike.smb2.FILE_READ_DATA | pike.smb2.FILE_WRITE_DATA | pike.smb2.DELETE, - share=share_all, - disposition=pike.smb2.FILE_SUPERSEDE, - options=pike.smb2.FILE_DELETE_ON_CLOSE).result() - - bytes_written = chan.write(file, - 0, - buffer) + locks = [ + ( + 8, + 8, + pike.smb2.SMB2_LOCKFLAG_EXCLUSIVE_LOCK + | pike.smb2.SMB2_LOCKFLAG_FAIL_IMMEDIATELY, + ) + ] + + share_all = ( + pike.smb2.FILE_SHARE_READ + | pike.smb2.FILE_SHARE_WRITE + | pike.smb2.FILE_SHARE_DELETE + ) + + file = chan.create( + tree, + "lock.txt", + access=pike.smb2.FILE_READ_DATA + | pike.smb2.FILE_WRITE_DATA + | pike.smb2.DELETE, + share=share_all, + disposition=pike.smb2.FILE_SUPERSEDE, + options=pike.smb2.FILE_DELETE_ON_CLOSE, + ).result() + + bytes_written = chan.write(file, 0, buffer) self.assertEqual(bytes_written, len(buffer)) chan.lock(file, locks).result() - + chan.close(file) # Test that pending lock request can be cancelled, yielding STATUS_CANCELLED @@ -52,30 +65,36 @@ def test_cancel(self): buffer = "0123456789012345678901" locks = [(8, 8, pike.smb2.SMB2_LOCKFLAG_EXCLUSIVE_LOCK)] - share_all = pike.smb2.FILE_SHARE_READ | pike.smb2.FILE_SHARE_WRITE | pike.smb2.FILE_SHARE_DELETE + share_all = ( + pike.smb2.FILE_SHARE_READ + | pike.smb2.FILE_SHARE_WRITE + | pike.smb2.FILE_SHARE_DELETE + ) access = pike.smb2.FILE_READ_DATA | pike.smb2.FILE_WRITE_DATA | pike.smb2.DELETE # Create file, lock - file1 = chan.create(tree, - 'lock.txt', - access=access, - share=share_all, - disposition=pike.smb2.FILE_SUPERSEDE).result() - - bytes_written = chan.write(file1, - 0, - buffer) + file1 = chan.create( + tree, + "lock.txt", + access=access, + share=share_all, + disposition=pike.smb2.FILE_SUPERSEDE, + ).result() + + bytes_written = chan.write(file1, 0, buffer) self.assertEqual(bytes_written, len(buffer)) chan.lock(file1, locks).result() # Open file again (with delete on close) - file2 = chan.create(tree, - 'lock.txt', - access=access, - share=share_all, - disposition=pike.smb2.FILE_OPEN, - options=pike.smb2.FILE_DELETE_ON_CLOSE).result() + file2 = chan.create( + tree, + "lock.txt", + access=access, + share=share_all, + disposition=pike.smb2.FILE_OPEN, + options=pike.smb2.FILE_DELETE_ON_CLOSE, + ).result() # This will block since the lock is already held, so only wait for interim response lock_future = chan.lock(file2, locks) @@ -84,7 +103,7 @@ def test_cancel(self): # Cancel, wait for response, verify error response with self.assert_error(pike.ntstatus.STATUS_CANCELLED): chan.cancel(lock_future).result() - + chan.close(file1) chan.close(file2) @@ -95,35 +114,45 @@ def test_deny_write(self): lock_size = 8 locks = [(lock_offset, lock_size, pike.smb2.SMB2_LOCKFLAG_EXCLUSIVE_LOCK)] - share_all = pike.smb2.FILE_SHARE_READ | pike.smb2.FILE_SHARE_WRITE | pike.smb2.FILE_SHARE_DELETE + share_all = ( + pike.smb2.FILE_SHARE_READ + | pike.smb2.FILE_SHARE_WRITE + | pike.smb2.FILE_SHARE_DELETE + ) access = pike.smb2.FILE_READ_DATA | pike.smb2.FILE_WRITE_DATA | pike.smb2.DELETE # Create file, lock - file1 = chan.create(tree, - 'lock.txt', - access=access, - share=share_all, - disposition=pike.smb2.FILE_SUPERSEDE).result() - + file1 = chan.create( + tree, + "lock.txt", + access=access, + share=share_all, + disposition=pike.smb2.FILE_SUPERSEDE, + ).result() + bytes_written = chan.write(file1, 0, buffer) self.assertEqual(bytes_written, len(buffer)) chan.lock(file1, locks).result() # Open file again (with delete on close) - file2 = chan.create(tree, - 'lock.txt', - access=access, - share=share_all, - disposition=pike.smb2.FILE_OPEN, - options=pike.smb2.FILE_DELETE_ON_CLOSE).result() - - cases = ((offset,size) for offset in range(0, 16) for size in range(0, 16)) - - for (offset,size) in cases: - if ranges_intersect(offset, offset+size, lock_offset, lock_offset + lock_size): + file2 = chan.create( + tree, + "lock.txt", + access=access, + share=share_all, + disposition=pike.smb2.FILE_OPEN, + options=pike.smb2.FILE_DELETE_ON_CLOSE, + ).result() + + cases = ((offset, size) for offset in range(0, 16) for size in range(0, 16)) + + for (offset, size) in cases: + if ranges_intersect( + offset, offset + size, lock_offset, lock_offset + lock_size + ): with self.assert_error(pike.ntstatus.STATUS_FILE_LOCK_CONFLICT): - chan.write(file2, offset, 'a' * size) + chan.write(file2, offset, "a" * size) chan.close(file1) chan.close(file2) @@ -135,28 +164,36 @@ def test_allow_zero_byte_write(self): lock_size = 8 locks = [(lock_offset, lock_size, pike.smb2.SMB2_LOCKFLAG_EXCLUSIVE_LOCK)] - share_all = pike.smb2.FILE_SHARE_READ | pike.smb2.FILE_SHARE_WRITE | pike.smb2.FILE_SHARE_DELETE + share_all = ( + pike.smb2.FILE_SHARE_READ + | pike.smb2.FILE_SHARE_WRITE + | pike.smb2.FILE_SHARE_DELETE + ) access = pike.smb2.FILE_READ_DATA | pike.smb2.FILE_WRITE_DATA | pike.smb2.DELETE # Create file, lock - file1 = chan.create(tree, - 'lock.txt', - access=access, - share=share_all, - disposition=pike.smb2.FILE_SUPERSEDE).result() - + file1 = chan.create( + tree, + "lock.txt", + access=access, + share=share_all, + disposition=pike.smb2.FILE_SUPERSEDE, + ).result() + bytes_written = chan.write(file1, 0, buffer) self.assertEqual(bytes_written, len(buffer)) chan.lock(file1, locks).result() # Open file again (with delete on close) - file2 = chan.create(tree, - 'lock.txt', - access=access, - share=share_all, - disposition=pike.smb2.FILE_OPEN, - options=pike.smb2.FILE_DELETE_ON_CLOSE).result() + file2 = chan.create( + tree, + "lock.txt", + access=access, + share=share_all, + disposition=pike.smb2.FILE_OPEN, + options=pike.smb2.FILE_DELETE_ON_CLOSE, + ).result() chan.write(file2, lock_offset + 1, None) @@ -169,7 +206,13 @@ def range_contains(a1, a2, b): def ranges_intersect(a1, a2, b1, b2): - return a2 > a1 and b2 > b1 and \ - (range_contains(a1, a2, b1) or range_contains(a1, a2, b2-1) or \ - range_contains(b1, b2, a1) or range_contains(b1, b2, a2-1)) - + return ( + a2 > a1 + and b2 > b1 + and ( + range_contains(a1, a2, b1) + or range_contains(a1, a2, b2 - 1) + or range_contains(b1, b2, a1) + or range_contains(b1, b2, a2 - 1) + ) + ) diff --git a/pike/test/multichannel.py b/pike/test/multichannel.py index d95e9c87..b60775b5 100644 --- a/pike/test/multichannel.py +++ b/pike/test/multichannel.py @@ -24,29 +24,35 @@ @pike.test.RequireCapabilities(pike.smb2.SMB2_GLOBAL_CAP_MULTI_CHANNEL) class MultiChannelTest(pike.test.PikeTest): def session_bind(self, chan): - return chan.connection.client.connect(self.server).negotiate().session_setup(self.creds, bind=chan.session) + return ( + chan.connection.client.connect(self.server) + .negotiate() + .session_setup(self.creds, bind=chan.session) + ) # Open a file, binding session to second channel, and close it there def test_open_bind_close(self): chan, tree = self.tree_connect() - handle = chan.create(tree, 'hello.txt').result() + handle = chan.create(tree, "hello.txt").result() # Open a second channel and bind the session chan2 = self.session_bind(chan) - + # Close the handle on the second channel chan2.close(handle) # Simulate a channel failover during a write and confirm that a # stale write sent on the original channel is rejected def test_write_fence_reject_stale(self): - data_stale = b'stale' - data_fresh = b'fresh' + data_stale = b"stale" + data_fresh = b"fresh" chan, tree = self.tree_connect() client = chan.connection.client - + # Open a file - handle = chan.create(tree, 'hello.txt', disposition=pike.smb2.FILE_SUPERSEDE).result() + handle = chan.create( + tree, "hello.txt", disposition=pike.smb2.FILE_SUPERSEDE + ).result() # Open a second channel chan2 = self.session_bind(chan) diff --git a/pike/test/negotiate.py b/pike/test/negotiate.py index 9216bd7a..656e5a3b 100644 --- a/pike/test/negotiate.py +++ b/pike/test/negotiate.py @@ -74,14 +74,15 @@ def test_smb3(self): @test.RequireDialect(smb2.DIALECT_SMB3_0) @test.RequireShareCapabilities(smb2.SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY) def test_smb3_many_capabilities(self): - advertise_caps = \ - smb2.SMB2_GLOBAL_CAP_MULTI_CHANNEL | \ - smb2.SMB2_GLOBAL_CAP_PERSISTENT_HANDLES | \ - smb2.SMB2_GLOBAL_CAP_DIRECTORY_LEASING | \ - smb2.SMB2_GLOBAL_CAP_ENCRYPTION - self.positive_cap(smb2.DIALECT_SMB3_0, - advertise_caps, - smb2.SMB2_GLOBAL_CAP_PERSISTENT_HANDLES) + advertise_caps = ( + smb2.SMB2_GLOBAL_CAP_MULTI_CHANNEL + | smb2.SMB2_GLOBAL_CAP_PERSISTENT_HANDLES + | smb2.SMB2_GLOBAL_CAP_DIRECTORY_LEASING + | smb2.SMB2_GLOBAL_CAP_ENCRYPTION + ) + self.positive_cap( + smb2.DIALECT_SMB3_0, advertise_caps, smb2.SMB2_GLOBAL_CAP_PERSISTENT_HANDLES + ) # persistent cap is not advertised if we don't advertise it def test_smb3_no_advert(self): @@ -105,14 +106,15 @@ def test_smb3(self): # multichannel cap is advertised if we ask for lots of caps @test.RequireDialect(smb2.DIALECT_SMB3_0) def test_smb3_many_capabilities(self): - advertise_caps = \ - smb2.SMB2_GLOBAL_CAP_MULTI_CHANNEL | \ - smb2.SMB2_GLOBAL_CAP_PERSISTENT_HANDLES | \ - smb2.SMB2_GLOBAL_CAP_DIRECTORY_LEASING | \ - smb2.SMB2_GLOBAL_CAP_ENCRYPTION - self.positive_cap(smb2.DIALECT_SMB3_0, - advertise_caps, - smb2.SMB2_GLOBAL_CAP_MULTI_CHANNEL) + advertise_caps = ( + smb2.SMB2_GLOBAL_CAP_MULTI_CHANNEL + | smb2.SMB2_GLOBAL_CAP_PERSISTENT_HANDLES + | smb2.SMB2_GLOBAL_CAP_DIRECTORY_LEASING + | smb2.SMB2_GLOBAL_CAP_ENCRYPTION + ) + self.positive_cap( + smb2.DIALECT_SMB3_0, advertise_caps, smb2.SMB2_GLOBAL_CAP_MULTI_CHANNEL + ) # multichannel cap is not advertised if we don't advertise it def test_smb3_no_advert(self): @@ -136,14 +138,15 @@ def test_smb3(self): # largemtu cap is advertised if we ask for lots of caps @test.RequireDialect(smb2.DIALECT_SMB3_0) def test_smb3_many_capabilities(self): - advertise_caps = \ - smb2.SMB2_GLOBAL_CAP_MULTI_CHANNEL | \ - smb2.SMB2_GLOBAL_CAP_PERSISTENT_HANDLES | \ - smb2.SMB2_GLOBAL_CAP_LARGE_MTU | \ - smb2.SMB2_GLOBAL_CAP_ENCRYPTION - self.positive_cap(smb2.DIALECT_SMB3_0, - advertise_caps, - smb2.SMB2_GLOBAL_CAP_LARGE_MTU) + advertise_caps = ( + smb2.SMB2_GLOBAL_CAP_MULTI_CHANNEL + | smb2.SMB2_GLOBAL_CAP_PERSISTENT_HANDLES + | smb2.SMB2_GLOBAL_CAP_LARGE_MTU + | smb2.SMB2_GLOBAL_CAP_ENCRYPTION + ) + self.positive_cap( + smb2.DIALECT_SMB3_0, advertise_caps, smb2.SMB2_GLOBAL_CAP_LARGE_MTU + ) # largemtu cap is advertised if we ask for it def test_smb21(self): @@ -170,7 +173,9 @@ def test_preauth_integrity_capabilities(self): self.assertGreater(len(ctx.salt), 0) def test_encryption_capabilities_both_prefer_ccm(self): - resp = self.negotiate(ciphers=[crypto.SMB2_AES_128_CCM, crypto.SMB2_AES_128_GCM]) + resp = self.negotiate( + ciphers=[crypto.SMB2_AES_128_CCM, crypto.SMB2_AES_128_GCM] + ) if resp.dialect_revision >= smb2.DIALECT_SMB3_1_1: for ctx in resp: if isinstance(ctx, crypto.EncryptionCapabilitiesResponse): @@ -178,7 +183,9 @@ def test_encryption_capabilities_both_prefer_ccm(self): self.assertIn(crypto.SMB2_AES_128_CCM, ctx.ciphers) def test_encryption_capabilities_both_prefer_gcm(self): - resp = self.negotiate(ciphers=[crypto.SMB2_AES_128_GCM, crypto.SMB2_AES_128_CCM]) + resp = self.negotiate( + ciphers=[crypto.SMB2_AES_128_GCM, crypto.SMB2_AES_128_CCM] + ) if resp.dialect_revision >= smb2.DIALECT_SMB3_1_1: for ctx in resp: if isinstance(ctx, crypto.EncryptionCapabilitiesResponse): diff --git a/pike/test/oplock.py b/pike/test/oplock.py index 94f13337..773b34c0 100644 --- a/pike/test/oplock.py +++ b/pike/test/oplock.py @@ -24,19 +24,27 @@ class OplockTest(pike.test.PikeTest): def test_oplock_break(self): chan, tree = self.tree_connect() - share_all = pike.smb2.FILE_SHARE_READ | pike.smb2.FILE_SHARE_WRITE | pike.smb2.FILE_SHARE_DELETE + share_all = ( + pike.smb2.FILE_SHARE_READ + | pike.smb2.FILE_SHARE_WRITE + | pike.smb2.FILE_SHARE_DELETE + ) + + handle1 = chan.create( + tree, + "oplock.txt", + share=share_all, + oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_EXCLUSIVE, + ).result() - handle1 = chan.create(tree, - 'oplock.txt', - share=share_all, - oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_EXCLUSIVE).result() - handle1.on_oplock_break(lambda level: level) - - handle2 = chan.create(tree, - 'oplock.txt', - share=share_all, - oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_II).result() - + + handle2 = chan.create( + tree, + "oplock.txt", + share=share_all, + oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_II, + ).result() + chan.close(handle1) chan.close(handle2) diff --git a/pike/test/persistent.py b/pike/test/persistent.py index aa04dddd..abcf53dd 100644 --- a/pike/test/persistent.py +++ b/pike/test/persistent.py @@ -26,15 +26,15 @@ import pike.ntstatus as ntstatus # Constants -LEASE_R = smb2.SMB2_LEASE_READ_CACHING -LEASE_RW = LEASE_R | smb2.SMB2_LEASE_WRITE_CACHING -LEASE_RH = LEASE_R | smb2.SMB2_LEASE_HANDLE_CACHING +LEASE_R = smb2.SMB2_LEASE_READ_CACHING +LEASE_RW = LEASE_R | smb2.SMB2_LEASE_WRITE_CACHING +LEASE_RH = LEASE_R | smb2.SMB2_LEASE_HANDLE_CACHING LEASE_RWH = LEASE_RW | LEASE_RH SHARE_ALL = smb2.FILE_SHARE_READ | smb2.FILE_SHARE_WRITE | smb2.FILE_SHARE_DELETE class InvalidNetworkResiliencyRequestRequest(pike.smb2.NetworkResiliencyRequestRequest): - def _encode(self, cur): + def _encode(self, cur): cur.encode_uint32le(self.timeout) cur.encode_uint16le(self.reserved) @@ -43,26 +43,25 @@ def _encode(self, cur): @test.RequireCapabilities(smb2.SMB2_GLOBAL_CAP_PERSISTENT_HANDLES) @test.RequireShareCapabilities(smb2.SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY) class Persistent(test.PikeTest): - def setup(self): - self.lease_key = array.array('B', map(random.randint, [0] * 16, [255] * 16)) + self.lease_key = array.array("B", map(random.randint, [0] * 16, [255] * 16)) self.channel, self.tree = self.tree_connect() - def create_persistent(self, prev_handle = 0): + def create_persistent(self, prev_handle=0): """Helper to create a persistent handle, optionally reconnecting an old one""" handle = self.channel.create( self.tree, "persistent.txt", - access = smb2.FILE_READ_DATA | smb2.FILE_WRITE_DATA | smb2.DELETE, - share = SHARE_ALL, - disposition = smb2.FILE_OPEN_IF, - options = smb2.FILE_DELETE_ON_CLOSE, - oplock_level = smb2.SMB2_OPLOCK_LEVEL_LEASE, - lease_key = self.lease_key, - lease_state = LEASE_RWH, - durable = prev_handle, - persistent = True - ).result() + access=smb2.FILE_READ_DATA | smb2.FILE_WRITE_DATA | smb2.DELETE, + share=SHARE_ALL, + disposition=smb2.FILE_OPEN_IF, + options=smb2.FILE_DELETE_ON_CLOSE, + oplock_level=smb2.SMB2_OPLOCK_LEVEL_LEASE, + lease_key=self.lease_key, + lease_state=LEASE_RWH, + durable=prev_handle, + persistent=True, + ).result() self.assertEqual(handle.durable_flags, smb2.SMB2_DHANDLE_FLAG_PERSISTENT) return handle @@ -79,7 +78,7 @@ def test_reconnect(self): self.channel.connection.close() self.channel, self.tree = self.tree_connect() - handle2 = self.create_persistent(prev_handle = handle1) + handle2 = self.create_persistent(prev_handle=handle1) # Was the original lease state granted in the response? self.assertEqual(handle2.lease.lease_state, LEASE_RWH) @@ -99,14 +98,15 @@ def test_open_while_disconnected(self): self.channel.create( self.tree, "persistent.txt", - access = smb2.FILE_READ_DATA, - share = SHARE_ALL, - disposition = smb2.FILE_OPEN).result() + access=smb2.FILE_READ_DATA, + share=SHARE_ALL, + disposition=smb2.FILE_OPEN, + ).result() # Clean up: Reconnect and close file (handle) self.channel.connection.close() self.channel, self.tree = self.tree_connect() - handle2 = self.create_persistent(prev_handle = handle1) + handle2 = self.create_persistent(prev_handle=handle1) self.assertEqual(handle1.file_id, handle2.file_id) self.channel.close(handle2) @@ -119,16 +119,18 @@ def test_resiliency_same_timeout_reconnect_before_timeout(self): self.channel.connection.close() # sleeping time = resiliemcy < ca's default 120s - time.sleep(min(handle1.durable_timeout/1000.0,1)) + time.sleep(min(handle1.durable_timeout / 1000.0, 1)) self.channel, self.tree = self.tree_connect(client=pike.model.Client()) # Invalidate handle from separate client with self.assert_error(ntstatus.STATUS_FILE_NOT_AVAILABLE): - handle2 = self.channel.create(self.tree, - "persistent.txt", - access=smb2.FILE_READ_DATA, - share=SHARE_ALL, - disposition=pike.smb2.FILE_OPEN).result() + handle2 = self.channel.create( + self.tree, + "persistent.txt", + access=smb2.FILE_READ_DATA, + share=SHARE_ALL, + disposition=pike.smb2.FILE_OPEN, + ).result() self.channel.connection.close() @@ -158,11 +160,13 @@ def test_resiliency_reconnect_before_timeout(self): self.channel, self.tree = self.tree_connect(client=pike.model.Client()) with self.assert_error(ntstatus.STATUS_FILE_NOT_AVAILABLE): - handle2 = self.channel.create(self.tree, - "persistent.txt", - access=smb2.FILE_READ_DATA, - share=SHARE_ALL, - disposition=pike.smb2.FILE_OPEN).result() + handle2 = self.channel.create( + self.tree, + "persistent.txt", + access=smb2.FILE_READ_DATA, + share=SHARE_ALL, + disposition=pike.smb2.FILE_OPEN, + ).result() self.channel.connection.close() @@ -193,11 +197,13 @@ def test_resiliency_reconnect_after_timeout(self): self.channel, self.tree = self.tree_connect(client=pike.model.Client()) # Because resiliency timeout, so another opener:handle2 break the persistent - handle2 = self.channel.create(self.tree, - 'persistent.txt', - access=smb2.FILE_READ_DATA, - share=SHARE_ALL, - disposition=pike.smb2.FILE_OPEN) + handle2 = self.channel.create( + self.tree, + "persistent.txt", + access=smb2.FILE_READ_DATA, + share=SHARE_ALL, + disposition=pike.smb2.FILE_OPEN, + ) self.channel.connection.close() self.channel, self.tree = self.tree_connect() @@ -216,7 +222,7 @@ def test_resiliency_same_timeout_reconnect_after_timeout(self): self.channel.connection.close() # resilience's timeout = ca's defaut 120s < sleeping time - time.sleep(handle1.durable_timeout/1000.0+1) + time.sleep(handle1.durable_timeout / 1000.0 + 1) # timeout, can't get object name self.channel, self.tree = self.tree_connect() @@ -242,11 +248,13 @@ def test_buffer_too_small(self): self.channel, self.tree = self.tree_connect(client=pike.model.Client()) with self.assert_error(ntstatus.STATUS_FILE_NOT_AVAILABLE): - handle2 = self.channel.create(self.tree, - "persistent.txt", - access=smb2.FILE_READ_DATA, - share=SHARE_ALL, - disposition=pike.smb2.FILE_OPEN).result() + handle2 = self.channel.create( + self.tree, + "persistent.txt", + access=smb2.FILE_READ_DATA, + share=SHARE_ALL, + disposition=pike.smb2.FILE_OPEN, + ).result() self.channel.connection.close() diff --git a/pike/test/query.py b/pike/test/query.py index 17f6aef7..38ed3539 100644 --- a/pike/test/query.py +++ b/pike/test/query.py @@ -21,7 +21,6 @@ class QueryTest(pike.test.PikeTest): - def __init__(self, *args, **kwargs): super(QueryTest, self).__init__(*args, **kwargs) self.chan = None @@ -30,13 +29,21 @@ def __init__(self, *args, **kwargs): def open_file(self): """Helper to open basic file""" self.chan, self.tree = self.tree_connect() - return self.chan.create(self.tree, "test.txt", disposition=pike.smb2.FILE_SUPERSEDE).result() + return self.chan.create( + self.tree, "test.txt", disposition=pike.smb2.FILE_SUPERSEDE + ).result() - def basic_test(self, level, info_type=pike.smb2.SMB2_0_INFO_FILE, additional_information=None): + def basic_test( + self, level, info_type=pike.smb2.SMB2_0_INFO_FILE, additional_information=None + ): """Helper to perform a basic query test""" handle = self.open_file() info = self.chan.query_file_info( - handle, level, info_type=info_type, additional_information=additional_information) + handle, + level, + info_type=info_type, + additional_information=additional_information, + ) self.chan.close(handle) def mismatch_test(self, level, size): @@ -53,30 +60,40 @@ def test_query_file_basic_info(self): def test_query_file_sec_info_owner(self): sec_info = pike.smb2.OWNER_SECURITY_INFORMATION - self.basic_test(pike.smb2.FILE_SECURITY_INFORMATION, - info_type=pike.smb2.SMB2_0_INFO_SECURITY, - additional_information=sec_info) + self.basic_test( + pike.smb2.FILE_SECURITY_INFORMATION, + info_type=pike.smb2.SMB2_0_INFO_SECURITY, + additional_information=sec_info, + ) def test_query_file_sec_info_group(self): sec_info = pike.smb2.GROUP_SECURITY_INFORMATION - self.basic_test(pike.smb2.FILE_SECURITY_INFORMATION, - info_type=pike.smb2.SMB2_0_INFO_SECURITY, - additional_information=sec_info) + self.basic_test( + pike.smb2.FILE_SECURITY_INFORMATION, + info_type=pike.smb2.SMB2_0_INFO_SECURITY, + additional_information=sec_info, + ) def test_query_file_sec_info_dacl(self): sec_info = pike.smb2.DACL_SECURITY_INFORMATION - self.basic_test(pike.smb2.FILE_SECURITY_INFORMATION, - info_type=pike.smb2.SMB2_0_INFO_SECURITY, - additional_information=sec_info) + self.basic_test( + pike.smb2.FILE_SECURITY_INFORMATION, + info_type=pike.smb2.SMB2_0_INFO_SECURITY, + additional_information=sec_info, + ) def test_query_file_sec_info_all(self): - sec_info = (pike.smb2.OWNER_SECURITY_INFORMATION + - pike.smb2.GROUP_SECURITY_INFORMATION + - pike.smb2.DACL_SECURITY_INFORMATION) - - self.basic_test(pike.smb2.FILE_SECURITY_INFORMATION, - info_type=pike.smb2.SMB2_0_INFO_SECURITY, - additional_information=sec_info) + sec_info = ( + pike.smb2.OWNER_SECURITY_INFORMATION + + pike.smb2.GROUP_SECURITY_INFORMATION + + pike.smb2.DACL_SECURITY_INFORMATION + ) + + self.basic_test( + pike.smb2.FILE_SECURITY_INFORMATION, + info_type=pike.smb2.SMB2_0_INFO_SECURITY, + additional_information=sec_info, + ) def test_query_file_standard_info(self): self.basic_test(pike.smb2.FILE_STANDARD_INFORMATION) @@ -130,7 +147,9 @@ def test_query_sec_desc_0(self): smb2_req = self.chan.request(obj=handle) query_req = pike.smb2.QueryInfoRequest(smb2_req) query_req.info_type = pike.smb2.SMB2_0_INFO_SECURITY - query_req.additional_information = pike.smb2.OWNER_SECURITY_INFORMATION | pike.smb2.DACL_SECURITY_INFORMATION + query_req.additional_information = ( + pike.smb2.OWNER_SECURITY_INFORMATION | pike.smb2.DACL_SECURITY_INFORMATION + ) query_req.output_buffer_length = 0 query_req.file_id = handle.file_id diff --git a/pike/test/querydirectory.py b/pike/test/querydirectory.py index d00614ac..a9ef5425 100644 --- a/pike/test/querydirectory.py +++ b/pike/test/querydirectory.py @@ -26,15 +26,17 @@ class QueryDirectoryTest(pike.test.PikeTest): def test_file_directory_info(self): chan, tree = self.tree_connect() - root = chan.create(tree, - '', - access=pike.smb2.GENERIC_READ, - options=pike.smb2.FILE_DIRECTORY_FILE, - share=pike.smb2.FILE_SHARE_READ).result() + root = chan.create( + tree, + "", + access=pike.smb2.GENERIC_READ, + options=pike.smb2.FILE_DIRECTORY_FILE, + share=pike.smb2.FILE_SHARE_READ, + ).result() names = [info.file_name for info in chan.enum_directory(root)] - self.assertIn('.', names) + self.assertIn(".", names) chan.close(root) @@ -43,19 +45,23 @@ def test_file_directory_info(self): # fails with STATUS_NO_MORE_FILES the second. def test_specific_name(self): chan, tree = self.tree_connect() - name = 'hello.txt' - - hello = chan.create(tree, - name, - access=pike.smb2.GENERIC_WRITE | pike.smb2.GENERIC_READ | pike.smb2.DELETE, - disposition=pike.smb2.FILE_SUPERSEDE, - options=pike.smb2.FILE_DELETE_ON_CLOSE).result() - - root = chan.create(tree, - '', - access=pike.smb2.GENERIC_READ, - options=pike.smb2.FILE_DIRECTORY_FILE, - share=pike.smb2.FILE_SHARE_READ).result() + name = "hello.txt" + + hello = chan.create( + tree, + name, + access=pike.smb2.GENERIC_WRITE | pike.smb2.GENERIC_READ | pike.smb2.DELETE, + disposition=pike.smb2.FILE_SUPERSEDE, + options=pike.smb2.FILE_DELETE_ON_CLOSE, + ).result() + + root = chan.create( + tree, + "", + access=pike.smb2.GENERIC_READ, + options=pike.smb2.FILE_DIRECTORY_FILE, + share=pike.smb2.FILE_SHARE_READ, + ).result() query1 = chan.query_directory(root, file_name=name) @@ -68,16 +74,20 @@ def test_specific_name(self): def test_file_id_both_directory_information(self): chan, tree = self.tree_connect() - root = chan.create(tree, - '', - access=pike.smb2.GENERIC_READ, - options=pike.smb2.FILE_DIRECTORY_FILE, - share=pike.smb2.FILE_SHARE_READ).result() - - result = chan.query_directory(root, file_information_class=pike.smb2.FILE_ID_BOTH_DIR_INFORMATION) + root = chan.create( + tree, + "", + access=pike.smb2.GENERIC_READ, + options=pike.smb2.FILE_DIRECTORY_FILE, + share=pike.smb2.FILE_SHARE_READ, + ).result() + + result = chan.query_directory( + root, file_information_class=pike.smb2.FILE_ID_BOTH_DIR_INFORMATION + ) names = [info.file_name for info in result] - self.assertIn('.', names) - self.assertIn('..', names) + self.assertIn(".", names) + self.assertIn("..", names) valid_file_ids = [info.file_id >= 0 for info in result] self.assertNotIn(False, valid_file_ids) @@ -87,20 +97,22 @@ def test_file_id_both_directory_information(self): def test_restart_scan(self): chan, tree = self.tree_connect() - root = chan.create(tree, - '', - access=pike.smb2.GENERIC_READ, - options=pike.smb2.FILE_DIRECTORY_FILE, - share=pike.smb2.FILE_SHARE_READ).result() + root = chan.create( + tree, + "", + access=pike.smb2.GENERIC_READ, + options=pike.smb2.FILE_DIRECTORY_FILE, + share=pike.smb2.FILE_SHARE_READ, + ).result() result = chan.query_directory(root) names = [info.file_name for info in result] - self.assertIn('.', names) + self.assertIn(".", names) - result = chan.query_directory(root, - flags=pike.smb2.SL_RESTART_SCAN, - file_name='*') + result = chan.query_directory( + root, flags=pike.smb2.SL_RESTART_SCAN, file_name="*" + ) names = [info.file_name for info in result] - self.assertIn('.', names) + self.assertIn(".", names) chan.close(root) diff --git a/pike/test/queryondiskid.py b/pike/test/queryondiskid.py index 5a646b93..7e7b0011 100644 --- a/pike/test/queryondiskid.py +++ b/pike/test/queryondiskid.py @@ -20,18 +20,20 @@ import pike.smb2 import pike.test -share_all = pike.smb2.FILE_SHARE_READ | \ - pike.smb2.FILE_SHARE_WRITE | \ - pike.smb2.FILE_SHARE_DELETE -access_rwd = pike.smb2.GENERIC_READ | \ - pike.smb2.GENERIC_WRITE | \ - pike.smb2.DELETE -null_fid = array.array('B', [0]*32) +share_all = ( + pike.smb2.FILE_SHARE_READ | pike.smb2.FILE_SHARE_WRITE | pike.smb2.FILE_SHARE_DELETE +) +access_rwd = pike.smb2.GENERIC_READ | pike.smb2.GENERIC_WRITE | pike.smb2.DELETE +null_fid = array.array("B", [0] * 32) class TestQueryOnDiskID(pike.test.PikeTest): - test_files = [ "qfid_file.bin", "qfid_same_file.bin", - "qfid_diff_file1.bin", "qfid_diff_file2.bin" ] + test_files = [ + "qfid_file.bin", + "qfid_same_file.bin", + "qfid_diff_file1.bin", + "qfid_diff_file2.bin", + ] def extract_file_id(self, response): """ @@ -42,16 +44,19 @@ def extract_file_id(self, response): if isinstance(child, pike.smb2.CreateResponse): create_res = child break - self.assertIsNotNone(create_res, - "response didn't contain a " - "CreateResponse: {0}".format(response)) + self.assertIsNotNone( + create_res, + "response didn't contain a " "CreateResponse: {0}".format(response), + ) for child in create_res: if isinstance(child, pike.smb2.QueryOnDiskIDResponse): qfid_res = child break - self.assertIsNotNone(qfid_res, - "CreateResponse didn't contain a " - "QueryOnDiskIDResponse: {0}".format(create_res)) + self.assertIsNotNone( + qfid_res, + "CreateResponse didn't contain a " + "QueryOnDiskIDResponse: {0}".format(create_res), + ) return qfid_res.file_id def test_qfid_functional(self): @@ -60,17 +65,17 @@ def test_qfid_functional(self): """ chan, tree = self.tree_connect() - open_future = chan.create(tree, - "qfid_file.bin", - access=access_rwd, - disposition=pike.smb2.FILE_SUPERSEDE, - options=pike.smb2.FILE_DELETE_ON_CLOSE, - query_on_disk_id=True) + open_future = chan.create( + tree, + "qfid_file.bin", + access=access_rwd, + disposition=pike.smb2.FILE_SUPERSEDE, + options=pike.smb2.FILE_DELETE_ON_CLOSE, + query_on_disk_id=True, + ) fh = open_future.result() fid = self.extract_file_id(open_future.request_future.result()) - self.assertNotEqual(fid, - null_fid, - "On disk file_id was null") + self.assertNotEqual(fid, null_fid, "On disk file_id was null") def test_qfid_same_file(self): """ @@ -79,28 +84,29 @@ def test_qfid_same_file(self): chan1, tree1 = self.tree_connect() chan2, tree2 = self.tree_connect() - open_future1 = chan1.create(tree1, - "qfid_same_file.bin", - access=access_rwd, - share=share_all, - disposition=pike.smb2.FILE_SUPERSEDE, - options=pike.smb2.FILE_DELETE_ON_CLOSE, - query_on_disk_id=True) + open_future1 = chan1.create( + tree1, + "qfid_same_file.bin", + access=access_rwd, + share=share_all, + disposition=pike.smb2.FILE_SUPERSEDE, + options=pike.smb2.FILE_DELETE_ON_CLOSE, + query_on_disk_id=True, + ) fh1 = open_future1.result() fid1 = self.extract_file_id(open_future1.request_future.result()) - open_future2 = chan2.create(tree2, - "qfid_same_file.bin", - access=access_rwd, - share=share_all, - disposition=pike.smb2.FILE_OPEN, - query_on_disk_id=True) + open_future2 = chan2.create( + tree2, + "qfid_same_file.bin", + access=access_rwd, + share=share_all, + disposition=pike.smb2.FILE_OPEN, + query_on_disk_id=True, + ) fh2 = open_future2.result() fid2 = self.extract_file_id(open_future2.request_future.result()) - self.assertNotEqual(fid1, - null_fid, - "On disk file_id was null") - self.assertEqual(fid1, fid2, - "On disk file_id for same file didn't match") + self.assertNotEqual(fid1, null_fid, "On disk file_id was null") + self.assertEqual(fid1, fid2, "On disk file_id for same file didn't match") def test_qfid_diff_file(self): """ @@ -110,27 +116,30 @@ def test_qfid_diff_file(self): chan1, tree1 = self.tree_connect() chan2, tree2 = self.tree_connect() - open_future1 = chan1.create(tree1, - "qfid_diff_file1.bin", - access=access_rwd, - disposition=pike.smb2.FILE_SUPERSEDE, - options=pike.smb2.FILE_DELETE_ON_CLOSE, - query_on_disk_id=True) + open_future1 = chan1.create( + tree1, + "qfid_diff_file1.bin", + access=access_rwd, + disposition=pike.smb2.FILE_SUPERSEDE, + options=pike.smb2.FILE_DELETE_ON_CLOSE, + query_on_disk_id=True, + ) fh1 = open_future1.result() fid1 = self.extract_file_id(open_future1.request_future.result()) - open_future2 = chan2.create(tree2, - "qfid_diff_file2.bin", - access=access_rwd, - disposition=pike.smb2.FILE_SUPERSEDE, - options=pike.smb2.FILE_DELETE_ON_CLOSE, - query_on_disk_id=True) + open_future2 = chan2.create( + tree2, + "qfid_diff_file2.bin", + access=access_rwd, + disposition=pike.smb2.FILE_SUPERSEDE, + options=pike.smb2.FILE_DELETE_ON_CLOSE, + query_on_disk_id=True, + ) fh2 = open_future2.result() fid2 = self.extract_file_id(open_future2.request_future.result()) - self.assertNotEqual(fid1, - null_fid, - "On disk file_id was null") - self.assertNotEqual(fid1, fid2, - "On disk file_id for different files was the same") + self.assertNotEqual(fid1, null_fid, "On disk file_id was null") + self.assertNotEqual( + fid1, fid2, "On disk file_id for different files was the same" + ) def test_qfid_same_file_seq(self): """ @@ -139,32 +148,31 @@ def test_qfid_same_file_seq(self): """ chan, tree = self.tree_connect() - open_future = chan.create(tree, - "qfid_file.bin", - access=access_rwd, - disposition=pike.smb2.FILE_SUPERSEDE, - query_on_disk_id=True) + open_future = chan.create( + tree, + "qfid_file.bin", + access=access_rwd, + disposition=pike.smb2.FILE_SUPERSEDE, + query_on_disk_id=True, + ) fh = open_future.result() fid = self.extract_file_id(open_future.request_future.result()) - self.assertNotEqual(fid, - null_fid, - "On disk file_id was null") + self.assertNotEqual(fid, null_fid, "On disk file_id was null") first_fid = fid chan.close(fh) - open_future = chan.create(tree, - "qfid_file.bin", - access=access_rwd, - disposition=pike.smb2.FILE_OPEN, - options=pike.smb2.FILE_DELETE_ON_CLOSE, - query_on_disk_id=True) + open_future = chan.create( + tree, + "qfid_file.bin", + access=access_rwd, + disposition=pike.smb2.FILE_OPEN, + options=pike.smb2.FILE_DELETE_ON_CLOSE, + query_on_disk_id=True, + ) fh = open_future.result() fid = self.extract_file_id(open_future.request_future.result()) - self.assertNotEqual(fid, - null_fid, - "On disk file_id was null") - self.assertEqual(fid, first_fid, - "Subsequent open returns different file id") + self.assertNotEqual(fid, null_fid, "On disk file_id was null") + self.assertEqual(fid, first_fid, "Subsequent open returns different file id") def test_qfid_same_file_seq_delete(self): """ @@ -173,31 +181,31 @@ def test_qfid_same_file_seq_delete(self): """ chan, tree = self.tree_connect() - open_future = chan.create(tree, - "qfid_file.bin", - access=access_rwd, - disposition=pike.smb2.FILE_SUPERSEDE, - options=pike.smb2.FILE_DELETE_ON_CLOSE, - query_on_disk_id=True) + open_future = chan.create( + tree, + "qfid_file.bin", + access=access_rwd, + disposition=pike.smb2.FILE_SUPERSEDE, + options=pike.smb2.FILE_DELETE_ON_CLOSE, + query_on_disk_id=True, + ) fh = open_future.result() fid = self.extract_file_id(open_future.request_future.result()) - self.assertNotEqual(fid, - null_fid, - "On disk file_id was null") + self.assertNotEqual(fid, null_fid, "On disk file_id was null") first_fid = fid chan.close(fh) - open_future = chan.create(tree, - "qfid_file.bin", - access=access_rwd, - disposition=pike.smb2.FILE_CREATE, - options=pike.smb2.FILE_DELETE_ON_CLOSE, - query_on_disk_id=True) + open_future = chan.create( + tree, + "qfid_file.bin", + access=access_rwd, + disposition=pike.smb2.FILE_CREATE, + options=pike.smb2.FILE_DELETE_ON_CLOSE, + query_on_disk_id=True, + ) fh = open_future.result() fid = self.extract_file_id(open_future.request_future.result()) - self.assertNotEqual(fid, - null_fid, - "On disk file_id was null") - self.assertNotEqual(fid, first_fid, - "Subsequent open after delete returns same file id") - + self.assertNotEqual(fid, null_fid, "On disk file_id was null") + self.assertNotEqual( + fid, first_fid, "Subsequent open after delete returns same file id" + ) diff --git a/pike/test/readwrite.py b/pike/test/readwrite.py index b684e7a4..fd2aac3e 100644 --- a/pike/test/readwrite.py +++ b/pike/test/readwrite.py @@ -31,21 +31,27 @@ def test_write(self): chan, tree = self.tree_connect() buffer = "testing123" - share_all = pike.smb2.FILE_SHARE_READ | pike.smb2.FILE_SHARE_WRITE | pike.smb2.FILE_SHARE_DELETE - - file = chan.create(tree, - 'write.txt', - access=pike.smb2.FILE_READ_DATA | pike.smb2.FILE_WRITE_DATA | pike.smb2.DELETE, - share=share_all, - disposition=pike.smb2.FILE_SUPERSEDE, - options=pike.smb2.FILE_DELETE_ON_CLOSE, - oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_EXCLUSIVE).result() - - bytes_written = chan.write(file, - 0, - buffer) + share_all = ( + pike.smb2.FILE_SHARE_READ + | pike.smb2.FILE_SHARE_WRITE + | pike.smb2.FILE_SHARE_DELETE + ) + + file = chan.create( + tree, + "write.txt", + access=pike.smb2.FILE_READ_DATA + | pike.smb2.FILE_WRITE_DATA + | pike.smb2.DELETE, + share=share_all, + disposition=pike.smb2.FILE_SUPERSEDE, + options=pike.smb2.FILE_DELETE_ON_CLOSE, + oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_EXCLUSIVE, + ).result() + + bytes_written = chan.write(file, 0, buffer) self.assertEqual(bytes_written, len(buffer)) - + chan.close(file) # Test that a 0-byte write succeeds @@ -53,21 +59,27 @@ def test_write_none(self): chan, tree = self.tree_connect() buffer = None - share_all = pike.smb2.FILE_SHARE_READ | pike.smb2.FILE_SHARE_WRITE | pike.smb2.FILE_SHARE_DELETE - - file = chan.create(tree, - 'write.txt', - access=pike.smb2.FILE_READ_DATA | pike.smb2.FILE_WRITE_DATA | pike.smb2.DELETE, - share=share_all, - disposition=pike.smb2.FILE_SUPERSEDE, - options=pike.smb2.FILE_DELETE_ON_CLOSE, - oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_EXCLUSIVE).result() - - bytes_written = chan.write(file, - 0, - buffer) + share_all = ( + pike.smb2.FILE_SHARE_READ + | pike.smb2.FILE_SHARE_WRITE + | pike.smb2.FILE_SHARE_DELETE + ) + + file = chan.create( + tree, + "write.txt", + access=pike.smb2.FILE_READ_DATA + | pike.smb2.FILE_WRITE_DATA + | pike.smb2.DELETE, + share=share_all, + disposition=pike.smb2.FILE_SUPERSEDE, + options=pike.smb2.FILE_DELETE_ON_CLOSE, + oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_EXCLUSIVE, + ).result() + + bytes_written = chan.write(file, 0, buffer) self.assertEqual(bytes_written, 0) - + chan.close(file) # Test that a 0-byte write succeeds @@ -75,21 +87,27 @@ def test_write_none(self): chan, tree = self.tree_connect() buffer = None - share_all = pike.smb2.FILE_SHARE_READ | pike.smb2.FILE_SHARE_WRITE | pike.smb2.FILE_SHARE_DELETE - - file = chan.create(tree, - 'write.txt', - access=pike.smb2.FILE_READ_DATA | pike.smb2.FILE_WRITE_DATA | pike.smb2.DELETE, - share=share_all, - disposition=pike.smb2.FILE_SUPERSEDE, - options=pike.smb2.FILE_DELETE_ON_CLOSE, - oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_EXCLUSIVE).result() - - bytes_written = chan.write(file, - 0, - buffer) + share_all = ( + pike.smb2.FILE_SHARE_READ + | pike.smb2.FILE_SHARE_WRITE + | pike.smb2.FILE_SHARE_DELETE + ) + + file = chan.create( + tree, + "write.txt", + access=pike.smb2.FILE_READ_DATA + | pike.smb2.FILE_WRITE_DATA + | pike.smb2.DELETE, + share=share_all, + disposition=pike.smb2.FILE_SUPERSEDE, + options=pike.smb2.FILE_DELETE_ON_CLOSE, + oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_EXCLUSIVE, + ).result() + + bytes_written = chan.write(file, 0, buffer) self.assertEqual(bytes_written, 0) - + chan.close(file) # Test that a 0-byte write triggers access checks @@ -97,46 +115,62 @@ def test_write_none(self): def test_write_none_access(self): chan, tree = self.tree_connect() - share_all = pike.smb2.FILE_SHARE_READ | pike.smb2.FILE_SHARE_WRITE | pike.smb2.FILE_SHARE_DELETE + share_all = ( + pike.smb2.FILE_SHARE_READ + | pike.smb2.FILE_SHARE_WRITE + | pike.smb2.FILE_SHARE_DELETE + ) + + file = chan.create( + tree, + "write.txt", + access=pike.smb2.FILE_READ_DATA | pike.smb2.DELETE, + share=share_all, + disposition=pike.smb2.FILE_SUPERSEDE, + oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_EXCLUSIVE, + ).result() - file = chan.create(tree, - 'write.txt', - access=pike.smb2.FILE_READ_DATA | pike.smb2.DELETE, - share=share_all, - disposition=pike.smb2.FILE_SUPERSEDE, - oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_EXCLUSIVE).result() - with pike.model.pike_status(pike.ntstatus.STATUS_ACCESS_DENIED): chan.write(file, 0, None) - + chan.close(file) # Test that 0-byte write does not cause an oplock break def test_write_none_oplock(self): chan, tree = self.tree_connect() - share_all = pike.smb2.FILE_SHARE_READ | pike.smb2.FILE_SHARE_WRITE | pike.smb2.FILE_SHARE_DELETE - - file = chan.create(tree, - 'write.txt', - access=pike.smb2.FILE_READ_DATA | pike.smb2.FILE_WRITE_DATA | pike.smb2.DELETE, - share=share_all, - disposition=pike.smb2.FILE_SUPERSEDE, - options=pike.smb2.FILE_DELETE_ON_CLOSE, - oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_NONE).result() - - file2 = chan.create(tree, - 'write.txt', - access=pike.smb2.FILE_READ_DATA | pike.smb2.FILE_WRITE_DATA | pike.smb2.DELETE, - share=share_all, - disposition=pike.smb2.FILE_SUPERSEDE, - options=pike.smb2.FILE_DELETE_ON_CLOSE, - oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_II).result() + share_all = ( + pike.smb2.FILE_SHARE_READ + | pike.smb2.FILE_SHARE_WRITE + | pike.smb2.FILE_SHARE_DELETE + ) + + file = chan.create( + tree, + "write.txt", + access=pike.smb2.FILE_READ_DATA + | pike.smb2.FILE_WRITE_DATA + | pike.smb2.DELETE, + share=share_all, + disposition=pike.smb2.FILE_SUPERSEDE, + options=pike.smb2.FILE_DELETE_ON_CLOSE, + oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_NONE, + ).result() + + file2 = chan.create( + tree, + "write.txt", + access=pike.smb2.FILE_READ_DATA + | pike.smb2.FILE_WRITE_DATA + | pike.smb2.DELETE, + share=share_all, + disposition=pike.smb2.FILE_SUPERSEDE, + options=pike.smb2.FILE_DELETE_ON_CLOSE, + oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_II, + ).result() self.assertEqual(file2.oplock_level, pike.smb2.SMB2_OPLOCK_LEVEL_II) - bytes_written = chan.write(file, - 0, - None) + bytes_written = chan.write(file, 0, None) self.assertEqual(bytes_written, 0) # We should not receive an oplock break @@ -151,25 +185,37 @@ def test_write_none_oplock(self): @pike.test.RequireCapabilities(pike.smb2.SMB2_GLOBAL_CAP_LEASING) def test_write_none_lease(self): chan, tree = self.tree_connect() - lease1 = array.array('B', map(random.randint, [0] * 16, [255] * 16)) - - share_all = pike.smb2.FILE_SHARE_READ | pike.smb2.FILE_SHARE_WRITE | pike.smb2.FILE_SHARE_DELETE - - file = chan.create(tree, - 'write.txt', - access=pike.smb2.FILE_READ_DATA | pike.smb2.FILE_WRITE_DATA | pike.smb2.DELETE, - share=share_all, - disposition=pike.smb2.FILE_SUPERSEDE, - oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_NONE).result() - - file2 = chan.create(tree, - 'write.txt', - access=pike.smb2.FILE_READ_DATA | pike.smb2.FILE_WRITE_DATA | pike.smb2.DELETE, - share=share_all, - disposition=pike.smb2.FILE_SUPERSEDE, - oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, - lease_key=lease1, - lease_state=pike.smb2.SMB2_LEASE_READ_CACHING).result() + lease1 = array.array("B", map(random.randint, [0] * 16, [255] * 16)) + + share_all = ( + pike.smb2.FILE_SHARE_READ + | pike.smb2.FILE_SHARE_WRITE + | pike.smb2.FILE_SHARE_DELETE + ) + + file = chan.create( + tree, + "write.txt", + access=pike.smb2.FILE_READ_DATA + | pike.smb2.FILE_WRITE_DATA + | pike.smb2.DELETE, + share=share_all, + disposition=pike.smb2.FILE_SUPERSEDE, + oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_NONE, + ).result() + + file2 = chan.create( + tree, + "write.txt", + access=pike.smb2.FILE_READ_DATA + | pike.smb2.FILE_WRITE_DATA + | pike.smb2.DELETE, + share=share_all, + disposition=pike.smb2.FILE_SUPERSEDE, + oplock_level=pike.smb2.SMB2_OPLOCK_LEVEL_LEASE, + lease_key=lease1, + lease_state=pike.smb2.SMB2_LEASE_READ_CACHING, + ).result() bytes_written = chan.write(file, 64, None) self.assertEqual(bytes_written, 0) diff --git a/pike/test/reparse.py b/pike/test/reparse.py index 41620e5f..acdb60bc 100644 --- a/pike/test/reparse.py +++ b/pike/test/reparse.py @@ -17,7 +17,10 @@ import pike.model import pike.test -share_all = pike.smb2.FILE_SHARE_READ | pike.smb2.FILE_SHARE_WRITE | pike.smb2.FILE_SHARE_DELETE +share_all = ( + pike.smb2.FILE_SHARE_READ | pike.smb2.FILE_SHARE_WRITE | pike.smb2.FILE_SHARE_DELETE +) + class TestReparsePoint(pike.test.PikeTest): def test_set_get_reparse_point(self): @@ -25,11 +28,12 @@ def test_set_get_reparse_point(self): target = "target" - link = chan.create(tree, - "symlink", - pike.smb2.FILE_READ_DATA | pike.smb2.FILE_WRITE_DATA | pike.smb2.DELETE, - options=pike.smb2.FILE_OPEN_REPARSE_POINT | \ - pike.smb2.FILE_DELETE_ON_CLOSE).result() + link = chan.create( + tree, + "symlink", + pike.smb2.FILE_READ_DATA | pike.smb2.FILE_WRITE_DATA | pike.smb2.DELETE, + options=pike.smb2.FILE_OPEN_REPARSE_POINT | pike.smb2.FILE_DELETE_ON_CLOSE, + ).result() chan.set_symlink(link, target, pike.smb2.SYMLINK_FLAG_RELATIVE) result = chan.get_symlink(link) self.assertEqual(result[0][0].reparse_data.substitute_name, target) @@ -40,18 +44,20 @@ def test_symbolic_link_error_response(self): target = "target" - link = chan.create(tree, - "symlink", - pike.smb2.FILE_READ_DATA | pike.smb2.FILE_WRITE_DATA | pike.smb2.DELETE, - share=share_all, - options=pike.smb2.FILE_OPEN_REPARSE_POINT | \ - pike.smb2.FILE_DELETE_ON_CLOSE).result() + link = chan.create( + tree, + "symlink", + pike.smb2.FILE_READ_DATA | pike.smb2.FILE_WRITE_DATA | pike.smb2.DELETE, + share=share_all, + options=pike.smb2.FILE_OPEN_REPARSE_POINT | pike.smb2.FILE_DELETE_ON_CLOSE, + ).result() chan.set_symlink(link, target, pike.smb2.SYMLINK_FLAG_RELATIVE) try: chan.create(tree, "symlink", share=share_all).result() except pike.model.ResponseError as err: - self.assertEqual(err.response.status, pike.ntstatus.STATUS_STOPPED_ON_SYMLINK) + self.assertEqual( + err.response.status, pike.ntstatus.STATUS_STOPPED_ON_SYMLINK + ) self.assertEqual(err.response[0][0].error_data.substitute_name, target) self.assertEqual(err.response[0][0].error_data.print_name, target) chan.close(link) - diff --git a/pike/test/session.py b/pike/test/session.py index 41a6fde4..500bbb2f 100644 --- a/pike/test/session.py +++ b/pike/test/session.py @@ -22,6 +22,7 @@ class SessionTest(pike.test.PikeTest): def test_session_logoff(self): chan, tree = self.tree_connect() chan.logoff() + def test_session_multiplex(self): chan, tree = self.tree_connect() chan2 = chan.connection.session_setup(self.creds) diff --git a/pike/test/set.py b/pike/test/set.py index c52210d3..6fab6b93 100644 --- a/pike/test/set.py +++ b/pike/test/set.py @@ -25,21 +25,29 @@ class SetTest(pike.test.PikeTest): def open_file(self): self.chan, self.tree = self.tree_connect() - return self.chan.create(self.tree, "test.txt", disposition=pike.smb2.FILE_SUPERSEDE).result() + return self.chan.create( + self.tree, "test.txt", disposition=pike.smb2.FILE_SUPERSEDE + ).result() # Set timestamps and file attributes with FILE_BASIC_INFORMATION def test_set_file_basic_info(self): handle = self.open_file() now = pike.nttime.NtTime(datetime.datetime.now()) - with self.chan.set_file_info(handle, pike.smb2.FileBasicInformation) as file_info: + with self.chan.set_file_info( + handle, pike.smb2.FileBasicInformation + ) as file_info: file_info.last_write_time = now file_info.last_access_time = now - with self.chan.set_file_info(handle, pike.smb2.FileBasicInformation) as file_info: + with self.chan.set_file_info( + handle, pike.smb2.FileBasicInformation + ) as file_info: file_info.file_attributes = pike.smb2.FILE_ATTRIBUTE_READONLY - with self.chan.set_file_info(handle, pike.smb2.FileBasicInformation) as file_info: + with self.chan.set_file_info( + handle, pike.smb2.FileBasicInformation + ) as file_info: file_info.file_attributes = pike.smb2.FILE_ATTRIBUTE_NORMAL self.chan.close(handle) @@ -47,8 +55,10 @@ def test_set_file_basic_info(self): # Set file cursor position with FILE_POSITION_INFORMATION def test_set_file_position_info(self): handle = self.open_file() - - with self.chan.set_file_info(handle, pike.smb2.FilePositionInformation) as file_info: + + with self.chan.set_file_info( + handle, pike.smb2.FilePositionInformation + ) as file_info: file_info.current_byte_offset = 100 self.chan.close(handle) @@ -57,7 +67,9 @@ def test_set_file_position_info(self): def test_set_file_mode_info(self): handle = self.open_file() - with self.chan.set_file_info(handle, pike.smb2.FileModeInformation) as file_info: + with self.chan.set_file_info( + handle, pike.smb2.FileModeInformation + ) as file_info: file_info.mode = pike.smb2.FILE_SEQUENTIAL_ONLY self.chan.close(handle) @@ -65,20 +77,27 @@ def test_set_file_mode_info(self): # Set file name with FILE_RENAME_INFORMATION def test_set_file_name(self): self.chan, self.tree = self.tree_connect() - handle = self.chan.create(self.tree, "test.txt", - disposition=pike.smb2.FILE_SUPERSEDE, - access=pike.smb2.DELETE).result() - - with self.chan.set_file_info(handle, pike.smb2.FileRenameInformation) as file_info: + handle = self.chan.create( + self.tree, + "test.txt", + disposition=pike.smb2.FILE_SUPERSEDE, + access=pike.smb2.DELETE, + ).result() + + with self.chan.set_file_info( + handle, pike.smb2.FileRenameInformation + ) as file_info: file_info.replace_if_exists = 1 file_info.file_name = "renamed.txt" self.chan.close(handle) # open the renamed file for delete and ensure that it exists - handle2 = self.chan.create(self.tree, "renamed.txt", - disposition=pike.smb2.FILE_OPEN, # fail if doesn't exist - access=pike.smb2.DELETE, - options=pike.smb2.FILE_DELETE_ON_CLOSE).result() + handle2 = self.chan.create( + self.tree, + "renamed.txt", + disposition=pike.smb2.FILE_OPEN, # fail if doesn't exist + access=pike.smb2.DELETE, + options=pike.smb2.FILE_DELETE_ON_CLOSE, + ).result() self.chan.close(handle2) - diff --git a/pike/test/test_smb3_encryption_vector.py b/pike/test/test_smb3_encryption_vector.py index 734bd95f..b2712aa0 100644 --- a/pike/test/test_smb3_encryption_vector.py +++ b/pike/test/test_smb3_encryption_vector.py @@ -20,6 +20,7 @@ from binascii import unhexlify + class bogus_connection(object): def signing_key(self, *args, **kwds): return self._signing_key @@ -30,132 +31,170 @@ def encryption_context(self, *args, **kwds): def signing_digest(self, *args, **kwds): return digest.aes128_cmac + class bogus_300_connection(bogus_connection): def __init__(self, session_key): self._signing_key = digest.derive_key( - session_key, - b'SMB2AESCMAC', - b'SmbSign\0')[:16] + session_key, b"SMB2AESCMAC", b"SmbSign\0" + )[:16] self._encryption_context = crypto.EncryptionContext( - crypto.CryptoKeys300(session_key), - [crypto.SMB2_AES_128_CCM]) + crypto.CryptoKeys300(session_key), [crypto.SMB2_AES_128_CCM] + ) + class bogus_311_connection(bogus_connection): def __init__(self, session_key, pre_auth_integrity_value, ciphers): self._signing_key = digest.derive_key( - session_key, - b'SMBSigningKey', - pre_auth_integrity_value)[:16] + session_key, b"SMBSigningKey", pre_auth_integrity_value + )[:16] self._encryption_context = crypto.EncryptionContext( - crypto.CryptoKeys311(session_key, - pre_auth_integrity_value), - ciphers) + crypto.CryptoKeys311(session_key, pre_auth_integrity_value), ciphers + ) + class PAIntegrity(object): def __init__(self): - self.hash = array.array('B', b"\0"*64) + self.hash = array.array("B", b"\0" * 64) + def update(self, data): - self.hash = digest.smb3_sha512( - self.hash + - data) + self.hash = digest.smb3_sha512(self.hash + data) + class TestVector(unittest.TestCase): def test_pre_auth_integrity(self): h = PAIntegrity() - negotiate_request = array.array('B', unhexlify( - "FE534D4240000100000000000000800000000000000000000100000000000000FFFE000000000000" - "00000000000000000000000000000000000000000000000024000500000000003F000000ECD86F32" - "6276024F9F7752B89BB33F3A70000000020000000202100200030203110300000100260000000000" - "010020000100FA49E6578F1F3A9F4CD3E9CC14A67AA884B3D05844E0E5A118225C15887F32FF0000" - "0200060000000000020002000100")) + negotiate_request = array.array( + "B", + unhexlify( + "FE534D4240000100000000000000800000000000000000000100000000000000FFFE000000000000" + "00000000000000000000000000000000000000000000000024000500000000003F000000ECD86F32" + "6276024F9F7752B89BB33F3A70000000020000000202100200030203110300000100260000000000" + "010020000100FA49E6578F1F3A9F4CD3E9CC14A67AA884B3D05844E0E5A118225C15887F32FF0000" + "0200060000000000020002000100" + ), + ) h.update(negotiate_request) - exp_pae_1 = array.array('B', unhexlify( - "DD94EFC5321BB618A2E208BA8920D2F422992526947A409B5037DE1E0FE8C7362B8C47122594CDE0" - "CE26AA9DFC8BCDBDE0621957672623351A7540F1E54A0426")) + exp_pae_1 = array.array( + "B", + unhexlify( + "DD94EFC5321BB618A2E208BA8920D2F422992526947A409B5037DE1E0FE8C7362B8C47122594CDE0" + "CE26AA9DFC8BCDBDE0621957672623351A7540F1E54A0426" + ), + ) self.assertEqual(h.hash, exp_pae_1) - negotiate_response = array.array('B', unhexlify( - "FE534D4240000100000000000000010001000000000000000100000000000000FFFE000000000000" - "000000000000000000000000000000000000000000000000410001001103020039CBCAF329714942" - "BDCE5D60F09AB3FB2F000000000080000000800000008000D8DAE5ADCBAED00109094AB095AED001" - "80004001C00100006082013C06062B0601050502A08201303082012CA01A3018060A2B0601040182" - "3702021E060A2B06010401823702020AA282010C048201084E45474F455854530100000000000000" - "60000000700000007C7CC0FD06D6362D02DDE1CF343BFE292900F49750B4AA97934D9C4296B26E51" - "FD370471B235E15A50DAE15BD5489C87000000000000000060000000010000000000000000000000" - "5C33530DEAF90D4DB2EC4AE3786EC3084E45474F4558545303000000010000004000000098000000" - "7C7CC0FD06D6362D02DDE1CF343BFE295C33530DEAF90D4DB2EC4AE3786EC3084000000058000000" - "3056A05430523027802530233121301F06035504031318546F6B656E205369676E696E6720507562" - "6C6963204B65793027802530233121301F06035504031318546F6B656E205369676E696E67205075" - "626C6963204B6579010026000000000001002000010060A3C3B95C3C7CCD51EC536648D9B3AC74C4" - "83CA5B65385A251117BEB30712E50000020004000000000001000200")) + negotiate_response = array.array( + "B", + unhexlify( + "FE534D4240000100000000000000010001000000000000000100000000000000FFFE000000000000" + "000000000000000000000000000000000000000000000000410001001103020039CBCAF329714942" + "BDCE5D60F09AB3FB2F000000000080000000800000008000D8DAE5ADCBAED00109094AB095AED001" + "80004001C00100006082013C06062B0601050502A08201303082012CA01A3018060A2B0601040182" + "3702021E060A2B06010401823702020AA282010C048201084E45474F455854530100000000000000" + "60000000700000007C7CC0FD06D6362D02DDE1CF343BFE292900F49750B4AA97934D9C4296B26E51" + "FD370471B235E15A50DAE15BD5489C87000000000000000060000000010000000000000000000000" + "5C33530DEAF90D4DB2EC4AE3786EC3084E45474F4558545303000000010000004000000098000000" + "7C7CC0FD06D6362D02DDE1CF343BFE295C33530DEAF90D4DB2EC4AE3786EC3084000000058000000" + "3056A05430523027802530233121301F06035504031318546F6B656E205369676E696E6720507562" + "6C6963204B65793027802530233121301F06035504031318546F6B656E205369676E696E67205075" + "626C6963204B6579010026000000000001002000010060A3C3B95C3C7CCD51EC536648D9B3AC74C4" + "83CA5B65385A251117BEB30712E50000020004000000000001000200" + ), + ) h.update(negotiate_response) - exp_pae_2 = array.array('B', unhexlify( - "324BFA92A4F3A190E466EBEA08D9C110DC88BFED758D9846ECC6F541CC1D02AE3C94A79F36011E99" - "7E13F841B91B50957AD07B19C8E2539C0B23FDAE09D2C513")) + exp_pae_2 = array.array( + "B", + unhexlify( + "324BFA92A4F3A190E466EBEA08D9C110DC88BFED758D9846ECC6F541CC1D02AE3C94A79F36011E99" + "7E13F841B91B50957AD07B19C8E2539C0B23FDAE09D2C513" + ), + ) self.assertEqual(h.hash, exp_pae_2) - session_setup_request = array.array('B', unhexlify( - "FE534D4240000100000000000100800000000000000000000200000000000000FFFE000000000000" - "00000000000000000000000000000000000000000000000019000001010000000000000058004A00" - "0000000000000000604806062B0601050502A03E303CA00E300C060A2B06010401823702020AA22A" - "04284E544C4D5353500001000000978208E200000000000000000000000000000000060380250000" - "000F")) + session_setup_request = array.array( + "B", + unhexlify( + "FE534D4240000100000000000100800000000000000000000200000000000000FFFE000000000000" + "00000000000000000000000000000000000000000000000019000001010000000000000058004A00" + "0000000000000000604806062B0601050502A03E303CA00E300C060A2B06010401823702020AA22A" + "04284E544C4D5353500001000000978208E200000000000000000000000000000000060380250000" + "000F" + ), + ) h.update(session_setup_request) - exp_pae_3 = array.array('B', unhexlify( - "AC0B0F2B9986257700365E416D142A6EDC96DF03594A19E52A15F6BD0D041CD5D432F8ED42C55E33" - "197A50C9EC00F1462B50C592211B1471A04B56088FDFD5F9")) + exp_pae_3 = array.array( + "B", + unhexlify( + "AC0B0F2B9986257700365E416D142A6EDC96DF03594A19E52A15F6BD0D041CD5D432F8ED42C55E33" + "197A50C9EC00F1462B50C592211B1471A04B56088FDFD5F9" + ), + ) self.assertEqual(h.hash, exp_pae_3) - session_setup_response = array.array('B', unhexlify( - "FE534D4240000100160000C00100010001000000000000000200000000000000FFFE000000000000" - "190000000010000000000000000000000000000000000000090000004800B300A181B03081ADA003" - "0A0101A10C060A2B06010401823702020AA281970481944E544C4D53535000020000000C000C0038" - "00000015828AE20D1D8BA31179D008000000000000000050005000440000000A0092270000000F53" - "005500540033003100310002000C0053005500540033003100310001000C00530055005400330031" - "00310004000C0053005500540033003100310003000C0053005500540033003100310007000800A1" - "A1F5ADCBAED00100000000")) + session_setup_response = array.array( + "B", + unhexlify( + "FE534D4240000100160000C00100010001000000000000000200000000000000FFFE000000000000" + "190000000010000000000000000000000000000000000000090000004800B300A181B03081ADA003" + "0A0101A10C060A2B06010401823702020AA281970481944E544C4D53535000020000000C000C0038" + "00000015828AE20D1D8BA31179D008000000000000000050005000440000000A0092270000000F53" + "005500540033003100310002000C0053005500540033003100310001000C00530055005400330031" + "00310004000C0053005500540033003100310003000C0053005500540033003100310007000800A1" + "A1F5ADCBAED00100000000" + ), + ) h.update(session_setup_response) - exp_pae_4 = array.array('B', unhexlify( - "2729E3440DFDDD839E37193F6E8F20C20CEFB3469E453A70CD980EEC06B8835740A7376008563336" - "4C8989895ECE81BF102DEEB14D4B7D48AFA76901A7A38387")) + exp_pae_4 = array.array( + "B", + unhexlify( + "2729E3440DFDDD839E37193F6E8F20C20CEFB3469E453A70CD980EEC06B8835740A7376008563336" + "4C8989895ECE81BF102DEEB14D4B7D48AFA76901A7A38387" + ), + ) self.assertEqual(h.hash, exp_pae_4) - session_setup_response2 = array.array('B', unhexlify( - "FE534D4240000100000000000100800000000000000000000300000000000000FFFE000000000000" - "1900000000100000000000000000000000000000000000001900000101000000000000005800CF01" - "0000000000000000A18201CB308201C7A0030A0101A28201AA048201A64E544C4D53535000030000" - "001800180090000000EE00EE00A80000000C000C00580000001A001A0064000000120012007E0000" - "001000100096010000158288E2060380250000000FECAC77A5F385A8BF9C38C706EEEDDCD3530055" - "005400330031003100610064006D0069006E006900730074007200610074006F0072004400520049" - "0056004500520033003100310000000000000000000000000000000000000000000000000063078E" - "B639FE03E20A231C3AE3BF23080101000000000000A1A1F5ADCBAED001BC4AD05F223CC90F000000" - "0002000C0053005500540033003100310001000C0053005500540033003100310004000C00530055" - "00540033003100310003000C0053005500540033003100310007000800A1A1F5ADCBAED001060004" - "00020000000800300030000000000000000000000000300000B61FEFCAA857EA57BF1EDCEBF8974B" - "8E0EBA5A6DFD9D07A31D11B548F8C9D0CC0A00100000000000000000000000000000000000090016" - "0063006900660073002F005300550054003300310031000000000000000000000000003B9BDFF38F" - "5EE8F9663F11A0F4C03A78A31204100100000063775A9A5FD97F0600000000")) + session_setup_response2 = array.array( + "B", + unhexlify( + "FE534D4240000100000000000100800000000000000000000300000000000000FFFE000000000000" + "1900000000100000000000000000000000000000000000001900000101000000000000005800CF01" + "0000000000000000A18201CB308201C7A0030A0101A28201AA048201A64E544C4D53535000030000" + "001800180090000000EE00EE00A80000000C000C00580000001A001A0064000000120012007E0000" + "001000100096010000158288E2060380250000000FECAC77A5F385A8BF9C38C706EEEDDCD3530055" + "005400330031003100610064006D0069006E006900730074007200610074006F0072004400520049" + "0056004500520033003100310000000000000000000000000000000000000000000000000063078E" + "B639FE03E20A231C3AE3BF23080101000000000000A1A1F5ADCBAED001BC4AD05F223CC90F000000" + "0002000C0053005500540033003100310001000C0053005500540033003100310004000C00530055" + "00540033003100310003000C0053005500540033003100310007000800A1A1F5ADCBAED001060004" + "00020000000800300030000000000000000000000000300000B61FEFCAA857EA57BF1EDCEBF8974B" + "8E0EBA5A6DFD9D07A31D11B548F8C9D0CC0A00100000000000000000000000000000000000090016" + "0063006900660073002F005300550054003300310031000000000000000000000000003B9BDFF38F" + "5EE8F9663F11A0F4C03A78A31204100100000063775A9A5FD97F0600000000" + ), + ) h.update(session_setup_response2) - exp_pae_5 = array.array('B', unhexlify( - "0DD13628CC3ED218EF9DF9772D436D0887AB9814BFAE63A80AA845F36909DB7928622DDDAD522D97" - "51640A459762C5A9D6BB084CBB3CE6BDADEF5D5BCE3C6C01")) + exp_pae_5 = array.array( + "B", + unhexlify( + "0DD13628CC3ED218EF9DF9772D436D0887AB9814BFAE63A80AA845F36909DB7928622DDDAD522D97" + "51640A459762C5A9D6BB084CBB3CE6BDADEF5D5BCE3C6C01" + ), + ) self.assertEqual(h.hash, exp_pae_5) - session_key = array.array('B', unhexlify("270E1BA896585EEB7AF3472D3B4C75A7")) - signing_key = digest.derive_key( - session_key, - b'SMBSigningKey', - h.hash)[:16] - exp_signing_key = array.array('B', unhexlify("73FE7A9A77BEF0BDE49C650D8CCB5F76")) + session_key = array.array("B", unhexlify("270E1BA896585EEB7AF3472D3B4C75A7")) + signing_key = digest.derive_key(session_key, b"SMBSigningKey", h.hash)[:16] + exp_signing_key = array.array( + "B", unhexlify("73FE7A9A77BEF0BDE49C650D8CCB5F76") + ) self.assertEqual(signing_key, exp_signing_key) def test_encryption_smb_300(self): - session_key = array.array('B', unhexlify("B4546771B515F766A86735532DD6C4F0")) - session_id = 0x8e40014000011 + session_key = array.array("B", unhexlify("B4546771B515F766A86735532DD6C4F0")) + session_id = 0x8E40014000011 conn = bogus_300_connection(session_key) exp_encryption_key = unhexlify("261B72350558F2E9DCF613070383EDBF") - self.assertEqual(conn.encryption_context().keys.encryption, - exp_encryption_key) + self.assertEqual(conn.encryption_context().keys.encryption, exp_encryption_key) # construct the request nb = netbios.Netbios() th = crypto.TransformHeader(nb) - th.nonce = array.array('B', unhexlify("66E69A111892584FB5ED524A744DA3EE")) + th.nonce = array.array("B", unhexlify("66E69A111892584FB5ED524A744DA3EE")) th.session_id = session_id th.encryption_context = conn.encryption_context() @@ -173,75 +212,95 @@ def test_encryption_smb_300(self): write_req.buffer = b"Smb3 encryption testing" write_req.write_channel_info_offset = 0x70 - exp_serialized = array.array('B', unhexlify( - "FE534D4240000100000000000900400008000000000000000400000000000000" - "FFFE0000010000001100001400E4080000000000000000000000000000000000" - "3100700017000000000000000000000015010000390000020100000039020000" - "00000000000000007000000000000000536D623320656E6372797074696F6E20" - "74657374696E67")) + exp_serialized = array.array( + "B", + unhexlify( + "FE534D4240000100000000000900400008000000000000000400000000000000" + "FFFE0000010000001100001400E4080000000000000000000000000000000000" + "3100700017000000000000000000000015010000390000020100000039020000" + "00000000000000007000000000000000536D623320656E6372797074696F6E20" + "74657374696E67" + ), + ) serialized = smb_packet.serialize() self.assertEqual(serialized, exp_serialized) transformed_serial = th.serialize() - exp_encrypted = array.array('B', unhexlify( - "25C8FEE16605A437832D1CD52DA9F4645333482A175FE5384563F45FCDAFAEF3" - "8BC62BA4D5C62897996625A44C29BE5658DE2E6117585779E7B59FFD971278D0" - "8580D7FA899E410E910EABF5AA1DB43050B33B49182637759AC15D84BFCDF5B6" - "B238993C0F4CF4D6012023F6C627297075D84B7803912D0A9639634453595EF3" - "E33FFE4E7AC2AB")) + exp_encrypted = array.array( + "B", + unhexlify( + "25C8FEE16605A437832D1CD52DA9F4645333482A175FE5384563F45FCDAFAEF3" + "8BC62BA4D5C62897996625A44C29BE5658DE2E6117585779E7B59FFD971278D0" + "8580D7FA899E410E910EABF5AA1DB43050B33B49182637759AC15D84BFCDF5B6" + "B238993C0F4CF4D6012023F6C627297075D84B7803912D0A9639634453595EF3" + "E33FFE4E7AC2AB" + ), + ) self.assertEqual(th.ciphertext, exp_encrypted) - exp_transformed = array.array('B', unhexlify( - "FD534D4281A286535415445DAE393921E44FA42E66E69A111892584FB5ED524A" - "744DA3EE87000000000001001100001400E4080025C8FEE16605A437832D1CD5" - "2DA9F4645333482A175FE5384563F45FCDAFAEF38BC62BA4D5C62897996625A4" - "4C29BE5658DE2E6117585779E7B59FFD971278D08580D7FA899E410E910EABF5" - "AA1DB43050B33B49182637759AC15D84BFCDF5B6B238993C0F4CF4D6012023F6" - "C627297075D84B7803912D0A9639634453595EF3E33FFE4E7AC2AB")) + exp_transformed = array.array( + "B", + unhexlify( + "FD534D4281A286535415445DAE393921E44FA42E66E69A111892584FB5ED524A" + "744DA3EE87000000000001001100001400E4080025C8FEE16605A437832D1CD5" + "2DA9F4645333482A175FE5384563F45FCDAFAEF38BC62BA4D5C62897996625A4" + "4C29BE5658DE2E6117585779E7B59FFD971278D08580D7FA899E410E910EABF5" + "AA1DB43050B33B49182637759AC15D84BFCDF5B6B238993C0F4CF4D6012023F6" + "C627297075D84B7803912D0A9639634453595EF3E33FFE4E7AC2AB" + ), + ) self.assertEqual(transformed_serial, exp_transformed) def test_decryption_smb_300(self): - session_key = array.array('B', unhexlify("B4546771B515F766A86735532DD6C4F0")) - session_id = 0x8e40014000011 + session_key = array.array("B", unhexlify("B4546771B515F766A86735532DD6C4F0")) + session_id = 0x8E40014000011 conn = bogus_300_connection(session_key) exp_decryption_key = unhexlify("8FE2B57EC34D2DB5B1A9727F526BBDB5") - self.assertEqual(conn.encryption_context().keys.decryption, - exp_decryption_key) - transform_message = array.array('B', unhexlify( - "FD534D42A6015530A18F6D9AFFE22AFAE8E66484860000000000000011000014" - "00E4080050000000000001001100001400E40800DBF46435C5F14169293CE079" - "E344479BF670227E49873F458672C3098DAC467DD5809F369D67409166515787" - "1483E01F7BECD02064EAC3E235F913668BBC2F097980D4B378F1993EFF6E60D1" - "77309E5B")) + self.assertEqual(conn.encryption_context().keys.decryption, exp_decryption_key) + transform_message = array.array( + "B", + unhexlify( + "FD534D42A6015530A18F6D9AFFE22AFAE8E66484860000000000000011000014" + "00E4080050000000000001001100001400E40800DBF46435C5F14169293CE079" + "E344479BF670227E49873F458672C3098DAC467DD5809F369D67409166515787" + "1483E01F7BECD02064EAC3E235F913668BBC2F097980D4B378F1993EFF6E60D1" + "77309E5B" + ), + ) nb = netbios.Netbios() th = crypto.TransformHeader(nb) th.encryption_context = conn.encryption_context() th.parse(transform_message) - exp_smb_message = array.array('B', unhexlify( - "FE534D4240000100000000000900210009000000000000000400000000000000" - "FFFE0000010000001100001400E4080000000000000000000000000000000000" - "11000000170000000000000000000000")) + exp_smb_message = array.array( + "B", + unhexlify( + "FE534D4240000100000000000900210009000000000000000400000000000000" + "FFFE0000010000001100001400E4080000000000000000000000000000000000" + "11000000170000000000000000000000" + ), + ) self.assertEqual(nb[0].buf, exp_smb_message) def test_encryption_smb_311(self): - session_key = array.array('B', unhexlify("419FDDF34C1E001909D362AE7FB6AF79")) - pre_auth_integrity_hash = array.array('B', unhexlify( - "B23F3CBFD69487D9832B79B1594A367CDD950909B774C3A4C412B4FCEA9EDDDBA7DB256BA2EA30E9" - "77F11F9B113247578E0E915C6D2A513B8F2FCA5707DC8770")) + session_key = array.array("B", unhexlify("419FDDF34C1E001909D362AE7FB6AF79")) + pre_auth_integrity_hash = array.array( + "B", + unhexlify( + "B23F3CBFD69487D9832B79B1594A367CDD950909B774C3A4C412B4FCEA9EDDDBA7DB256BA2EA30E9" + "77F11F9B113247578E0E915C6D2A513B8F2FCA5707DC8770" + ), + ) session_id = 0x100000000025 ciphers = [crypto.SMB2_AES_128_GCM] - conn = bogus_311_connection(session_key, - pre_auth_integrity_hash, - ciphers) + conn = bogus_311_connection(session_key, pre_auth_integrity_hash, ciphers) exp_encryption_key = unhexlify("A2F5E80E5D59103034F32E52F698E5EC") - self.assertEqual(conn.encryption_context().keys.encryption, - exp_encryption_key) + self.assertEqual(conn.encryption_context().keys.encryption, exp_encryption_key) # construct the request nb = netbios.Netbios() th = crypto.TransformHeader(nb) - th.nonce = array.array('B', unhexlify("C7D6822D269CAF48904C664C")) + th.nonce = array.array("B", unhexlify("C7D6822D269CAF48904C664C")) th.session_id = session_id th.encryption_context = conn.encryption_context() @@ -259,58 +318,80 @@ def test_encryption_smb_311(self): write_req.buffer = b"Smb3 encryption testing" write_req.write_channel_info_offset = 0x70 - exp_serialized = array.array('B', unhexlify( - "FE534D4240000100000000000900010008000000000000000500000000000000FFFE000001000000" - "25000000001000000000000000000000000000000000000031007000170000000000000000000000" - "0600000004000000010000000400000000000000000000007000000000000000536D623320656E63" - "72797074696F6E2074657374696E67")) + exp_serialized = array.array( + "B", + unhexlify( + "FE534D4240000100000000000900010008000000000000000500000000000000FFFE000001000000" + "25000000001000000000000000000000000000000000000031007000170000000000000000000000" + "0600000004000000010000000400000000000000000000007000000000000000536D623320656E63" + "72797074696F6E2074657374696E67" + ), + ) serialized = smb_packet.serialize() self.assertEqual(serialized, exp_serialized) transformed_serial = th.serialize() - exp_encrypted = array.array('B', unhexlify( - "6ECDD2A7AFC7B47763057A041B8FD4DAFFE990B70C9E09D36C084E02D14EF247F8BDE38ACF6256F8" - "B1D3B56F77FBDEB312FEA5E92CBCC1ED8FB2EBBFAA75E49A4A394BB44576545567C24D4C014D47C9" - "FBDFDAFD2C4F9B72F8D256452620A299F48E29E53D6B61D1C13A19E91AF013F00D17E3ABC2FC3D36" - "C8C1B6B93973253852DBD442E46EE8")) + exp_encrypted = array.array( + "B", + unhexlify( + "6ECDD2A7AFC7B47763057A041B8FD4DAFFE990B70C9E09D36C084E02D14EF247F8BDE38ACF6256F8" + "B1D3B56F77FBDEB312FEA5E92CBCC1ED8FB2EBBFAA75E49A4A394BB44576545567C24D4C014D47C9" + "FBDFDAFD2C4F9B72F8D256452620A299F48E29E53D6B61D1C13A19E91AF013F00D17E3ABC2FC3D36" + "C8C1B6B93973253852DBD442E46EE8" + ), + ) self.assertEqual(th.ciphertext, exp_encrypted) - exp_transformed = array.array('B', unhexlify( - "FD534D42BD73D97D2BC9001BCAFAC0FDFF5FEEBCC7D6822D269CAF48904C664C0000000087000000" - "0000010025000000001000006ECDD2A7AFC7B47763057A041B8FD4DAFFE990B70C9E09D36C084E02" - "D14EF247F8BDE38ACF6256F8B1D3B56F77FBDEB312FEA5E92CBCC1ED8FB2EBBFAA75E49A4A394BB4" - "4576545567C24D4C014D47C9FBDFDAFD2C4F9B72F8D256452620A299F48E29E53D6B61D1C13A19E9" - "1AF013F00D17E3ABC2FC3D36C8C1B6B93973253852DBD442E46EE8")) + exp_transformed = array.array( + "B", + unhexlify( + "FD534D42BD73D97D2BC9001BCAFAC0FDFF5FEEBCC7D6822D269CAF48904C664C0000000087000000" + "0000010025000000001000006ECDD2A7AFC7B47763057A041B8FD4DAFFE990B70C9E09D36C084E02" + "D14EF247F8BDE38ACF6256F8B1D3B56F77FBDEB312FEA5E92CBCC1ED8FB2EBBFAA75E49A4A394BB4" + "4576545567C24D4C014D47C9FBDFDAFD2C4F9B72F8D256452620A299F48E29E53D6B61D1C13A19E9" + "1AF013F00D17E3ABC2FC3D36C8C1B6B93973253852DBD442E46EE8" + ), + ) self.assertEqual(transformed_serial, exp_transformed) def test_decryption_smb_311(self): - session_key = array.array('B', unhexlify("419FDDF34C1E001909D362AE7FB6AF79")) - pre_auth_integrity_hash = array.array('B', unhexlify( - "B23F3CBFD69487D9832B79B1594A367CDD950909B774C3A4C412B4FCEA9EDDDBA7DB256BA2EA30E9" - "77F11F9B113247578E0E915C6D2A513B8F2FCA5707DC8770")) + session_key = array.array("B", unhexlify("419FDDF34C1E001909D362AE7FB6AF79")) + pre_auth_integrity_hash = array.array( + "B", + unhexlify( + "B23F3CBFD69487D9832B79B1594A367CDD950909B774C3A4C412B4FCEA9EDDDBA7DB256BA2EA30E9" + "77F11F9B113247578E0E915C6D2A513B8F2FCA5707DC8770" + ), + ) session_id = 0x100000000025 ciphers = [crypto.SMB2_AES_128_GCM] - conn = bogus_311_connection(session_key, - pre_auth_integrity_hash, - ciphers) + conn = bogus_311_connection(session_key, pre_auth_integrity_hash, ciphers) exp_decryption_key = unhexlify("748C50868C90F302962A5C35F5F9A8BF") - self.assertEqual(conn.encryption_context().keys.decryption, - exp_decryption_key) - - transform_message = array.array('B', unhexlify( - "FD534D42ACBE1CB7ED343ADF1725EF144D90D4B0E06831DD2E8EB7B4000000000000000050000000" - "00000100250000000010000026BBBF949983A6C1C796559D0F2C510CB651D1F7B6AC8DED32A2A0B8" - "F2D793A815C6F6B848D69767A215841A42D400AE6DDB5F0B44173A014973321FDD7950DA6179159B" - "82E03C9E18A050FF0EA1C967")) + self.assertEqual(conn.encryption_context().keys.decryption, exp_decryption_key) + + transform_message = array.array( + "B", + unhexlify( + "FD534D42ACBE1CB7ED343ADF1725EF144D90D4B0E06831DD2E8EB7B4000000000000000050000000" + "00000100250000000010000026BBBF949983A6C1C796559D0F2C510CB651D1F7B6AC8DED32A2A0B8" + "F2D793A815C6F6B848D69767A215841A42D400AE6DDB5F0B44173A014973321FDD7950DA6179159B" + "82E03C9E18A050FF0EA1C967" + ), + ) nb = netbios.Netbios() th = crypto.TransformHeader(nb) th.encryption_context = conn.encryption_context() th.parse(transform_message) - exp_smb_message = array.array('B', unhexlify( - "FE534D4240000100000000000900010001000000000000000500000000000000FFFE000001000000" - "25000000001000000000000000000000000000000000000011000000170000000000000000000000")) + exp_smb_message = array.array( + "B", + unhexlify( + "FE534D4240000100000000000900010001000000000000000500000000000000FFFE000001000000" + "25000000001000000000000000000000000000000000000011000000170000000000000000000000" + ), + ) self.assertEqual(nb[0].buf, exp_smb_message) + if __name__ == "__main__": unittest.main()