diff --git a/CHANGELOG b/CHANGELOG
index e52126b..aed051f 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,53 @@
+pysmb-1.1.26, 5 Jan 2019
+========================
+- Prevents OperationError from being raised when listPath() operation does not
+ return any matching file results.
+- SMBConnection is now a context manager #122.
+
+pysmb-1.1.25, 28 July 2018
+========================
+- Fix buggy support for search parameter in listPath() method. Add
+ SMB_FILE_ATTRIBUTE_INCL_NORMAL bit constant to include 'normal' files with
+ other file types in the returned result. From now on, pysmb defines a 'normal' file
+ as a file entry that is not read-only, not hidden, not system, not archive and
+ not a directory; it ignores other attributes like compression, indexed, sparse,
+ temporary and encryption. listPath() method will now include 'normal' files
+ using the default search parameter.
+- Add isNormal property to SharedFile class to support test if the file is a
+ 'normal' file (according to pysmb definition of 'normal' file).
+
+pysmb-1.1.24, 19 July 2018
+========================
+- Improve listPath implementation for SMB1
+- Support for STATUS_PENDING responses across all SMB2 operations.
+
+pysmb-1.1.23, 5 May 2018
+========================
+- Fix bug in listShares() method which fails when the remote server has many shares.
+- Improve echo() method to test and fail if the provided data to echo is not a bytes object.
+- Fix bug in listPath() method where the path to query is not properly terminated.
+
+pysmb-1.1.22, 17 Sep 2017
+========================
+- Fix bug in getAttributes() method which should return only the filename
+ instead of the entire path for the filename property for the return result.
+
+pysmb-1.1.21, 9 Sep 2017
+========================
+- Fix bug where timestamp values for SMB1 getAttributes() response are not
+ converted properly from FILETIME to epoch time values.
+
+pysmb-1.1.20, 13 Aug 2017
+=========================
+- Add getSecurity() method to support security descriptors query via SMB2
+- Improve retrieveFile() and retrieveFileFromOffset() methods to allow file
+ retrievals over SMB2 even when the file is being locked on the server.
+- Silently discards NMB SESSION_KEEPALIVE packets instead of raising warnings.
+- SMB sessionID will be sent in ECHO requests to conform to SMB2 specs.
+- Fix type errors for MD4 functions in python3.
+
pysmb-1.1.19, 13 Nov 2016
-========================
+=========================
- Ignore STATUS_PENDING during delete and file store operations
pysmb-1.1.18, 9 Apr 2016
diff --git a/LICENSE b/LICENSE
index d183506..7eaccfa 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,5 +1,5 @@
-Copyright (C) 2001-2015 Michael Teo
+Copyright (C) 2001-2019 Michael Teo
This software is provided 'as-is', without any express or implied warranty.
In no event will the author be held liable for any damages arising from the
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..b22628d
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,11 @@
+include LICENSE
+include CHANGELOG
+recursive-include python2 *
+recursive-exclude python2 *.pyc
+recursive-exclude python2 *~
+recursive-include python3 *
+recursive-exclude python3 *.pyc
+recursive-exclude python3 *~
+recursive-include sphinx *
+recursive-include docs *
+recursive-exclude docs *.zip
diff --git a/PKG-INFO b/PKG-INFO
index ba886a1..9f8779d 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: pysmb
-Version: 1.1.19
+Version: 1.1.26
Summary: pysmb is an experimental SMB/CIFS library written in Python to support file sharing between Windows and Linux machines
Home-page: https://miketeo.net/projects/pysmb
Author: Michael Teo
@@ -16,9 +16,6 @@
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX
Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 2.4
-Classifier: Programming Language :: Python :: 2.5
-Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Communications :: File Sharing
diff --git a/debian/changelog b/debian/changelog
index 75cead5..e5ec9f2 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+pysmb (1.1.26-0kali1) UNRELEASED; urgency=low
+
+ * New upstream release.
+
+ -- Kali Janitor Wed, 21 Jul 2021 16:36:57 -0000
+
pysmb (1.1.19-0kali2) kali-dev; urgency=medium
[ Raphaël Hertzog ]
diff --git a/docs/doctrees/api/nmb_NetBIOS.doctree b/docs/doctrees/api/nmb_NetBIOS.doctree
index 9b279b3..970596a 100644
Binary files a/docs/doctrees/api/nmb_NetBIOS.doctree and b/docs/doctrees/api/nmb_NetBIOS.doctree differ
diff --git a/docs/doctrees/api/smb_SMBConnection.doctree b/docs/doctrees/api/smb_SMBConnection.doctree
index 383d6bf..063d562 100644
Binary files a/docs/doctrees/api/smb_SMBConnection.doctree and b/docs/doctrees/api/smb_SMBConnection.doctree differ
diff --git a/docs/doctrees/api/smb_SMBHandler.doctree b/docs/doctrees/api/smb_SMBHandler.doctree
index 2fb06a4..5b414de 100644
Binary files a/docs/doctrees/api/smb_SMBHandler.doctree and b/docs/doctrees/api/smb_SMBHandler.doctree differ
diff --git a/docs/doctrees/api/smb_SMBProtocolFactory.doctree b/docs/doctrees/api/smb_SMBProtocolFactory.doctree
index d424daa..1e5933d 100644
Binary files a/docs/doctrees/api/smb_SMBProtocolFactory.doctree and b/docs/doctrees/api/smb_SMBProtocolFactory.doctree differ
diff --git a/docs/doctrees/api/smb_SharedDevice.doctree b/docs/doctrees/api/smb_SharedDevice.doctree
index eb0fa96..d2b2c34 100644
Binary files a/docs/doctrees/api/smb_SharedDevice.doctree and b/docs/doctrees/api/smb_SharedDevice.doctree differ
diff --git a/docs/doctrees/api/smb_SharedFile.doctree b/docs/doctrees/api/smb_SharedFile.doctree
index faa32e5..d4d3b8a 100644
Binary files a/docs/doctrees/api/smb_SharedFile.doctree and b/docs/doctrees/api/smb_SharedFile.doctree differ
diff --git a/docs/doctrees/api/smb_exceptions.doctree b/docs/doctrees/api/smb_exceptions.doctree
index aec1229..31eff13 100644
Binary files a/docs/doctrees/api/smb_exceptions.doctree and b/docs/doctrees/api/smb_exceptions.doctree differ
diff --git a/docs/doctrees/api/smb_security_descriptors.doctree b/docs/doctrees/api/smb_security_descriptors.doctree
new file mode 100644
index 0000000..734f4f6
Binary files /dev/null and b/docs/doctrees/api/smb_security_descriptors.doctree differ
diff --git a/docs/doctrees/environment.pickle b/docs/doctrees/environment.pickle
index 987c4bf..843712b 100644
Binary files a/docs/doctrees/environment.pickle and b/docs/doctrees/environment.pickle differ
diff --git a/docs/doctrees/extending.doctree b/docs/doctrees/extending.doctree
index dc0b3fc..4031973 100644
Binary files a/docs/doctrees/extending.doctree and b/docs/doctrees/extending.doctree differ
diff --git a/docs/doctrees/index.doctree b/docs/doctrees/index.doctree
index 807f40d..abeb85f 100644
Binary files a/docs/doctrees/index.doctree and b/docs/doctrees/index.doctree differ
diff --git a/docs/html/.buildinfo b/docs/html/.buildinfo
index bf80f8a..69caef7 100644
--- a/docs/html/.buildinfo
+++ b/docs/html/.buildinfo
@@ -1,4 +1,4 @@
# Sphinx build info version 1
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
-config: 8ec856095809db2990831edf01ebc5a4
+config: 24e4dd110b51998b070280bf87a2d415
tags: 645f666f9bcd5a90fca523b33c5a78b7
diff --git a/docs/html/_modules/index.html b/docs/html/_modules/index.html
index c518f1e..972635b 100644
--- a/docs/html/_modules/index.html
+++ b/docs/html/_modules/index.html
@@ -6,7 +6,7 @@
- Overview: module code — pysmb 1.1.18 documentation
+ Overview: module code — pysmb 1.1.25 documentation
@@ -14,7 +14,7 @@
-
+
[docs]classSMBConnection(SMB):
-
- log=logging.getLogger('SMB.SMBConnection')
-
- #: SMB messages will never be signed regardless of remote server's configurations; access errors will occur if the remote server requires signing.
- SIGN_NEVER=0
- #: SMB messages will be signed when remote server supports signing but not requires signing.
- SIGN_WHEN_SUPPORTED=1
- #: SMB messages will only be signed when remote server requires signing.
- SIGN_WHEN_REQUIRED=2
-
-
[docs]def__init__(self,username,password,my_name,remote_name,domain='',use_ntlm_v2=True,sign_options=SIGN_WHEN_REQUIRED,is_direct_tcp=False):
- """
- Create a new SMBConnection instance.
-
- *username* and *password* are the user credentials required to authenticate the underlying SMB connection with the remote server.
- File operations can only be proceeded after the connection has been authenticated successfully.
-
- Note that you need to call *connect* method to actually establish the SMB connection to the remote server and perform authentication.
-
- The default TCP port for most SMB/CIFS servers using NetBIOS over TCP/IP is 139.
- Some newer server installations might also support Direct hosting of SMB over TCP/IP; for these servers, the default TCP port is 445.
-
- :param string my_name: The local NetBIOS machine name that will identify where this connection is originating from.
- You can freely choose a name as long as it contains a maximum of 15 alphanumeric characters and does not contain spaces and any of ``\/:*?";|+``
- :param string remote_name: The NetBIOS machine name of the remote server.
- On windows, you can find out the machine name by right-clicking on the "My Computer" and selecting "Properties".
- This parameter must be the same as what has been configured on the remote server, or else the connection will be rejected.
- :param string domain: The network domain. On windows, it is known as the workgroup. Usually, it is safe to leave this parameter as an empty string.
- :param boolean use_ntlm_v2: Indicates whether pysmb should be NTLMv1 or NTLMv2 authentication algorithm for authentication.
- The choice of NTLMv1 and NTLMv2 is configured on the remote server, and there is no mechanism to auto-detect which algorithm has been configured.
- Hence, we can only "guess" or try both algorithms.
- On Sambda, Windows Vista and Windows 7, NTLMv2 is enabled by default. On Windows XP, we can use NTLMv1 before NTLMv2.
- :param int sign_options: Determines whether SMB messages will be signed. Default is *SIGN_WHEN_REQUIRED*.
- If *SIGN_WHEN_REQUIRED* (value=2), SMB messages will only be signed when remote server requires signing.
- If *SIGN_WHEN_SUPPORTED* (value=1), SMB messages will be signed when remote server supports signing but not requires signing.
- If *SIGN_NEVER* (value=0), SMB messages will never be signed regardless of remote server's configurations; access errors will occur if the remote server requires signing.
- :param boolean is_direct_tcp: Controls whether the NetBIOS over TCP/IP (is_direct_tcp=False) or the newer Direct hosting of SMB over TCP/IP (is_direct_tcp=True) will be used for the communication.
- The default parameter is False which will use NetBIOS over TCP/IP for wider compatibility (TCP port: 139).
- """
- SMB.__init__(self,username,password,my_name,remote_name,domain,use_ntlm_v2,sign_options,is_direct_tcp)
- self.sock=None
- self.auth_result=None
- self.is_busy=False
- self.is_direct_tcp=is_direct_tcp
[docs]defconnect(self,ip,port=139,sock_family=socket.AF_INET,timeout=60):
- """
- Establish the SMB connection to the remote SMB/CIFS server.
-
- You must call this method before attempting any of the file operations with the remote server.
- This method will block until the SMB connection has attempted at least one authentication.
-
- :return: A boolean value indicating the result of the authentication atttempt: True if authentication is successful; False, if otherwise.
- """
- ifself.sock:
- self.sock.close()
-
- self.auth_result=None
- self.sock=socket.socket(sock_family)
- self.sock.settimeout(timeout)
- self.sock.connect((ip,port))
-
- self.is_busy=True
- try:
- ifnotself.is_direct_tcp:
- self.requestNMBSession()
- else:
- self.onNMBSessionOK()
- whileself.auth_resultisNone:
- self._pollForNetBIOSPacket(timeout)
- finally:
- self.is_busy=False
-
- returnself.auth_result
-
-
[docs]defclose(self):
- """
- Terminate the SMB connection (if it has been started) and release any sources held by the underlying socket.
- """
- ifself.sock:
- self.sock.close()
- self.sock=None
-
-
[docs]deflistShares(self,timeout=30):
- """
- Retrieve a list of shared resources on remote server.
-
- :return: A list of :doc:`smb.base.SharedDevice<smb_SharedDevice>` instances describing the shared resource
- """
- ifnotself.sock:
- raiseNotConnectedError('Not connected to server')
-
- results=[]
-
- defcb(entries):
- self.is_busy=False
- results.extend(entries)
-
- defeb(failure):
- self.is_busy=False
- raisefailure
-
- self.is_busy=True
- try:
- self._listShares(cb,eb,timeout)
- whileself.is_busy:
- self._pollForNetBIOSPacket(timeout)
- finally:
- self.is_busy=False
-
- returnresults
-
-
[docs]deflistPath(self,service_name,path,
- search=SMB_FILE_ATTRIBUTE_READONLY|SMB_FILE_ATTRIBUTE_HIDDEN|SMB_FILE_ATTRIBUTE_SYSTEM|SMB_FILE_ATTRIBUTE_DIRECTORY|SMB_FILE_ATTRIBUTE_ARCHIVE,
- pattern='*',timeout=30):
- """
- Retrieve a directory listing of files/folders at *path*
-
- :param string/unicode service_name: the name of the shared folder for the *path*
- :param string/unicode path: path relative to the *service_name* where we are interested to learn about its files/sub-folders.
- :param integer search: integer value made up from a bitwise-OR of *SMB_FILE_ATTRIBUTE_xxx* bits (see smb_constants.py).
- The default *search* value will query for all read-only, hidden, system, archive files and directories.
- :param string/unicode pattern: the filter to apply to the results before returning to the client.
- :return: A list of :doc:`smb.base.SharedFile<smb_SharedFile>` instances.
- """
- ifnotself.sock:
- raiseNotConnectedError('Not connected to server')
-
- results=[]
-
- defcb(entries):
- self.is_busy=False
- results.extend(entries)
-
- defeb(failure):
- self.is_busy=False
- raisefailure
-
- self.is_busy=True
- try:
- self._listPath(service_name,path,cb,eb,search=search,pattern=pattern,timeout=timeout)
- whileself.is_busy:
- self._pollForNetBIOSPacket(timeout)
- finally:
- self.is_busy=False
-
- returnresults
-
-
[docs]deflistSnapshots(self,service_name,path,timeout=30):
- """
- Retrieve a list of available snapshots (shadow copies) for *path*.
-
- Note that snapshot features are only supported on Windows Vista Business, Enterprise and Ultimate, and on all Windows 7 editions.
-
- :param string/unicode service_name: the name of the shared folder for the *path*
- :param string/unicode path: path relative to the *service_name* where we are interested in the list of available snapshots
- :return: A list of python *datetime.DateTime* instances in GMT/UTC time zone
- """
- ifnotself.sock:
- raiseNotConnectedError('Not connected to server')
-
- results=[]
-
- defcb(entries):
- self.is_busy=False
- results.extend(entries)
-
- defeb(failure):
- self.is_busy=False
- raisefailure
-
- self.is_busy=True
- try:
- self._listSnapshots(service_name,path,cb,eb,timeout=timeout)
- whileself.is_busy:
- self._pollForNetBIOSPacket(timeout)
- finally:
- self.is_busy=False
-
- returnresults
-
-
[docs]defgetAttributes(self,service_name,path,timeout=30):
- """
- Retrieve information about the file at *path* on the *service_name*.
-
- :param string/unicode service_name: the name of the shared folder for the *path*
- :param string/unicode path: Path of the file on the remote server. If the file cannot be opened for reading, an :doc:`OperationFailure<smb_exceptions>` will be raised.
- :return: A :doc:`smb.base.SharedFile<smb_SharedFile>` instance containing the attributes of the file.
- """
- ifnotself.sock:
- raiseNotConnectedError('Not connected to server')
-
- results=[]
-
- defcb(info):
- self.is_busy=False
- results.append(info)
-
- defeb(failure):
- self.is_busy=False
- raisefailure
-
- self.is_busy=True
- try:
- self._getAttributes(service_name,path,cb,eb,timeout)
- whileself.is_busy:
- self._pollForNetBIOSPacket(timeout)
- finally:
- self.is_busy=False
-
- returnresults[0]
-
-
[docs]defretrieveFile(self,service_name,path,file_obj,timeout=30):
- """
- Retrieve the contents of the file at *path* on the *service_name* and write these contents to the provided *file_obj*.
-
- Use *retrieveFileFromOffset()* method if you wish to specify the offset to read from the remote *path* and/or the number of bytes to write to the *file_obj*.
-
- :param string/unicode service_name: the name of the shared folder for the *path*
- :param string/unicode path: Path of the file on the remote server. If the file cannot be opened for reading, an :doc:`OperationFailure<smb_exceptions>` will be raised.
- :param file_obj: A file-like object that has a *write* method. Data will be written continuously to *file_obj* until EOF is received from the remote service.
- :return: A 2-element tuple of ( file attributes of the file on server, number of bytes written to *file_obj* ).
- The file attributes is an integer value made up from a bitwise-OR of *SMB_FILE_ATTRIBUTE_xxx* bits (see smb_constants.py)
- """
- returnself.retrieveFileFromOffset(service_name,path,file_obj,0L,-1L,timeout)
-
-
[docs]defretrieveFileFromOffset(self,service_name,path,file_obj,offset=0L,max_length=-1L,timeout=30):
- """
- Retrieve the contents of the file at *path* on the *service_name* and write these contents to the provided *file_obj*.
-
- :param string/unicode service_name: the name of the shared folder for the *path*
- :param string/unicode path: Path of the file on the remote server. If the file cannot be opened for reading, an :doc:`OperationFailure<smb_exceptions>` will be raised.
- :param file_obj: A file-like object that has a *write* method. Data will be written continuously to *file_obj* up to *max_length* number of bytes.
- :param integer/long offset: the offset in the remote *path* where the first byte will be read and written to *file_obj*. Must be either zero or a positive integer/long value.
- :param integer/long max_length: maximum number of bytes to read from the remote *path* and write to the *file_obj*. Specify a negative value to read from *offset* to the EOF.
- If zero, the method returns immediately after the file is opened successfully for reading.
- :return: A 2-element tuple of ( file attributes of the file on server, number of bytes written to *file_obj* ).
- The file attributes is an integer value made up from a bitwise-OR of *SMB_FILE_ATTRIBUTE_xxx* bits (see smb_constants.py)
- """
- ifnotself.sock:
- raiseNotConnectedError('Not connected to server')
-
- results=[]
-
- defcb(r):
- self.is_busy=False
- results.append(r[1:])
-
- defeb(failure):
- self.is_busy=False
- raisefailure
-
- self.is_busy=True
- try:
- self._retrieveFileFromOffset(service_name,path,file_obj,cb,eb,offset,max_length,timeout=timeout)
- whileself.is_busy:
- self._pollForNetBIOSPacket(timeout)
- finally:
- self.is_busy=False
-
- returnresults[0]
-
-
[docs]defstoreFile(self,service_name,path,file_obj,timeout=30):
- """
- Store the contents of the *file_obj* at *path* on the *service_name*.
- If the file already exists on the remote server, it will be truncated and overwritten.
-
- :param string/unicode service_name: the name of the shared folder for the *path*
- :param string/unicode path: Path of the file on the remote server. If the file at *path* does not exist, it will be created. Otherwise, it will be overwritten.
- If the *path* refers to a folder or the file cannot be opened for writing, an :doc:`OperationFailure<smb_exceptions>` will be raised.
- :param file_obj: A file-like object that has a *read* method. Data will read continuously from *file_obj* until EOF.
- :return: Number of bytes uploaded
- """
- returnself.storeFileFromOffset(service_name,path,file_obj,0L,True,timeout)
-
-
[docs]defstoreFileFromOffset(self,service_name,path,file_obj,offset=0L,truncate=False,timeout=30):
- """
- Store the contents of the *file_obj* at *path* on the *service_name*.
-
- :param string/unicode service_name: the name of the shared folder for the *path*
- :param string/unicode path: Path of the file on the remote server. If the file at *path* does not exist, it will be created.
- If the *path* refers to a folder or the file cannot be opened for writing, an :doc:`OperationFailure<smb_exceptions>` will be raised.
- :param file_obj: A file-like object that has a *read* method. Data will read continuously from *file_obj* until EOF.
- :param offset: Long integer value which specifies the offset in the remote server to start writing. First byte of the file is 0.
- :param truncate: Boolean value. If True and the file exists on the remote server, it will be truncated first before writing. Default is False.
- :return: the file position where the next byte will be written.
- """
- ifnotself.sock:
- raiseNotConnectedError('Not connected to server')
-
- results=[]
-
- defcb(r):
- self.is_busy=False
- results.append(r[1])
-
- defeb(failure):
- self.is_busy=False
- raisefailure
-
- self.is_busy=True
- try:
- self._storeFileFromOffset(service_name,path,file_obj,cb,eb,offset,truncate=truncate,timeout=timeout)
- whileself.is_busy:
- self._pollForNetBIOSPacket(timeout)
- finally:
- self.is_busy=False
-
- returnresults[0]
-
-
[docs]defdeleteFiles(self,service_name,path_file_pattern,timeout=30):
- """
- Delete one or more regular files. It supports the use of wildcards in file names, allowing for deletion of multiple files in a single request.
-
- :param string/unicode service_name: Contains the name of the shared folder.
- :param string/unicode path_file_pattern: The pathname of the file(s) to be deleted, relative to the service_name.
- Wildcards may be used in th filename component of the path.
- If your path/filename contains non-English characters, you must pass in an unicode string.
- :return: None
- """
- ifnotself.sock:
- raiseNotConnectedError('Not connected to server')
-
- defcb(r):
- self.is_busy=False
-
- defeb(failure):
- self.is_busy=False
- raisefailure
-
- self.is_busy=True
- try:
- self._deleteFiles(service_name,path_file_pattern,cb,eb,timeout=timeout)
- whileself.is_busy:
- self._pollForNetBIOSPacket(timeout)
- finally:
- self.is_busy=False
-
-
[docs]defresetFileAttributes(self,service_name,path_file_pattern,timeout=30):
- """
- Reset file attributes of one or more regular files or folders.
- It supports the use of wildcards in file names, allowing for unlocking of multiple files/folders in a single request.
- This function is very helpful when deleting files/folders that are read-only.
- Note: this function is currently only implemented for SMB2! Technically, it sets the FILE_ATTRIBUTE_NORMAL flag, therefore clearing all other flags. (See https://msdn.microsoft.com/en-us/library/cc232110.aspx for further information)
-
- :param string/unicode service_name: Contains the name of the shared folder.
- :param string/unicode path_file_pattern: The pathname of the file(s) to be deleted, relative to the service_name.
- Wildcards may be used in the filename component of the path.
- If your path/filename contains non-English characters, you must pass in an unicode string.
- :return: None
- """
- ifnotself.sock:
- raiseNotConnectedError('Not connected to server')
-
- defcb(r):
- self.is_busy=False
-
- defeb(failure):
- self.is_busy=False
- raisefailure
-
- self.is_busy=True
- try:
- self._resetFileAttributes(service_name,path_file_pattern,cb,eb,timeout=timeout)
- whileself.is_busy:
- self._pollForNetBIOSPacket(timeout)
- finally:
- self.is_busy=False
-
-
[docs]defcreateDirectory(self,service_name,path,timeout=30):
- """
- Creates a new directory *path* on the *service_name*.
-
- :param string/unicode service_name: Contains the name of the shared folder.
- :param string/unicode path: The path of the new folder (relative to) the shared folder.
- If the path contains non-English characters, an unicode string must be used to pass in the path.
- :return: None
- """
- ifnotself.sock:
- raiseNotConnectedError('Not connected to server')
-
- defcb(r):
- self.is_busy=False
-
- defeb(failure):
- self.is_busy=False
- raisefailure
-
- self.is_busy=True
- try:
- self._createDirectory(service_name,path,cb,eb,timeout=timeout)
- whileself.is_busy:
- self._pollForNetBIOSPacket(timeout)
- finally:
- self.is_busy=False
-
-
[docs]defdeleteDirectory(self,service_name,path,timeout=30):
- """
- Delete the empty folder at *path* on *service_name*
-
- :param string/unicode service_name: Contains the name of the shared folder.
- :param string/unicode path: The path of the to-be-deleted folder (relative to) the shared folder.
- If the path contains non-English characters, an unicode string must be used to pass in the path.
- :return: None
- """
- ifnotself.sock:
- raiseNotConnectedError('Not connected to server')
-
- defcb(r):
- self.is_busy=False
-
- defeb(failure):
- self.is_busy=False
- raisefailure
-
- self.is_busy=True
- try:
- self._deleteDirectory(service_name,path,cb,eb,timeout=timeout)
- whileself.is_busy:
- self._pollForNetBIOSPacket(timeout)
- finally:
- self.is_busy=False
-
-
[docs]defrename(self,service_name,old_path,new_path,timeout=30):
- """
- Rename a file or folder at *old_path* to *new_path* shared at *service_name*. Note that this method cannot be used to rename file/folder across different shared folders
-
- *old_path* and *new_path* are string/unicode referring to the old and new path of the renamed resources (relative to) the shared folder.
- If the path contains non-English characters, an unicode string must be used to pass in the path.
-
- :param string/unicode service_name: Contains the name of the shared folder.
- :return: None
- """
- ifnotself.sock:
- raiseNotConnectedError('Not connected to server')
-
- defcb(r):
- self.is_busy=False
-
- defeb(failure):
- self.is_busy=False
- raisefailure
-
- self.is_busy=True
- try:
- self._rename(service_name,old_path,new_path,cb,eb)
- whileself.is_busy:
- self._pollForNetBIOSPacket(timeout)
- finally:
- self.is_busy=False
-
-
[docs]defecho(self,data,timeout=10):
- """
- Send an echo command containing *data* to the remote SMB/CIFS server. The remote SMB/CIFS will reply with the same *data*.
-
- :param string data: Data to send to the remote server.
- :return: The *data* parameter
- """
- ifnotself.sock:
- raiseNotConnectedError('Not connected to server')
-
- results=[]
-
- defcb(r):
- self.is_busy=False
- results.append(r)
-
- defeb(failure):
- self.is_busy=False
- raisefailure
-
- self.is_busy=True
- try:
- self._echo(data,cb,eb)
- whileself.is_busy:
- self._pollForNetBIOSPacket(timeout)
- finally:
- self.is_busy=False
-
- returnresults[0]
[docs]classSMBProtocolFactory(ClientFactory):
-
- protocol=SMBProtocol
- log=logging.getLogger('SMB.SMBFactory')
-
- #: SMB messages will never be signed regardless of remote server's configurations; access errors will occur if the remote server requires signing.
- SIGN_NEVER=0
- #: SMB messages will be signed when remote server supports signing but not requires signing.
- SIGN_WHEN_SUPPORTED=1
- #: SMB messages will only be signed when remote server requires signing.
- SIGN_WHEN_REQUIRED=2
-
-
[docs]def__init__(self,username,password,my_name,remote_name,domain='',use_ntlm_v2=True,sign_options=SIGN_WHEN_REQUIRED,is_direct_tcp=False):
- """
- Create a new SMBProtocolFactory instance. You will pass this instance to *reactor.connectTCP()* which will then instantiate the TCP connection to the remote SMB/CIFS server.
- Note that the default TCP port for most SMB/CIFS servers using NetBIOS over TCP/IP is 139.
- Some newer server installations might also support Direct hosting of SMB over TCP/IP; for these servers, the default TCP port is 445.
-
- *username* and *password* are the user credentials required to authenticate the underlying SMB connection with the remote server.
- File operations can only be proceeded after the connection has been authenticated successfully.
-
- :param string my_name: The local NetBIOS machine name that will identify where this connection is originating from.
- You can freely choose a name as long as it contains a maximum of 15 alphanumeric characters and does not contain spaces and any of ``\/:*?";|+``.
- :param string remote_name: The NetBIOS machine name of the remote server.
- On windows, you can find out the machine name by right-clicking on the "My Computer" and selecting "Properties".
- This parameter must be the same as what has been configured on the remote server, or else the connection will be rejected.
- :param string domain: The network domain. On windows, it is known as the workgroup. Usually, it is safe to leave this parameter as an empty string.
- :param boolean use_ntlm_v2: Indicates whether pysmb should be NTLMv1 or NTLMv2 authentication algorithm for authentication.
- The choice of NTLMv1 and NTLMv2 is configured on the remote server, and there is no mechanism to auto-detect which algorithm has been configured.
- Hence, we can only "guess" or try both algorithms.
- On Sambda, Windows Vista and Windows 7, NTLMv2 is enabled by default. On Windows XP, we can use NTLMv1 before NTLMv2.
- :param int sign_options: Determines whether SMB messages will be signed. Default is *SIGN_WHEN_REQUIRED*.
- If *SIGN_WHEN_REQUIRED* (value=2), SMB messages will only be signed when remote server requires signing.
- If *SIGN_WHEN_SUPPORTED* (value=1), SMB messages will be signed when remote server supports signing but not requires signing.
- If *SIGN_NEVER* (value=0), SMB messages will never be signed regardless of remote server's configurations; access errors will occur if the remote server requires signing.
- :param boolean is_direct_tcp: Controls whether the NetBIOS over TCP/IP (is_direct_tcp=False) or the newer Direct hosting of SMB over TCP/IP (is_direct_tcp=True) will be used for the communication.
- The default parameter is False which will use NetBIOS over TCP/IP for wider compatibility (TCP port: 139).
- """
- self.username=username
- self.password=password
- self.my_name=my_name
- self.remote_name=remote_name
- self.domain=domain
- self.use_ntlm_v2=use_ntlm_v2
- self.sign_options=sign_options
- self.is_direct_tcp=is_direct_tcp
- self.instance=None#: The single SMBProtocol instance for each SMBProtocolFactory instance. Usually, you should not need to touch this attribute directly.
-
- #
- # Public Property
- #
-
- @property
- defisReady(self):
- """A convenient property to return True if the underlying SMB connection has connected to remote server, has successfully authenticated itself and is ready for file operations."""
- returnbool(self.instanceandself.instance.has_authenticated)
-
- @property
- defisUsingSMB2(self):
- """A convenient property to return True if the underlying SMB connection is using SMB2 protocol."""
- returnself.instanceandself.instance.is_using_smb2
-
- #
- # Public Methods for Callbacks
- #
-
-
[docs]defonAuthOK(self):
- """
- Override this method in your *SMBProtocolFactory* subclass to add in post-authentication handling.
- This method will be called when the server has replied that the SMB connection has been successfully authenticated.
- File operations can proceed when this method has been called.
- """
- pass
-
-
[docs]defonAuthFailed(self):
- """
- Override this method in your *SMBProtocolFactory* subclass to add in post-authentication handling.
- This method will be called when the server has replied that the SMB connection has been successfully authenticated.
-
- If you want to retry authenticating from this method,
- 1. Disconnect the underlying SMB connection (call ``self.instance.transport.loseConnection()``)
- 2. Create a new SMBProtocolFactory subclass instance with different user credientials or different NTLM algorithm flag.
- 3. Call ``reactor.connectTCP`` with the new instance to re-establish the SMB connection
- """
- pass
-
- #
- # Public Methods
- #
-
-
[docs]deflistShares(self,timeout=30):
- """
- Retrieve a list of shared resources on remote server.
-
- :param integer/float timeout: Number of seconds that pysmb will wait before raising *SMBTimeout* via the returned *Deferred* instance's *errback* method.
- :return: A *twisted.internet.defer.Deferred* instance. The callback function will be called with a list of :doc:`smb.base.SharedDevice<smb_SharedDevice>` instances.
- """
- ifnotself.instance:
- raiseNotConnectedError('Not connected to server')
-
- d=defer.Deferred()
- self.instance._listShares(d.callback,d.errback,timeout)
- returnd
-
-
[docs]deflistPath(self,service_name,path,
- search=SMB_FILE_ATTRIBUTE_READONLY|SMB_FILE_ATTRIBUTE_HIDDEN|SMB_FILE_ATTRIBUTE_SYSTEM|SMB_FILE_ATTRIBUTE_DIRECTORY|SMB_FILE_ATTRIBUTE_ARCHIVE,
- pattern='*',timeout=30):
- """
- Retrieve a directory listing of files/folders at *path*
-
- :param string/unicode service_name: the name of the shared folder for the *path*
- :param string/unicode path: path relative to the *service_name* where we are interested to learn about its files/sub-folders.
- :param integer search: integer value made up from a bitwise-OR of *SMB_FILE_ATTRIBUTE_xxx* bits (see smb_constants.py).
- The default *search* value will query for all read-only, hidden, system, archive files and directories.
- :param string/unicode pattern: the filter to apply to the results before returning to the client.
- :param integer/float timeout: Number of seconds that pysmb will wait before raising *SMBTimeout* via the returned *Deferred* instance's *errback* method.
- :return: A *twisted.internet.defer.Deferred* instance. The callback function will be called with a list of :doc:`smb.base.SharedFile<smb_SharedFile>` instances.
- """
- ifnotself.instance:
- raiseNotConnectedError('Not connected to server')
-
- d=defer.Deferred()
- self.instance._listPath(service_name,path,d.callback,d.errback,search=search,pattern=pattern,timeout=timeout)
- returnd
-
-
[docs]deflistSnapshots(self,service_name,path,timeout=30):
- """
- Retrieve a list of available snapshots (a.k.a. shadow copies) for *path*.
-
- Note that snapshot features are only supported on Windows Vista Business, Enterprise and Ultimate, and on all Windows 7 editions.
-
- :param string/unicode service_name: the name of the shared folder for the *path*
- :param string/unicode path: path relative to the *service_name* where we are interested in the list of available snapshots
- :return: A *twisted.internet.defer.Deferred* instance. The callback function will be called with a list of python *datetime.DateTime*
- instances in GMT/UTC time zone
- """
- ifnotself.instance:
- raiseNotConnectedError('Not connected to server')
-
- d=defer.Deferred()
- self.instance._listSnapshots(service_name,path,d.callback,d.errback,timeout=timeout)
- returnd
-
-
[docs]defgetAttributes(self,service_name,path,timeout=30):
- """
- Retrieve information about the file at *path* on the *service_name*.
-
- :param string/unicode service_name: the name of the shared folder for the *path*
- :param string/unicode path: Path of the file on the remote server. If the file cannot be opened for reading, an :doc:`OperationFailure<smb_exceptions>` will be raised.
- :return: A *twisted.internet.defer.Deferred* instance. The callback function will be called with a :doc:`smb.base.SharedFile<smb_SharedFile>` instance containing the attributes of the file.
- """
- ifnotself.instance:
- raiseNotConnectedError('Not connected to server')
-
- d=defer.Deferred()
- self.instance._getAttributes(service_name,path,d.callback,d.errback,timeout=timeout)
- returnd
-
-
[docs]defretrieveFile(self,service_name,path,file_obj,timeout=30):
- """
- Retrieve the contents of the file at *path* on the *service_name* and write these contents to the provided *file_obj*.
-
- Use *retrieveFileFromOffset()* method if you need to specify the offset to read from the remote *path* and/or the maximum number of bytes to write to the *file_obj*.
-
- The meaning of the *timeout* parameter will be different from other file operation methods. As the downloaded file usually exceeeds the maximum size
- of each SMB/CIFS data message, it will be packetized into a series of request messages (each message will request about about 60kBytes).
- The *timeout* parameter is an integer/float value that specifies the timeout interval for these individual SMB/CIFS message to be transmitted and downloaded from the remote SMB/CIFS server.
-
- :param string/unicode service_name: the name of the shared folder for the *path*
- :param string/unicode path: Path of the file on the remote server. If the file cannot be opened for reading, an :doc:`OperationFailure<smb_exceptions>` will be called in the returned *Deferred* errback.
- :param file_obj: A file-like object that has a *write* method. Data will be written continuously to *file_obj* until EOF is received from the remote service.
- :return: A *twisted.internet.defer.Deferred* instance. The callback function will be called with a 3-element tuple of ( *file_obj*, file attributes of the file on server, number of bytes written to *file_obj* ).
- The file attributes is an integer value made up from a bitwise-OR of *SMB_FILE_ATTRIBUTE_xxx* bits (see smb_constants.py)
- """
- returnself.retrieveFileFromOffset(service_name,path,file_obj,0L,-1L,timeout)
-
-
[docs]defretrieveFileFromOffset(self,service_name,path,file_obj,offset=0L,max_length=-1L,timeout=30):
- """
- Retrieve the contents of the file at *path* on the *service_name* and write these contents to the provided *file_obj*.
-
- The meaning of the *timeout* parameter will be different from other file operation methods. As the downloaded file usually exceeeds the maximum size
- of each SMB/CIFS data message, it will be packetized into a series of request messages (each message will request about about 60kBytes).
- The *timeout* parameter is an integer/float value that specifies the timeout interval for these individual SMB/CIFS message to be transmitted and downloaded from the remote SMB/CIFS server.
-
- :param string/unicode service_name: the name of the shared folder for the *path*
- :param string/unicode path: Path of the file on the remote server. If the file cannot be opened for reading, an :doc:`OperationFailure<smb_exceptions>` will be called in the returned *Deferred* errback.
- :param file_obj: A file-like object that has a *write* method. Data will be written continuously to *file_obj* until EOF is received from the remote service.
- :param integer/long offset: the offset in the remote *path* where the first byte will be read and written to *file_obj*. Must be either zero or a positive integer/long value.
- :param integer/long max_length: maximum number of bytes to read from the remote *path* and write to the *file_obj*. Specify a negative value to read from *offset* to the EOF.
- If zero, the *Deferred* callback is invoked immediately after the file is opened successfully for reading.
- :return: A *twisted.internet.defer.Deferred* instance. The callback function will be called with a 3-element tuple of ( *file_obj*, file attributes of the file on server, number of bytes written to *file_obj* ).
- The file attributes is an integer value made up from a bitwise-OR of *SMB_FILE_ATTRIBUTE_xxx* bits (see smb_constants.py)
- """
- ifnotself.instance:
- raiseNotConnectedError('Not connected to server')
-
- d=defer.Deferred()
- self.instance._retrieveFileFromOffset(service_name,path,file_obj,d.callback,d.errback,offset,max_length,timeout=timeout)
- returnd
-
-
[docs]defstoreFile(self,service_name,path,file_obj,timeout=30):
- """
- Store the contents of the *file_obj* at *path* on the *service_name*.
-
- The meaning of the *timeout* parameter will be different from other file operation methods. As the uploaded file usually exceeeds the maximum size
- of each SMB/CIFS data message, it will be packetized into a series of messages (usually about 60kBytes).
- The *timeout* parameter is an integer/float value that specifies the timeout interval for these individual SMB/CIFS message to be transmitted and acknowledged
- by the remote SMB/CIFS server.
-
- :param string/unicode service_name: the name of the shared folder for the *path*
- :param string/unicode path: Path of the file on the remote server. If the file at *path* does not exist, it will be created. Otherwise, it will be overwritten.
- If the *path* refers to a folder or the file cannot be opened for writing, an :doc:`OperationFailure<smb_exceptions>` will be called in the returned *Deferred* errback.
- :param file_obj: A file-like object that has a *read* method. Data will read continuously from *file_obj* until EOF.
- :return: A *twisted.internet.defer.Deferred* instance. The callback function will be called with a 2-element tuple of ( *file_obj*, number of bytes uploaded ).
- """
- ifnotself.instance:
- raiseNotConnectedError('Not connected to server')
-
- d=defer.Deferred()
- self.instance._storeFile(service_name,path,file_obj,d.callback,d.errback,timeout=timeout)
- returnd
-
-
[docs]defdeleteFiles(self,service_name,path_file_pattern,timeout=30):
- """
- Delete one or more regular files. It supports the use of wildcards in file names, allowing for deletion of multiple files in a single request.
-
- :param string/unicode service_name: Contains the name of the shared folder.
- :param string/unicode path_file_pattern: The pathname of the file(s) to be deleted, relative to the service_name.
- Wildcards may be used in th filename component of the path.
- If your path/filename contains non-English characters, you must pass in an unicode string.
- :param integer/float timeout: Number of seconds that pysmb will wait before raising *SMBTimeout* via the returned *Deferred* instance's *errback* method.
- :return: A *twisted.internet.defer.Deferred* instance. The callback function will be called with the *path_file_pattern* parameter.
- """
- ifnotself.instance:
- raiseNotConnectedError('Not connected to server')
-
- d=defer.Deferred()
- self.instance._deleteFiles(service_name,path_file_pattern,d.callback,d.errback,timeout=timeout)
- returnd
-
-
[docs]defcreateDirectory(self,service_name,path):
- """
- Creates a new directory *path* on the *service_name*.
-
- :param string/unicode service_name: Contains the name of the shared folder.
- :param string/unicode path: The path of the new folder (relative to) the shared folder.
- If the path contains non-English characters, an unicode string must be used to pass in the path.
- :param integer/float timeout: Number of seconds that pysmb will wait before raising *SMBTimeout* via the returned *Deferred* instance's *errback* method.
- :return: A *twisted.internet.defer.Deferred* instance. The callback function will be called with the *path* parameter.
- """
- ifnotself.instance:
- raiseNotConnectedError('Not connected to server')
-
- d=defer.Deferred()
- self.instance._createDirectory(service_name,path,d.callback,d.errback)
- returnd
-
-
[docs]defdeleteDirectory(self,service_name,path):
- """
- Delete the empty folder at *path* on *service_name*
-
- :param string/unicode service_name: Contains the name of the shared folder.
- :param string/unicode path: The path of the to-be-deleted folder (relative to) the shared folder.
- If the path contains non-English characters, an unicode string must be used to pass in the path.
- :param integer/float timeout: Number of seconds that pysmb will wait before raising *SMBTimeout* via the returned *Deferred* instance's *errback* method.
- :return: A *twisted.internet.defer.Deferred* instance. The callback function will be called with the *path* parameter.
- """
- ifnotself.instance:
- raiseNotConnectedError('Not connected to server')
-
- d=defer.Deferred()
- self.instance._deleteDirectory(service_name,path,d.callback,d.errback)
- returnd
-
-
[docs]defrename(self,service_name,old_path,new_path):
- """
- Rename a file or folder at *old_path* to *new_path* shared at *service_name*. Note that this method cannot be used to rename file/folder across different shared folders
-
- *old_path* and *new_path* are string/unicode referring to the old and new path of the renamed resources (relative to) the shared folder.
- If the path contains non-English characters, an unicode string must be used to pass in the path.
-
- :param string/unicode service_name: Contains the name of the shared folder.
- :param integer/float timeout: Number of seconds that pysmb will wait before raising *SMBTimeout* via the returned *Deferred* instance's *errback* method.
- :return: A *twisted.internet.defer.Deferred* instance. The callback function will be called with a 2-element tuple of ( *old_path*, *new_path* ).
- """
- ifnotself.instance:
- raiseNotConnectedError('Not connected to server')
-
- d=defer.Deferred()
- self.instance._rename(service_name,old_path,new_path,d.callback,d.errback)
- returnd
-
-
[docs]defecho(self,data,timeout=10):
- """
- Send an echo command containing *data* to the remote SMB/CIFS server. The remote SMB/CIFS will reply with the same *data*.
-
- :param string data: Data to send to the remote server.
- :param integer/float timeout: Number of seconds that pysmb will wait before raising *SMBTimeout* via the returned *Deferred* instance's *errback* method.
- :return: A *twisted.internet.defer.Deferred* instance. The callback function will be called with the *data* parameter.
- """
- ifnotself.instance:
- raiseNotConnectedError('Not connected to server')
-
- d=defer.Deferred()
- self.instance._echo(data,d.callback,d.errback,timeout)
- returnd
-
-
[docs]defcloseConnection(self):
- """
- Disconnect from the remote SMB/CIFS server. The TCP connection will be closed at the earliest opportunity after this method returns.
-
- :return: None
- """
- ifnotself.instance:
- raiseNotConnectedError('Not connected to server')
-
- self.instance.transport.loseConnection()
-
- #
- # ClientFactory methods
- # (Do not touch these unless you know what you are doing)
- #
-
- defbuildProtocol(self,addr):
- p=self.protocol(self.username,self.password,self.my_name,self.remote_name,self.domain,self.use_ntlm_v2,self.sign_options,self.is_direct_tcp)
- p.factory=self
- returnp
[docs]classNotReadyError(Exception):
- """Raised when SMB connection is not ready (i.e. not authenticated or authentication failed)"""
- pass
-
-
[docs]classNotConnectedError(Exception):
- """Raised when underlying SMB connection has been disconnected or not connected yet"""
- pass
-
-
[docs]classSMBTimeout(Exception):
- """Raised when a timeout has occurred while waiting for a response or for a SMB/CIFS operation to complete."""
- pass
-
-
-def_convert_to_unicode(string):
- ifnotisinstance(string,unicode):
- string=unicode(string,"utf-8")
- returnstring
-
-
-classSMB(NMBSession):
- """
- This class represents a "connection" to the remote SMB/CIFS server.
- It is not meant to be used directly in an application as it does not have any network transport implementations.
-
- For application use, please refer to
- - L{SMBProtocol.SMBProtocolFactory<smb.SMBProtocol>} if you are using Twisted framework
-
- In [MS-CIFS], this class will contain attributes of Client, Client.Connection and Client.Session abstract data models.
-
- References:
- ===========
- - [MS-CIFS]: 3.2.1
- """
-
- log=logging.getLogger('SMB.SMB')
-
- SIGN_NEVER=0
- SIGN_WHEN_SUPPORTED=1
- SIGN_WHEN_REQUIRED=2
-
- def__init__(self,username,password,my_name,remote_name,domain='',use_ntlm_v2=True,sign_options=SIGN_WHEN_REQUIRED,is_direct_tcp=False):
- NMBSession.__init__(self,my_name,remote_name,is_direct_tcp=is_direct_tcp)
- self.username=_convert_to_unicode(username)
- self.password=_convert_to_unicode(password)
- self.domain=_convert_to_unicode(domain)
- self.sign_options=sign_options
- self.is_direct_tcp=is_direct_tcp
- self.use_ntlm_v2=use_ntlm_v2#: Similar to LMAuthenticationPolicy and NTAuthenticationPolicy as described in [MS-CIFS] 3.2.1.1
- self.smb_message=SMBMessage()
- self.is_using_smb2=False#: Are we communicating using SMB2 protocol? self.smb_message will be a SMB2Message instance if this flag is True
- self.pending_requests={}#: MID mapped to _PendingRequest instance
- self.connected_trees={}#: Share name mapped to TID
- self.next_rpc_call_id=1#: Next RPC callID value. Not used directly in SMB message. Usually encapsulated in sub-commands under SMB_COM_TRANSACTION or SMB_COM_TRANSACTION2 messages
-
- self.has_negotiated=False
- self.has_authenticated=False
- self.is_signing_active=False#: True if the remote server accepts message signing. All outgoing messages will be signed. Simiar to IsSigningActive as described in [MS-CIFS] 3.2.1.2
- self.signing_session_key=None#: Session key for signing packets, if signing is active. Similar to SigningSessionKey as described in [MS-CIFS] 3.2.1.2
- self.signing_challenge_response=None#: Contains the challenge response for signing, if signing is active. Similar to SigningChallengeResponse as described in [MS-CIFS] 3.2.1.2
- self.mid=0
- self.uid=0
- self.next_signing_id=2#: Similar to ClientNextSendSequenceNumber as described in [MS-CIFS] 3.2.1.2
-
- # SMB1 and SMB2 attributes
- # Note that the interpretations of the values may differ between SMB1 and SMB2 protocols
- self.capabilities=0
- self.security_mode=0#: Initialized from the SecurityMode field of the SMB_COM_NEGOTIATE message
-
- # SMB1 attributes
- # Most of the following attributes will be initialized upon receipt of SMB_COM_NEGOTIATE message from server (via self._updateServerInfo_SMB1 method)
- self.use_plaintext_authentication=False#: Similar to PlaintextAuthenticationPolicy in in [MS-CIFS] 3.2.1.1
- self.max_raw_size=0
- self.max_buffer_size=0#: Similar to MaxBufferSize as described in [MS-CIFS] 3.2.1.1
- self.max_mpx_count=0#: Similar to MaxMpxCount as described in [MS-CIFS] 3.2.1.1
-
- # SMB2 attributes
- self.max_read_size=0#: Similar to MaxReadSize as described in [MS-SMB2] 2.2.4
- self.max_write_size=0#: Similar to MaxWriteSize as described in [MS-SMB2] 2.2.4
- self.max_transact_size=0#: Similar to MaxTransactSize as described in [MS-SMB2] 2.2.4
- self.session_id=0#: Similar to SessionID as described in [MS-SMB2] 2.2.4. This will be set in _updateState_SMB2 method
-
- self._setupSMB1Methods()
-
- self.log.info('Authentication with remote machine "%s" for user "%s" will be using NTLM %s authentication (%s extended security)',
- self.remote_name,self.username,
- (self.use_ntlm_v2and'v2')or'v1',
- (SUPPORT_EXTENDED_SECURITYand'with')or'without')
-
-
- #
- # NMBSession Methods
- #
-
- defonNMBSessionOK(self):
- self._sendSMBMessage(SMBMessage(ComNegotiateRequest()))
-
- defonNMBSessionFailed(self):
- pass
-
- defonNMBSessionMessage(self,flags,data):
- whileTrue:
- try:
- i=self.smb_message.decode(data)
- exceptSMB2ProtocolHeaderError:
- self.log.info('Now switching over to SMB2 protocol communication')
- self.is_using_smb2=True
- self.mid=0# Must reset messageID counter, or else remote SMB2 server will disconnect
- self._setupSMB2Methods()
- self.smb_message=self._klassSMBMessage()
- i=self.smb_message.decode(data)
-
- next_message_offset=0
- ifself.is_using_smb2:
- next_message_offset=self.smb_message.next_command_offset
-
- ifi>0:
- ifnotself.is_using_smb2:
- self.log.debug('Received SMB message "%s" (command:0x%2X flags:0x%02X flags2:0x%04X TID:%d UID:%d)',
- SMB_COMMAND_NAMES.get(self.smb_message.command,'<unknown>'),
- self.smb_message.command,self.smb_message.flags,self.smb_message.flags2,self.smb_message.tid,self.smb_message.uid)
- else:
- self.log.debug('Received SMB2 message "%s" (command:0x%04X flags:0x%04x)',
- SMB2_COMMAND_NAMES.get(self.smb_message.command,'<unknown>'),
- self.smb_message.command,self.smb_message.flags)
- ifself._updateState(self.smb_message):
- # We need to create a new instance instead of calling reset() because the instance could be captured in the message history.
- self.smb_message=self._klassSMBMessage()
-
- ifnext_message_offset>0:
- data=data[next_message_offset:]
- else:
- break
-
- #
- # Public Methods for Overriding in Subclasses
- #
-
- defonAuthOK(self):
- pass
-
- defonAuthFailed(self):
- pass
-
- #
- # Protected Methods
- #
-
- def_setupSMB1Methods(self):
- self._klassSMBMessage=SMBMessage
- self._updateState=self._updateState_SMB1
- self._updateServerInfo=self._updateServerInfo_SMB1
- self._handleNegotiateResponse=self._handleNegotiateResponse_SMB1
- self._sendSMBMessage=self._sendSMBMessage_SMB1
- self._handleSessionChallenge=self._handleSessionChallenge_SMB1
- self._listShares=self._listShares_SMB1
- self._listPath=self._listPath_SMB1
- self._listSnapshots=self._listSnapshots_SMB1
- self._getAttributes=self._getAttributes_SMB1
- self._retrieveFile=self._retrieveFile_SMB1
- self._retrieveFileFromOffset=self._retrieveFileFromOffset_SMB1
- self._storeFile=self._storeFile_SMB1
- self._storeFileFromOffset=self._storeFileFromOffset_SMB1
- self._deleteFiles=self._deleteFiles_SMB1
- self._resetFileAttributes=self._resetFileAttributes_SMB1
- self._createDirectory=self._createDirectory_SMB1
- self._deleteDirectory=self._deleteDirectory_SMB1
- self._rename=self._rename_SMB1
- self._echo=self._echo_SMB1
-
- def_setupSMB2Methods(self):
- self._klassSMBMessage=SMB2Message
- self._updateState=self._updateState_SMB2
- self._updateServerInfo=self._updateServerInfo_SMB2
- self._handleNegotiateResponse=self._handleNegotiateResponse_SMB2
- self._sendSMBMessage=self._sendSMBMessage_SMB2
- self._handleSessionChallenge=self._handleSessionChallenge_SMB2
- self._listShares=self._listShares_SMB2
- self._listPath=self._listPath_SMB2
- self._listSnapshots=self._listSnapshots_SMB2
- self._getAttributes=self._getAttributes_SMB2
- self._retrieveFile=self._retrieveFile_SMB2
- self._retrieveFileFromOffset=self._retrieveFileFromOffset_SMB2
- self._storeFile=self._storeFile_SMB2
- self._storeFileFromOffset=self._storeFileFromOffset_SMB2
- self._deleteFiles=self._deleteFiles_SMB2
- self._resetFileAttributes=self._resetFileAttributes_SMB2
- self._createDirectory=self._createDirectory_SMB2
- self._deleteDirectory=self._deleteDirectory_SMB2
- self._rename=self._rename_SMB2
- self._echo=self._echo_SMB2
-
- def_getNextRPCCallID(self):
- self.next_rpc_call_id+=1
- returnself.next_rpc_call_id
-
- #
- # SMB2 Methods Family
- #
-
- def_sendSMBMessage_SMB2(self,smb_message):
- ifsmb_message.mid==0:
- smb_message.mid=self._getNextMID_SMB2()
-
- ifsmb_message.command!=SMB2_COM_NEGOTIATEandsmb_message.command!=SMB2_COM_ECHO:
- smb_message.session_id=self.session_id
-
- ifself.is_signing_active:
- smb_message.flags|=SMB2_FLAGS_SIGNED
- raw_data=smb_message.encode()
- smb_message.signature=hmac.new(self.signing_session_key,raw_data,sha256).digest()[:16]
-
- smb_message.raw_data=smb_message.encode()
- self.log.debug('MID is %d. Signature is %s. Total raw message is %d bytes',smb_message.mid,binascii.hexlify(smb_message.signature),len(smb_message.raw_data))
- else:
- smb_message.raw_data=smb_message.encode()
- self.sendNMBMessage(smb_message.raw_data)
-
- def_getNextMID_SMB2(self):
- self.mid+=1
- returnself.mid
-
- def_updateState_SMB2(self,message):
- ifmessage.isReply:
- ifmessage.command==SMB2_COM_NEGOTIATE:
- ifmessage.status==0:
- self.has_negotiated=True
- self.log.info('SMB2 dialect negotiation successful')
- self._updateServerInfo(message.payload)
- self._handleNegotiateResponse(message)
- else:
- raiseProtocolError('Unknown status value (0x%08X) in SMB2_COM_NEGOTIATE'%message.status,
- message.raw_data,message)
- elifmessage.command==SMB2_COM_SESSION_SETUP:
- ifmessage.status==0:
- self.session_id=message.session_id
- try:
- result=securityblob.decodeAuthResponseSecurityBlob(message.payload.security_blob)
- ifresult==securityblob.RESULT_ACCEPT_COMPLETED:
- self.has_authenticated=True
- self.log.info('Authentication (on SMB2) successful!')
- self.onAuthOK()
- else:
- raiseProtocolError('SMB2_COM_SESSION_SETUP status is 0 but security blob negResult value is %d'%result,message.raw_data,message)
- exceptsecurityblob.BadSecurityBlobError,ex:
- raiseProtocolError(str(ex),message.raw_data,message)
- elifmessage.status==0xc0000016:# STATUS_MORE_PROCESSING_REQUIRED
- self.session_id=message.session_id
- try:
- result,ntlm_token=securityblob.decodeChallengeSecurityBlob(message.payload.security_blob)
- ifresult==securityblob.RESULT_ACCEPT_INCOMPLETE:
- self._handleSessionChallenge(message,ntlm_token)
- except(securityblob.BadSecurityBlobError,securityblob.UnsupportedSecurityProvider),ex:
- raiseProtocolError(str(ex),message.raw_data,message)
- elifmessage.status==0xc000006d:# STATUS_LOGON_FAILURE
- self.has_authenticated=False
- self.log.info('Authentication (on SMB2) failed. Please check username and password.')
- self.onAuthFailed()
- else:
- raiseProtocolError('Unknown status value (0x%08X) in SMB_COM_SESSION_SETUP_ANDX (with extended security)'%message.status,
- message.raw_data,message)
-
- req=self.pending_requests.pop(message.mid,None)
- ifreq:
- req.callback(message,**req.kwargs)
- returnTrue
-
-
- def_updateServerInfo_SMB2(self,payload):
- self.capabilities=payload.capabilities
- self.security_mode=payload.security_mode
- self.max_transact_size=payload.max_transact_size
- self.max_read_size=payload.max_read_size
- self.max_write_size=payload.max_write_size
- self.use_plaintext_authentication=False# SMB2 never allows plaintext authentication
-
-
- def_handleNegotiateResponse_SMB2(self,message):
- ntlm_data=ntlm.generateNegotiateMessage()
- blob=securityblob.generateNegotiateSecurityBlob(ntlm_data)
- self._sendSMBMessage(SMB2Message(SMB2SessionSetupRequest(blob)))
-
-
- def_handleSessionChallenge_SMB2(self,message,ntlm_token):
- server_challenge,server_flags,server_info=ntlm.decodeChallengeMessage(ntlm_token)
-
- self.log.info('Performing NTLMv2 authentication (on SMB2) with server challenge "%s"',binascii.hexlify(server_challenge))
-
- ifself.use_ntlm_v2:
- self.log.info('Performing NTLMv2 authentication (on SMB2) with server challenge "%s"',binascii.hexlify(server_challenge))
- nt_challenge_response,lm_challenge_response,session_key=ntlm.generateChallengeResponseV2(self.password,
- self.username,
- server_challenge,
- server_info,
- self.domain)
-
- else:
- self.log.info('Performing NTLMv1 authentication (on SMB2) with server challenge "%s"',binascii.hexlify(server_challenge))
- nt_challenge_response,lm_challenge_response,session_key=ntlm.generateChallengeResponseV1(self.password,server_challenge,True)
-
- ntlm_data=ntlm.generateAuthenticateMessage(server_flags,
- nt_challenge_response,
- lm_challenge_response,
- session_key,
- self.username,
- self.domain)
-
- ifself.log.isEnabledFor(logging.DEBUG):
- self.log.debug('NT challenge response is "%s" (%d bytes)',binascii.hexlify(nt_challenge_response),len(nt_challenge_response))
- self.log.debug('LM challenge response is "%s" (%d bytes)',binascii.hexlify(lm_challenge_response),len(lm_challenge_response))
-
- blob=securityblob.generateAuthSecurityBlob(ntlm_data)
- self._sendSMBMessage(SMB2Message(SMB2SessionSetupRequest(blob)))
-
- ifself.security_mode&SMB2_NEGOTIATE_SIGNING_REQUIRED:
- self.log.info('Server requires all SMB messages to be signed')
- self.is_signing_active=(self.sign_options!=SMB.SIGN_NEVER)
- elifself.security_mode&SMB2_NEGOTIATE_SIGNING_ENABLED:
- self.log.info('Server supports SMB signing')
- self.is_signing_active=(self.sign_options==SMB.SIGN_WHEN_SUPPORTED)
- else:
- self.is_signing_active=False
-
- ifself.is_signing_active:
- self.log.info("SMB signing activated. All SMB messages will be signed.")
- self.signing_session_key=(session_key+'\0'*16)[:16]
- ifself.capabilities&CAP_EXTENDED_SECURITY:
- self.signing_challenge_response=None
- else:
- self.signing_challenge_response=blob
- else:
- self.log.info("SMB signing deactivated. SMB messages will NOT be signed.")
-
-
- def_listShares_SMB2(self,callback,errback,timeout=30):
- ifnotself.has_authenticated:
- raiseNotReadyError('SMB connection not authenticated')
-
- expiry_time=time.time()+timeout
- path='IPC$'
- messages_history=[]
-
- defconnectSrvSvc(tid):
- m=SMB2Message(SMB2CreateRequest('srvsvc',
- file_attributes=0,
- access_mask=FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_READ_EA|FILE_WRITE_EA|READ_CONTROL|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES|SYNCHRONIZE,
- share_access=FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
- oplock=SMB2_OPLOCK_LEVEL_NONE,
- impersonation=SEC_IMPERSONATE,
- create_options=FILE_NON_DIRECTORY_FILE|FILE_OPEN_NO_RECALL,
- create_disp=FILE_OPEN))
-
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,connectSrvSvcCB,errback)
- messages_history.append(m)
-
- defconnectSrvSvcCB(create_message,**kwargs):
- messages_history.append(create_message)
- ifcreate_message.status==0:
- call_id=self._getNextRPCCallID()
- # The data_bytes are binding call to Server Service RPC using DCE v1.1 RPC over SMB. See [MS-SRVS] and [C706]
- # If you wish to understand the meanings of the byte stream, I would suggest you use a recent version of WireShark to packet capture the stream
- data_bytes= \
- binascii.unhexlify("""05 00 0b 03 10 00 00 00 74 00 00 00""".replace(' ',''))+ \
- struct.pack('<I',call_id)+ \
- binascii.unhexlify("""
-b8 10 b8 10 00 00 00 00 02 00 00 00 00 00 01 00
-c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88
-03 00 00 00 04 5d 88 8a eb 1c c9 11 9f e8 08 00
-2b 10 48 60 02 00 00 00 01 00 01 00 c8 4f 32 4b
-70 16 d3 01 12 78 5a 47 bf 6e e1 88 03 00 00 00
-2c 1c b7 6c 12 98 40 45 03 00 00 00 00 00 00 00
-01 00 00 00
-""".replace(' ','').replace('\n',''))
- m=SMB2Message(SMB2WriteRequest(create_message.payload.fid,data_bytes,0))
- m.tid=create_message.tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,rpcBindCB,errback,fid=create_message.payload.fid)
- messages_history.append(m)
- else:
- errback(OperationFailure('Failed to list shares: Unable to locate Server Service RPC endpoint',messages_history))
-
- defrpcBindCB(trans_message,**kwargs):
- messages_history.append(trans_message)
- iftrans_message.status==0:
- m=SMB2Message(SMB2ReadRequest(kwargs['fid'],read_len=1024,read_offset=0))
- m.tid=trans_message.tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,rpcReadCB,errback,fid=kwargs['fid'])
- messages_history.append(m)
- else:
- closeFid(trans_message.tid,kwargs['fid'],error='Failed to list shares: Unable to read from Server Service RPC endpoint')
-
- defrpcReadCB(read_message,**kwargs):
- messages_history.append(read_message)
- ifread_message.status==0:
- call_id=self._getNextRPCCallID()
-
- padding=''
- remote_name='\\\\'+self.remote_name
- server_len=len(remote_name)+1
- server_bytes_len=server_len*2
- ifserver_len%2!=0:
- padding='\0\0'
- server_bytes_len+=2
-
- # The data bytes are the RPC call to NetrShareEnum (Opnum 15) at Server Service RPC.
- # If you wish to understand the meanings of the byte stream, I would suggest you use a recent version of WireShark to packet capture the stream
- data_bytes= \
- binascii.unhexlify("""05 00 00 03 10 00 00 00""".replace(' ',''))+ \
- struct.pack('<HHI',72+server_bytes_len,0,call_id)+ \
- binascii.unhexlify("""4c 00 00 00 00 00 0f 00 00 00 02 00""".replace(' ',''))+ \
- struct.pack('<III',server_len,0,server_len)+ \
- (remote_name+'\0').encode('UTF-16LE')+padding+ \
- binascii.unhexlify("""
-01 00 00 00 01 00 00 00 04 00 02 00 00 00 00 00
-00 00 00 00 ff ff ff ff 08 00 02 00 00 00 00 00
-""".replace(' ','').replace('\n',''))
- m=SMB2Message(SMB2IoctlRequest(kwargs['fid'],0x0011C017,flags=0x01,max_out_size=8196,in_data=data_bytes))
- m.tid=read_message.tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,listShareResultsCB,errback,fid=kwargs['fid'])
- messages_history.append(m)
- else:
- closeFid(read_message.tid,kwargs['fid'],error='Failed to list shares: Unable to bind to Server Service RPC endpoint')
-
- deflistShareResultsCB(result_message,**kwargs):
- messages_history.append(result_message)
- ifresult_message.status==0:
- # The payload.data_bytes will contain the results of the RPC call to NetrShareEnum (Opnum 15) at Server Service RPC.
- data_bytes=result_message.payload.out_data
-
- iford(data_bytes[3])&0x02==0:
- sendReadRequest(result_message.tid,kwargs['fid'],data_bytes)
- else:
- decodeResults(result_message.tid,kwargs['fid'],data_bytes)
- elifresult_message.status==0x0103:# STATUS_PENDING
- self.pending_requests[result_message.mid]=_PendingRequest(result_message.mid,expiry_time,listShareResultsCB,errback,fid=kwargs['fid'])
- else:
- closeFid(result_message.tid,kwargs['fid'])
- errback(OperationFailure('Failed to list shares: Unable to retrieve shared device list',messages_history))
-
- defdecodeResults(tid,fid,data_bytes):
- shares_count=struct.unpack('<I',data_bytes[36:40])[0]
- results=[]# A list of SharedDevice instances
- offset=36+12# You need to study the byte stream to understand the meaning of these constants
- foriinrange(0,shares_count):
- results.append(SharedDevice(struct.unpack('<I',data_bytes[offset+4:offset+8])[0],None,None))
- offset+=12
-
- foriinrange(0,shares_count):
- max_length,_,length=struct.unpack('<III',data_bytes[offset:offset+12])
- offset+=12
- results[i].name=unicode(data_bytes[offset:offset+length*2-2],'UTF-16LE')
-
- iflength%2!=0:
- offset+=(length*2+2)
- else:
- offset+=(length*2)
-
- max_length,_,length=struct.unpack('<III',data_bytes[offset:offset+12])
- offset+=12
- results[i].comments=unicode(data_bytes[offset:offset+length*2-2],'UTF-16LE')
-
- iflength%2!=0:
- offset+=(length*2+2)
- else:
- offset+=(length*2)
-
- closeFid(tid,fid)
- callback(results)
-
- defsendReadRequest(tid,fid,data_bytes):
- read_count=min(4280,self.max_read_size)
- m=SMB2Message(SMB2ReadRequest(fid,0,read_count))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,readCB,errback,
- fid=fid,data_bytes=data_bytes)
-
- defreadCB(read_message,**kwargs):
- messages_history.append(read_message)
- ifread_message.status==0:
- data_len=read_message.payload.data_length
- data_bytes=read_message.payload.data
-
- iford(data_bytes[3])&0x02==0:
- sendReadRequest(read_message.tid,kwargs['fid'],kwargs['data_bytes']+data_bytes[24:data_len-24])
- else:
- decodeResults(read_message.tid,kwargs['fid'],kwargs['data_bytes']+data_bytes[24:data_len-24])
- else:
- closeFid(read_message.tid,kwargs['fid'])
- errback(OperationFailure('Failed to list shares: Unable to retrieve shared device list',messages_history))
-
- defcloseFid(tid,fid,results=None,error=None):
- m=SMB2Message(SMB2CloseRequest(fid))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,closeCB,errback,results=results,error=error)
- messages_history.append(m)
-
- defcloseCB(close_message,**kwargs):
- ifkwargs['results']isnotNone:
- callback(kwargs['results'])
- elifkwargs['error']isnotNone:
- errback(OperationFailure(kwargs['error'],messages_history))
-
- ifnotself.connected_trees.has_key(path):
- defconnectCB(connect_message,**kwargs):
- messages_history.append(connect_message)
- ifconnect_message.status==0:
- self.connected_trees[path]=connect_message.tid
- connectSrvSvc(connect_message.tid)
- else:
- errback(OperationFailure('Failed to list shares: Unable to connect to IPC$',messages_history))
-
- m=SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s'%(self.remote_name.upper(),path)))
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,connectCB,errback,path=path)
- messages_history.append(m)
- else:
- connectSrvSvc(self.connected_trees[path])
-
- def_listPath_SMB2(self,service_name,path,callback,errback,search,pattern,timeout=30):
- ifnotself.has_authenticated:
- raiseNotReadyError('SMB connection not authenticated')
-
- expiry_time=time.time()+timeout
- path=path.replace('/','\\')
- ifpath.startswith('\\'):
- path=path[1:]
- ifpath.endswith('\\'):
- path=path[:-1]
- messages_history=[]
- results=[]
-
- defsendCreate(tid):
- create_context_data=binascii.unhexlify("""
-28 00 00 00 10 00 04 00 00 00 18 00 10 00 00 00
-44 48 6e 51 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 18 00 00 00 10 00 04 00
-00 00 18 00 00 00 00 00 4d 78 41 63 00 00 00 00
-00 00 00 00 10 00 04 00 00 00 18 00 00 00 00 00
-51 46 69 64 00 00 00 00
-""".replace(' ','').replace('\n',''))
- m=SMB2Message(SMB2CreateRequest(path,
- file_attributes=0,
- access_mask=FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES|SYNCHRONIZE,
- share_access=FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
- oplock=SMB2_OPLOCK_LEVEL_NONE,
- impersonation=SEC_IMPERSONATE,
- create_options=FILE_DIRECTORY_FILE,
- create_disp=FILE_OPEN,
- create_context_data=create_context_data))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,createCB,errback)
- messages_history.append(m)
-
- defcreateCB(create_message,**kwargs):
- messages_history.append(create_message)
- ifcreate_message.status==0:
- sendQuery(create_message.tid,create_message.payload.fid,'')
- else:
- errback(OperationFailure('Failed to list %s on %s: Unable to open directory'%(path,service_name),messages_history))
-
- defsendQuery(tid,fid,data_buf):
- m=SMB2Message(SMB2QueryDirectoryRequest(fid,pattern,
- info_class=0x03,# FileBothDirectoryInformation
- flags=0,
- output_buf_len=self.max_transact_size))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,queryCB,errback,fid=fid,data_buf=data_buf)
- messages_history.append(m)
-
- defqueryCB(query_message,**kwargs):
- messages_history.append(query_message)
- ifquery_message.status==0:
- data_buf=decodeQueryStruct(kwargs['data_buf']+query_message.payload.data)
- sendQuery(query_message.tid,kwargs['fid'],data_buf)
- elifquery_message.status==0x80000006L:# STATUS_NO_MORE_FILES
- closeFid(query_message.tid,kwargs['fid'],results=results)
- else:
- closeFid(query_message.tid,kwargs['fid'],error=query_message.status)
-
- defdecodeQueryStruct(data_bytes):
- # SMB_FIND_FILE_BOTH_DIRECTORY_INFO structure. See [MS-CIFS]: 2.2.8.1.7 and [MS-SMB]: 2.2.8.1.1
- info_format='<IIQQQQQQIIIBB24s'
- info_size=struct.calcsize(info_format)
-
- data_length=len(data_bytes)
- offset=0
- whileoffset<data_length:
- ifoffset+info_size>data_length:
- returndata_bytes[offset:]
-
- next_offset,_, \
- create_time,last_access_time,last_write_time,last_attr_change_time, \
- file_size,alloc_size,file_attributes,filename_length,ea_size, \
- short_name_length,_,short_name=struct.unpack(info_format,data_bytes[offset:offset+info_size])
-
- offset2=offset+info_size
- ifoffset2+filename_length>data_length:
- returndata_bytes[offset:]
-
- filename=data_bytes[offset2:offset2+filename_length].decode('UTF-16LE')
- short_name=short_name.decode('UTF-16LE')
- results.append(SharedFile(convertFILETIMEtoEpoch(create_time),convertFILETIMEtoEpoch(last_access_time),
- convertFILETIMEtoEpoch(last_write_time),convertFILETIMEtoEpoch(last_attr_change_time),
- file_size,alloc_size,file_attributes,short_name,filename))
-
- ifnext_offset:
- offset+=next_offset
- else:
- break
- return''
-
- defcloseFid(tid,fid,results=None,error=None):
- m=SMB2Message(SMB2CloseRequest(fid))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,closeCB,errback,results=results,error=error)
- messages_history.append(m)
-
- defcloseCB(close_message,**kwargs):
- ifkwargs['results']isnotNone:
- callback(kwargs['results'])
- elifkwargs['error']isnotNone:
- errback(OperationFailure('Failed to list %s on %s: Query failed with errorcode 0x%08x'%(path,service_name,kwargs['error']),messages_history))
-
- ifnotself.connected_trees.has_key(service_name):
- defconnectCB(connect_message,**kwargs):
- messages_history.append(connect_message)
- ifconnect_message.status==0:
- self.connected_trees[service_name]=connect_message.tid
- sendCreate(connect_message.tid)
- else:
- errback(OperationFailure('Failed to list %s on %s: Unable to connect to shared device'%(path,service_name),messages_history))
-
- m=SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s'%(self.remote_name.upper(),service_name)))
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,connectCB,errback,path=service_name)
- messages_history.append(m)
- else:
- sendCreate(self.connected_trees[service_name])
-
- def_getAttributes_SMB2(self,service_name,path,callback,errback,timeout=30):
- ifnotself.has_authenticated:
- raiseNotReadyError('SMB connection not authenticated')
-
- expiry_time=time.time()+timeout
- path=path.replace('/','\\')
- ifpath.startswith('\\'):
- path=path[1:]
- ifpath.endswith('\\'):
- path=path[:-1]
- messages_history=[]
-
- defsendCreate(tid):
- create_context_data=binascii.unhexlify("""
-28 00 00 00 10 00 04 00 00 00 18 00 10 00 00 00
-44 48 6e 51 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 18 00 00 00 10 00 04 00
-00 00 18 00 00 00 00 00 4d 78 41 63 00 00 00 00
-00 00 00 00 10 00 04 00 00 00 18 00 00 00 00 00
-51 46 69 64 00 00 00 00
-""".replace(' ','').replace('\n',''))
- m=SMB2Message(SMB2CreateRequest(path,
- file_attributes=0,
- access_mask=FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES|SYNCHRONIZE,
- share_access=FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
- oplock=SMB2_OPLOCK_LEVEL_NONE,
- impersonation=SEC_IMPERSONATE,
- create_options=0,
- create_disp=FILE_OPEN,
- create_context_data=create_context_data))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,createCB,errback)
- messages_history.append(m)
-
- defcreateCB(create_message,**kwargs):
- messages_history.append(create_message)
- ifcreate_message.status==0:
- p=create_message.payload
- info=SharedFile(p.create_time,p.lastaccess_time,p.lastwrite_time,p.change_time,
- p.file_size,p.allocation_size,p.file_attributes,
- unicode(path),unicode(path))
- closeFid(create_message.tid,p.fid,info=info)
- else:
- errback(OperationFailure('Failed to get attributes for %s on %s: Unable to open remote file object'%(path,service_name),messages_history))
-
- defcloseFid(tid,fid,info=None,error=None):
- m=SMB2Message(SMB2CloseRequest(fid))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,closeCB,errback,info=info,error=error)
- messages_history.append(m)
-
- defcloseCB(close_message,**kwargs):
- ifkwargs['info']isnotNone:
- callback(kwargs['info'])
- elifkwargs['error']isnotNone:
- errback(OperationFailure('Failed to get attributes for %s on %s: Query failed with errorcode 0x%08x'%(path,service_name,kwargs['error']),messages_history))
-
- ifnotself.connected_trees.has_key(service_name):
- defconnectCB(connect_message,**kwargs):
- messages_history.append(connect_message)
- ifconnect_message.status==0:
- self.connected_trees[service_name]=connect_message.tid
- sendCreate(connect_message.tid)
- else:
- errback(OperationFailure('Failed to get attributes for %s on %s: Unable to connect to shared device'%(path,service_name),messages_history))
-
- m=SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s'%(self.remote_name.upper(),service_name)))
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,connectCB,errback,path=service_name)
- messages_history.append(m)
- else:
- sendCreate(self.connected_trees[service_name])
-
- def_retrieveFile_SMB2(self,service_name,path,file_obj,callback,errback,timeout=30):
- returnself._retrieveFileFromOffset(service_name,path,file_obj,callback,errback,0L,-1L,timeout)
-
- def_retrieveFileFromOffset_SMB2(self,service_name,path,file_obj,callback,errback,starting_offset,max_length,timeout=30):
- ifnotself.has_authenticated:
- raiseNotReadyError('SMB connection not authenticated')
-
- expiry_time=time.time()+timeout
- path=path.replace('/','\\')
- ifpath.startswith('\\'):
- path=path[1:]
- ifpath.endswith('\\'):
- path=path[:-1]
- messages_history=[]
- results=[]
-
- defsendCreate(tid):
- create_context_data=binascii.unhexlify("""
-28 00 00 00 10 00 04 00 00 00 18 00 10 00 00 00
-44 48 6e 51 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 18 00 00 00 10 00 04 00
-00 00 18 00 00 00 00 00 4d 78 41 63 00 00 00 00
-00 00 00 00 10 00 04 00 00 00 18 00 00 00 00 00
-51 46 69 64 00 00 00 00
-""".replace(' ','').replace('\n',''))
- m=SMB2Message(SMB2CreateRequest(path,
- file_attributes=0,
- access_mask=FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES|READ_CONTROL|SYNCHRONIZE,
- share_access=FILE_SHARE_READ,
- oplock=SMB2_OPLOCK_LEVEL_NONE,
- impersonation=SEC_IMPERSONATE,
- create_options=FILE_SEQUENTIAL_ONLY|FILE_NON_DIRECTORY_FILE,
- create_disp=FILE_OPEN,
- create_context_data=create_context_data))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,createCB,errback,tid=tid)
- messages_history.append(m)
-
- defcreateCB(create_message,**kwargs):
- messages_history.append(create_message)
- ifcreate_message.status==0:
- m=SMB2Message(SMB2QueryInfoRequest(create_message.payload.fid,
- flags=0,
- additional_info=0,
- info_type=SMB2_INFO_FILE,
- file_info_class=0x16,# FileStreamInformation [MS-FSCC] 2.4
- input_buf='',
- output_buf_len=4096))
- m.tid=create_message.tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,infoCB,errback,
- fid=create_message.payload.fid,file_attributes=create_message.payload.file_attributes)
- messages_history.append(m)
- else:
- errback(OperationFailure('Failed to list %s on %s: Unable to open file'%(path,service_name),messages_history))
-
- definfoCB(info_message,**kwargs):
- messages_history.append(info_message)
- ifinfo_message.status==0:
- file_len=struct.unpack('<Q',info_message.payload.data[8:16])[0]
- ifmax_length==0orstarting_offset>file_len:
- closeFid(info_message.tid,kwargs['fid'])
- callback((file_obj,kwargs['file_attributes'],0))# Note that this is a tuple of 3-elements
- else:
- remaining_len=max_length
- ifremaining_len<0:
- remaining_len=file_len
- ifstarting_offset+remaining_len>file_len:
- remaining_len=file_len-starting_offset
- sendRead(info_message.tid,kwargs['fid'],starting_offset,remaining_len,0,kwargs['file_attributes'])
- else:
- errback(OperationFailure('Failed to list %s on %s: Unable to retrieve information on file'%(path,service_name),messages_history))
-
- defsendRead(tid,fid,offset,remaining_len,read_len,file_attributes):
- read_count=min(self.max_read_size,remaining_len)
- m=SMB2Message(SMB2ReadRequest(fid,offset,read_count))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,readCB,errback,
- fid=fid,offset=offset,
- remaining_len=remaining_len,
- read_len=read_len,
- file_attributes=file_attributes)
-
- defreadCB(read_message,**kwargs):
- # To avoid crazy memory usage when retrieving large files, we do not save every read_message in messages_history.
- ifread_message.status==0:
- data_len=read_message.payload.data_length
- file_obj.write(read_message.payload.data)
-
- remaining_len=kwargs['remaining_len']-data_len
-
- ifremaining_len>0:
- sendRead(read_message.tid,kwargs['fid'],kwargs['offset']+data_len,remaining_len,kwargs['read_len']+data_len,kwargs['file_attributes'])
- else:
- closeFid(read_message.tid,kwargs['fid'],ret=(file_obj,kwargs['file_attributes'],kwargs['read_len']+data_len))
- else:
- messages_history.append(read_message)
- closeFid(read_message.tid,kwargs['fid'],error=read_message.status)
-
- defcloseFid(tid,fid,ret=None,error=None):
- m=SMB2Message(SMB2CloseRequest(fid))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,closeCB,errback,ret=ret,error=error)
- messages_history.append(m)
-
- defcloseCB(close_message,**kwargs):
- ifkwargs['ret']isnotNone:
- callback(kwargs['ret'])
- elifkwargs['error']isnotNone:
- errback(OperationFailure('Failed to retrieve %s on %s: Read failed'%(path,service_name),messages_history))
-
- ifnotself.connected_trees.has_key(service_name):
- defconnectCB(connect_message,**kwargs):
- messages_history.append(connect_message)
- ifconnect_message.status==0:
- self.connected_trees[service_name]=connect_message.tid
- sendCreate(connect_message.tid)
- else:
- errback(OperationFailure('Failed to retrieve %s on %s: Unable to connect to shared device'%(path,service_name),messages_history))
-
- m=SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s'%(self.remote_name.upper(),service_name)))
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,connectCB,errback,path=service_name)
- messages_history.append(m)
- else:
- sendCreate(self.connected_trees[service_name])
-
- def_storeFile_SMB2(self,service_name,path,file_obj,callback,errback,timeout=30):
- self._storeFileFromOffset_SMB2(service_name,path,file_obj,callback,errback,0L,True,timeout)
-
- def_storeFileFromOffset_SMB2(self,service_name,path,file_obj,callback,errback,starting_offset,truncate=False,timeout=30):
- ifnotself.has_authenticated:
- raiseNotReadyError('SMB connection not authenticated')
-
- path=path.replace('/','\\')
- ifpath.startswith('\\'):
- path=path[1:]
- ifpath.endswith('\\'):
- path=path[:-1]
- messages_history=[]
-
- defsendCreate(tid):
- create_context_data=binascii.unhexlify("""
-28 00 00 00 10 00 04 00 00 00 18 00 10 00 00 00
-44 48 6e 51 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 20 00 00 00 10 00 04 00
-00 00 18 00 08 00 00 00 41 6c 53 69 00 00 00 00
-85 62 00 00 00 00 00 00 18 00 00 00 10 00 04 00
-00 00 18 00 00 00 00 00 4d 78 41 63 00 00 00 00
-00 00 00 00 10 00 04 00 00 00 18 00 00 00 00 00
-51 46 69 64 00 00 00 00
-""".replace(' ','').replace('\n',''))
- m=SMB2Message(SMB2CreateRequest(path,
- file_attributes=ATTR_ARCHIVE,
- access_mask=FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES|FILE_READ_EA|FILE_WRITE_EA|READ_CONTROL|SYNCHRONIZE,
- share_access=0,
- oplock=SMB2_OPLOCK_LEVEL_NONE,
- impersonation=SEC_IMPERSONATE,
- create_options=FILE_SEQUENTIAL_ONLY|FILE_NON_DIRECTORY_FILE,
- create_disp=FILE_OVERWRITE_IFiftruncateelseFILE_OPEN_IF,
- create_context_data=create_context_data))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,createCB,errback,tid=tid)
- messages_history.append(m)
-
- defcreateCB(create_message,**kwargs):
- messages_history.append(create_message)
- ifcreate_message.status==0:
- sendWrite(create_message.tid,create_message.payload.fid,starting_offset)
- else:
- errback(OperationFailure('Failed to store %s on %s: Unable to open file'%(path,service_name),messages_history))
-
- defsendWrite(tid,fid,offset):
- write_count=self.max_write_size
- data=file_obj.read(write_count)
- data_len=len(data)
- ifdata_len>0:
- m=SMB2Message(SMB2WriteRequest(fid,data,offset))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,writeCB,errback,fid=fid,offset=offset+data_len)
- else:
- closeFid(tid,fid,offset=offset)
-
- defwriteCB(write_message,**kwargs):
- # To avoid crazy memory usage when saving large files, we do not save every write_message in messages_history.
- ifwrite_message.status==0:
- sendWrite(write_message.tid,kwargs['fid'],kwargs['offset'])
- else:
- messages_history.append(write_message)
- closeFid(write_message.tid,kwargs['fid'])
- errback(OperationFailure('Failed to store %s on %s: Write failed'%(path,service_name),messages_history))
-
- defcloseFid(tid,fid,error=None,offset=None):
- m=SMB2Message(SMB2CloseRequest(fid))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,closeCB,errback,fid=fid,offset=offset,error=error)
- messages_history.append(m)
-
- defcloseCB(close_message,**kwargs):
- ifkwargs['offset']isnotNone:
- callback((file_obj,kwargs['offset']))# Note that this is a tuple of 2-elements
- elifkwargs['error']isnotNone:
- errback(OperationFailure('Failed to store %s on %s: Write failed'%(path,service_name),messages_history))
-
- ifnotself.connected_trees.has_key(service_name):
- defconnectCB(connect_message,**kwargs):
- messages_history.append(connect_message)
- ifconnect_message.status==0:
- self.connected_trees[service_name]=connect_message.tid
- sendCreate(connect_message.tid)
- else:
- errback(OperationFailure('Failed to store %s on %s: Unable to connect to shared device'%(path,service_name),messages_history))
-
- m=SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s'%(self.remote_name.upper(),service_name)))
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,connectCB,errback,path=service_name)
- messages_history.append(m)
- else:
- sendCreate(self.connected_trees[service_name])
-
-
- def_deleteFiles_SMB2(self,service_name,path_file_pattern,callback,errback,timeout=30):
- ifnotself.has_authenticated:
- raiseNotReadyError('SMB connection not authenticated')
-
- expiry_time=time.time()+timeout
- path=path_file_pattern.replace('/','\\')
- ifpath.startswith('\\'):
- path=path[1:]
- ifpath.endswith('\\'):
- path=path[:-1]
- messages_history=[]
-
- defsendCreate(tid):
- create_context_data=binascii.unhexlify("""
-28 00 00 00 10 00 04 00 00 00 18 00 10 00 00 00
-44 48 6e 51 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 18 00 00 00 10 00 04 00
-00 00 18 00 00 00 00 00 4d 78 41 63 00 00 00 00
-00 00 00 00 10 00 04 00 00 00 18 00 00 00 00 00
-51 46 69 64 00 00 00 00
-""".replace(' ','').replace('\n',''))
- m=SMB2Message(SMB2CreateRequest(path,
- file_attributes=0,
- access_mask=DELETE|FILE_READ_ATTRIBUTES,
- share_access=FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
- oplock=SMB2_OPLOCK_LEVEL_NONE,
- impersonation=SEC_IMPERSONATE,
- create_options=FILE_NON_DIRECTORY_FILE,
- create_disp=FILE_OPEN,
- create_context_data=create_context_data))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,createCB,errback,tid=tid)
- messages_history.append(m)
-
- defcreateCB(open_message,**kwargs):
- messages_history.append(open_message)
- ifopen_message.status==0:
- sendDelete(open_message.tid,open_message.payload.fid)
- else:
- errback(OperationFailure('Failed to delete %s on %s: Unable to open file'%(path,service_name),messages_history))
-
- defsendDelete(tid,fid):
- m=SMB2Message(SMB2SetInfoRequest(fid,
- additional_info=0,
- info_type=SMB2_INFO_FILE,
- file_info_class=0x0d,# SMB2_FILE_DISPOSITION_INFO
- data='\x01'))
- '''
- Resources:
- https://msdn.microsoft.com/en-us/library/cc246560.aspx
- https://msdn.microsoft.com/en-us/library/cc232098.aspx
- '''
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,deleteCB,errback,fid=fid)
- messages_history.append(m)
-
- defdeleteCB(delete_message,**kwargs):
- messages_history.append(delete_message)
- ifdelete_message.status==0:
- closeFid(delete_message.tid,kwargs['fid'],status=0)
- else:
- closeFid(delete_message.tid,kwargs['fid'],status=delete_message.status)
-
- defcloseFid(tid,fid,status=None):
- m=SMB2Message(SMB2CloseRequest(fid))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,closeCB,errback,status=status)
- messages_history.append(m)
-
- defcloseCB(close_message,**kwargs):
- ifkwargs['status']==0:
- callback(path_file_pattern)
- else:
- errback(OperationFailure('Failed to delete %s on %s: Delete failed'%(path,service_name),messages_history))
-
- ifnotself.connected_trees.has_key(service_name):
- defconnectCB(connect_message,**kwargs):
- messages_history.append(connect_message)
- ifconnect_message.status==0:
- self.connected_trees[service_name]=connect_message.tid
- sendCreate(connect_message.tid)
- else:
- errback(OperationFailure('Failed to delete %s on %s: Unable to connect to shared device'%(path,service_name),messages_history))
-
- m=SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s'%(self.remote_name.upper(),service_name)))
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,connectCB,errback,path=service_name)
- messages_history.append(m)
- else:
- sendCreate(self.connected_trees[service_name])
-
- def_resetFileAttributes_SMB2(self,service_name,path_file_pattern,callback,errback,timeout=30):
- ifnotself.has_authenticated:
- raiseNotReadyError('SMB connection not authenticated')
-
- expiry_time=time.time()+timeout
- path=path_file_pattern.replace('/','\\')
- ifpath.startswith('\\'):
- path=path[1:]
- ifpath.endswith('\\'):
- path=path[:-1]
- messages_history=[]
-
- defsendCreate(tid):
- create_context_data=binascii.unhexlify("""
-28 00 00 00 10 00 04 00 00 00 18 00 10 00 00 00
-44 48 6e 51 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 18 00 00 00 10 00 04 00
-00 00 18 00 00 00 00 00 4d 78 41 63 00 00 00 00
-00 00 00 00 10 00 04 00 00 00 18 00 00 00 00 00
-51 46 69 64 00 00 00 00
-""".replace(' ','').replace('\n',''))
-
- m=SMB2Message(SMB2CreateRequest(path,
- file_attributes=0,
- access_mask=FILE_WRITE_ATTRIBUTES,
- share_access=FILE_SHARE_READ|FILE_SHARE_WRITE,
- oplock=SMB2_OPLOCK_LEVEL_NONE,
- impersonation=SEC_IMPERSONATE,
- create_options=0,
- create_disp=FILE_OPEN,
- create_context_data=create_context_data))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,createCB,errback,tid=tid)
- messages_history.append(m)
-
- defcreateCB(open_message,**kwargs):
- messages_history.append(open_message)
- ifopen_message.status==0:
- sendReset(open_message.tid,open_message.payload.fid)
- else:
- errback(OperationFailure('Failed to reset attributes of %s on %s: Unable to open file'%(path,service_name),messages_history))
-
- defsendReset(tid,fid):
- m=SMB2Message(SMB2SetInfoRequest(fid,
- additional_info=0,
- info_type=SMB2_INFO_FILE,
- file_info_class=4,# FileBasicInformation
- data=struct.pack('qqqqii',0,0,0,0,0x80,0)))# FILE_ATTRIBUTE_NORMAL
- '''
- Resources:
- https://msdn.microsoft.com/en-us/library/cc246560.aspx
- https://msdn.microsoft.com/en-us/library/cc232064.aspx
- https://msdn.microsoft.com/en-us/library/cc232094.aspx
- https://msdn.microsoft.com/en-us/library/cc232110.aspx
- '''
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,resetCB,errback,fid=fid)
- messages_history.append(m)
-
- defresetCB(reset_message,**kwargs):
- messages_history.append(reset_message)
- ifreset_message.status==0:
- closeFid(reset_message.tid,kwargs['fid'],status=0)
- else:
- closeFid(reset_message.tid,kwargs['fid'],status=reset_message.status)
-
- defcloseFid(tid,fid,status=None):
- m=SMB2Message(SMB2CloseRequest(fid))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,closeCB,errback,status=status)
- messages_history.append(m)
-
- defcloseCB(close_message,**kwargs):
- ifkwargs['status']==0:
- callback(path_file_pattern)
- else:
- errback(OperationFailure('Failed to reset attributes of %s on %s: Reset failed'%(path,service_name),messages_history))
-
- ifnotself.connected_trees.has_key(service_name):
- defconnectCB(connect_message,**kwargs):
- messages_history.append(connect_message)
- ifconnect_message.status==0:
- self.connected_trees[service_name]=connect_message.tid
- sendCreate(connect_message.tid)
- else:
- errback(OperationFailure('Failed to reset attributes of %s on %s: Unable to connect to shared device'%(path,service_name),messages_history))
-
- m=SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s'%(self.remote_name.upper(),service_name)))
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,connectCB,errback,path=service_name)
- messages_history.append(m)
- else:
- sendCreate(self.connected_trees[service_name])
-
- def_createDirectory_SMB2(self,service_name,path,callback,errback,timeout=30):
- ifnotself.has_authenticated:
- raiseNotReadyError('SMB connection not authenticated')
-
- expiry_time=time.time()+timeout
- path=path.replace('/','\\')
- ifpath.startswith('\\'):
- path=path[1:]
- ifpath.endswith('\\'):
- path=path[:-1]
- messages_history=[]
-
- defsendCreate(tid):
- create_context_data=binascii.unhexlify("""
-28 00 00 00 10 00 04 00 00 00 18 00 10 00 00 00
-44 48 6e 51 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 18 00 00 00 10 00 04 00
-00 00 18 00 00 00 00 00 4d 78 41 63 00 00 00 00
-00 00 00 00 10 00 04 00 00 00 18 00 00 00 00 00
-51 46 69 64 00 00 00 00
-""".replace(' ','').replace('\n',''))
- m=SMB2Message(SMB2CreateRequest(path,
- file_attributes=0,
- access_mask=FILE_READ_DATA|FILE_WRITE_DATA|FILE_READ_EA|FILE_WRITE_EA|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES|READ_CONTROL|DELETE|SYNCHRONIZE,
- share_access=0,
- oplock=SMB2_OPLOCK_LEVEL_NONE,
- impersonation=SEC_IMPERSONATE,
- create_options=FILE_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT,
- create_disp=FILE_CREATE,
- create_context_data=create_context_data))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,createCB,errback)
- messages_history.append(m)
-
- defcreateCB(create_message,**kwargs):
- messages_history.append(create_message)
- ifcreate_message.status==0:
- closeFid(create_message.tid,create_message.payload.fid)
- else:
- errback(OperationFailure('Failed to create directory %s on %s: Create failed'%(path,service_name),messages_history))
-
- defcloseFid(tid,fid):
- m=SMB2Message(SMB2CloseRequest(fid))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,closeCB,errback)
- messages_history.append(m)
-
- defcloseCB(close_message,**kwargs):
- callback(path)
-
- ifnotself.connected_trees.has_key(service_name):
- defconnectCB(connect_message,**kwargs):
- messages_history.append(connect_message)
- ifconnect_message.status==0:
- self.connected_trees[service_name]=connect_message.tid
- sendCreate(connect_message.tid)
- else:
- errback(OperationFailure('Failed to create directory %s on %s: Unable to connect to shared device'%(path,service_name),messages_history))
-
- m=SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s'%(self.remote_name.upper(),service_name)))
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,connectCB,errback,path=service_name)
- messages_history.append(m)
- else:
- sendCreate(self.connected_trees[service_name])
-
- def_deleteDirectory_SMB2(self,service_name,path,callback,errback,timeout=30):
- ifnotself.has_authenticated:
- raiseNotReadyError('SMB connection not authenticated')
-
- expiry_time=time.time()+timeout
- path=path.replace('/','\\')
- ifpath.startswith('\\'):
- path=path[1:]
- ifpath.endswith('\\'):
- path=path[:-1]
- messages_history=[]
-
- defsendCreate(tid):
- create_context_data=binascii.unhexlify("""
-28 00 00 00 10 00 04 00 00 00 18 00 10 00 00 00
-44 48 6e 51 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 18 00 00 00 10 00 04 00
-00 00 18 00 00 00 00 00 4d 78 41 63 00 00 00 00
-00 00 00 00 10 00 04 00 00 00 18 00 00 00 00 00
-51 46 69 64 00 00 00 00
-""".replace(' ','').replace('\n',''))
- m=SMB2Message(SMB2CreateRequest(path,
- file_attributes=0,
- access_mask=DELETE|FILE_READ_ATTRIBUTES,
- share_access=FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
- oplock=SMB2_OPLOCK_LEVEL_NONE,
- impersonation=SEC_IMPERSONATE,
- create_options=FILE_DIRECTORY_FILE,
- create_disp=FILE_OPEN,
- create_context_data=create_context_data))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,createCB,errback,tid=tid)
- messages_history.append(m)
-
- defcreateCB(open_message,**kwargs):
- messages_history.append(open_message)
- ifopen_message.status==0:
- sendDelete(open_message.tid,open_message.payload.fid)
- else:
- errback(OperationFailure('Failed to delete %s on %s: Unable to open directory'%(path,service_name),messages_history))
-
- defsendDelete(tid,fid):
- m=SMB2Message(SMB2SetInfoRequest(fid,
- additional_info=0,
- info_type=SMB2_INFO_FILE,
- file_info_class=0x0d,# SMB2_FILE_DISPOSITION_INFO
- data='\x01'))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,deleteCB,errback,fid=fid)
- messages_history.append(m)
-
- defdeleteCB(delete_message,**kwargs):
- messages_history.append(delete_message)
- ifdelete_message.status==0:
- closeFid(delete_message.tid,kwargs['fid'],status=0)
- else:
- closeFid(delete_message.tid,kwargs['fid'],status=delete_message.status)
-
- defcloseFid(tid,fid,status=None):
- m=SMB2Message(SMB2CloseRequest(fid))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,closeCB,errback,status=status)
- messages_history.append(m)
-
- defcloseCB(close_message,**kwargs):
- ifkwargs['status']==0:
- callback(path)
- else:
- errback(OperationFailure('Failed to delete %s on %s: Delete failed'%(path,service_name),messages_history))
-
- ifnotself.connected_trees.has_key(service_name):
- defconnectCB(connect_message,**kwargs):
- messages_history.append(connect_message)
- ifconnect_message.status==0:
- self.connected_trees[service_name]=connect_message.tid
- sendCreate(connect_message.tid)
- else:
- errback(OperationFailure('Failed to delete %s on %s: Unable to connect to shared device'%(path,service_name),messages_history))
-
- m=SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s'%(self.remote_name.upper(),service_name)))
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,connectCB,errback,path=service_name)
- messages_history.append(m)
- else:
- sendCreate(self.connected_trees[service_name])
-
- def_rename_SMB2(self,service_name,old_path,new_path,callback,errback,timeout=30):
- ifnotself.has_authenticated:
- raiseNotReadyError('SMB connection not authenticated')
-
- expiry_time=time.time()+timeout
- messages_history=[]
-
- new_path=new_path.replace('/','\\')
- ifnew_path.startswith('\\'):
- new_path=new_path[1:]
- ifnew_path.endswith('\\'):
- new_path=new_path[:-1]
-
- old_path=old_path.replace('/','\\')
- ifold_path.startswith('\\'):
- old_path=old_path[1:]
- ifold_path.endswith('\\'):
- old_path=old_path[:-1]
-
- defsendCreate(tid):
- create_context_data=binascii.unhexlify("""
-28 00 00 00 10 00 04 00 00 00 18 00 10 00 00 00
-44 48 6e 51 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 18 00 00 00 10 00 04 00
-00 00 18 00 00 00 00 00 4d 78 41 63 00 00 00 00
-00 00 00 00 10 00 04 00 00 00 18 00 00 00 00 00
-51 46 69 64 00 00 00 00
-""".replace(' ','').replace('\n',''))
- m=SMB2Message(SMB2CreateRequest(old_path,
- file_attributes=0,
- access_mask=DELETE|FILE_READ_ATTRIBUTES|SYNCHRONIZE,
- share_access=FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
- oplock=SMB2_OPLOCK_LEVEL_NONE,
- impersonation=SEC_IMPERSONATE,
- create_options=FILE_SYNCHRONOUS_IO_NONALERT,
- create_disp=FILE_OPEN,
- create_context_data=create_context_data))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,createCB,errback,tid=tid)
- messages_history.append(m)
-
- defcreateCB(create_message,**kwargs):
- messages_history.append(create_message)
- ifcreate_message.status==0:
- sendRename(create_message.tid,create_message.payload.fid)
- else:
- errback(OperationFailure('Failed to rename %s on %s: Unable to open file/directory'%(old_path,service_name),messages_history))
-
- defsendRename(tid,fid):
- data='\x00'*16+struct.pack('<I',len(new_path)*2)+new_path.encode('UTF-16LE')
- m=SMB2Message(SMB2SetInfoRequest(fid,
- additional_info=0,
- info_type=SMB2_INFO_FILE,
- file_info_class=0x0a,# SMB2_FILE_RENAME_INFO
- data=data))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,renameCB,errback,fid=fid)
- messages_history.append(m)
-
- defrenameCB(rename_message,**kwargs):
- messages_history.append(rename_message)
- ifrename_message.status==0:
- closeFid(rename_message.tid,kwargs['fid'],status=0)
- else:
- closeFid(rename_message.tid,kwargs['fid'],status=rename_message.status)
-
- defcloseFid(tid,fid,status=None):
- m=SMB2Message(SMB2CloseRequest(fid))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,closeCB,errback,status=status)
- messages_history.append(m)
-
- defcloseCB(close_message,**kwargs):
- ifkwargs['status']==0:
- callback((old_path,new_path))
- else:
- errback(OperationFailure('Failed to rename %s on %s: Rename failed'%(old_path,service_name),messages_history))
-
- ifnotself.connected_trees.has_key(service_name):
- defconnectCB(connect_message,**kwargs):
- messages_history.append(connect_message)
- ifconnect_message.status==0:
- self.connected_trees[service_name]=connect_message.tid
- sendCreate(connect_message.tid)
- else:
- errback(OperationFailure('Failed to rename %s on %s: Unable to connect to shared device'%(old_path,service_name),messages_history))
-
- m=SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s'%(self.remote_name.upper(),service_name)))
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,connectCB,errback,path=service_name)
- messages_history.append(m)
- else:
- sendCreate(self.connected_trees[service_name])
-
- def_listSnapshots_SMB2(self,service_name,path,callback,errback,timeout=30):
- ifnotself.has_authenticated:
- raiseNotReadyError('SMB connection not authenticated')
-
- expiry_time=time.time()+timeout
- path=path.replace('/','\\')
- ifpath.startswith('\\'):
- path=path[1:]
- ifpath.endswith('\\'):
- path=path[:-1]
- messages_history=[]
-
- defsendCreate(tid):
- create_context_data=binascii.unhexlify("""
-28 00 00 00 10 00 04 00 00 00 18 00 10 00 00 00
-44 48 6e 51 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 10 00 04 00
-00 00 18 00 00 00 00 00 4d 78 41 63 00 00 00 00
-""".replace(' ','').replace('\n',''))
- m=SMB2Message(SMB2CreateRequest(path,
- file_attributes=0,
- access_mask=FILE_READ_DATA|FILE_READ_ATTRIBUTES|SYNCHRONIZE,
- share_access=FILE_SHARE_READ|FILE_SHARE_WRITE,
- oplock=SMB2_OPLOCK_LEVEL_NONE,
- impersonation=SEC_IMPERSONATE,
- create_options=FILE_SYNCHRONOUS_IO_NONALERT,
- create_disp=FILE_OPEN,
- create_context_data=create_context_data))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,createCB,errback,tid=tid)
- messages_history.append(m)
-
- defcreateCB(create_message,**kwargs):
- messages_history.append(create_message)
- ifcreate_message.status==0:
- sendEnumSnapshots(create_message.tid,create_message.payload.fid)
- else:
- errback(OperationFailure('Failed to list snapshots %s on %s: Unable to open file/directory'%(old_path,service_name),messages_history))
-
- defsendEnumSnapshots(tid,fid):
- m=SMB2Message(SMB2IoctlRequest(fid,
- ctlcode=0x00144064,# FSCTL_SRV_ENUMERATE_SNAPSHOTS
- flags=0x0001,
- in_data=''))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,enumSnapshotsCB,errback,tid=tid,fid=fid)
- messages_history.append(m)
-
- defenumSnapshotsCB(enum_message,**kwargs):
- messages_history.append(enum_message)
- ifenum_message.status==0:
- results=[]
- snapshots_count=struct.unpack('<I',enum_message.payload.out_data[4:8])[0]
- foriinrange(0,snapshots_count):
- s=enum_message.payload.out_data[12+i*50:12+48+i*50].decode('UTF-16LE')
- results.append(datetime(*map(int,(s[5:9],s[10:12],s[13:15],s[16:18],s[19:21],s[22:24]))))
- closeFid(kwargs['tid'],kwargs['fid'],results=results)
- else:
- closeFid(kwargs['tid'],kwargs['fid'],status=enum_message.status)
-
- defcloseFid(tid,fid,status=None,results=None):
- m=SMB2Message(SMB2CloseRequest(fid))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,closeCB,errback,status=status,results=results)
- messages_history.append(m)
-
- defcloseCB(close_message,**kwargs):
- ifkwargs['results']isnotNone:
- callback(kwargs['results'])
- else:
- errback(OperationFailure('Failed to list snapshots %s on %s: List failed'%(path,service_name),messages_history))
-
- ifnotself.connected_trees.has_key(service_name):
- defconnectCB(connect_message,**kwargs):
- messages_history.append(connect_message)
- ifconnect_message.status==0:
- self.connected_trees[service_name]=connect_message.tid
- sendCreate(connect_message.tid)
- else:
- errback(OperationFailure('Failed to list snapshots %s on %s: Unable to connect to shared device'%(path,service_name),messages_history))
-
- m=SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s'%(self.remote_name.upper(),service_name)))
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,connectCB,errback,path=service_name)
- messages_history.append(m)
- else:
- sendCreate(self.connected_trees[service_name])
-
- def_echo_SMB2(self,data,callback,errback,timeout=30):
- messages_history=[]
-
- defechoCB(echo_message,**kwargs):
- messages_history.append(echo_message)
- ifecho_message.status==0:
- callback(data)
- else:
- errback(OperationFailure('Echo failed',messages_history))
-
- m=SMB2Message(SMB2EchoRequest())
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,echoCB,errback)
- messages_history.append(m)
-
-
- #
- # SMB1 Methods Family
- #
-
- def_sendSMBMessage_SMB1(self,smb_message):
- ifsmb_message.mid==0:
- smb_message.mid=self._getNextMID_SMB1()
- ifnotsmb_message.uid:
- smb_message.uid=self.uid
- ifself.is_signing_active:
- smb_message.flags2|=SMB_FLAGS2_SMB_SECURITY_SIGNATURE
-
- # Increment the next_signing_id as described in [MS-CIFS] 3.2.4.1.3
- smb_message.security=self.next_signing_id
- self.next_signing_id+=2# All our defined messages currently have responses, so always increment by 2
- raw_data=smb_message.encode()
-
- md=ntlm.MD5(self.signing_session_key)
- ifself.signing_challenge_response:
- md.update(self.signing_challenge_response)
- md.update(raw_data)
- signature=md.digest()[:8]
-
- self.log.debug('MID is %d. Signing ID is %d. Signature is %s. Total raw message is %d bytes',smb_message.mid,smb_message.security,binascii.hexlify(signature),len(raw_data))
- smb_message.raw_data=raw_data[:14]+signature+raw_data[22:]
- else:
- smb_message.raw_data=smb_message.encode()
- self.sendNMBMessage(smb_message.raw_data)
-
- def_getNextMID_SMB1(self):
- self.mid+=1
- ifself.mid>=0xFFFF:# MID cannot be 0xFFFF. [MS-CIFS]: 2.2.1.6.2
- # We don't use MID of 0 as MID can be reused for SMB_COM_TRANSACTION2_SECONDARY messages
- # where if mid=0, _sendSMBMessage will re-assign new MID values again
- self.mid=1
- returnself.mid
-
- def_updateState_SMB1(self,message):
- ifmessage.isReply:
- ifmessage.command==SMB_COM_NEGOTIATE:
- ifnotmessage.status.hasError:
- self.has_negotiated=True
- self.log.info('SMB dialect negotiation successful (ExtendedSecurity:%s)',message.hasExtendedSecurity)
- self._updateServerInfo(message.payload)
- self._handleNegotiateResponse(message)
- else:
- raiseProtocolError('Unknown status value (0x%08X) in SMB_COM_NEGOTIATE'%message.status.internal_value,
- message.raw_data,message)
- elifmessage.command==SMB_COM_SESSION_SETUP_ANDX:
- ifmessage.hasExtendedSecurity:
- ifnotmessage.status.hasError:
- try:
- result=securityblob.decodeAuthResponseSecurityBlob(message.payload.security_blob)
- ifresult==securityblob.RESULT_ACCEPT_COMPLETED:
- self.log.debug('SMB uid is now %d',message.uid)
- self.uid=message.uid
- self.has_authenticated=True
- self.log.info('Authentication (with extended security) successful!')
- self.onAuthOK()
- else:
- raiseProtocolError('SMB_COM_SESSION_SETUP_ANDX status is 0 but security blob negResult value is %d'%result,message.raw_data,message)
- exceptsecurityblob.BadSecurityBlobError,ex:
- raiseProtocolError(str(ex),message.raw_data,message)
- elifmessage.status.internal_value==0xc0000016:# STATUS_MORE_PROCESSING_REQUIRED
- try:
- result,ntlm_token=securityblob.decodeChallengeSecurityBlob(message.payload.security_blob)
- ifresult==securityblob.RESULT_ACCEPT_INCOMPLETE:
- self._handleSessionChallenge(message,ntlm_token)
- except(securityblob.BadSecurityBlobError,securityblob.UnsupportedSecurityProvider),ex:
- raiseProtocolError(str(ex),message.raw_data,message)
- elifmessage.status.internal_value==0xc000006d:# STATUS_LOGON_FAILURE
- self.has_authenticated=False
- self.log.info('Authentication (with extended security) failed. Please check username and password. You may need to enable/disable NTLMv2 authentication.')
- self.onAuthFailed()
- else:
- raiseProtocolError('Unknown status value (0x%08X) in SMB_COM_SESSION_SETUP_ANDX (with extended security)'%message.status.internal_value,
- message.raw_data,message)
- else:
- ifmessage.status.internal_value==0:
- self.log.debug('SMB uid is now %d',message.uid)
- self.uid=message.uid
- self.has_authenticated=True
- self.log.info('Authentication (without extended security) successful!')
- self.onAuthOK()
- else:
- self.has_authenticated=False
- self.log.info('Authentication (without extended security) failed. Please check username and password')
- self.onAuthFailed()
- elifmessage.command==SMB_COM_TREE_CONNECT_ANDX:
- try:
- req=self.pending_requests[message.mid]
- exceptKeyError:
- pass
- else:
- ifnotmessage.status.hasError:
- self.connected_trees[req.kwargs['path']]=message.tid
-
- req=self.pending_requests.pop(message.mid,None)
- ifreq:
- req.callback(message,**req.kwargs)
- returnTrue
-
-
- def_updateServerInfo_SMB1(self,payload):
- self.capabilities=payload.capabilities
- self.security_mode=payload.security_mode
- self.max_raw_size=payload.max_raw_size
- self.max_buffer_size=payload.max_buffer_size
- self.max_mpx_count=payload.max_mpx_count
- self.use_plaintext_authentication=notbool(payload.security_mode&NEGOTIATE_ENCRYPT_PASSWORDS)
-
- ifself.use_plaintext_authentication:
- self.log.warning('Remote server only supports plaintext authentication. Your password can be stolen easily over the network.')
-
-
- def_handleSessionChallenge_SMB1(self,message,ntlm_token):
- assertmessage.hasExtendedSecurity
-
- ifmessage.uidandnotself.uid:
- self.uid=message.uid
-
- server_challenge,server_flags,server_info=ntlm.decodeChallengeMessage(ntlm_token)
- ifself.use_ntlm_v2:
- self.log.info('Performing NTLMv2 authentication (with extended security) with server challenge "%s"',binascii.hexlify(server_challenge))
- nt_challenge_response,lm_challenge_response,session_key=ntlm.generateChallengeResponseV2(self.password,
- self.username,
- server_challenge,
- server_info,
- self.domain)
-
- else:
- self.log.info('Performing NTLMv1 authentication (with extended security) with server challenge "%s"',binascii.hexlify(server_challenge))
- nt_challenge_response,lm_challenge_response,session_key=ntlm.generateChallengeResponseV1(self.password,server_challenge,True)
-
- ntlm_data=ntlm.generateAuthenticateMessage(server_flags,
- nt_challenge_response,
- lm_challenge_response,
- session_key,
- self.username,
- self.domain)
-
- ifself.log.isEnabledFor(logging.DEBUG):
- self.log.debug('NT challenge response is "%s" (%d bytes)',binascii.hexlify(nt_challenge_response),len(nt_challenge_response))
- self.log.debug('LM challenge response is "%s" (%d bytes)',binascii.hexlify(lm_challenge_response),len(lm_challenge_response))
-
- blob=securityblob.generateAuthSecurityBlob(ntlm_data)
- self._sendSMBMessage(SMBMessage(ComSessionSetupAndxRequest__WithSecurityExtension(0,blob)))
-
- ifself.security_mode&NEGOTIATE_SECURITY_SIGNATURES_REQUIRE:
- self.log.info('Server requires all SMB messages to be signed')
- self.is_signing_active=(self.sign_options!=SMB.SIGN_NEVER)
- elifself.security_mode&NEGOTIATE_SECURITY_SIGNATURES_ENABLE:
- self.log.info('Server supports SMB signing')
- self.is_signing_active=(self.sign_options==SMB.SIGN_WHEN_SUPPORTED)
- else:
- self.is_signing_active=False
-
- ifself.is_signing_active:
- self.log.info("SMB signing activated. All SMB messages will be signed.")
- self.signing_session_key=session_key
- ifself.capabilities&CAP_EXTENDED_SECURITY:
- self.signing_challenge_response=None
- else:
- self.signing_challenge_response=blob
- else:
- self.log.info("SMB signing deactivated. SMB messages will NOT be signed.")
-
-
- def_handleNegotiateResponse_SMB1(self,message):
- ifmessage.uidandnotself.uid:
- self.uid=message.uid
-
- ifmessage.hasExtendedSecurityormessage.payload.supportsExtendedSecurity:
- ntlm_data=ntlm.generateNegotiateMessage()
- blob=securityblob.generateNegotiateSecurityBlob(ntlm_data)
- self._sendSMBMessage(SMBMessage(ComSessionSetupAndxRequest__WithSecurityExtension(message.payload.session_key,blob)))
- else:
- nt_password,_,_=ntlm.generateChallengeResponseV1(self.password,message.payload.challenge,False)
- self.log.info('Performing NTLMv1 authentication (without extended security) with challenge "%s" and hashed password of "%s"',
- binascii.hexlify(message.payload.challenge),
- binascii.hexlify(nt_password))
- self._sendSMBMessage(SMBMessage(ComSessionSetupAndxRequest__NoSecurityExtension(message.payload.session_key,
- self.username,
- nt_password,
- True,
- self.domain)))
-
- def_listShares_SMB1(self,callback,errback,timeout=30):
- ifnotself.has_authenticated:
- raiseNotReadyError('SMB connection not authenticated')
-
- expiry_time=time.time()+timeout
- path='IPC$'
- messages_history=[]
-
- defconnectSrvSvc(tid):
- m=SMBMessage(ComNTCreateAndxRequest('\\srvsvc',
- flags=NT_CREATE_REQUEST_EXTENDED_RESPONSE,
- access_mask=READ_CONTROL|FILE_WRITE_ATTRIBUTES|FILE_READ_ATTRIBUTES|FILE_WRITE_EA|FILE_READ_EA|FILE_APPEND_DATA|FILE_WRITE_DATA|FILE_READ_DATA,
- share_access=FILE_SHARE_READ|FILE_SHARE_WRITE,
- create_disp=FILE_OPEN,
- create_options=FILE_OPEN_NO_RECALL|FILE_NON_DIRECTORY_FILE,
- impersonation=SEC_IMPERSONATE,
- security_flags=0))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,connectSrvSvcCB,errback)
- messages_history.append(m)
-
- defconnectSrvSvcCB(create_message,**kwargs):
- messages_history.append(create_message)
- ifnotcreate_message.status.hasError:
- call_id=self._getNextRPCCallID()
- # See [MS-CIFS]: 2.2.5.6.1 for more information on TRANS_TRANSACT_NMPIPE (0x0026) parameters
- setup_bytes=struct.pack('<HH',0x0026,create_message.payload.fid)
- # The data_bytes are binding call to Server Service RPC using DCE v1.1 RPC over SMB. See [MS-SRVS] and [C706]
- # If you wish to understand the meanings of the byte stream, I would suggest you use a recent version of WireShark to packet capture the stream
- data_bytes= \
- binascii.unhexlify("""05 00 0b 03 10 00 00 00 48 00 00 00""".replace(' ',''))+ \
- struct.pack('<I',call_id)+ \
- binascii.unhexlify("""
-b8 10 b8 10 00 00 00 00 01 00 00 00 00 00 01 00
-c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88
-03 00 00 00 04 5d 88 8a eb 1c c9 11 9f e8 08 00
-2b 10 48 60 02 00 00 00""".replace(' ','').replace('\n',''))
- m=SMBMessage(ComTransactionRequest(max_params_count=0,
- max_data_count=4280,
- max_setup_count=0,
- data_bytes=data_bytes,
- setup_bytes=setup_bytes))
- m.tid=create_message.tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,rpcBindCB,errback,fid=create_message.payload.fid)
- messages_history.append(m)
- else:
- errback(OperationFailure('Failed to list shares: Unable to locate Server Service RPC endpoint',messages_history))
-
- defrpcBindCB(trans_message,**kwargs):
- messages_history.append(trans_message)
- ifnottrans_message.status.hasError:
- call_id=self._getNextRPCCallID()
-
- padding=''
- server_len=len(self.remote_name)+1
- server_bytes_len=server_len*2
- ifserver_len%2!=0:
- padding='\0\0'
- server_bytes_len+=2
-
- # See [MS-CIFS]: 2.2.5.6.1 for more information on TRANS_TRANSACT_NMPIPE (0x0026) parameters
- setup_bytes=struct.pack('<HH',0x0026,kwargs['fid'])
- # The data bytes are the RPC call to NetrShareEnum (Opnum 15) at Server Service RPC.
- # If you wish to understand the meanings of the byte stream, I would suggest you use a recent version of WireShark to packet capture the stream
- data_bytes= \
- binascii.unhexlify("""05 00 00 03 10 00 00 00""".replace(' ',''))+ \
- struct.pack('<HHI',72+server_bytes_len,0,call_id)+ \
- binascii.unhexlify("""4c 00 00 00 00 00 0f 00 00 00 02 00""".replace(' ',''))+ \
- struct.pack('<III',server_len,0,server_len)+ \
- (self.remote_name+'\0').encode('UTF-16LE')+padding+ \
- binascii.unhexlify("""
-01 00 00 00 01 00 00 00 04 00 02 00 00 00 00 00
-00 00 00 00 ff ff ff ff 08 00 02 00 00 00 00 00
-""".replace(' ','').replace('\n',''))
- m=SMBMessage(ComTransactionRequest(max_params_count=0,
- max_data_count=4280,
- max_setup_count=0,
- data_bytes=data_bytes,
- setup_bytes=setup_bytes))
- m.tid=trans_message.tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,listShareResultsCB,errback,fid=kwargs['fid'])
- messages_history.append(m)
- else:
- closeFid(trans_message.tid,kwargs['fid'])
- errback(OperationFailure('Failed to list shares: Unable to bind to Server Service RPC endpoint',messages_history))
-
- deflistShareResultsCB(result_message,**kwargs):
- messages_history.append(result_message)
- ifnotresult_message.status.hasError:
- # The payload.data_bytes will contain the results of the RPC call to NetrShareEnum (Opnum 15) at Server Service RPC.
- data_bytes=result_message.payload.data_bytes
-
- iford(data_bytes[3])&0x02==0:
- sendReadRequest(result_message.tid,kwargs['fid'],data_bytes)
- else:
- decodeResults(result_message.tid,kwargs['fid'],data_bytes)
- else:
- closeFid(result_message.tid,kwargs['fid'])
- errback(OperationFailure('Failed to list shares: Unable to retrieve shared device list',messages_history))
-
- defdecodeResults(tid,fid,data_bytes):
- shares_count=struct.unpack('<I',data_bytes[36:40])[0]
- results=[]# A list of SharedDevice instances
- offset=36+12# You need to study the byte stream to understand the meaning of these constants
- foriinrange(0,shares_count):
- results.append(SharedDevice(struct.unpack('<I',data_bytes[offset+4:offset+8])[0],None,None))
- offset+=12
-
- foriinrange(0,shares_count):
- max_length,_,length=struct.unpack('<III',data_bytes[offset:offset+12])
- offset+=12
- results[i].name=unicode(data_bytes[offset:offset+length*2-2],'UTF-16LE')
-
- iflength%2!=0:
- offset+=(length*2+2)
- else:
- offset+=(length*2)
-
- max_length,_,length=struct.unpack('<III',data_bytes[offset:offset+12])
- offset+=12
- results[i].comments=unicode(data_bytes[offset:offset+length*2-2],'UTF-16LE')
-
- iflength%2!=0:
- offset+=(length*2+2)
- else:
- offset+=(length*2)
-
- closeFid(tid,fid)
- callback(results)
-
- defsendReadRequest(tid,fid,data_bytes):
- read_count=min(4280,self.max_raw_size-2)
- m=SMBMessage(ComReadAndxRequest(fid=fid,
- offset=0,
- max_return_bytes_count=read_count,
- min_return_bytes_count=read_count))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,readCB,errback,fid=fid,data_bytes=data_bytes)
-
- defreadCB(read_message,**kwargs):
- messages_history.append(read_message)
- ifnotread_message.status.hasError:
- data_len=read_message.payload.data_length
- data_bytes=read_message.payload.data
-
- iford(data_bytes[3])&0x02==0:
- sendReadRequest(read_message.tid,kwargs['fid'],kwargs['data_bytes']+data_bytes[24:data_len-24])
- else:
- decodeResults(read_message.tid,kwargs['fid'],kwargs['data_bytes']+data_bytes[24:data_len-24])
- else:
- closeFid(read_message.tid,kwargs['fid'])
- errback(OperationFailure('Failed to list shares: Unable to retrieve shared device list',messages_history))
-
- defcloseFid(tid,fid):
- m=SMBMessage(ComCloseRequest(fid))
- m.tid=tid
- self._sendSMBMessage(m)
- messages_history.append(m)
-
- defconnectCB(connect_message,**kwargs):
- messages_history.append(connect_message)
- ifnotconnect_message.status.hasError:
- self.connected_trees[path]=connect_message.tid
- connectSrvSvc(connect_message.tid)
- else:
- errback(OperationFailure('Failed to list shares: Unable to connect to IPC$',messages_history))
-
- m=SMBMessage(ComTreeConnectAndxRequest(r'\\%s\%s'%(self.remote_name.upper(),path),SERVICE_ANY,''))
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,connectCB,errback,path=path)
- messages_history.append(m)
-
- def_listPath_SMB1(self,service_name,path,callback,errback,search,pattern,timeout=30):
- ifnotself.has_authenticated:
- raiseNotReadyError('SMB connection not authenticated')
-
- expiry_time=time.time()+timeout
- path=path.replace('/','\\')
- ifnotpath.endswith('\\'):
- path+='\\'
- messages_history=[]
- results=[]
-
- defsendFindFirst(tid,support_dfs=False):
- setup_bytes=struct.pack('<H',0x0001)# TRANS2_FIND_FIRST2 sub-command. See [MS-CIFS]: 2.2.6.2.1
- params_bytes= \
- struct.pack('<HHHHI',
- search,# SearchAttributes
- 100,# SearchCount
- 0x0006,# Flags: SMB_FIND_CLOSE_AT_EOS | SMB_FIND_RETURN_RESUME_KEYS
- 0x0104,# InfoLevel: SMB_FIND_FILE_BOTH_DIRECTORY_INFO
- 0x0000)# SearchStorageType
- ifsupport_dfs:
- params_bytes+=("\\"+self.remote_name+"\\"+service_name+path+pattern+'\0').encode('UTF-16LE')
- else:
- params_bytes+=(path+pattern).encode('UTF-16LE')
-
- m=SMBMessage(ComTransaction2Request(max_params_count=10,
- max_data_count=16644,
- max_setup_count=0,
- params_bytes=params_bytes,
- setup_bytes=setup_bytes))
- m.tid=tid
- ifsupport_dfs:
- m.flags2|=SMB_FLAGS2_DFS
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,findFirstCB,errback,support_dfs=support_dfs)
- messages_history.append(m)
-
- defdecodeFindStruct(data_bytes):
- # SMB_FIND_FILE_BOTH_DIRECTORY_INFO structure. See [MS-CIFS]: 2.2.8.1.7 and [MS-SMB]: 2.2.8.1.1
- info_format='<IIQQQQQQIIIBB24s'
- info_size=struct.calcsize(info_format)
-
- data_length=len(data_bytes)
- offset=0
- whileoffset<data_length:
- ifoffset+info_size>data_length:
- returndata_bytes[offset:]
-
- next_offset,_, \
- create_time,last_access_time,last_write_time,last_attr_change_time, \
- file_size,alloc_size,file_attributes,filename_length,ea_size, \
- short_name_length,_,short_name=struct.unpack(info_format,data_bytes[offset:offset+info_size])
-
- offset2=offset+info_size
- ifoffset2+filename_length>data_length:
- returndata_bytes[offset:]
-
- filename=data_bytes[offset2:offset2+filename_length].decode('UTF-16LE')
- short_name=short_name.decode('UTF-16LE')
- results.append(SharedFile(convertFILETIMEtoEpoch(create_time),convertFILETIMEtoEpoch(last_access_time),
- convertFILETIMEtoEpoch(last_write_time),convertFILETIMEtoEpoch(last_attr_change_time),
- file_size,alloc_size,file_attributes,short_name,filename))
-
- ifnext_offset:
- offset+=next_offset
- else:
- break
- return''
-
- deffindFirstCB(find_message,**kwargs):
- messages_history.append(find_message)
- ifnotfind_message.status.hasError:
- ifnotkwargs.has_key('total_count'):
- # TRANS2_FIND_FIRST2 response. [MS-CIFS]: 2.2.6.2.2
- sid,search_count,end_of_search,_,last_name_offset=struct.unpack('<HHHHH',find_message.payload.params_bytes[:10])
- kwargs.update({'sid':sid,'end_of_search':end_of_search,'last_name_offset':last_name_offset,'data_buf':''})
- else:
- sid,end_of_search,last_name_offset=kwargs['sid'],kwargs['end_of_search'],kwargs['last_name_offset']
-
- send_next=True
- iffind_message.payload.data_bytes:
- d=decodeFindStruct(kwargs['data_buf']+find_message.payload.data_bytes)
- ifnotkwargs.has_key('data_count'):
- iflen(find_message.payload.data_bytes)!=find_message.payload.total_data_count:
- kwargs.update({'data_count':len(find_message.payload.data_bytes),
- 'total_count':find_message.payload.total_data_count,
- 'data_buf':d,
- })
- send_next=False
- else:
- kwargs['data_count']+=len(find_message.payload.data_bytes)
- kwargs['total_count']=min(find_message.payload.total_data_count,kwargs['total_count'])
- kwargs['data_buf']=d
- ifkwargs['data_count']!=kwargs['total_count']:
- send_next=False
-
- ifnotsend_next:
- self.pending_requests[find_message.mid]=_PendingRequest(find_message.mid,expiry_time,findFirstCB,errback,**kwargs)
- elifend_of_search:
- callback(results)
- else:
- sendFindNext(find_message.tid,sid,last_name_offset,kwargs.get('support_dfs',False))
- else:
- errback(OperationFailure('Failed to list %s on %s: Unable to retrieve file list'%(path,service_name),messages_history))
-
- defsendFindNext(tid,sid,resume_key,support_dfs=False):
- setup_bytes=struct.pack('<H',0x0002)# TRANS2_FIND_NEXT2 sub-command. See [MS-CIFS]: 2.2.6.3.1
- params_bytes= \
- struct.pack('<HHHIH',
- sid,# SID
- 100,# SearchCount
- 0x0104,# InfoLevel: SMB_FIND_FILE_BOTH_DIRECTORY_INFO
- resume_key,# ResumeKey
- 0x000a)# Flags: SMB_FIND_RETURN_RESUME_KEYS | SMB_FIND_CLOSE_AT_EOS | SMB_FIND_RETURN_RESUME_KEYS
- ifsupport_dfs:
- params_bytes+=("\\"+self.remote_name+"\\"+service_name+path+pattern+'\0').encode('UTF-16LE')
- else:
- params_bytes+=(path+pattern).encode('UTF-16LE')
-
- m=SMBMessage(ComTransaction2Request(max_params_count=10,
- max_data_count=16644,
- max_setup_count=0,
- params_bytes=params_bytes,
- setup_bytes=setup_bytes))
- m.tid=tid
- ifsupport_dfs:
- m.flags2|=SMB_FLAGS2_DFS
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,findNextCB,errback,sid=sid,support_dfs=support_dfs)
- messages_history.append(m)
-
- deffindNextCB(find_message,**kwargs):
- messages_history.append(find_message)
- ifnotfind_message.status.hasError:
- ifnotkwargs.has_key('total_count'):
- # TRANS2_FIND_NEXT2 response. [MS-CIFS]: 2.2.6.3.2
- search_count,end_of_search,_,last_name_offset=struct.unpack('<HHHH',find_message.payload.params_bytes[:8])
- kwargs.update({'end_of_search':end_of_search,'last_name_offset':last_name_offset,'data_buf':''})
- else:
- end_of_search,last_name_offset=kwargs['end_of_search'],kwargs['last_name_offset']
-
- send_next=True
- iffind_message.payload.data_bytes:
- d=decodeFindStruct(kwargs['data_buf']+find_message.payload.data_bytes)
- ifnotkwargs.has_key('data_count'):
- iflen(find_message.payload.data_bytes)!=find_message.payload.total_data_count:
- kwargs.update({'data_count':len(find_message.payload.data_bytes),
- 'total_count':find_message.payload.total_data_count,
- 'data_buf':d,
- })
- send_next=False
- else:
- kwargs['data_count']+=len(find_message.payload.data_bytes)
- kwargs['total_count']=min(find_message.payload.total_data_count,kwargs['total_count'])
- kwargs['data_buf']=d
- ifkwargs['data_count']!=kwargs['total_count']:
- send_next=False
-
- ifnotsend_next:
- self.pending_requests[find_message.mid]=_PendingRequest(find_message.mid,expiry_time,findNextCB,errback,**kwargs)
- elifend_of_search:
- callback(results)
- else:
- sendFindNext(find_message.tid,kwargs['sid'],last_name_offset,kwargs.get('support_dfs',False))
- else:
- errback(OperationFailure('Failed to list %s on %s: Unable to retrieve file list'%(path,service_name),messages_history))
-
- defsendDFSReferral(tid):
- setup_bytes=struct.pack('<H',0x0010)# TRANS2_GET_DFS_REFERRAL sub-command. See [MS-CIFS]: 2.2.6.16.1
- params_bytes=struct.pack('<H',3)# Max referral level 3
- params_bytes+=("\\"+self.remote_name+"\\"+service_name).encode('UTF-16LE')
-
- m=SMBMessage(ComTransaction2Request(max_params_count=10,
- max_data_count=16644,
- max_setup_count=0,
- params_bytes=params_bytes,
- setup_bytes=setup_bytes))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,dfsReferralCB,errback)
- messages_history.append(m)
-
- defdfsReferralCB(dfs_message,**kwargs):
- sendFindFirst(dfs_message.tid,True)
-
- ifnotself.connected_trees.has_key(service_name):
- defconnectCB(connect_message,**kwargs):
- messages_history.append(connect_message)
- ifnotconnect_message.status.hasError:
- self.connected_trees[service_name]=connect_message.tid
- ifconnect_message.payload.optional_support&SMB_TREE_CONNECTX_SUPPORT_DFS:
- sendDFSReferral(connect_message.tid)
- else:
- sendFindFirst(connect_message.tid,False)
- else:
- errback(OperationFailure('Failed to list %s on %s: Unable to connect to shared device'%(path,service_name),messages_history))
-
- m=SMBMessage(ComTreeConnectAndxRequest(r'\\%s\%s'%(self.remote_name.upper(),service_name),SERVICE_ANY,''))
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,connectCB,errback,path=service_name)
- messages_history.append(m)
- else:
- sendFindFirst(self.connected_trees[service_name])
-
- def_getAttributes_SMB1(self,service_name,path,callback,errback,timeout=30):
- ifnotself.has_authenticated:
- raiseNotReadyError('SMB connection not authenticated')
-
- expiry_time=time.time()+timeout
- path=path.replace('/','\\')
- ifpath.startswith('\\'):
- path=path[1:]
- ifpath.endswith('\\'):
- path=path[:-1]
- messages_history=[]
-
- defsendQuery(tid):
- setup_bytes=struct.pack('<H',0x0005)# TRANS2_QUERY_PATH_INFORMATION sub-command. See [MS-CIFS]: 2.2.6.6.1
- params_bytes= \
- struct.pack('<HI',
- 0x0107,# SMB_QUERY_FILE_ALL_INFO ([MS-CIFS] 2.2.2.3.3)
- 0x0000)# Reserved
- params_bytes+=(path+'\0').encode('UTF-16LE')
-
- m=SMBMessage(ComTransaction2Request(max_params_count=2,
- max_data_count=65535,
- max_setup_count=0,
- params_bytes=params_bytes,
- setup_bytes=setup_bytes))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,queryCB,errback)
- messages_history.append(m)
-
- defqueryCB(query_message,**kwargs):
- messages_history.append(query_message)
- ifnotquery_message.status.hasError:
- info_format='<QQQQIIQQ'
- info_size=struct.calcsize(info_format)
- create_time,last_access_time,last_write_time,last_attr_change_time, \
- file_attributes,_,alloc_size,file_size=struct.unpack(info_format,query_message.payload.data_bytes[:info_size])
-
- info=SharedFile(create_time,last_access_time,last_write_time,last_attr_change_time,
- file_size,alloc_size,file_attributes,unicode(path),unicode(path))
- callback(info)
- else:
- errback(OperationFailure('Failed to get attributes for %s on %s: Read failed'%(path,service_name),messages_history))
-
- ifnotself.connected_trees.has_key(service_name):
- defconnectCB(connect_message,**kwargs):
- messages_history.append(connect_message)
- ifnotconnect_message.status.hasError:
- self.connected_trees[service_name]=connect_message.tid
- sendQuery(connect_message.tid)
- else:
- errback(OperationFailure('Failed to get attributes for %s on %s: Unable to connect to shared device'%(path,service_name),messages_history))
-
- m=SMBMessage(ComTreeConnectAndxRequest(r'\\%s\%s'%(self.remote_name.upper(),service_name),SERVICE_ANY,''))
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,connectCB,errback,path=service_name)
- messages_history.append(m)
- else:
- sendQuery(self.connected_trees[service_name])
-
- def_retrieveFile_SMB1(self,service_name,path,file_obj,callback,errback,timeout=30):
- returnself._retrieveFileFromOffset(service_name,path,file_obj,callback,errback,0L,-1L,timeout)
-
- def_retrieveFileFromOffset_SMB1(self,service_name,path,file_obj,callback,errback,starting_offset,max_length,timeout=30):
- ifnotself.has_authenticated:
- raiseNotReadyError('SMB connection not authenticated')
-
- path=path.replace('/','\\')
- messages_history=[]
-
- defsendOpen(tid):
- m=SMBMessage(ComOpenAndxRequest(filename=path,
- access_mode=0x0040,# Sharing mode: Deny nothing to others
- open_mode=0x0001,# Failed if file does not exist
- search_attributes=SMB_FILE_ATTRIBUTE_HIDDEN|SMB_FILE_ATTRIBUTE_SYSTEM,
- timeout=timeout*1000))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,openCB,errback)
- messages_history.append(m)
-
- defopenCB(open_message,**kwargs):
- messages_history.append(open_message)
- ifnotopen_message.status.hasError:
- ifmax_length==0:
- closeFid(open_message.tid,open_message.payload.fid)
- callback((file_obj,open_message.payload.file_attributes,0L))
- else:
- sendRead(open_message.tid,open_message.payload.fid,starting_offset,open_message.payload.file_attributes,0L,max_length)
- else:
- errback(OperationFailure('Failed to retrieve %s on %s: Unable to open file'%(path,service_name),messages_history))
-
- defsendRead(tid,fid,offset,file_attributes,read_len,remaining_len):
- read_count=self.max_raw_size-2
- m=SMBMessage(ComReadAndxRequest(fid=fid,
- offset=offset,
- max_return_bytes_count=read_count,
- min_return_bytes_count=min(0xFFFF,read_count)))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,readCB,errback,fid=fid,offset=offset,file_attributes=file_attributes,
- read_len=read_len,remaining_len=remaining_len)
-
- defreadCB(read_message,**kwargs):
- # To avoid crazy memory usage when retrieving large files, we do not save every read_message in messages_history.
- ifnotread_message.status.hasError:
- read_len=kwargs['read_len']
- remaining_len=kwargs['remaining_len']
- data_len=read_message.payload.data_length
- ifmax_length>0:
- ifdata_len>remaining_len:
- file_obj.write(read_message.payload.data[:remaining_len])
- read_len+=remaining_len
- remaining_len=0
- else:
- file_obj.write(read_message.payload.data)
- remaining_len-=data_len
- read_len+=data_len
- else:
- file_obj.write(read_message.payload.data)
- read_len+=data_len
-
- if(max_length>0andremaining_len<=0)ordata_len<(self.max_raw_size-2):
- closeFid(read_message.tid,kwargs['fid'])
- callback((file_obj,kwargs['file_attributes'],read_len))# Note that this is a tuple of 3-elements
- else:
- sendRead(read_message.tid,kwargs['fid'],kwargs['offset']+data_len,kwargs['file_attributes'],read_len,remaining_len)
- else:
- messages_history.append(read_message)
- closeFid(read_message.tid,kwargs['fid'])
- errback(OperationFailure('Failed to retrieve %s on %s: Read failed'%(path,service_name),messages_history))
-
- defcloseFid(tid,fid):
- m=SMBMessage(ComCloseRequest(fid))
- m.tid=tid
- self._sendSMBMessage(m)
- messages_history.append(m)
-
- ifnotself.connected_trees.has_key(service_name):
- defconnectCB(connect_message,**kwargs):
- messages_history.append(connect_message)
- ifnotconnect_message.status.hasError:
- self.connected_trees[service_name]=connect_message.tid
- sendOpen(connect_message.tid)
- else:
- errback(OperationFailure('Failed to retrieve %s on %s: Unable to connect to shared device'%(path,service_name),messages_history))
-
- m=SMBMessage(ComTreeConnectAndxRequest(r'\\%s\%s'%(self.remote_name.upper(),service_name),SERVICE_ANY,''))
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,connectCB,errback,path=service_name)
- messages_history.append(m)
- else:
- sendOpen(self.connected_trees[service_name])
-
- def_storeFile_SMB1(self,service_name,path,file_obj,callback,errback,timeout=30):
- self._storeFileFromOffset_SMB1(service_name,path,file_obj,callback,errback,0L,True,timeout)
-
- def_storeFileFromOffset_SMB1(self,service_name,path,file_obj,callback,errback,starting_offset,truncate=False,timeout=30):
- ifnotself.has_authenticated:
- raiseNotReadyError('SMB connection not authenticated')
-
- path=path.replace('/','\\')
- messages_history=[]
-
- defsendOpen(tid):
- m=SMBMessage(ComOpenAndxRequest(filename=path,
- access_mode=0x0041,# Sharing mode: Deny nothing to others + Open for writing
- open_mode=0x0012iftruncateelse0x0011,# Create file if file does not exist. Overwrite or append depending on truncate parameter.
- search_attributes=SMB_FILE_ATTRIBUTE_HIDDEN|SMB_FILE_ATTRIBUTE_SYSTEM,
- timeout=timeout*1000))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,openCB,errback)
- messages_history.append(m)
-
- defopenCB(open_message,**kwargs):
- messages_history.append(open_message)
- ifnotopen_message.status.hasError:
- sendWrite(open_message.tid,open_message.payload.fid,starting_offset)
- else:
- errback(OperationFailure('Failed to store %s on %s: Unable to open file'%(path,service_name),messages_history))
-
- defsendWrite(tid,fid,offset):
- # For message signing, the total SMB message size must be not exceed the max_buffer_size. Non-message signing does not have this limitation
- write_count=min((self.is_signing_activeand(self.max_buffer_size-64))orself.max_raw_size,0xFFFF-1)# Need to minus 1 byte from 0xFFFF because of the first NULL byte in the ComWriteAndxRequest message data
- data_bytes=file_obj.read(write_count)
- data_len=len(data_bytes)
- ifdata_len>0:
- m=SMBMessage(ComWriteAndxRequest(fid=fid,offset=offset,data_bytes=data_bytes))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,writeCB,errback,fid=fid,offset=offset+data_len)
- else:
- closeFid(tid,fid)
- callback((file_obj,offset))# Note that this is a tuple of 2-elements
-
- defwriteCB(write_message,**kwargs):
- # To avoid crazy memory usage when saving large files, we do not save every write_message in messages_history.
- ifnotwrite_message.status.hasError:
- sendWrite(write_message.tid,kwargs['fid'],kwargs['offset'])
- else:
- messages_history.append(write_message)
- closeFid(write_message.tid,kwargs['fid'])
- errback(OperationFailure('Failed to store %s on %s: Write failed'%(path,service_name),messages_history))
-
- defcloseFid(tid,fid):
- m=SMBMessage(ComCloseRequest(fid))
- m.tid=tid
- self._sendSMBMessage(m)
- messages_history.append(m)
-
- ifnotself.connected_trees.has_key(service_name):
- defconnectCB(connect_message,**kwargs):
- messages_history.append(connect_message)
- ifnotconnect_message.status.hasError:
- self.connected_trees[service_name]=connect_message.tid
- sendOpen(connect_message.tid)
- else:
- errback(OperationFailure('Failed to store %s on %s: Unable to connect to shared device'%(path,service_name),messages_history))
-
- m=SMBMessage(ComTreeConnectAndxRequest(r'\\%s\%s'%(self.remote_name.upper(),service_name),SERVICE_ANY,''))
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,connectCB,errback,path=service_name)
- messages_history.append(m)
- else:
- sendOpen(self.connected_trees[service_name])
-
- def_deleteFiles_SMB1(self,service_name,path_file_pattern,callback,errback,timeout=30):
- ifnotself.has_authenticated:
- raiseNotReadyError('SMB connection not authenticated')
-
- path=path_file_pattern.replace('/','\\')
- messages_history=[]
-
- defsendDelete(tid):
- m=SMBMessage(ComDeleteRequest(filename_pattern=path,
- search_attributes=SMB_FILE_ATTRIBUTE_HIDDEN|SMB_FILE_ATTRIBUTE_SYSTEM))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,deleteCB,errback)
- messages_history.append(m)
-
- defdeleteCB(delete_message,**kwargs):
- messages_history.append(delete_message)
- ifnotdelete_message.status.hasError:
- callback(path_file_pattern)
- else:
- errback(OperationFailure('Failed to store %s on %s: Delete failed'%(path,service_name),messages_history))
-
- ifnotself.connected_trees.has_key(service_name):
- defconnectCB(connect_message,**kwargs):
- messages_history.append(connect_message)
- ifnotconnect_message.status.hasError:
- self.connected_trees[service_name]=connect_message.tid
- sendDelete(connect_message.tid)
- else:
- errback(OperationFailure('Failed to delete %s on %s: Unable to connect to shared device'%(path,service_name),messages_history))
-
- m=SMBMessage(ComTreeConnectAndxRequest(r'\\%s\%s'%(self.remote_name.upper(),service_name),SERVICE_ANY,''))
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,connectCB,errback,path=service_name)
- messages_history.append(m)
- else:
- sendDelete(self.connected_trees[service_name])
-
- def_resetFileAttributes_SMB1(self,service_name,path_file_pattern,callback,errback,timeout=30):
- raiseNotReadyError('resetFileAttributes is not yet implemented for SMB1')
-
- def_createDirectory_SMB1(self,service_name,path,callback,errback,timeout=30):
- ifnotself.has_authenticated:
- raiseNotReadyError('SMB connection not authenticated')
-
- path=path.replace('/','\\')
- messages_history=[]
-
- defsendCreate(tid):
- m=SMBMessage(ComCreateDirectoryRequest(path))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,createCB,errback)
- messages_history.append(m)
-
- defcreateCB(create_message,**kwargs):
- messages_history.append(create_message)
- ifnotcreate_message.status.hasError:
- callback(path)
- else:
- errback(OperationFailure('Failed to create directory %s on %s: Create failed'%(path,service_name),messages_history))
-
- ifnotself.connected_trees.has_key(service_name):
- defconnectCB(connect_message,**kwargs):
- messages_history.append(connect_message)
- ifnotconnect_message.status.hasError:
- self.connected_trees[service_name]=connect_message.tid
- sendCreate(connect_message.tid)
- else:
- errback(OperationFailure('Failed to create directory %s on %s: Unable to connect to shared device'%(path,service_name),messages_history))
-
- m=SMBMessage(ComTreeConnectAndxRequest(r'\\%s\%s'%(self.remote_name.upper(),service_name),SERVICE_ANY,''))
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,connectCB,errback,path=service_name)
- messages_history.append(m)
- else:
- sendCreate(self.connected_trees[service_name])
-
- def_deleteDirectory_SMB1(self,service_name,path,callback,errback,timeout=30):
- ifnotself.has_authenticated:
- raiseNotReadyError('SMB connection not authenticated')
-
- path=path.replace('/','\\')
- messages_history=[]
-
- defsendDelete(tid):
- m=SMBMessage(ComDeleteDirectoryRequest(path))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,deleteCB,errback)
- messages_history.append(m)
-
- defdeleteCB(delete_message,**kwargs):
- messages_history.append(delete_message)
- ifnotdelete_message.status.hasError:
- callback(path)
- else:
- errback(OperationFailure('Failed to delete directory %s on %s: Delete failed'%(path,service_name),messages_history))
-
- ifnotself.connected_trees.has_key(service_name):
- defconnectCB(connect_message,**kwargs):
- messages_history.append(connect_message)
- ifnotconnect_message.status.hasError:
- self.connected_trees[service_name]=connect_message.tid
- sendDelete(connect_message.tid)
- else:
- errback(OperationFailure('Failed to delete %s on %s: Unable to connect to shared device'%(path,service_name),messages_history))
-
- m=SMBMessage(ComTreeConnectAndxRequest(r'\\%s\%s'%(self.remote_name.upper(),service_name),SERVICE_ANY,''))
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,connectCB,errback,path=service_name)
- messages_history.append(m)
- else:
- sendDelete(self.connected_trees[service_name])
-
- def_rename_SMB1(self,service_name,old_path,new_path,callback,errback,timeout=30):
- ifnotself.has_authenticated:
- raiseNotReadyError('SMB connection not authenticated')
-
- new_path=new_path.replace('/','\\')
- old_path=old_path.replace('/','\\')
- messages_history=[]
-
- defsendRename(tid):
- m=SMBMessage(ComRenameRequest(old_path=old_path,
- new_path=new_path,
- search_attributes=SMB_FILE_ATTRIBUTE_HIDDEN|SMB_FILE_ATTRIBUTE_SYSTEM))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,renameCB,errback)
- messages_history.append(m)
-
- defrenameCB(rename_message,**kwargs):
- messages_history.append(rename_message)
- ifnotrename_message.status.hasError:
- callback((old_path,new_path))# Note that this is a tuple of 2-elements
- else:
- errback(OperationFailure('Failed to rename %s on %s: Rename failed'%(old_path,service_name),messages_history))
-
- ifnotself.connected_trees.has_key(service_name):
- defconnectCB(connect_message,**kwargs):
- messages_history.append(connect_message)
- ifnotconnect_message.status.hasError:
- self.connected_trees[service_name]=connect_message.tid
- sendRename(connect_message.tid)
- else:
- errback(OperationFailure('Failed to rename %s on %s: Unable to connect to shared device'%(old_path,service_name),messages_history))
-
- m=SMBMessage(ComTreeConnectAndxRequest(r'\\%s\%s'%(self.remote_name.upper(),service_name),SERVICE_ANY,''))
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,connectCB,errback,path=service_name)
- messages_history.append(m)
- else:
- sendRename(self.connected_trees[service_name])
-
- def_listSnapshots_SMB1(self,service_name,path,callback,errback,timeout=30):
- ifnotself.has_authenticated:
- raiseNotReadyError('SMB connection not authenticated')
-
- expiry_time=time.time()+timeout
- path=path.replace('/','\\')
- ifnotpath.endswith('\\'):
- path+='\\'
- messages_history=[]
- results=[]
-
- defsendOpen(tid):
- m=SMBMessage(ComOpenAndxRequest(filename=path,
- access_mode=0x0040,# Sharing mode: Deny nothing to others
- open_mode=0x0001,# Failed if file does not exist
- search_attributes=0,
- timeout=timeout*1000))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,openCB,errback)
- messages_history.append(m)
-
- defopenCB(open_message,**kwargs):
- messages_history.append(open_message)
- ifnotopen_message.status.hasError:
- sendEnumSnapshots(open_message.tid,open_message.payload.fid)
- else:
- errback(OperationFailure('Failed to list snapshots %s on %s: Unable to open path'%(path,service_name),messages_history))
-
- defsendEnumSnapshots(tid,fid):
- # [MS-CIFS]: 2.2.7.2
- # [MS-SMB]: 2.2.7.2.1
- setup_bytes=struct.pack('<IHBB',
- 0x00144064,# [MS-SMB]: 2.2.7.2.1
- fid,# FID
- 0x01,# IsFctl
- 0)# IsFlags
- m=SMBMessage(ComNTTransactRequest(function=0x0002,# NT_TRANSACT_IOCTL. [MS-CIFS]: 2.2.7.2.1
- max_params_count=0,
- max_data_count=0xFFFF,
- max_setup_count=0,
- setup_bytes=setup_bytes))
- m.tid=tid
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,enumSnapshotsCB,errback,tid=tid,fid=fid)
- messages_history.append(m)
-
- defenumSnapshotsCB(enum_message,**kwargs):
- messages_history.append(enum_message)
- ifnotenum_message.status.hasError:
- results=[]
- snapshots_count=struct.unpack('<I',enum_message.payload.data_bytes[4:8])[0]
- foriinrange(0,snapshots_count):
- s=enum_message.payload.data_bytes[12+i*50:12+48+i*50].decode('UTF-16LE')
- results.append(datetime(*map(int,(s[5:9],s[10:12],s[13:15],s[16:18],s[19:21],s[22:24]))))
- closeFid(kwargs['tid'],kwargs['fid'])
- callback(results)
- else:
- closeFid(kwargs['tid'],kwargs['fid'])
- errback(OperationFailure('Failed to list snapshots %s on %s: Unable to list snapshots on path'%(path,service_name),messages_history))
-
- defcloseFid(tid,fid):
- m=SMBMessage(ComCloseRequest(fid))
- m.tid=tid
- self._sendSMBMessage(m)
- messages_history.append(m)
-
- ifnotself.connected_trees.has_key(service_name):
- defconnectCB(connect_message,**kwargs):
- messages_history.append(connect_message)
- ifnotconnect_message.status.hasError:
- self.connected_trees[service_name]=connect_message.tid
- sendOpen(connect_message.tid)
- else:
- errback(OperationFailure('Failed to list snapshots %s on %s: Unable to connect to shared device'%(path,service_name),messages_history))
-
- m=SMBMessage(ComTreeConnectAndxRequest(r'\\%s\%s'%(self.remote_name.upper(),service_name),SERVICE_ANY,''))
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,expiry_time,connectCB,errback,path=service_name)
- messages_history.append(m)
- else:
- sendOpen(self.connected_trees[service_name])
-
- def_echo_SMB1(self,data,callback,errback,timeout=30):
- messages_history=[]
-
- defechoCB(echo_message,**kwargs):
- messages_history.append(echo_message)
- ifnotecho_message.status.hasError:
- callback(echo_message.payload.data)
- else:
- errback(OperationFailure('Echo failed',messages_history))
-
- m=SMBMessage(ComEchoRequest(echo_data=data))
- self._sendSMBMessage(m)
- self.pending_requests[m.mid]=_PendingRequest(m.mid,int(time.time())+timeout,echoCB,errback)
- messages_history.append(m)
-
-
-
[docs]classSharedDevice:
- """
- Contains information about a single shared device on the remote server.
- """
-
- # The following constants are taken from [MS-SRVS]: 2.2.2.4
- # They are used to identify the type of shared resource from the results from the NetrShareEnum in Server Service RPC
- DISK_TREE=0x00
- PRINT_QUEUE=0x01
- COMM_DEVICE=0x02
- IPC=0x03
-
- def__init__(self,type,name,comments):
- self._type=type
- self.name=name#: An unicode string containing the name of the shared device
- self.comments=comments#: An unicode string containing the user description of the shared device
-
- @property
- deftype(self):
- """
- Returns one of the following integral constants.
- - SharedDevice.DISK_TREE
- - SharedDevice.PRINT_QUEUE
- - SharedDevice.COMM_DEVICE
- - SharedDevice.IPC
- """
- returnself._type&0xFFFF
-
- @property
- defisSpecial(self):
- """
- Returns True if this shared device is a special share reserved for interprocess communication (IPC$)
- or remote administration of the server (ADMIN$). Can also refer to administrative shares such as
- C$, D$, E$, and so forth
- """
- returnbool(self._type&0x80000000)
-
- @property
- defisTemporary(self):
- """
- Returns True if this is a temporary share that is not persisted for creation each time the file server initializes.
- """
- returnbool(self._type&0x40000000)
-
- def__unicode__(self):
- returnu'Shared device: %s (type:0x%02x comments:%s)'%(self.name,self.type,self.comments)
-
-
-
[docs]classSharedFile:
- """
- Contain information about a file/folder entry that is shared on the shared device.
-
- As an application developer, you should not need to instantiate a *SharedFile* instance directly in your application.
- These *SharedFile* instances are usually returned via a call to *listPath* method in :doc:`smb.SMBProtocol.SMBProtocolFactory<smb_SMBProtocolFactory>`.
-
- If you encounter *SharedFile* instance where its short_name attribute is empty but the filename attribute contains a short name which does not correspond
- to any files/folders on your remote shared device, it could be that the original filename on the file/folder entry on the shared device contains
- one of these prohibited characters: "\/[]:+|<>=;?,* (see [MS-CIFS]: 2.2.1.1.1 for more details).
- """
-
- def__init__(self,create_time,last_access_time,last_write_time,last_attr_change_time,file_size,alloc_size,file_attributes,short_name,filename):
- self.create_time=create_time#: Float value in number of seconds since 1970-01-01 00:00:00 to the time of creation of this file resource on the remote server
- self.last_access_time=last_access_time#: Float value in number of seconds since 1970-01-01 00:00:00 to the time of last access of this file resource on the remote server
- self.last_write_time=last_write_time#: Float value in number of seconds since 1970-01-01 00:00:00 to the time of last modification of this file resource on the remote server
- self.last_attr_change_time=last_attr_change_time#: Float value in number of seconds since 1970-01-01 00:00:00 to the time of last attribute change of this file resource on the remote server
- self.file_size=file_size#: File size in number of bytes
- self.alloc_size=alloc_size#: Total number of bytes allocated to store this file
- self.file_attributes=file_attributes#: A SMB_EXT_FILE_ATTR integer value. See [MS-CIFS]: 2.2.1.2.3
- self.short_name=short_name#: Unicode string containing the short name of this file (usually in 8.3 notation)
- self.filename=filename#: Unicode string containing the long filename of this file. Each OS has a limit to the length of this file name. On Windows, it is 256 characters.
-
- @property
- defisDirectory(self):
- """A convenient property to return True if this file resource is a directory on the remote server"""
- returnbool(self.file_attributes&ATTR_DIRECTORY)
-
- @property
- defisReadOnly(self):
- """A convenient property to return True if this file resource is read-only on the remote server"""
- returnbool(self.file_attributes&ATTR_READONLY)
-
- def__unicode__(self):
- returnu'Shared file: %s (FileSize:%d bytes, isDirectory:%s)'%(self.filename,self.file_size,self.isDirectory)
[docs]classSID(object):
+ """
+ A Windows security identifier. Represents a single principal, such a
+ user or a group, as a sequence of numbers consisting of the revision,
+ identifier authority, and a variable-length list of subauthorities.
+
+ See [MS-DTYP]: 2.4.2
+ """
+ def__init__(self,revision,identifier_authority,subauthorities):
+ #: Revision, should always be 1.
+ self.revision=revision
+ #: An integer representing the identifier authority.
+ self.identifier_authority=identifier_authority
+ #: A list of integers representing all subauthorities.
+ self.subauthorities=subauthorities
+
+ def__str__(self):
+ """
+ String representation, as specified in [MS-DTYP]: 2.4.2.1
+ """
+ ifself.identifier_authority>=2**32:
+ id_auth='%#x'%(self.identifier_authority,)
+ else:
+ id_auth=self.identifier_authority
+ auths=[self.revision,id_auth]+self.subauthorities
+ return'S-'+'-'.join(str(subauth)forsubauthinauths)
+
+ def__repr__(self):
+ return'SID(%r)'%(str(self),)
+
+ @classmethod
+ deffrom_bytes(cls,data,return_tail=False):
+ revision,subauth_count=struct.unpack('<BB',data[:2])
+ identifier_authority=struct.unpack('>Q','\x00\x00'+data[2:8])[0]
+ subauth_data=data[8:]
+ subauthorities=[struct.unpack('<L',subauth_data[4*i:4*(i+1)])[0]
+ foriinrange(subauth_count)]
+ sid=cls(revision,identifier_authority,subauthorities)
+ ifreturn_tail:
+ returnsid,subauth_data[4*subauth_count:]
+ returnsid
+
+
+
[docs]classACE(object):
+ """
+ Represents a single access control entry.
+
+ See [MS-DTYP]: 2.4.4
+ """
+ HEADER_FORMAT='<BBH'
+
+ def__init__(self,type_,flags,mask,sid,additional_data):
+ #: An integer representing the type of the ACE. One of the
+ #: ``ACE_TYPE_*`` constants. Corresponds to the ``AceType`` field
+ #: from [MS-DTYP] 2.4.4.1.
+ self.type=type_
+ #: An integer bitmask with ACE flags, corresponds to the
+ #: ``AceFlags`` field.
+ self.flags=flags
+ #: An integer representing the ``ACCESS_MASK`` as specified in
+ #: [MS-DTYP] 2.4.3.
+ self.mask=mask
+ #: The :class:`SID` of a trustee.
+ self.sid=sid
+ #: A dictionary of additional fields present in the ACE, depending
+ #: on the type. The following fields can be present:
+ #:
+ #: * ``flags``
+ #: * ``object_type``
+ #: * ``inherited_object_type``
+ #: * ``application_data``
+ #: * ``attribute_data``
+ self.additional_data=additional_data
+
+ def__repr__(self):
+ return"ACE(type=%#04x, flags=%#04x, mask=%#010x, sid=%s)"%(
+ self.type,self.flags,self.mask,self.sid,
+ )
+
+ @property
+ defisInheritOnly(self):
+ """Convenience property which indicates if this ACE is inherit
+ only, meaning that it doesn't apply to the object itself."""
+ returnbool(self.flags&ACE_FLAG_INHERIT_ONLY)
+
+ @classmethod
+ deffrom_bytes(cls,data):
+ header_size=struct.calcsize(cls.HEADER_FORMAT)
+ header=data[:header_size]
+ type_,flags,size=struct.unpack(cls.HEADER_FORMAT,header)
+
+ assertlen(data)>=size
+
+ body=data[header_size:size]
+ additional_data={}
+
+ # In all ACE types, the mask immediately follows the header.
+ mask=struct.unpack('<I',body[:4])[0]
+ body=body[4:]
+
+ # All OBJECT-type ACEs contain additional flags, and two GUIDs as
+ # the following fields.
+ iftype_in(ACE_TYPE_ACCESS_ALLOWED_OBJECT,
+ ACE_TYPE_ACCESS_DENIED_OBJECT,
+ ACE_TYPE_ACCESS_ALLOWED_CALLBACK_OBJECT,
+ ACE_TYPE_ACCESS_DENIED_CALLBACK_OBJECT,
+ ACE_TYPE_SYSTEM_AUDIT_OBJECT,
+ ACE_TYPE_SYSTEM_AUDIT_CALLBACK_OBJECT):
+ additional_data['flags']=struct.unpack('<I',body[:4])[0]
+ additional_data['object_type']=body[4:20]
+ additional_data['inherited_object_type']=body[20:36]
+ body=body[36:]
+
+ # Then the SID in all types.
+ sid,body=SID.from_bytes(body,return_tail=True)
+
+ # CALLBACK-type ACEs (and for some obscure reason,
+ # SYSTEM_AUDIT_OBJECT) have a final tail of application data.
+ iftype_in(ACE_TYPE_ACCESS_ALLOWED_CALLBACK,
+ ACE_TYPE_ACCESS_DENIED_CALLBACK,
+ ACE_TYPE_ACCESS_ALLOWED_CALLBACK_OBJECT,
+ ACE_TYPE_ACCESS_DENIED_CALLBACK_OBJECT,
+ ACE_TYPE_SYSTEM_AUDIT_OBJECT,
+ ACE_TYPE_SYSTEM_AUDIT_CALLBACK,
+ ACE_TYPE_SYSTEM_AUDIT_CALLBACK_OBJECT):
+ additional_data['application_data']=body
+
+ # SYSTEM_RESOURCE_ATTRIBUTE ACEs have a tail of attribute data.
+ iftype_==ACE_TYPE_SYSTEM_RESOURCE_ATTRIBUTE:
+ additional_data['attribute_data']=body
+
+ returncls(type_,flags,mask,sid,additional_data)
+
+
+
[docs]classACL(object):
+ """
+ Access control list, encapsulating a sequence of access control
+ entries.
+
+ See [MS-DTYP]: 2.4.5
+ """
+ HEADER_FORMAT='<BBHHH'
+
+ def__init__(self,revision,aces):
+ #: Integer value of the revision.
+ self.revision=revision
+ #: List of :class:`ACE` instances.
+ self.aces=aces
+
+ def__repr__(self):
+ return"ACL(%r)"%(self.aces,)
+
+ @classmethod
+ deffrom_bytes(cls,data):
+ revision=None
+ aces=[]
+
+ header_size=struct.calcsize(cls.HEADER_FORMAT)
+ header,remaining=data[:header_size],data[header_size:]
+ revision,sbz1,size,count,sbz2=struct.unpack(cls.HEADER_FORMAT,header)
+
+ assertlen(data)>=size
+
+ foriinrange(count):
+ ace_size=struct.unpack('<H',remaining[2:4])[0]
+ ace_data,remaining=remaining[:ace_size],remaining[ace_size:]
+ aces.append(ACE.from_bytes(ace_data))
+
+ returncls(revision,aces)
+
+
+
[docs]classSecurityDescriptor(object):
+ """
+ Represents a security descriptor.
+
+ See [MS-DTYP]: 2.4.6
+ """
+
+ HEADER_FORMAT='<BBHIIII'
+
+ def__init__(self,flags,owner,group,dacl,sacl):
+ #: Integer bitmask of control flags. Corresponds to the
+ #: ``Control`` field in [MS-DTYP] 2.4.6.
+ self.flags=flags
+ #: Instance of :class:`SID` representing the owner user.
+ self.owner=owner
+ #: Instance of :class:`SID` representing the owner group.
+ self.group=group
+ #: Instance of :class:`ACL` representing the discretionary access
+ #: control list, which specifies access restrictions of an object.
+ self.dacl=dacl
+ #: Instance of :class:`ACL` representing the system access control
+ #: list, which specifies audit logging of an object.
+ self.sacl=sacl
+
+ @classmethod
+ deffrom_bytes(cls,data):
+ owner=None
+ group=None
+ dacl=None
+ sacl=None
+
+ header=data[:struct.calcsize(cls.HEADER_FORMAT)]
+ (revision,sbz1,flags,owner_offset,group_offset,sacl_offset,
+ dacl_offset)=struct.unpack(cls.HEADER_FORMAT,header)
+
+ assertrevision==1
+ assertflags&SECURITY_DESCRIPTOR_SELF_RELATIVE
+ foroffsetin(owner_offset,group_offset,sacl_offset,dacl_offset):
+ assert0<=offset<len(data)
+
+ ifowner_offset:
+ owner=SID.from_bytes(data[owner_offset:])
+ ifgroup_offset:
+ group=SID.from_bytes(data[group_offset:])
+ ifdacl_offset:
+ dacl=ACL.from_bytes(data[dacl_offset:])
+ ifsacl_offset:
+ sacl=ACL.from_bytes(data[sacl_offset:])
+
+ returncls(flags,owner,group,dacl,sacl)
@@ -73,17 +76,20 @@
# Set to True if you want to enable SMB2 protocol.SUPPORT_SMB2=True
+# Set to True if you want to enable SMB2.1 and above protocol.
+SUPPORT_SMB2x=True
+
# Supported dialects
-DIALECTS=[]
-fori,(name,dialect)inenumerate([('NT_LAN_MANAGER_DIALECT','NT LM 0.12'),]):
- DIALECTS.append(dialect)
- globals()[name]=i
-
-DIALECTS2=[]
-fori,(name,dialect)inenumerate([('SMB2_DIALECT','SMB 2.002')]):
- DIALECTS2.append(dialect)
- globals()[name]=i+len(DIALECTS)
-
+NT_LAN_MANAGER_DIALECT=0# 'NT LM 0.12' is always the first element in the dialect list and must always be included (MS-SMB 2.2.4.5.1)
+
+# Return the list of support SMB dialects based on the SUPPORT_x constants
+definit_dialects_list():
+ dialects=['NT LM 0.12']
+ ifSUPPORT_SMB2:
+ dialects.append('SMB 2.002')
+ ifSUPPORT_SMB2x:
+ dialects.append('SMB 2.???')
+ returndialects
A Windows security identifier. Represents a single principal, such a
+user or a group, as a sequence of numbers consisting of the revision,
+identifier authority, and a variable-length list of subauthorities.
@@ -136,401 +139,6 @@
Most SMB/CIFS servers have some sort of keepalive mechanism and impose a timeout limit.
If the clients fail to respond within the timeout limit, the SMB/CIFS server may disconnect the client.
-
username and password are the user credentials required to authenticate the underlying SMB connection with the remote server.
-File operations can only be proceeded after the connection has been authenticated successfully.
-
Note that you need to call connect method to actually establish the SMB connection to the remote server and perform authentication.
-
The default TCP port for most SMB/CIFS servers using NetBIOS over TCP/IP is 139.
-Some newer server installations might also support Direct hosting of SMB over TCP/IP; for these servers, the default TCP port is 445.
-
-
-
-
-
Parameters:
-
my_name (string) – The local NetBIOS machine name that will identify where this connection is originating from.
-You can freely choose a name as long as it contains a maximum of 15 alphanumeric characters and does not contain spaces and any of \/:*?";|+
-
remote_name (string) – The NetBIOS machine name of the remote server.
-On windows, you can find out the machine name by right-clicking on the “My Computer” and selecting “Properties”.
-This parameter must be the same as what has been configured on the remote server, or else the connection will be rejected.
-
domain (string) – The network domain. On windows, it is known as the workgroup. Usually, it is safe to leave this parameter as an empty string.
-
use_ntlm_v2 (boolean) – Indicates whether pysmb should be NTLMv1 or NTLMv2 authentication algorithm for authentication.
-The choice of NTLMv1 and NTLMv2 is configured on the remote server, and there is no mechanism to auto-detect which algorithm has been configured.
-Hence, we can only “guess” or try both algorithms.
-On Sambda, Windows Vista and Windows 7, NTLMv2 is enabled by default. On Windows XP, we can use NTLMv1 before NTLMv2.
-
sign_options (int) – Determines whether SMB messages will be signed. Default is SIGN_WHEN_REQUIRED.
-If SIGN_WHEN_REQUIRED (value=2), SMB messages will only be signed when remote server requires signing.
-If SIGN_WHEN_SUPPORTED (value=1), SMB messages will be signed when remote server supports signing but not requires signing.
-If SIGN_NEVER (value=0), SMB messages will never be signed regardless of remote server’s configurations; access errors will occur if the remote server requires signing.
-
is_direct_tcp (boolean) – Controls whether the NetBIOS over TCP/IP (is_direct_tcp=False) or the newer Direct hosting of SMB over TCP/IP (is_direct_tcp=True) will be used for the communication.
-The default parameter is False which will use NetBIOS over TCP/IP for wider compatibility (TCP port: 139).
Establish the SMB connection to the remote SMB/CIFS server.
-
You must call this method before attempting any of the file operations with the remote server.
-This method will block until the SMB connection has attempted at least one authentication.
-
-
-
-
-
Returns:
A boolean value indicating the result of the authentication atttempt: True if authentication is successful; False, if otherwise.
service_name (string/unicode) – Contains the name of the shared folder.
-
path (string/unicode) – The path of the new folder (relative to) the shared folder.
-If the path contains non-English characters, an unicode string must be used to pass in the path.
service_name (string/unicode) – Contains the name of the shared folder.
-
path (string/unicode) – The path of the to-be-deleted folder (relative to) the shared folder.
-If the path contains non-English characters, an unicode string must be used to pass in the path.
Delete one or more regular files. It supports the use of wildcards in file names, allowing for deletion of multiple files in a single request.
-
-
-
-
-
Parameters:
-
service_name (string/unicode) – Contains the name of the shared folder.
-
path_file_pattern (string/unicode) – The pathname of the file(s) to be deleted, relative to the service_name.
-Wildcards may be used in th filename component of the path.
-If your path/filename contains non-English characters, you must pass in an unicode string.
Retrieve a directory listing of files/folders at path
-
-
-
-
-
Parameters:
-
service_name (string/unicode) – the name of the shared folder for the path
-
path (string/unicode) – path relative to the service_name where we are interested to learn about its files/sub-folders.
-
search (integer) – integer value made up from a bitwise-OR of SMB_FILE_ATTRIBUTE_xxx bits (see smb_constants.py).
-The default search value will query for all read-only, hidden, system, archive files and directories.
-
pattern (string/unicode) – the filter to apply to the results before returning to the client.
Rename a file or folder at old_path to new_path shared at service_name. Note that this method cannot be used to rename file/folder across different shared folders
-
old_path and new_path are string/unicode referring to the old and new path of the renamed resources (relative to) the shared folder.
-If the path contains non-English characters, an unicode string must be used to pass in the path.
-
-
-
-
-
Parameters:
service_name (string/unicode) – Contains the name of the shared folder.
Reset file attributes of one or more regular files or folders.
-It supports the use of wildcards in file names, allowing for unlocking of multiple files/folders in a single request.
-This function is very helpful when deleting files/folders that are read-only.
-Note: this function is currently only implemented for SMB2! Technically, it sets the FILE_ATTRIBUTE_NORMAL flag, therefore clearing all other flags. (See https://msdn.microsoft.com/en-us/library/cc232110.aspx for further information)
-
-
-
-
-
Parameters:
-
service_name (string/unicode) – Contains the name of the shared folder.
-
path_file_pattern (string/unicode) – The pathname of the file(s) to be deleted, relative to the service_name.
-Wildcards may be used in the filename component of the path.
-If your path/filename contains non-English characters, you must pass in an unicode string.
Retrieve the contents of the file at path on the service_name and write these contents to the provided file_obj.
-
Use retrieveFileFromOffset() method if you wish to specify the offset to read from the remote path and/or the number of bytes to write to the file_obj.
-
-
-
-
-
Parameters:
-
service_name (string/unicode) – the name of the shared folder for the path
-
path (string/unicode) – Path of the file on the remote server. If the file cannot be opened for reading, an OperationFailure will be raised.
-
file_obj – A file-like object that has a write method. Data will be written continuously to file_obj until EOF is received from the remote service.
-
-
-
-
Returns:
A 2-element tuple of ( file attributes of the file on server, number of bytes written to file_obj ).
-The file attributes is an integer value made up from a bitwise-OR of SMB_FILE_ATTRIBUTE_xxx bits (see smb_constants.py)
Retrieve the contents of the file at path on the service_name and write these contents to the provided file_obj.
-
-
-
-
-
Parameters:
-
service_name (string/unicode) – the name of the shared folder for the path
-
path (string/unicode) – Path of the file on the remote server. If the file cannot be opened for reading, an OperationFailure will be raised.
-
file_obj – A file-like object that has a write method. Data will be written continuously to file_obj up to max_length number of bytes.
-
offset (integer/long) – the offset in the remote path where the first byte will be read and written to file_obj. Must be either zero or a positive integer/long value.
-
max_length (integer/long) – maximum number of bytes to read from the remote path and write to the file_obj. Specify a negative value to read from offset to the EOF.
-If zero, the method returns immediately after the file is opened successfully for reading.
-
-
-
-
Returns:
A 2-element tuple of ( file attributes of the file on server, number of bytes written to file_obj ).
-The file attributes is an integer value made up from a bitwise-OR of SMB_FILE_ATTRIBUTE_xxx bits (see smb_constants.py)
Store the contents of the file_obj at path on the service_name.
-If the file already exists on the remote server, it will be truncated and overwritten.
-
-
-
-
-
Parameters:
-
service_name (string/unicode) – the name of the shared folder for the path
-
path (string/unicode) – Path of the file on the remote server. If the file at path does not exist, it will be created. Otherwise, it will be overwritten.
-If the path refers to a folder or the file cannot be opened for writing, an OperationFailure will be raised.
-
file_obj – A file-like object that has a read method. Data will read continuously from file_obj until EOF.
Store the contents of the file_obj at path on the service_name.
-
-
-
-
-
Parameters:
-
service_name (string/unicode) – the name of the shared folder for the path
-
path (string/unicode) – Path of the file on the remote server. If the file at path does not exist, it will be created.
-If the path refers to a folder or the file cannot be opened for writing, an OperationFailure will be raised.
-
file_obj – A file-like object that has a read method. Data will read continuously from file_obj until EOF.
-
offset – Long integer value which specifies the offset in the remote server to start writing. First byte of the file is 0.
-
truncate – Boolean value. If True and the file exists on the remote server, it will be truncated first before writing. Default is False.
-
-
-
-
Returns:
the file position where the next byte will be written.
The timeout parameter in the file operation methods are not precise; it is accurate to within 1 second interval, i.e. with a timeout of 0.5 sec, pysmb might raise
SMBTimeout exception after 1.5 sec.
Create a new SMBProtocolFactory instance. You will pass this instance to reactor.connectTCP() which will then instantiate the TCP connection to the remote SMB/CIFS server.
-Note that the default TCP port for most SMB/CIFS servers using NetBIOS over TCP/IP is 139.
-Some newer server installations might also support Direct hosting of SMB over TCP/IP; for these servers, the default TCP port is 445.
-
username and password are the user credentials required to authenticate the underlying SMB connection with the remote server.
-File operations can only be proceeded after the connection has been authenticated successfully.
-
-
-
-
-
Parameters:
-
my_name (string) – The local NetBIOS machine name that will identify where this connection is originating from.
-You can freely choose a name as long as it contains a maximum of 15 alphanumeric characters and does not contain spaces and any of \/:*?";|+.
-
remote_name (string) – The NetBIOS machine name of the remote server.
-On windows, you can find out the machine name by right-clicking on the “My Computer” and selecting “Properties”.
-This parameter must be the same as what has been configured on the remote server, or else the connection will be rejected.
-
domain (string) – The network domain. On windows, it is known as the workgroup. Usually, it is safe to leave this parameter as an empty string.
-
use_ntlm_v2 (boolean) – Indicates whether pysmb should be NTLMv1 or NTLMv2 authentication algorithm for authentication.
-The choice of NTLMv1 and NTLMv2 is configured on the remote server, and there is no mechanism to auto-detect which algorithm has been configured.
-Hence, we can only “guess” or try both algorithms.
-On Sambda, Windows Vista and Windows 7, NTLMv2 is enabled by default. On Windows XP, we can use NTLMv1 before NTLMv2.
-
sign_options (int) – Determines whether SMB messages will be signed. Default is SIGN_WHEN_REQUIRED.
-If SIGN_WHEN_REQUIRED (value=2), SMB messages will only be signed when remote server requires signing.
-If SIGN_WHEN_SUPPORTED (value=1), SMB messages will be signed when remote server supports signing but not requires signing.
-If SIGN_NEVER (value=0), SMB messages will never be signed regardless of remote server’s configurations; access errors will occur if the remote server requires signing.
-
is_direct_tcp (boolean) – Controls whether the NetBIOS over TCP/IP (is_direct_tcp=False) or the newer Direct hosting of SMB over TCP/IP (is_direct_tcp=True) will be used for the communication.
-The default parameter is False which will use NetBIOS over TCP/IP for wider compatibility (TCP port: 139).
service_name (string/unicode) – Contains the name of the shared folder.
-
path (string/unicode) – The path of the new folder (relative to) the shared folder.
-If the path contains non-English characters, an unicode string must be used to pass in the path.
-
timeout (integer/float) – Number of seconds that pysmb will wait before raising SMBTimeout via the returned Deferred instance’s errback method.
-
-
-
-
Returns:
A twisted.internet.defer.Deferred instance. The callback function will be called with the path parameter.
service_name (string/unicode) – Contains the name of the shared folder.
-
path (string/unicode) – The path of the to-be-deleted folder (relative to) the shared folder.
-If the path contains non-English characters, an unicode string must be used to pass in the path.
-
timeout (integer/float) – Number of seconds that pysmb will wait before raising SMBTimeout via the returned Deferred instance’s errback method.
-
-
-
-
Returns:
A twisted.internet.defer.Deferred instance. The callback function will be called with the path parameter.
Delete one or more regular files. It supports the use of wildcards in file names, allowing for deletion of multiple files in a single request.
-
-
-
-
-
Parameters:
-
service_name (string/unicode) – Contains the name of the shared folder.
-
path_file_pattern (string/unicode) – The pathname of the file(s) to be deleted, relative to the service_name.
-Wildcards may be used in th filename component of the path.
-If your path/filename contains non-English characters, you must pass in an unicode string.
-
timeout (integer/float) – Number of seconds that pysmb will wait before raising SMBTimeout via the returned Deferred instance’s errback method.
-
-
-
-
Returns:
A twisted.internet.defer.Deferred instance. The callback function will be called with the path_file_pattern parameter.
Retrieve information about the file at path on the service_name.
-
-
-
-
-
Parameters:
-
service_name (string/unicode) – the name of the shared folder for the path
-
path (string/unicode) – Path of the file on the remote server. If the file cannot be opened for reading, an OperationFailure will be raised.
-
-
-
-
Returns:
A twisted.internet.defer.Deferred instance. The callback function will be called with a smb.base.SharedFile instance containing the attributes of the file.
Retrieve a directory listing of files/folders at path
-
-
-
-
-
Parameters:
-
service_name (string/unicode) – the name of the shared folder for the path
-
path (string/unicode) – path relative to the service_name where we are interested to learn about its files/sub-folders.
-
search (integer) – integer value made up from a bitwise-OR of SMB_FILE_ATTRIBUTE_xxx bits (see smb_constants.py).
-The default search value will query for all read-only, hidden, system, archive files and directories.
-
pattern (string/unicode) – the filter to apply to the results before returning to the client.
-
timeout (integer/float) – Number of seconds that pysmb will wait before raising SMBTimeout via the returned Deferred instance’s errback method.
-
-
-
-
Returns:
A twisted.internet.defer.Deferred instance. The callback function will be called with a list of smb.base.SharedFile instances.
Retrieve a list of available snapshots (a.k.a. shadow copies) for path.
-
Note that snapshot features are only supported on Windows Vista Business, Enterprise and Ultimate, and on all Windows 7 editions.
-
-
-
-
-
Parameters:
-
service_name (string/unicode) – the name of the shared folder for the path
-
path (string/unicode) – path relative to the service_name where we are interested in the list of available snapshots
-
-
-
-
Returns:
A twisted.internet.defer.Deferred instance. The callback function will be called with a list of python datetime.DateTime
-instances in GMT/UTC time zone
Override this method in your SMBProtocolFactory subclass to add in post-authentication handling.
-This method will be called when the server has replied that the SMB connection has been successfully authenticated.
-
-
If you want to retry authenticating from this method,
-
-
Disconnect the underlying SMB connection (call self.instance.transport.loseConnection())
-
Create a new SMBProtocolFactory subclass instance with different user credientials or different NTLM algorithm flag.
-
Call reactor.connectTCP with the new instance to re-establish the SMB connection
Override this method in your SMBProtocolFactory subclass to add in post-authentication handling.
-This method will be called when the server has replied that the SMB connection has been successfully authenticated.
-File operations can proceed when this method has been called.
Rename a file or folder at old_path to new_path shared at service_name. Note that this method cannot be used to rename file/folder across different shared folders
-
old_path and new_path are string/unicode referring to the old and new path of the renamed resources (relative to) the shared folder.
-If the path contains non-English characters, an unicode string must be used to pass in the path.
-
-
-
-
-
Parameters:
-
service_name (string/unicode) – Contains the name of the shared folder.
-
timeout (integer/float) – Number of seconds that pysmb will wait before raising SMBTimeout via the returned Deferred instance’s errback method.
-
-
-
-
Returns:
A twisted.internet.defer.Deferred instance. The callback function will be called with a 2-element tuple of ( old_path, new_path ).
Retrieve the contents of the file at path on the service_name and write these contents to the provided file_obj.
-
Use retrieveFileFromOffset() method if you need to specify the offset to read from the remote path and/or the maximum number of bytes to write to the file_obj.
-
The meaning of the timeout parameter will be different from other file operation methods. As the downloaded file usually exceeeds the maximum size
-of each SMB/CIFS data message, it will be packetized into a series of request messages (each message will request about about 60kBytes).
-The timeout parameter is an integer/float value that specifies the timeout interval for these individual SMB/CIFS message to be transmitted and downloaded from the remote SMB/CIFS server.
-
-
-
-
-
Parameters:
-
service_name (string/unicode) – the name of the shared folder for the path
-
path (string/unicode) – Path of the file on the remote server. If the file cannot be opened for reading, an OperationFailure will be called in the returned Deferred errback.
-
file_obj – A file-like object that has a write method. Data will be written continuously to file_obj until EOF is received from the remote service.
-
-
-
-
Returns:
A twisted.internet.defer.Deferred instance. The callback function will be called with a 3-element tuple of ( file_obj, file attributes of the file on server, number of bytes written to file_obj ).
-The file attributes is an integer value made up from a bitwise-OR of SMB_FILE_ATTRIBUTE_xxx bits (see smb_constants.py)
Retrieve the contents of the file at path on the service_name and write these contents to the provided file_obj.
-
The meaning of the timeout parameter will be different from other file operation methods. As the downloaded file usually exceeeds the maximum size
-of each SMB/CIFS data message, it will be packetized into a series of request messages (each message will request about about 60kBytes).
-The timeout parameter is an integer/float value that specifies the timeout interval for these individual SMB/CIFS message to be transmitted and downloaded from the remote SMB/CIFS server.
-
-
-
-
-
Parameters:
-
service_name (string/unicode) – the name of the shared folder for the path
-
path (string/unicode) – Path of the file on the remote server. If the file cannot be opened for reading, an OperationFailure will be called in the returned Deferred errback.
-
file_obj – A file-like object that has a write method. Data will be written continuously to file_obj until EOF is received from the remote service.
-
offset (integer/long) – the offset in the remote path where the first byte will be read and written to file_obj. Must be either zero or a positive integer/long value.
-
max_length (integer/long) – maximum number of bytes to read from the remote path and write to the file_obj. Specify a negative value to read from offset to the EOF.
-If zero, the Deferred callback is invoked immediately after the file is opened successfully for reading.
-
-
-
-
Returns:
A twisted.internet.defer.Deferred instance. The callback function will be called with a 3-element tuple of ( file_obj, file attributes of the file on server, number of bytes written to file_obj ).
-The file attributes is an integer value made up from a bitwise-OR of SMB_FILE_ATTRIBUTE_xxx bits (see smb_constants.py)
Store the contents of the file_obj at path on the service_name.
-
The meaning of the timeout parameter will be different from other file operation methods. As the uploaded file usually exceeeds the maximum size
-of each SMB/CIFS data message, it will be packetized into a series of messages (usually about 60kBytes).
-The timeout parameter is an integer/float value that specifies the timeout interval for these individual SMB/CIFS message to be transmitted and acknowledged
-by the remote SMB/CIFS server.
-
-
-
-
-
Parameters:
-
service_name (string/unicode) – the name of the shared folder for the path
-
path (string/unicode) – Path of the file on the remote server. If the file at path does not exist, it will be created. Otherwise, it will be overwritten.
-If the path refers to a folder or the file cannot be opened for writing, an OperationFailure will be called in the returned Deferred errback.
-
file_obj – A file-like object that has a read method. Data will read continuously from file_obj until EOF.
-
-
-
-
Returns:
A twisted.internet.defer.Deferred instance. The callback function will be called with a 2-element tuple of ( file_obj, number of bytes uploaded ).
A convenient property to return True if the underlying SMB connection has connected to remote server, has successfully authenticated itself and is ready for file operations.
Returns True if this shared device is a special share reserved for interprocess communication (IPC$)
-or remote administration of the server (ADMIN$). Can also refer to administrative shares such as
-C$, D$, E$, and so forth
Contain information about a file/folder entry that is shared on the shared device.
-
As an application developer, you should not need to instantiate a SharedFile instance directly in your application.
-These SharedFile instances are usually returned via a call to listPath method in smb.SMBProtocol.SMBProtocolFactory.
-
If you encounter SharedFile instance where its short_name attribute is empty but the filename attribute contains a short name which does not correspond
-to any files/folders on your remote shared device, it could be that the original filename on the file/folder entry on the shared device contains
-one of these prohibited characters: “/[]:+|<>=;?,* (see [MS-CIFS]: 2.2.1.1.1 for more details).