diff options
Diffstat (limited to 'tests/python_dependencies/impacket/smb.py')
-rw-r--r-- | tests/python_dependencies/impacket/smb.py | 4099 |
1 files changed, 4099 insertions, 0 deletions
diff --git a/tests/python_dependencies/impacket/smb.py b/tests/python_dependencies/impacket/smb.py new file mode 100644 index 000000000..95efb2c63 --- /dev/null +++ b/tests/python_dependencies/impacket/smb.py @@ -0,0 +1,4099 @@ +# Copyright (c) 2003-2016 CORE Security Technologies +# +# This software is provided under under a slightly modified version +# of the Apache Software License. See the accompanying LICENSE file +# for more information. +# +# Copyright (C) 2001 Michael Teo <michaelteo@bigfoot.com> +# smb.py - SMB/CIFS library +# +# 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 +# use of this software. +# +# Permission is granted to anyone to use this software for any purpose, +# including commercial applications, and to alter it and redistribute it +# freely, subject to the following restrictions: +# +# 1. The origin of this software must not be misrepresented; you must not +# claim that you wrote the original software. If you use this software +# in a product, an acknowledgment in the product documentation would be +# appreciated but is not required. +# +# 2. Altered source versions must be plainly marked as such, and must not be +# misrepresented as being the original software. +# +# 3. This notice cannot be removed or altered from any source distribution. +# +# Altered source done by Alberto Solino (@agsolino) + +# Todo: +# [ ] Try [SMB]transport fragmentation using Transact requests +# [ ] Try other methods of doing write (write_raw, transact2, write, write_and_unlock, write_and_close, write_mpx) +# [-] Try replacements for SMB_COM_NT_CREATE_ANDX (CREATE, T_TRANSACT_CREATE, OPEN_ANDX works +# [x] Fix forceWriteAndx, which needs to send a RecvRequest, because recv() will not send it +# [x] Fix Recv() when using RecvAndx and the answer comes splet in several packets +# [ ] Try [SMB]transport fragmentation with overlaping segments +# [ ] Try [SMB]transport fragmentation with out of order segments +# [x] Do chained AndX requests +# [ ] Transform the rest of the calls to structure +# [X] Implement TRANS/TRANS2 reassembly for list_path + +import os +import socket +import string +from binascii import a2b_hex +import datetime +from struct import pack, unpack +from contextlib import contextmanager + +from impacket import nmb, ntlm, nt_errors, LOG +from impacket.structure import Structure +from impacket.spnego import SPNEGO_NegTokenInit, TypesMech, SPNEGO_NegTokenResp + +# For signing +import hashlib + +unicode_support = 0 +unicode_convert = 1 + +try: + from cStringIO import StringIO +except ImportError: + from StringIO import StringIO + +# Dialect for SMB1 +SMB_DIALECT = 'NT LM 0.12' + +# Shared Device Type +SHARED_DISK = 0x00 +SHARED_DISK_HIDDEN = 0x80000000 +SHARED_PRINT_QUEUE = 0x01 +SHARED_DEVICE = 0x02 +SHARED_IPC = 0x03 + +# Extended attributes mask +ATTR_ARCHIVE = 0x020 +ATTR_COMPRESSED = 0x800 +ATTR_NORMAL = 0x080 +ATTR_HIDDEN = 0x002 +ATTR_READONLY = 0x001 +ATTR_TEMPORARY = 0x100 +ATTR_DIRECTORY = 0x010 +ATTR_SYSTEM = 0x004 + +# Service Type +SERVICE_DISK = 'A:' +SERVICE_PRINTER = 'LPT1:' +SERVICE_IPC = 'IPC' +SERVICE_COMM = 'COMM' +SERVICE_ANY = '?????' + +# Server Type (Can be used to mask with SMBMachine.get_type() or SMBDomain.get_type()) +SV_TYPE_WORKSTATION = 0x00000001 +SV_TYPE_SERVER = 0x00000002 +SV_TYPE_SQLSERVER = 0x00000004 +SV_TYPE_DOMAIN_CTRL = 0x00000008 +SV_TYPE_DOMAIN_BAKCTRL = 0x00000010 +SV_TYPE_TIME_SOURCE = 0x00000020 +SV_TYPE_AFP = 0x00000040 +SV_TYPE_NOVELL = 0x00000080 +SV_TYPE_DOMAIN_MEMBER = 0x00000100 +SV_TYPE_PRINTQ_SERVER = 0x00000200 +SV_TYPE_DIALIN_SERVER = 0x00000400 +SV_TYPE_XENIX_SERVER = 0x00000800 +SV_TYPE_NT = 0x00001000 +SV_TYPE_WFW = 0x00002000 +SV_TYPE_SERVER_NT = 0x00004000 +SV_TYPE_POTENTIAL_BROWSER = 0x00010000 +SV_TYPE_BACKUP_BROWSER = 0x00020000 +SV_TYPE_MASTER_BROWSER = 0x00040000 +SV_TYPE_DOMAIN_MASTER = 0x00080000 +SV_TYPE_LOCAL_LIST_ONLY = 0x40000000 +SV_TYPE_DOMAIN_ENUM = 0x80000000 + +# Options values for SMB.stor_file and SMB.retr_file +SMB_O_CREAT = 0x10 # Create the file if file does not exists. Otherwise, operation fails. +SMB_O_EXCL = 0x00 # When used with SMB_O_CREAT, operation fails if file exists. Cannot be used with SMB_O_OPEN. +SMB_O_OPEN = 0x01 # Open the file if the file exists +SMB_O_TRUNC = 0x02 # Truncate the file if the file exists + +# Share Access Mode +SMB_SHARE_COMPAT = 0x00 +SMB_SHARE_DENY_EXCL = 0x10 +SMB_SHARE_DENY_WRITE = 0x20 +SMB_SHARE_DENY_READEXEC = 0x30 +SMB_SHARE_DENY_NONE = 0x40 +SMB_ACCESS_READ = 0x00 +SMB_ACCESS_WRITE = 0x01 +SMB_ACCESS_READWRITE = 0x02 +SMB_ACCESS_EXEC = 0x03 + +TRANS_DISCONNECT_TID = 1 +TRANS_NO_RESPONSE = 2 + +STATUS_SUCCESS = 0x00000000 +STATUS_LOGON_FAILURE = 0xC000006D +STATUS_LOGON_TYPE_NOT_GRANTED = 0xC000015B +MAX_TFRAG_SIZE = 5840 +EVASION_NONE = 0 +EVASION_LOW = 1 +EVASION_HIGH = 2 +EVASION_MAX = 3 +RPC_X_BAD_STUB_DATA = 0x6F7 + +# SMB_FILE_ATTRIBUTES + +SMB_FILE_ATTRIBUTE_NORMAL = 0x0000 +SMB_FILE_ATTRIBUTE_READONLY = 0x0001 +SMB_FILE_ATTRIBUTE_HIDDEN = 0x0002 +SMB_FILE_ATTRIBUTE_SYSTEM = 0x0004 +SMB_FILE_ATTRIBUTE_VOLUME = 0x0008 +SMB_FILE_ATTRIBUTE_DIRECTORY = 0x0010 +SMB_FILE_ATTRIBUTE_ARCHIVE = 0x0020 +SMB_SEARCH_ATTRIBUTE_READONLY = 0x0100 +SMB_SEARCH_ATTRIBUTE_HIDDEN = 0x0200 +SMB_SEARCH_ATTRIBUTE_SYSTEM = 0x0400 +SMB_SEARCH_ATTRIBUTE_DIRECTORY = 0x1000 +SMB_SEARCH_ATTRIBUTE_ARCHIVE = 0x2000 + +# Session SetupAndX Action flags +SMB_SETUP_GUEST = 0x01 +SMB_SETUP_USE_LANMAN_KEY = 0x02 + +# QUERY_INFORMATION levels +SMB_INFO_ALLOCATION = 0x0001 +SMB_INFO_VOLUME = 0x0002 +FILE_FS_SIZE_INFORMATION = 0x0003 +SMB_QUERY_FS_VOLUME_INFO = 0x0102 +SMB_QUERY_FS_SIZE_INFO = 0x0103 +SMB_QUERY_FILE_EA_INFO = 0x0103 +SMB_QUERY_FS_DEVICE_INFO = 0x0104 +SMB_QUERY_FS_ATTRIBUTE_INFO = 0x0105 +SMB_QUERY_FILE_BASIC_INFO = 0x0101 +SMB_QUERY_FILE_STANDARD_INFO = 0x0102 +SMB_QUERY_FILE_ALL_INFO = 0x0107 +FILE_FS_FULL_SIZE_INFORMATION = 0x03EF + +# SET_INFORMATION levels +SMB_SET_FILE_DISPOSITION_INFO = 0x0102 +SMB_SET_FILE_BASIC_INFO = 0x0101 +SMB_SET_FILE_END_OF_FILE_INFO = 0x0104 + + +# File System Attributes +FILE_CASE_SENSITIVE_SEARCH = 0x00000001 +FILE_CASE_PRESERVED_NAMES = 0x00000002 +FILE_UNICODE_ON_DISK = 0x00000004 +FILE_PERSISTENT_ACLS = 0x00000008 +FILE_FILE_COMPRESSION = 0x00000010 +FILE_VOLUME_IS_COMPRESSED = 0x00008000 + +# FIND_FIRST2 flags and levels +SMB_FIND_CLOSE_AFTER_REQUEST = 0x0001 +SMB_FIND_CLOSE_AT_EOS = 0x0002 +SMB_FIND_RETURN_RESUME_KEYS = 0x0004 +SMB_FIND_CONTINUE_FROM_LAST = 0x0008 +SMB_FIND_WITH_BACKUP_INTENT = 0x0010 + +FILE_DIRECTORY_FILE = 0x00000001 +FILE_DELETE_ON_CLOSE = 0x00001000 +FILE_NON_DIRECTORY_FILE = 0x00000040 + +SMB_FIND_INFO_STANDARD = 0x0001 +SMB_FIND_FILE_DIRECTORY_INFO = 0x0101 +SMB_FIND_FILE_FULL_DIRECTORY_INFO= 0x0102 +SMB_FIND_FILE_NAMES_INFO = 0x0103 +SMB_FIND_FILE_BOTH_DIRECTORY_INFO= 0x0104 +SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO = 0x105 +SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO = 0x106 + + +# DesiredAccess flags +FILE_READ_DATA = 0x00000001 +FILE_WRITE_DATA = 0x00000002 +FILE_APPEND_DATA = 0x00000004 +FILE_EXECUTE = 0x00000020 +MAXIMUM_ALLOWED = 0x02000000 +GENERIC_ALL = 0x10000000 +GENERIC_EXECUTE = 0x20000000 +GENERIC_WRITE = 0x40000000 +GENERIC_READ = 0x80000000 + +# ShareAccess flags +FILE_SHARE_NONE = 0x00000000 +FILE_SHARE_READ = 0x00000001 +FILE_SHARE_WRITE = 0x00000002 +FILE_SHARE_DELETE = 0x00000004 + +# CreateDisposition flags +FILE_SUPERSEDE = 0x00000000 +FILE_OPEN = 0x00000001 +FILE_CREATE = 0x00000002 +FILE_OPEN_IF = 0x00000003 +FILE_OVERWRITE = 0x00000004 +FILE_OVERWRITE_IF = 0x00000005 + +def strerror(errclass, errcode): + if errclass == 0x01: + return 'OS error', ERRDOS.get(errcode, 'Unknown error') + elif errclass == 0x02: + return 'Server error', ERRSRV.get(errcode, 'Unknown error') + elif errclass == 0x03: + return 'Hardware error', ERRHRD.get(errcode, 'Unknown error') + # This is not a standard error class for SMB + #elif errclass == 0x80: + # return 'Browse error', ERRBROWSE.get(errcode, 'Unknown error') + elif errclass == 0xff: + return 'Bad command', 'Bad command. Please file bug report' + else: + return 'Unknown error', 'Unknown error' + +# Raised when an error has occured during a session +class SessionError(Exception): + # SMB X/Open error codes for the ERRDOS error class + ERRsuccess = 0 + ERRbadfunc = 1 + ERRbadfile = 2 + ERRbadpath = 3 + ERRnofids = 4 + ERRnoaccess = 5 + ERRbadfid = 6 + ERRbadmcb = 7 + ERRnomem = 8 + ERRbadmem = 9 + ERRbadenv = 10 + ERRbadaccess = 12 + ERRbaddata = 13 + ERRres = 14 + ERRbaddrive = 15 + ERRremcd = 16 + ERRdiffdevice = 17 + ERRnofiles = 18 + ERRgeneral = 31 + ERRbadshare = 32 + ERRlock = 33 + ERRunsup = 50 + ERRnetnamedel = 64 + ERRnosuchshare = 67 + ERRfilexists = 80 + ERRinvalidparam = 87 + ERRcannotopen = 110 + ERRinsufficientbuffer = 122 + ERRinvalidname = 123 + ERRunknownlevel = 124 + ERRnotlocked = 158 + ERRrename = 183 + ERRbadpipe = 230 + ERRpipebusy = 231 + ERRpipeclosing = 232 + ERRnotconnected = 233 + ERRmoredata = 234 + ERRnomoreitems = 259 + ERRbaddirectory = 267 + ERReasnotsupported = 282 + ERRlogonfailure = 1326 + ERRbuftoosmall = 2123 + ERRunknownipc = 2142 + ERRnosuchprintjob = 2151 + ERRinvgroup = 2455 + + # here's a special one from observing NT + ERRnoipc = 66 + + # These errors seem to be only returned by the NT printer driver system + ERRdriveralreadyinstalled = 1795 + ERRunknownprinterport = 1796 + ERRunknownprinterdriver = 1797 + ERRunknownprintprocessor = 1798 + ERRinvalidseparatorfile = 1799 + ERRinvalidjobpriority = 1800 + ERRinvalidprintername = 1801 + ERRprinteralreadyexists = 1802 + ERRinvalidprintercommand = 1803 + ERRinvaliddatatype = 1804 + ERRinvalidenvironment = 1805 + + ERRunknownprintmonitor = 3000 + ERRprinterdriverinuse = 3001 + ERRspoolfilenotfound = 3002 + ERRnostartdoc = 3003 + ERRnoaddjob = 3004 + ERRprintprocessoralreadyinstalled = 3005 + ERRprintmonitoralreadyinstalled = 3006 + ERRinvalidprintmonitor = 3007 + ERRprintmonitorinuse = 3008 + ERRprinterhasjobsqueued = 3009 + + # Error codes for the ERRSRV class + + ERRerror = 1 + ERRbadpw = 2 + ERRbadtype = 3 + ERRaccess = 4 + ERRinvnid = 5 + ERRinvnetname = 6 + ERRinvdevice = 7 + ERRqfull = 49 + ERRqtoobig = 50 + ERRinvpfid = 52 + ERRsmbcmd = 64 + ERRsrverror = 65 + ERRfilespecs = 67 + ERRbadlink = 68 + ERRbadpermits = 69 + ERRbadpid = 70 + ERRsetattrmode = 71 + ERRpaused = 81 + ERRmsgoff = 82 + ERRnoroom = 83 + ERRrmuns = 87 + ERRtimeout = 88 + ERRnoresource = 89 + ERRtoomanyuids = 90 + ERRbaduid = 91 + ERRuseMPX = 250 + ERRuseSTD = 251 + ERRcontMPX = 252 + ERRbadPW = None + ERRnosupport = 0 + ERRunknownsmb = 22 + + # Error codes for the ERRHRD class + + ERRnowrite = 19 + ERRbadunit = 20 + ERRnotready = 21 + ERRbadcmd = 22 + ERRdata = 23 + ERRbadreq = 24 + ERRseek = 25 + ERRbadmedia = 26 + ERRbadsector = 27 + ERRnopaper = 28 + ERRwrite = 29 + ERRread = 30 + ERRwrongdisk = 34 + ERRFCBunavail = 35 + ERRsharebufexc = 36 + ERRdiskfull = 39 + + + hard_msgs = { + 19: ("ERRnowrite", "Attempt to write on write-protected diskette."), + 20: ("ERRbadunit", "Unknown unit."), + 21: ("ERRnotready", "Drive not ready."), + 22: ("ERRbadcmd", "Unknown command."), + 23: ("ERRdata", "Data error (CRC)."), + 24: ("ERRbadreq", "Bad request structure length."), + 25: ("ERRseek", "Seek error."), + 26: ("ERRbadmedia", "Unknown media type."), + 27: ("ERRbadsector", "Sector not found."), + 28: ("ERRnopaper", "Printer out of paper."), + 29: ("ERRwrite", "Write fault."), + 30: ("ERRread", "Read fault."), + 31: ("ERRgeneral", "General failure."), + 32: ("ERRbadshare", "An open conflicts with an existing open."), + 33: ("ERRlock", "A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."), + 34: ("ERRwrongdisk", "The wrong disk was found in a drive."), + 35: ("ERRFCBUnavail", "No FCBs are available to process request."), + 36: ("ERRsharebufexc", "A sharing buffer has been exceeded.") + } + + dos_msgs = { + ERRbadfunc: ("ERRbadfunc", "Invalid function."), + ERRbadfile: ("ERRbadfile", "File not found."), + ERRbadpath: ("ERRbadpath", "Directory invalid."), + ERRnofids: ("ERRnofids", "No file descriptors available"), + ERRnoaccess: ("ERRnoaccess", "Access denied."), + ERRbadfid: ("ERRbadfid", "Invalid file handle."), + ERRbadmcb: ("ERRbadmcb", "Memory control blocks destroyed."), + ERRnomem: ("ERRnomem", "Insufficient server memory to perform the requested function."), + ERRbadmem: ("ERRbadmem", "Invalid memory block address."), + ERRbadenv: ("ERRbadenv", "Invalid environment."), + 11: ("ERRbadformat", "Invalid format."), + ERRbadaccess: ("ERRbadaccess", "Invalid open mode."), + ERRbaddata: ("ERRbaddata", "Invalid data."), + ERRres: ("ERRres", "reserved."), + ERRbaddrive: ("ERRbaddrive", "Invalid drive specified."), + ERRremcd: ("ERRremcd", "A Delete Directory request attempted to remove the server's current directory."), + ERRdiffdevice: ("ERRdiffdevice", "Not same device."), + ERRnofiles: ("ERRnofiles", "A File Search command can find no more files matching the specified criteria."), + ERRbadshare: ("ERRbadshare", "The sharing mode specified for an Open conflicts with existing FIDs on the file."), + ERRlock: ("ERRlock", "A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."), + ERRunsup: ("ERRunsup", "The operation is unsupported"), + ERRnosuchshare: ("ERRnosuchshare", "You specified an invalid share name"), + ERRfilexists: ("ERRfilexists", "The file named in a Create Directory, Make New File or Link request already exists."), + ERRinvalidname: ("ERRinvalidname", "Invalid name"), + ERRbadpipe: ("ERRbadpipe", "Pipe invalid."), + ERRpipebusy: ("ERRpipebusy", "All instances of the requested pipe are busy."), + ERRpipeclosing: ("ERRpipeclosing", "Pipe close in progress."), + ERRnotconnected: ("ERRnotconnected", "No process on other end of pipe."), + ERRmoredata: ("ERRmoredata", "There is more data to be returned."), + ERRinvgroup: ("ERRinvgroup", "Invalid workgroup (try the -W option)"), + ERRlogonfailure: ("ERRlogonfailure", "Logon failure"), + ERRdiskfull: ("ERRdiskfull", "Disk full"), + ERRgeneral: ("ERRgeneral", "General failure"), + ERRunknownlevel: ("ERRunknownlevel", "Unknown info level") + } + + server_msgs = { + 1: ("ERRerror", "Non-specific error code."), + 2: ("ERRbadpw", "Bad password - name/password pair in a Tree Connect or Session Setup are invalid."), + 3: ("ERRbadtype", "reserved."), + 4: ("ERRaccess", "The requester does not have the necessary access rights within the specified context for the requested function. The context is defined by the TID or the UID."), + 5: ("ERRinvnid", "The tree ID (TID) specified in a command was invalid."), + 6: ("ERRinvnetname", "Invalid network name in tree connect."), + 7: ("ERRinvdevice", "Invalid device - printer request made to non-printer connection or non-printer request made to printer connection."), + 49: ("ERRqfull", "Print queue full (files) -- returned by open print file."), + 50: ("ERRqtoobig", "Print queue full -- no space."), + 51: ("ERRqeof", "EOF on print queue dump."), + 52: ("ERRinvpfid", "Invalid print file FID."), + 64: ("ERRsmbcmd", "The server did not recognize the command received."), + 65: ("ERRsrverror","The server encountered an internal error, e.g., system file unavailable."), + 67: ("ERRfilespecs", "The file handle (FID) and pathname parameters contained an invalid combination of values."), + 68: ("ERRreserved", "reserved."), + 69: ("ERRbadpermits", "The access permissions specified for a file or directory are not a valid combination. The server cannot set the requested attribute."), + 70: ("ERRreserved", "reserved."), + 71: ("ERRsetattrmode", "The attribute mode in the Set File Attribute request is invalid."), + 81: ("ERRpaused", "Server is paused."), + 82: ("ERRmsgoff", "Not receiving messages."), + 83: ("ERRnoroom", "No room to buffer message."), + 87: ("ERRrmuns", "Too many remote user names."), + 88: ("ERRtimeout", "Operation timed out."), + 89: ("ERRnoresource", "No resources currently available for request."), + 90: ("ERRtoomanyuids", "Too many UIDs active on this session."), + 91: ("ERRbaduid", "The UID is not known as a valid ID on this session."), + 250: ("ERRusempx","Temp unable to support Raw, use MPX mode."), + 251: ("ERRusestd","Temp unable to support Raw, use standard read/write."), + 252: ("ERRcontmpx", "Continue in MPX mode."), + 253: ("ERRreserved", "reserved."), + 254: ("ERRreserved", "reserved."), + 0xFFFF: ("ERRnosupport", "Function not supported.") + } + # Error clases + + ERRDOS = 0x1 + error_classes = { 0: ("SUCCESS", {}), + ERRDOS: ("ERRDOS", dos_msgs), + 0x02: ("ERRSRV",server_msgs), + 0x03: ("ERRHRD",hard_msgs), + 0x04: ("ERRXOS", {} ), + 0xE1: ("ERRRMX1", {} ), + 0xE2: ("ERRRMX2", {} ), + 0xE3: ("ERRRMX3", {} ), + 0xFF: ("ERRCMD", {} ) } + + + + def __init__( self, error_string, error_class, error_code, nt_status = 0): + Exception.__init__(self, error_string) + self.nt_status = nt_status + self._args = error_string + if nt_status: + self.error_class = 0 + self.error_code = (error_code << 16) + error_class + else: + self.error_class = error_class + self.error_code = error_code + + + def get_error_class( self ): + return self.error_class + + def get_error_code( self ): + return self.error_code + + def __str__( self ): + error_class = SessionError.error_classes.get( self.error_class, None ) + if not error_class: + error_code_str = self.error_code + error_class_str = self.error_class + else: + error_class_str = error_class[0] + error_code = error_class[1].get( self.error_code, None ) + if not error_code: + error_code_str = self.error_code + else: + error_code_str = '%s(%s)' % error_code + + if self.nt_status: + return 'SMB SessionError: %s(%s)' % nt_errors.ERROR_MESSAGES[self.error_code] + else: + # Fall back to the old format + return 'SMB SessionError: class: %s, code: %s' % (error_class_str, error_code_str) + + +# Raised when an supported feature is present/required in the protocol but is not +# currently supported by pysmb +class UnsupportedFeature(Exception): pass + +# Contains information about a SMB shared device/service +class SharedDevice: + def __init__(self, name, share_type, comment): + self.__name = name + self.__type = share_type + self.__comment = comment + + def get_name(self): + return self.__name + + def get_type(self): + return self.__type + + def get_comment(self): + return self.__comment + + def __repr__(self): + return '<SharedDevice instance: name=' + self.__name + ', type=' + str(self.__type) + ', comment="' + self.__comment + '">' + + +# Contains information about the shared file/directory +class SharedFile: + def __init__(self, ctime, atime, mtime, filesize, allocsize, attribs, shortname, longname): + self.__ctime = ctime + self.__atime = atime + self.__mtime = mtime + self.__filesize = filesize + self.__allocsize = allocsize + self.__attribs = attribs + try: + self.__shortname = shortname[:string.index(shortname, '\0')] + except ValueError: + self.__shortname = shortname + try: + self.__longname = longname[:string.index(longname, '\0')] + except ValueError: + self.__longname = longname + + def get_ctime(self): + return self.__ctime + + def get_ctime_epoch(self): + return self.__convert_smbtime(self.__ctime) + + def get_mtime(self): + return self.__mtime + + def get_mtime_epoch(self): + return self.__convert_smbtime(self.__mtime) + + def get_atime(self): + return self.__atime + + def get_atime_epoch(self): + return self.__convert_smbtime(self.__atime) + + def get_filesize(self): + return self.__filesize + + def get_allocsize(self): + return self.__allocsize + + def get_attributes(self): + return self.__attribs + + def is_archive(self): + return self.__attribs & ATTR_ARCHIVE + + def is_compressed(self): + return self.__attribs & ATTR_COMPRESSED + + def is_normal(self): + return self.__attribs & ATTR_NORMAL + + def is_hidden(self): + return self.__attribs & ATTR_HIDDEN + + def is_readonly(self): + return self.__attribs & ATTR_READONLY + + def is_temporary(self): + return self.__attribs & ATTR_TEMPORARY + + def is_directory(self): + return self.__attribs & ATTR_DIRECTORY + + def is_system(self): + return self.__attribs & ATTR_SYSTEM + + def get_shortname(self): + return self.__shortname + + def get_longname(self): + return self.__longname + + def __repr__(self): + return '<SharedFile instance: shortname="' + self.__shortname + '", longname="' + self.__longname + '", filesize=' + str(self.__filesize) + '>' + + @staticmethod + def __convert_smbtime(t): + x = t >> 32 + y = t & 0xffffffffL + geo_cal_offset = 11644473600.0 # = 369.0 * 365.25 * 24 * 60 * 60 - (3.0 * 24 * 60 * 60 + 6.0 * 60 * 60) + return (x * 4.0 * (1 << 30) + (y & 0xfff00000L)) * 1.0e-7 - geo_cal_offset + + +# Contain information about a SMB machine +class SMBMachine: + def __init__(self, nbname, nbt_type, comment): + self.__nbname = nbname + self.__type = nbt_type + self.__comment = comment + + def __repr__(self): + return '<SMBMachine instance: nbname="' + self.__nbname + '", type=' + hex(self.__type) + ', comment="' + self.__comment + '">' + +class SMBDomain: + def __init__(self, nbgroup, domain_type, master_browser): + self.__nbgroup = nbgroup + self.__type = domain_type + self.__master_browser = master_browser + + def __repr__(self): + return '<SMBDomain instance: nbgroup="' + self.__nbgroup + '", type=' + hex(self.__type) + ', master browser="' + self.__master_browser + '">' + +# Represents a SMB Packet +class NewSMBPacket(Structure): + structure = ( + ('Signature', '"\xffSMB'), + ('Command','B=0'), + ('ErrorClass','B=0'), + ('_reserved','B=0'), + ('ErrorCode','<H=0'), + ('Flags1','B=0'), + ('Flags2','<H=0'), + ('PIDHigh','<H=0'), + ('SecurityFeatures','8s=""'), + ('Reserved','<H=0'), + ('Tid','<H=0xffff'), + ('Pid','<H=0'), + ('Uid','<H=0'), + ('Mid','<H=0'), + ('Data','*:'), + ) + + def __init__(self, **kargs): + Structure.__init__(self, **kargs) + + if self.fields.has_key('Flags2') is False: + self['Flags2'] = 0 + if self.fields.has_key('Flags1') is False: + self['Flags1'] = 0 + + if not kargs.has_key('data'): + self['Data'] = [] + + def addCommand(self, command): + if len(self['Data']) == 0: + self['Command'] = command.command + else: + self['Data'][-1]['Parameters']['AndXCommand'] = command.command + self['Data'][-1]['Parameters']['AndXOffset'] = len(self) + self['Data'].append(command) + + def isMoreData(self): + return (self['Command'] in [SMB.SMB_COM_TRANSACTION, SMB.SMB_COM_READ_ANDX, SMB.SMB_COM_READ_RAW] and + self['ErrorClass'] == 1 and self['ErrorCode'] == SessionError.ERRmoredata) + + def isMoreProcessingRequired(self): + return self['ErrorClass'] == 0x16 and self['ErrorCode'] == 0xc000 + + def isValidAnswer(self, cmd): + # this was inside a loop reading more from the net (with recv_packet(None)) + if self['Command'] == cmd: + if (self['ErrorClass'] == 0x00 and + self['ErrorCode'] == 0x00): + return 1 + elif self.isMoreData(): + return 1 + elif self.isMoreProcessingRequired(): + return 1 + raise SessionError, ("SMB Library Error", self['ErrorClass'] + (self['_reserved'] << 8), self['ErrorCode'], self['Flags2'] & SMB.FLAGS2_NT_STATUS) + else: + raise UnsupportedFeature, ("Unexpected answer from server: Got %d, Expected %d" % (self['Command'], cmd)) + + +class SMBCommand(Structure): + structure = ( + ('WordCount', 'B=len(Parameters)/2'), + ('_ParametersLength','_-Parameters','WordCount*2'), + ('Parameters',':'), # default set by constructor + ('ByteCount','<H-Data'), + ('Data',':'), # default set by constructor + ) + + def __init__(self, commandOrData = None, data = None, **kargs): + if type(commandOrData) == type(0): + self.command = commandOrData + else: + data = data or commandOrData + + Structure.__init__(self, data = data, **kargs) + + if data is None: + self['Parameters'] = '' + self['Data'] = '' + +class AsciiOrUnicodeStructure(Structure): + UnicodeStructure = () + AsciiStructure = () + def __init__(self, flags = 0, **kargs): + if flags & SMB.FLAGS2_UNICODE: + self.structure = self.UnicodeStructure + else: + self.structure = self.AsciiStructure + Structure.__init__(self, **kargs) + +class SMBCommand_Parameters(Structure): + pass + +class SMBAndXCommand_Parameters(Structure): + commonHdr = ( + ('AndXCommand','B=0xff'), + ('_reserved','B=0'), + ('AndXOffset','<H=0'), + ) + structure = ( # default structure, overriden by subclasses + ('Data',':=""'), + ) + +############# TRANSACTIONS RELATED +# TRANS2_QUERY_FS_INFORMATION +# QUERY_FS Information Levels +# SMB_QUERY_FS_ATTRIBUTE_INFO +class SMBQueryFsAttributeInfo(Structure): + structure = ( + ('FileSystemAttributes','<L'), + ('MaxFilenNameLengthInBytes','<L'), + ('LengthOfFileSystemName','<L-FileSystemName'), + ('FileSystemName',':'), + ) + +class SMBQueryFsInfoVolume(AsciiOrUnicodeStructure): + commonHdr = ( + ('ulVolSerialNbr','<L=0xABCDEFAA'), + ('cCharCount','<B-VolumeLabel'), + ) + AsciiStructure = ( + ('VolumeLabel','z'), + ) + UnicodeStructure = ( + ('VolumeLabel','u'), + ) + +# FILE_FS_SIZE_INFORMATION +class FileFsSizeInformation(Structure): + structure = ( + ('TotalAllocationUnits','<q=148529400'), + ('AvailableAllocationUnits','<q=14851044'), + ('SectorsPerAllocationUnit','<L=2'), + ('BytesPerSector','<L=512'), + ) + +# SMB_QUERY_FS_SIZE_INFO +class SMBQueryFsSizeInfo(Structure): + structure = ( + ('TotalAllocationUnits','<q=148529400'), + ('TotalFreeAllocationUnits','<q=14851044'), + ('SectorsPerAllocationUnit','<L=2'), + ('BytesPerSector','<L=512'), + ) +# FILE_FS_FULL_SIZE_INFORMATION +class SMBFileFsFullSizeInformation(Structure): + structure = ( + ('TotalAllocationUnits','<q=148529400'), + ('CallerAvailableAllocationUnits','<q=148529400'), + ('ActualAvailableAllocationUnits','<q=148529400'), + ('SectorsPerAllocationUnit','<L=15'), + ('BytesPerSector','<L=512') + ) +# SMB_QUERY_FS_VOLUME_INFO +class SMBQueryFsVolumeInfo(Structure): + structure = ( + ('VolumeCreationTime','<q'), + ('SerialNumber','<L=0xABCDEFAA'), + ('VolumeLabelSize','<L=len(VolumeLabel)'), + ('Reserved','<H=0x10'), + ('VolumeLabel',':') + ) +# SMB_FIND_FILE_BOTH_DIRECTORY_INFO level +class SMBFindFileBothDirectoryInfo(AsciiOrUnicodeStructure): + commonHdr = ( + ('NextEntryOffset','<L=0'), + ('FileIndex','<L=0'), + ('CreationTime','<q'), + ('LastAccessTime','<q'), + ('LastWriteTime','<q'), + ('LastChangeTime','<q'), + ('EndOfFile','<q=0'), + ('AllocationSize','<q=0'), + ('ExtFileAttributes','<L=0'), + ) + AsciiStructure = ( + ('FileNameLength','<L-FileName','len(FileName)'), + ('EaSize','<L=0'), + ('ShortNameLength','<B=0'), + ('Reserved','<B=0'), + ('ShortName','24s'), + ('FileName',':'), + ) + UnicodeStructure = ( + ('FileNameLength','<L-FileName','len(FileName)*2'), + ('EaSize','<L=0'), + ('ShortNameLength','<B=0'), + ('Reserved','<B=0'), + ('ShortName','24s'), + ('FileName',':'), + ) + +# SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO level +class SMBFindFileIdFullDirectoryInfo(AsciiOrUnicodeStructure): + commonHdr = ( + ('NextEntryOffset','<L=0'), + ('FileIndex','<L=0'), + ('CreationTime','<q'), + ('LastAccessTime','<q'), + ('LastWriteTime','<q'), + ('LastChangeTime','<q'), + ('EndOfFile','<q=0'), + ('AllocationSize','<q=0'), + ('ExtFileAttributes','<L=0'), + ) + AsciiStructure = ( + ('FileNameLength','<L-FileName','len(FileName)'), + ('EaSize','<L=0'), + ('FileID','<q=0'), + ('FileName',':'), + ) + UnicodeStructure = ( + ('FileNameLength','<L-FileName','len(FileName)*2'), + ('EaSize','<L=0'), + ('FileID','<q=0'), + ('FileName',':'), + ) + +# SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO level +class SMBFindFileIdBothDirectoryInfo(AsciiOrUnicodeStructure): + commonHdr = ( + ('NextEntryOffset','<L=0'), + ('FileIndex','<L=0'), + ('CreationTime','<q'), + ('LastAccessTime','<q'), + ('LastWriteTime','<q'), + ('LastChangeTime','<q'), + ('EndOfFile','<q=0'), + ('AllocationSize','<q=0'), + ('ExtFileAttributes','<L=0'), + ) + AsciiStructure = ( + ('FileNameLength','<L-FileName','len(FileName)'), + ('EaSize','<L=0'), + ('ShortNameLength','<B=0'), + ('Reserved','<B=0'), + ('ShortName','24s'), + ('Reserved','<H=0'), + ('FileID','<q=0'), + ('FileName','z'), + ) + UnicodeStructure = ( + ('FileNameLength','<L-FileName','len(FileName)*2'), + ('EaSize','<L=0'), + ('ShortNameLength','<B=0'), + ('Reserved','<B=0'), + ('ShortName','24s'), + ('Reserved','<H=0'), + ('FileID','<q=0'), + ('FileName',':'), + ) + +# SMB_FIND_FILE_DIRECTORY_INFO level +class SMBFindFileDirectoryInfo(AsciiOrUnicodeStructure): + commonHdr = ( + ('NextEntryOffset','<L=0'), + ('FileIndex','<L=0'), + ('CreationTime','<q'), + ('LastAccessTime','<q'), + ('LastWriteTime','<q'), + ('LastChangeTime','<q'), + ('EndOfFile','<q=0'), + ('AllocationSize','<q=1'), + ('ExtFileAttributes','<L=0'), + ) + AsciiStructure = ( + ('FileNameLength','<L-FileName','len(FileName)'), + ('FileName','z'), + ) + UnicodeStructure = ( + ('FileNameLength','<L-FileName','len(FileName)*2'), + ('FileName',':'), + ) + +# SMB_FIND_FILE_NAMES_INFO level +class SMBFindFileNamesInfo(AsciiOrUnicodeStructure): + commonHdr = ( + ('NextEntryOffset','<L=0'), + ('FileIndex','<L=0'), + ) + AsciiStructure = ( + ('FileNameLength','<L-FileName','len(FileName)'), + ('FileName','z'), + ) + UnicodeStructure = ( + ('FileNameLength','<L-FileName','len(FileName)*2'), + ('FileName',':'), + ) + +# SMB_FIND_FILE_FULL_DIRECTORY_INFO level +class SMBFindFileFullDirectoryInfo(AsciiOrUnicodeStructure): + commonHdr = ( + ('NextEntryOffset','<L=0'), + ('FileIndex','<L=0'), + ('CreationTime','<q'), + ('LastAccessTime','<q'), + ('LastWriteTime','<q'), + ('LastChangeTime','<q'), + ('EndOfFile','<q=0'), + ('AllocationSize','<q=1'), + ('ExtFileAttributes','<L=0'), + ) + AsciiStructure = ( + ('FileNameLength','<L-FileName','len(FileName)'), + ('EaSize','<L'), + ('FileName','z'), + ) + UnicodeStructure = ( + ('FileNameLength','<L-FileName','len(FileName)*2'), + ('EaSize','<L'), + ('FileName',':'), + ) + +# SMB_FIND_INFO_STANDARD level +class SMBFindInfoStandard(AsciiOrUnicodeStructure): + commonHdr = ( + ('ResumeKey','<L=0xff'), + ('CreationDate','<H=0'), + ('CreationTime','<H=0'), + ('LastAccessDate','<H=0'), + ('LastAccessTime','<H=0'), + ('LastWriteDate','<H=0'), + ('LastWriteTime','<H=0'), + ('EaSize','<L'), + ('AllocationSize','<L=1'), + ('ExtFileAttributes','<H=0'), + ) + AsciiStructure = ( + ('FileNameLength','<B-FileName','len(FileName)'), + ('FileName','z'), + ) + UnicodeStructure = ( + ('FileNameLength','<B-FileName','len(FileName)*2'), + ('FileName',':'), + ) + +# SET_FILE_INFORMATION structures +# SMB_SET_FILE_DISPOSITION_INFO +class SMBSetFileDispositionInfo(Structure): + structure = ( + ('DeletePending','<B'), + ) + +# SMB_SET_FILE_BASIC_INFO +class SMBSetFileBasicInfo(Structure): + structure = ( + ('CreationTime','<q'), + ('LastAccessTime','<q'), + ('LastWriteTime','<q'), + ('ChangeTime','<q'), + ('ExtFileAttributes','<H'), + ('Reserved','<L'), + ) + +# FILE_STREAM_INFORMATION +class SMBFileStreamInformation(Structure): + commonHdr = ( + ('NextEntryOffset','<L=0'), + ('StreamNameLength','<L=0'), + ('StreamSize','<q=0'), + ('StreamAllocationSize','<q=0'), + ('StreamName',':=""'), + ) + +# FILE_NETWORK_OPEN_INFORMATION +class SMBFileNetworkOpenInfo(Structure): + structure = ( + ('CreationTime','<q=0'), + ('LastAccessTime','<q=0'), + ('LastWriteTime','<q=0'), + ('ChangeTime','<q=0'), + ('AllocationSize','<q=0'), + ('EndOfFile','<q=0'), + ('FileAttributes','<L=0'), + ('Reserved','<L=0'), + ) + +# SMB_SET_FILE_END_OF_FILE_INFO +class SMBSetFileEndOfFileInfo(Structure): + structure = ( + ('EndOfFile','<q'), + ) + +# TRANS2_FIND_NEXT2 +class SMBFindNext2_Parameters(AsciiOrUnicodeStructure): + commonHdr = ( + ('SID','<H'), + ('SearchCount','<H'), + ('InformationLevel','<H'), + ('ResumeKey','<L'), + ('Flags','<H'), + ) + AsciiStructure = ( + ('FileName','z'), + ) + UnicodeStructure = ( + ('FileName','u'), + ) + +class SMBFindNext2Response_Parameters(Structure): + structure = ( + ('SearchCount','<H'), + ('EndOfSearch','<H=1'), + ('EaErrorOffset','<H=0'), + ('LastNameOffset','<H=0'), + ) + +class SMBFindNext2_Data(Structure): + structure = ( + ('GetExtendedAttributesListLength','_-GetExtendedAttributesList', 'self["GetExtendedAttributesListLength"]'), + ('GetExtendedAttributesList',':'), + ) + + +# TRANS2_FIND_FIRST2 +class SMBFindFirst2Response_Parameters(Structure): + structure = ( + ('SID','<H'), + ('SearchCount','<H'), + ('EndOfSearch','<H=1'), + ('EaErrorOffset','<H=0'), + ('LastNameOffset','<H=0'), + ) + +class SMBFindFirst2_Parameters(AsciiOrUnicodeStructure): + commonHdr = ( + ('SearchAttributes','<H'), + ('SearchCount','<H'), + ('Flags','<H'), + ('InformationLevel','<H'), + ('SearchStorageType','<L'), + ) + AsciiStructure = ( + ('FileName','z'), + ) + UnicodeStructure = ( + ('FileName','u'), + ) + +class SMBFindFirst2_Data(Structure): + structure = ( + ('GetExtendedAttributesListLength','_-GetExtendedAttributesList', 'self["GetExtendedAttributesListLength"]'), + ('GetExtendedAttributesList',':'), + ) + +# TRANS2_SET_PATH_INFORMATION +class SMBSetPathInformation_Parameters(AsciiOrUnicodeStructure): + commonHdr = ( + ('InformationLevel','<H'), + ('Reserved','<L'), + ) + AsciiStructure = ( + ('FileName','z'), + ) + UnicodeStructure = ( + ('FileName','u'), + ) + +class SMBSetPathInformationResponse_Parameters(Structure): + structure = ( + ('EaErrorOffset','<H=0'), + ) + +# TRANS2_SET_FILE_INFORMATION +class SMBSetFileInformation_Parameters(Structure): + structure = ( + ('FID','<H'), + ('InformationLevel','<H'), + ('Reserved','<H'), + ) + +class SMBSetFileInformationResponse_Parameters(Structure): + structure = ( + ('EaErrorOffset','<H=0'), + ) + +# TRANS2_QUERY_FILE_INFORMATION +class SMBQueryFileInformation_Parameters(Structure): + structure = ( + ('FID','<H'), + ('InformationLevel','<H'), + ) + +class SMBQueryFileInformationResponse_Parameters(Structure): + structure = ( + ('EaErrorOffset','<H=0'), + ) + +class SMBQueryFileInformation_Data(Structure): + structure = ( + ('GetExtendedAttributeList',':'), + ) + +# TRANS2_QUERY_PATH_INFORMATION +class SMBQueryPathInformationResponse_Parameters(Structure): + structure = ( + ('EaErrorOffset','<H=0'), + ) + +class SMBQueryPathInformation_Parameters(AsciiOrUnicodeStructure): + commonHdr = ( + ('InformationLevel','<H'), + ('Reserved','<L=0'), + ) + AsciiStructure = ( + ('FileName','z'), + ) + UnicodeStructure = ( + ('FileName','u'), + ) + +class SMBQueryPathInformation_Data(Structure): + structure = ( + ('GetExtendedAttributeList',':'), + ) + + +# SMB_QUERY_FILE_EA_INFO +class SMBQueryFileEaInfo(Structure): + structure = ( + ('EaSize','<L=0'), + ) + +# SMB_QUERY_FILE_BASIC_INFO +class SMBQueryFileBasicInfo(Structure): + structure = ( + ('CreationTime','<q'), + ('LastAccessTime','<q'), + ('LastWriteTime','<q'), + ('LastChangeTime','<q'), + ('ExtFileAttributes','<L'), + #('Reserved','<L=0'), + ) + +# SMB_QUERY_FILE_STANDARD_INFO +class SMBQueryFileStandardInfo(Structure): + structure = ( + ('AllocationSize','<q'), + ('EndOfFile','<q'), + ('NumberOfLinks','<L=0'), + ('DeletePending','<B=0'), + ('Directory','<B'), + ) + +# SMB_QUERY_FILE_ALL_INFO +class SMBQueryFileAllInfo(Structure): + structure = ( + ('CreationTime','<q'), + ('LastAccessTime','<q'), + ('LastWriteTime','<q'), + ('LastChangeTime','<q'), + ('ExtFileAttributes','<L'), + ('Reserved','<L=0'), + ('AllocationSize','<q'), + ('EndOfFile','<q'), + ('NumberOfLinks','<L=0'), + ('DeletePending','<B=0'), + ('Directory','<B'), + ('Reserved','<H=0'), + ('EaSize','<L=0'), + ('FileNameLength','<L-FileName','len(FileName)'), + ('FileName',':'), + ) + +# \PIPE\LANMAN NetShareEnum +class SMBNetShareEnum(Structure): + structure = ( + ('RAPOpcode','<H=0'), + ('ParamDesc','z'), + ('DataDesc','z'), + ('InfoLevel','<H'), + ('ReceiveBufferSize','<H'), + ) + +class SMBNetShareEnumResponse(Structure): + structure = ( + ('Status','<H=0'), + ('Convert','<H=0'), + ('EntriesReturned','<H'), + ('EntriesAvailable','<H'), + ) + +class NetShareInfo1(Structure): + structure = ( + ('NetworkName','13s'), + ('Pad','<B=0'), + ('Type','<H=0'), + ('RemarkOffsetLow','<H=0'), + ('RemarkOffsetHigh','<H=0'), + ) + +# \PIPE\LANMAN NetServerGetInfo +class SMBNetServerGetInfoResponse(Structure): + structure = ( + ('Status','<H=0'), + ('Convert','<H=0'), + ('TotalBytesAvailable','<H'), + ) + +class SMBNetServerInfo1(Structure): + # Level 1 Response + structure = ( + ('ServerName','16s'), + ('MajorVersion','B=5'), + ('MinorVersion','B=0'), + ('ServerType','<L=3'), + ('ServerCommentLow','<H=0'), + ('ServerCommentHigh','<H=0'), + ) + +# \PIPE\LANMAN NetShareGetInfo +class SMBNetShareGetInfo(Structure): + structure = ( + ('RAPOpcode','<H=0'), + ('ParamDesc','z'), + ('DataDesc','z'), + ('ShareName','z'), + ('InfoLevel','<H'), + ('ReceiveBufferSize','<H'), + ) + +class SMBNetShareGetInfoResponse(Structure): + structure = ( + ('Status','<H=0'), + ('Convert','<H=0'), + ('TotalBytesAvailable','<H'), + ) + +############# Security Features +class SecurityFeatures(Structure): + structure = ( + ('Key','<L=0'), + ('CID','<H=0'), + ('SequenceNumber','<H=0'), + ) + +############# SMB_COM_QUERY_INFORMATION2 (0x23) +class SMBQueryInformation2_Parameters(Structure): + structure = ( + ('Fid','<H'), + ) + +class SMBQueryInformation2Response_Parameters(Structure): + structure = ( + ('CreateDate','<H'), + ('CreationTime','<H'), + ('LastAccessDate','<H'), + ('LastAccessTime','<H'), + ('LastWriteDate','<H'), + ('LastWriteTime','<H'), + ('FileDataSize','<L'), + ('FileAllocationSize','<L'), + ('FileAttributes','<L'), + ) + + + +############# SMB_COM_SESSION_SETUP_ANDX (0x73) +class SMBSessionSetupAndX_Parameters(SMBAndXCommand_Parameters): + structure = ( + ('MaxBuffer','<H'), + ('MaxMpxCount','<H'), + ('VCNumber','<H'), + ('SessionKey','<L'), + ('AnsiPwdLength','<H'), + ('UnicodePwdLength','<H'), + ('_reserved','<L=0'), + ('Capabilities','<L'), + ) + +class SMBSessionSetupAndX_Extended_Parameters(SMBAndXCommand_Parameters): + structure = ( + ('MaxBufferSize','<H'), + ('MaxMpxCount','<H'), + ('VcNumber','<H'), + ('SessionKey','<L'), + ('SecurityBlobLength','<H'), + ('Reserved','<L=0'), + ('Capabilities','<L'), + ) + +class SMBSessionSetupAndX_Data(AsciiOrUnicodeStructure): + AsciiStructure = ( + ('AnsiPwdLength','_-AnsiPwd','self["AnsiPwdLength"]'), + ('UnicodePwdLength','_-UnicodePwd','self["UnicodePwdLength"]'), + ('AnsiPwd',':=""'), + ('UnicodePwd',':=""'), + ('Account','z=""'), + ('PrimaryDomain','z=""'), + ('NativeOS','z=""'), + ('NativeLanMan','z=""'), + ) + + UnicodeStructure = ( + ('AnsiPwdLength','_-AnsiPwd','self["AnsiPwdLength"]'), + ('UnicodePwdLength','_-UnicodePwd','self["UnicodePwdLength"]'), + ('AnsiPwd',':=""'), + ('UnicodePwd',':=""'), + ('Account','u=""'), + ('PrimaryDomain','u=""'), + ('NativeOS','u=""'), + ('NativeLanMan','u=""'), + ) + +class SMBSessionSetupAndX_Extended_Data(AsciiOrUnicodeStructure): + AsciiStructure = ( + ('SecurityBlobLength','_-SecurityBlob','self["SecurityBlobLength"]'), + ('SecurityBlob',':'), + ('NativeOS','z=""'), + ('NativeLanMan','z=""'), + ) + + UnicodeStructure = ( + ('SecurityBlobLength','_-SecurityBlob','self["SecurityBlobLength"]'), + ('SecurityBlob',':'), + ('NativeOS','u=""'), + ('NativeLanMan','u=""'), + ) + +class SMBSessionSetupAndXResponse_Parameters(SMBAndXCommand_Parameters): + structure = ( + ('Action','<H'), + ) + +class SMBSessionSetupAndX_Extended_Response_Parameters(SMBAndXCommand_Parameters): + structure = ( + ('Action','<H=0'), + ('SecurityBlobLength','<H'), + ) + +class SMBSessionSetupAndXResponse_Data(AsciiOrUnicodeStructure): + AsciiStructure = ( + ('NativeOS','z=""'), + ('NativeLanMan','z=""'), + ('PrimaryDomain','z=""'), + ) + + UnicodeStructure = ( + ('NativeOS','u=""'), + ('NativeLanMan','u=""'), + ('PrimaryDomain','u=""'), + ) + +class SMBSessionSetupAndX_Extended_Response_Data(AsciiOrUnicodeStructure): + AsciiStructure = ( + ('SecurityBlobLength','_-SecurityBlob','self["SecurityBlobLength"]'), + ('SecurityBlob',':'), + ('NativeOS','z=""'), + ('NativeLanMan','z=""'), + ) + + UnicodeStructure = ( + ('SecurityBlobLength','_-SecurityBlob','self["SecurityBlobLength"]'), + ('SecurityBlob',':'), + ('NativeOS','u=""'), + ('NativeLanMan','u=""'), + ) + +############# SMB_COM_TREE_CONNECT (0x70) +class SMBTreeConnect_Parameters(SMBCommand_Parameters): + structure = ( + ) + +class SMBTreeConnect_Data(SMBCommand_Parameters): + structure = ( + ('PathFormat','"\x04'), + ('Path','z'), + ('PasswordFormat','"\x04'), + ('Password','z'), + ('ServiceFormat','"\x04'), + ('Service','z'), + ) + +############# SMB_COM_TREE_CONNECT_ANDX (0x75) +class SMBTreeConnectAndX_Parameters(SMBAndXCommand_Parameters): + structure = ( + ('Flags','<H=0'), + ('PasswordLength','<H'), + ) + +class SMBTreeConnectAndXResponse_Parameters(SMBAndXCommand_Parameters): + structure = ( + ('OptionalSupport','<H=0'), + ) + +class SMBTreeConnectAndXExtendedResponse_Parameters(SMBAndXCommand_Parameters): + structure = ( + ('OptionalSupport','<H=1'), + ('MaximalShareAccessRights','<L=0x1fffff'), + ('GuestMaximalShareAccessRights','<L=0x1fffff'), + ) + +class SMBTreeConnectAndX_Data(AsciiOrUnicodeStructure): + AsciiStructure = ( + ('_PasswordLength','_-Password','self["_PasswordLength"]'), + ('Password',':'), + ('Path','z'), + ('Service','z'), + ) + + UnicodeStructure = ( + ('_PasswordLength','_-Password','self["_PasswordLength"] if self["_PasswordLength"] > 0 else 1'), + ('Password',':'), + ('Path','u'), + ('Service','z'), + ) + +class SMBTreeConnectAndXResponse_Data(AsciiOrUnicodeStructure): + AsciiStructure = ( + ('Service','z'), + ('PadLen','_-Pad','self["PadLen"]'), + ('Pad',':=""'), + ('NativeFileSystem','z'), + ) + UnicodeStructure = ( + ('Service','z'), + ('PadLen','_-Pad','self["PadLen"]'), + ('Pad',':=""'), + ('NativeFileSystem','u'), + ) + +############# SMB_COM_NT_CREATE_ANDX (0xA2) +class SMBNtCreateAndX_Parameters(SMBAndXCommand_Parameters): + structure = ( + ('_reserved', 'B=0'), + ('FileNameLength','<H'), # NameLength + ('CreateFlags','<L'), # Flags + ('RootFid','<L=0'), # RootDirectoryFID + ('AccessMask','<L'), # DesiredAccess + ('AllocationSizeLo','<L=0'), # AllocationSize + ('AllocationSizeHi','<L=0'), + ('FileAttributes','<L=0'), # ExtFileAttributes + ('ShareAccess','<L=3'), # + ('Disposition','<L=1'), # CreateDisposition + ('CreateOptions','<L'), # CreateOptions + ('Impersonation','<L=2'), + ('SecurityFlags','B=3'), + ) + +class SMBNtCreateAndXResponse_Parameters(SMBAndXCommand_Parameters): + # XXX Is there a memory leak in the response for NTCreate (where the Data section would be) in Win 2000, Win XP, and Win 2003? + structure = ( + ('OplockLevel', 'B=0'), + ('Fid','<H'), + ('CreateAction','<L'), + ('CreateTime','<q=0'), + ('LastAccessTime','<q=0'), + ('LastWriteTime','<q=0'), + ('LastChangeTime','<q=0'), + ('FileAttributes','<L=0x80'), + ('AllocationSize','<q=0'), + ('EndOfFile','<q=0'), + ('FileType','<H=0'), + ('IPCState','<H=0'), + ('IsDirectory','B'), + ) + +class SMBNtCreateAndXExtendedResponse_Parameters(SMBAndXCommand_Parameters): + # [MS-SMB] Extended response description + structure = ( + ('OplockLevel', 'B=0'), + ('Fid','<H'), + ('CreateAction','<L'), + ('CreateTime','<q=0'), + ('LastAccessTime','<q=0'), + ('LastWriteTime','<q=0'), + ('LastChangeTime','<q=0'), + ('FileAttributes','<L=0x80'), + ('AllocationSize','<q=0'), + ('EndOfFile','<q=0'), + ('FileType','<H=0'), + ('IPCState','<H=0'), + ('IsDirectory','B'), + ('VolumeGUID','16s'), + ('FileIdLow','<L=0'), + ('FileIdHigh','<L=0'), + ('MaximalAccessRights','<L=0x12019b'), + ('GuestMaximalAccessRights','<L=0x120089'), + ) + +class SMBNtCreateAndX_Data(AsciiOrUnicodeStructure): + AsciiStructure = ( + ('FileName','z'), + ) + UnicodeStructure = ( + ('Pad','B'), + ('FileName','u'), + ) + +############# SMB_COM_OPEN_ANDX (0xD2) +class SMBOpenAndX_Parameters(SMBAndXCommand_Parameters): + structure = ( + ('Flags','<H=0'), + ('DesiredAccess','<H=0'), + ('SearchAttributes','<H=0'), + ('FileAttributes','<H=0'), + ('CreationTime','<L=0'), + ('OpenMode','<H=1'), # SMB_O_OPEN = 1 + ('AllocationSize','<L=0'), + ('Reserved','8s=""'), + ) + +class SMBOpenAndX_Data(SMBNtCreateAndX_Data): + pass + +class SMBOpenAndXResponse_Parameters(SMBAndXCommand_Parameters): + structure = ( + ('Fid','<H=0'), + ('FileAttributes','<H=0'), + ('LastWriten','<L=0'), + ('FileSize','<L=0'), + ('GrantedAccess','<H=0'), + ('FileType','<H=0'), + ('IPCState','<H=0'), + ('Action','<H=0'), + ('ServerFid','<L=0'), + ('_reserved','<H=0'), + ) + +############# SMB_COM_WRITE (0x0B) +class SMBWrite_Parameters(SMBCommand_Parameters): + structure = ( + ('Fid','<H'), + ('Count','<H'), + ('Offset','<L'), + ('Remaining','<H'), + ) + +class SMBWriteResponse_Parameters(SMBCommand_Parameters): + structure = ( + ('Count','<H'), + ) + +class SMBWrite_Data(Structure): + structure = ( + ('BufferFormat','<B=1'), + ('DataLength','<H-Data'), + ('Data',':'), + ) + + +############# SMB_COM_WRITE_ANDX (0x2F) +class SMBWriteAndX_Parameters(SMBAndXCommand_Parameters): + structure = ( + ('Fid','<H=0'), + ('Offset','<L=0'), + ('_reserved','<L=0xff'), + ('WriteMode','<H=8'), + ('Remaining','<H=0'), + ('DataLength_Hi','<H=0'), + ('DataLength','<H=0'), + ('DataOffset','<H=0'), + ('HighOffset','<L=0'), + ) + +class SMBWriteAndX_Data_Short(Structure): + structure = ( + ('_PadLen','_-Pad','self["DataOffset"] - 59'), + ('Pad',':'), + #('Pad','<B=0'), + ('DataLength','_-Data','self["DataLength"]'), + ('Data',':'), + ) + +class SMBWriteAndX_Data(Structure): + structure = ( + ('_PadLen','_-Pad','self["DataOffset"] - 63'), + ('Pad',':'), + #('Pad','<B=0'), + ('DataLength','_-Data','self["DataLength"]'), + ('Data',':'), + ) + + +class SMBWriteAndX_Parameters_Short(SMBAndXCommand_Parameters): + structure = ( + ('Fid','<H'), + ('Offset','<L'), + ('_reserved','<L=0xff'), + ('WriteMode','<H=8'), + ('Remaining','<H'), + ('DataLength_Hi','<H=0'), + ('DataLength','<H'), + ('DataOffset','<H=0'), + ) + +class SMBWriteAndXResponse_Parameters(SMBAndXCommand_Parameters): + structure = ( + ('Count','<H'), + ('Available','<H'), + ('Reserved','<L=0'), + ) + +############# SMB_COM_WRITE_RAW (0x1D) +class SMBWriteRaw_Parameters(SMBCommand_Parameters): + structure = ( + ('Fid','<H'), + ('Count','<H'), + ('_reserved','<H=0'), + ('Offset','<L'), + ('Timeout','<L=0'), + ('WriteMode','<H=0'), + ('_reserved2','<L=0'), + ('DataLength','<H'), + ('DataOffset','<H=0'), + ) + +############# SMB_COM_READ (0x0A) +class SMBRead_Parameters(SMBCommand_Parameters): + structure = ( + ('Fid','<H'), + ('Count','<H'), + ('Offset','<L'), + ('Remaining','<H=Count'), + ) + +class SMBReadResponse_Parameters(Structure): + structure = ( + ('Count','<H=0'), + ('_reserved','8s=""'), + ) + +class SMBReadResponse_Data(Structure): + structure = ( + ('BufferFormat','<B=0x1'), + ('DataLength','<H-Data'), + ('Data',':'), + ) + +############# SMB_COM_READ_RAW (0x1A) +class SMBReadRaw_Parameters(SMBCommand_Parameters): + structure = ( + ('Fid','<H'), + ('Offset','<L'), + ('MaxCount','<H'), + ('MinCount','<H=MaxCount'), + ('Timeout','<L=0'), + ('_reserved','<H=0'), + ) + +############# SMB_COM_NT_TRANSACT (0xA0) +class SMBNTTransaction_Parameters(SMBCommand_Parameters): + structure = ( + ('MaxSetupCount','<B=0'), + ('Reserved1','<H=0'), + ('TotalParameterCount','<L'), + ('TotalDataCount','<L'), + ('MaxParameterCount','<L=1024'), + ('MaxDataCount','<L=65504'), + ('ParameterCount','<L'), + ('ParameterOffset','<L'), + ('DataCount','<L'), + ('DataOffset','<L'), + ('SetupCount','<B=len(Setup)/2'), + ('Function','<H=0'), + ('SetupLength','_-Setup','SetupCount*2'), + ('Setup',':'), + ) + +class SMBNTTransactionResponse_Parameters(SMBCommand_Parameters): + structure = ( + ('Reserved1','3s=""'), + ('TotalParameterCount','<L'), + ('TotalDataCount','<L'), + ('ParameterCount','<L'), + ('ParameterOffset','<L'), + ('ParameterDisplacement','<L=0'), + ('DataCount','<L'), + ('DataOffset','<L'), + ('DataDisplacement','<L=0'), + ('SetupCount','<B=0'), + ('SetupLength','_-Setup','SetupCount*2'), + ('Setup',':'), + ) + +class SMBNTTransaction_Data(Structure): + structure = ( + ('Pad1Length','_-Pad1','self["Pad1Length"]'), + ('Pad1',':'), + ('NT_Trans_ParametersLength','_-NT_Trans_Parameters','self["NT_Trans_ParametersLength"]'), + ('NT_Trans_Parameters',':'), + ('Pad2Length','_-Pad2','self["Pad2Length"]'), + ('Pad2',':'), + ('NT_Trans_DataLength','_-NT_Trans_Data','self["NT_Trans_DataLength"]'), + ('NT_Trans_Data',':'), + ) + +class SMBNTTransactionResponse_Data(Structure): + structure = ( + ('Pad1Length','_-Pad1','self["Pad1Length"]'), + ('Pad1',':'), + ('Trans_ParametersLength','_-Trans_Parameters','self["Trans_ParametersLength"]'), + ('Trans_Parameters',':'), + ('Pad2Length','_-Pad2','self["Pad2Length"]'), + ('Pad2',':'), + ('Trans_DataLength','_-Trans_Data','self["Trans_DataLength"]'), + ('Trans_Data',':'), + ) + + +############# SMB_COM_TRANSACTION2_SECONDARY (0x33) +class SMBTransaction2Secondary_Parameters(SMBCommand_Parameters): + structure = ( + ('TotalParameterCount','<H'), + ('TotalDataCount','<H'), + ('ParameterCount','<H'), + ('ParameterOffset','<H'), + ('DataCount','<H'), + ('DataOffset','<H'), + ('DataDisplacement','<H=0'), + ('FID','<H'), + ) + +class SMBTransaction2Secondary_Data(Structure): + structure = ( + ('Pad1Length','_-Pad1','self["Pad1Length"]'), + ('Pad1',':'), + ('Trans_ParametersLength','_-Trans_Parameters','self["Trans_ParametersLength"]'), + ('Trans_Parameters',':'), + ('Pad2Length','_-Pad2','self["Pad2Length"]'), + ('Pad2',':'), + ('Trans_DataLength','_-Trans_Data','self["Trans_DataLength"]'), + ('Trans_Data',':'), + ) + + +############# SMB_COM_TRANSACTION2 (0x32) + +class SMBTransaction2_Parameters(SMBCommand_Parameters): + structure = ( + ('TotalParameterCount','<H'), + ('TotalDataCount','<H'), + ('MaxParameterCount','<H=1024'), + ('MaxDataCount','<H=65504'), + ('MaxSetupCount','<B=0'), + ('Reserved1','<B=0'), + ('Flags','<H=0'), + ('Timeout','<L=0'), + ('Reserved2','<H=0'), + ('ParameterCount','<H'), + ('ParameterOffset','<H'), + ('DataCount','<H'), + ('DataOffset','<H'), + ('SetupCount','<B=len(Setup)/2'), + ('Reserved3','<B=0'), + ('SetupLength','_-Setup','SetupCount*2'), + ('Setup',':'), + ) + +class SMBTransaction2Response_Parameters(SMBCommand_Parameters): + structure = ( + ('TotalParameterCount','<H'), + ('TotalDataCount','<H'), + ('Reserved1','<H=0'), + ('ParameterCount','<H'), + ('ParameterOffset','<H'), + ('ParameterDisplacement','<H=0'), + ('DataCount','<H'), + ('DataOffset','<H'), + ('DataDisplacement','<H=0'), + ('SetupCount','<B=0'), + ('Reserved2','<B=0'), + ('SetupLength','_-Setup','SetupCount*2'), + ('Setup',':'), + ) + +class SMBTransaction2_Data(Structure): + structure = ( +# ('NameLength','_-Name','1'), +# ('Name',':'), + ('Pad1Length','_-Pad1','self["Pad1Length"]'), + ('Pad1',':'), + ('Trans_ParametersLength','_-Trans_Parameters','self["Trans_ParametersLength"]'), + ('Trans_Parameters',':'), + ('Pad2Length','_-Pad2','self["Pad2Length"]'), + ('Pad2',':'), + ('Trans_DataLength','_-Trans_Data','self["Trans_DataLength"]'), + ('Trans_Data',':'), + ) + +class SMBTransaction2Response_Data(Structure): + structure = ( + ('Pad1Length','_-Pad1','self["Pad1Length"]'), + ('Pad1',':'), + ('Trans_ParametersLength','_-Trans_Parameters','self["Trans_ParametersLength"]'), + ('Trans_Parameters',':'), + ('Pad2Length','_-Pad2','self["Pad2Length"]'), + ('Pad2',':'), + ('Trans_DataLength','_-Trans_Data','self["Trans_DataLength"]'), + ('Trans_Data',':'), + ) + +############# SMB_COM_QUERY_INFORMATION (0x08) + +class SMBQueryInformation_Data(AsciiOrUnicodeStructure): + AsciiStructure = ( + ('BufferFormat','B=4'), + ('FileName','z'), + ) + UnicodeStructure = ( + ('BufferFormat','B=4'), + ('FileName','u'), + ) + + +class SMBQueryInformationResponse_Parameters(Structure): + structure = ( + ('FileAttributes','<H'), + ('LastWriteTime','<L'), + ('FileSize','<L'), + ('Reserved','"0123456789'), + ) + +############# SMB_COM_TRANSACTION (0x25) +class SMBTransaction_Parameters(SMBCommand_Parameters): + structure = ( + ('TotalParameterCount','<H'), + ('TotalDataCount','<H'), + ('MaxParameterCount','<H=1024'), + ('MaxDataCount','<H=65504'), + ('MaxSetupCount','<B=0'), + ('Reserved1','<B=0'), + ('Flags','<H=0'), + ('Timeout','<L=0'), + ('Reserved2','<H=0'), + ('ParameterCount','<H'), + ('ParameterOffset','<H'), + ('DataCount','<H'), + ('DataOffset','<H'), + ('SetupCount','<B=len(Setup)/2'), + ('Reserved3','<B=0'), + ('SetupLength','_-Setup','SetupCount*2'), + ('Setup',':'), + ) + +class SMBTransactionResponse_Parameters(SMBCommand_Parameters): + structure = ( + ('TotalParameterCount','<H'), + ('TotalDataCount','<H'), + ('Reserved1','<H=0'), + ('ParameterCount','<H'), + ('ParameterOffset','<H'), + ('ParameterDisplacement','<H=0'), + ('DataCount','<H'), + ('DataOffset','<H'), + ('DataDisplacement','<H=0'), + ('SetupCount','<B'), + ('Reserved2','<B=0'), + ('SetupLength','_-Setup','SetupCount*2'), + ('Setup',':'), + ) + +# TODO: We should merge these both. But this will require fixing +# the instances where this structure is used on the client side +class SMBTransaction_SData(AsciiOrUnicodeStructure): + AsciiStructure = ( + ('Name','z'), + ('Trans_ParametersLength','_-Trans_Parameters'), + ('Trans_Parameters',':'), + ('Trans_DataLength','_-Trans_Data'), + ('Trans_Data',':'), + ) + UnicodeStructure = ( + ('Pad','B'), + ('Name','u'), + ('Trans_ParametersLength','_-Trans_Parameters'), + ('Trans_Parameters',':'), + ('Trans_DataLength','_-Trans_Data'), + ('Trans_Data',':'), + ) + +class SMBTransaction_Data(Structure): + structure = ( + ('NameLength','_-Name'), + ('Name',':'), + ('Trans_ParametersLength','_-Trans_Parameters'), + ('Trans_Parameters',':'), + ('Trans_DataLength','_-Trans_Data'), + ('Trans_Data',':'), + ) + +class SMBTransactionResponse_Data(Structure): + structure = ( + ('Trans_ParametersLength','_-Trans_Parameters'), + ('Trans_Parameters',':'), + ('Trans_DataLength','_-Trans_Data'), + ('Trans_Data',':'), + ) + +############# SMB_COM_READ_ANDX (0x2E) +class SMBReadAndX_Parameters(SMBAndXCommand_Parameters): + structure = ( + ('Fid','<H'), + ('Offset','<L'), + ('MaxCount','<H'), + ('MinCount','<H=MaxCount'), + ('_reserved','<L=0x0'), + ('Remaining','<H=MaxCount'), + ('HighOffset','<L=0'), + ) + +class SMBReadAndX_Parameters2(SMBAndXCommand_Parameters): + structure = ( + ('Fid','<H'), + ('Offset','<L'), + ('MaxCount','<H'), + ('MinCount','<H=MaxCount'), + ('_reserved','<L=0xffffffff'), + ('Remaining','<H=MaxCount'), + ) + +class SMBReadAndXResponse_Parameters(SMBAndXCommand_Parameters): + structure = ( + ('Remaining','<H=0'), + ('DataMode','<H=0'), + ('_reserved','<H=0'), + ('DataCount','<H'), + ('DataOffset','<H'), + ('DataCount_Hi','<L'), + ('_reserved2','6s=""'), + ) + +############# SMB_COM_ECHO (0x2B) +class SMBEcho_Data(Structure): + structure = ( + ('Data',':'), + ) + +class SMBEcho_Parameters(Structure): + structure = ( + ('EchoCount','<H'), + ) + +class SMBEchoResponse_Data(Structure): + structure = ( + ('Data',':'), + ) + +class SMBEchoResponse_Parameters(Structure): + structure = ( + ('SequenceNumber','<H=1'), + ) + +############# SMB_COM_QUERY_INFORMATION_DISK (0x80) +class SMBQueryInformationDiskResponse_Parameters(Structure): + structure = ( + ('TotalUnits','<H'), + ('BlocksPerUnit','<H'), + ('BlockSize','<H'), + ('FreeUnits','<H'), + ('Reserved','<H=0'), + ) + + +############# SMB_COM_LOGOFF_ANDX (0x74) +class SMBLogOffAndX(SMBAndXCommand_Parameters): + strucure = () + +############# SMB_COM_CLOSE (0x04) +class SMBClose_Parameters(SMBCommand_Parameters): + structure = ( + ('FID','<H'), + ('Time','<L=0'), + ) + +############# SMB_COM_FLUSH (0x05) +class SMBFlush_Parameters(SMBCommand_Parameters): + structure = ( + ('FID','<H'), + ) + +############# SMB_COM_CREATE_DIRECTORY (0x00) +class SMBCreateDirectory_Data(AsciiOrUnicodeStructure): + AsciiStructure = ( + ('BufferFormat','<B=4'), + ('DirectoryName','z'), + ) + UnicodeStructure = ( + ('BufferFormat','<B=4'), + ('DirectoryName','u'), + ) + +############# SMB_COM_DELETE (0x06) +class SMBDelete_Data(AsciiOrUnicodeStructure): + AsciiStructure = ( + ('BufferFormat','<B=4'), + ('FileName','z'), + ) + UnicodeStructure = ( + ('BufferFormat','<B=4'), + ('FileName','u'), + ) + +class SMBDelete_Parameters(Structure): + structure = ( + ('SearchAttributes','<H'), + ) + +############# SMB_COM_DELETE_DIRECTORY (0x01) +class SMBDeleteDirectory_Data(AsciiOrUnicodeStructure): + AsciiStructure = ( + ('BufferFormat','<B=4'), + ('DirectoryName','z'), + ) + UnicodeStructure = ( + ('BufferFormat','<B=4'), + ('DirectoryName','u'), + ) + +############# SMB_COM_CHECK_DIRECTORY (0x10) +class SMBCheckDirectory_Data(AsciiOrUnicodeStructure): + AsciiStructure = ( + ('BufferFormat','<B=4'), + ('DirectoryName','z'), + ) + UnicodeStructure = ( + ('BufferFormat','<B=4'), + ('DirectoryName','u'), + ) + +############# SMB_COM_RENAME (0x07) +class SMBRename_Parameters(SMBCommand_Parameters): + structure = ( + ('SearchAttributes','<H'), + ) + +class SMBRename_Data(AsciiOrUnicodeStructure): + AsciiStructure = ( + ('BufferFormat1','<B=4'), + ('OldFileName','z'), + ('BufferFormat2','<B=4'), + ('NewFileName','z'), + ) + UnicodeStructure = ( + ('BufferFormat1','<B=4'), + ('OldFileName','u'), + ('BufferFormat2','<B=4'), + ('Pad','B=0'), + ('NewFileName','u'), + ) + + +############# SMB_COM_OPEN (0x02) +class SMBOpen_Parameters(SMBCommand_Parameters): + structure = ( + ('DesiredAccess','<H=0'), + ('SearchAttributes','<H=0'), + ) + +class SMBOpen_Data(AsciiOrUnicodeStructure): + AsciiStructure = ( + ('FileNameFormat','"\x04'), + ('FileName','z'), + ) + UnicodeStructure = ( + ('FileNameFormat','"\x04'), + ('FileName','z'), + ) + +class SMBOpenResponse_Parameters(SMBCommand_Parameters): + structure = ( + ('Fid','<H=0'), + ('FileAttributes','<H=0'), + ('LastWriten','<L=0'), + ('FileSize','<L=0'), + ('GrantedAccess','<H=0'), + ) + +############# EXTENDED SECURITY CLASSES +class SMBExtended_Security_Parameters(Structure): + structure = ( + ('DialectIndex','<H'), + ('SecurityMode','<B'), + ('MaxMpxCount','<H'), + ('MaxNumberVcs','<H'), + ('MaxBufferSize','<L'), + ('MaxRawSize','<L'), + ('SessionKey','<L'), + ('Capabilities','<L'), + ('LowDateTime','<L'), + ('HighDateTime','<L'), + ('ServerTimeZone','<H'), + ('ChallengeLength','<B'), + ) + +class SMBExtended_Security_Data(Structure): + structure = ( + ('ServerGUID','16s'), + ('SecurityBlob',':'), + ) + +class SMBNTLMDialect_Parameters(Structure): + structure = ( + ('DialectIndex','<H'), + ('SecurityMode','<B'), + ('MaxMpxCount','<H'), + ('MaxNumberVcs','<H'), + ('MaxBufferSize','<L'), + ('MaxRawSize','<L'), + ('SessionKey','<L'), + ('Capabilities','<L'), + ('LowDateTime','<L'), + ('HighDateTime','<L'), + ('ServerTimeZone','<H'), + ('ChallengeLength','<B'), + ) + +class SMBNTLMDialect_Data(Structure): + structure = ( + ('ChallengeLength','_-Challenge','self["ChallengeLength"]'), + ('Challenge',':'), + ('Payload',':'), +# For some reason on an old Linux this field is not present, we have to check this out. There must be a flag stating this. + ('DomainName','_'), + ('ServerName','_'), + ) + def __init__(self,data = None, alignment = 0): + Structure.__init__(self,data,alignment) + #self['ChallengeLength']=8 + + def fromString(self,data): + Structure.fromString(self,data) + self['DomainName'] = '' + self['ServerName'] = '' + +class SMB: + # SMB Command Codes + SMB_COM_CREATE_DIRECTORY = 0x00 + SMB_COM_DELETE_DIRECTORY = 0x01 + SMB_COM_OPEN = 0x02 + SMB_COM_CREATE = 0x03 + SMB_COM_CLOSE = 0x04 + SMB_COM_FLUSH = 0x05 + SMB_COM_DELETE = 0x06 + SMB_COM_RENAME = 0x07 + SMB_COM_QUERY_INFORMATION = 0x08 + SMB_COM_SET_INFORMATION = 0x09 + SMB_COM_READ = 0x0A + SMB_COM_WRITE = 0x0B + SMB_COM_LOCK_BYTE_RANGE = 0x0C + SMB_COM_UNLOCK_BYTE_RANGE = 0x0D + SMB_COM_CREATE_TEMPORARY = 0x0E + SMB_COM_CREATE_NEW = 0x0F + SMB_COM_CHECK_DIRECTORY = 0x10 + SMB_COM_PROCESS_EXIT = 0x11 + SMB_COM_SEEK = 0x12 + SMB_COM_LOCK_AND_READ = 0x13 + SMB_COM_WRITE_AND_UNLOCK = 0x14 + SMB_COM_READ_RAW = 0x1A + SMB_COM_READ_MPX = 0x1B + SMB_COM_READ_MPX_SECONDARY = 0x1C + SMB_COM_WRITE_RAW = 0x1D + SMB_COM_WRITE_MPX = 0x1E + SMB_COM_WRITE_MPX_SECONDARY = 0x1F + SMB_COM_WRITE_COMPLETE = 0x20 + SMB_COM_QUERY_SERVER = 0x21 + SMB_COM_SET_INFORMATION2 = 0x22 + SMB_COM_QUERY_INFORMATION2 = 0x23 + SMB_COM_LOCKING_ANDX = 0x24 + SMB_COM_TRANSACTION = 0x25 + SMB_COM_TRANSACTION_SECONDARY = 0x26 + SMB_COM_IOCTL = 0x27 + SMB_COM_IOCTL_SECONDARY = 0x28 + SMB_COM_COPY = 0x29 + SMB_COM_MOVE = 0x2A + SMB_COM_ECHO = 0x2B + SMB_COM_WRITE_AND_CLOSE = 0x2C + SMB_COM_OPEN_ANDX = 0x2D + SMB_COM_READ_ANDX = 0x2E + SMB_COM_WRITE_ANDX = 0x2F + SMB_COM_NEW_FILE_SIZE = 0x30 + SMB_COM_CLOSE_AND_TREE_DISC = 0x31 + SMB_COM_TRANSACTION2 = 0x32 + SMB_COM_TRANSACTION2_SECONDARY = 0x33 + SMB_COM_FIND_CLOSE2 = 0x34 + SMB_COM_FIND_NOTIFY_CLOSE = 0x35 + # Used by Xenix/Unix 0x60 - 0x6E + SMB_COM_TREE_CONNECT = 0x70 + SMB_COM_TREE_DISCONNECT = 0x71 + SMB_COM_NEGOTIATE = 0x72 + SMB_COM_SESSION_SETUP_ANDX = 0x73 + SMB_COM_LOGOFF_ANDX = 0x74 + SMB_COM_TREE_CONNECT_ANDX = 0x75 + SMB_COM_QUERY_INFORMATION_DISK = 0x80 + SMB_COM_SEARCH = 0x81 + SMB_COM_FIND = 0x82 + SMB_COM_FIND_UNIQUE = 0x83 + SMB_COM_FIND_CLOSE = 0x84 + SMB_COM_NT_TRANSACT = 0xA0 + SMB_COM_NT_TRANSACT_SECONDARY = 0xA1 + SMB_COM_NT_CREATE_ANDX = 0xA2 + SMB_COM_NT_CANCEL = 0xA4 + SMB_COM_NT_RENAME = 0xA5 + SMB_COM_OPEN_PRINT_FILE = 0xC0 + SMB_COM_WRITE_PRINT_FILE = 0xC1 + SMB_COM_CLOSE_PRINT_FILE = 0xC2 + SMB_COM_GET_PRINT_QUEUE = 0xC3 + SMB_COM_READ_BULK = 0xD8 + SMB_COM_WRITE_BULK = 0xD9 + SMB_COM_WRITE_BULK_DATA = 0xDA + + # TRANSACT codes + TRANS_TRANSACT_NMPIPE = 0x26 + + # TRANSACT2 codes + TRANS2_FIND_FIRST2 = 0x0001 + TRANS2_FIND_NEXT2 = 0x0002 + TRANS2_QUERY_FS_INFORMATION = 0x0003 + TRANS2_QUERY_PATH_INFORMATION = 0x0005 + TRANS2_QUERY_FILE_INFORMATION = 0x0007 + TRANS2_SET_FILE_INFORMATION = 0x0008 + TRANS2_SET_PATH_INFORMATION = 0x0006 + + # Security Share Mode (Used internally by SMB class) + SECURITY_SHARE_MASK = 0x01 + SECURITY_SHARE_SHARE = 0x00 + SECURITY_SHARE_USER = 0x01 + SECURITY_SIGNATURES_ENABLED = 0X04 + SECURITY_SIGNATURES_REQUIRED = 0X08 + + # Security Auth Mode (Used internally by SMB class) + SECURITY_AUTH_MASK = 0x02 + SECURITY_AUTH_ENCRYPTED = 0x02 + SECURITY_AUTH_PLAINTEXT = 0x00 + + # Raw Mode Mask (Used internally by SMB class. Good for dialect up to and including LANMAN2.1) + RAW_READ_MASK = 0x01 + RAW_WRITE_MASK = 0x02 + + # Capabilities Mask (Used internally by SMB class. Good for dialect NT LM 0.12) + CAP_RAW_MODE = 0x00000001 + CAP_MPX_MODE = 0x0002 + CAP_UNICODE = 0x0004 + CAP_LARGE_FILES = 0x0008 + CAP_EXTENDED_SECURITY = 0x80000000 + CAP_USE_NT_ERRORS = 0x40 + CAP_NT_SMBS = 0x10 + CAP_LARGE_READX = 0x00004000 + CAP_LARGE_WRITEX = 0x00008000 + CAP_RPC_REMOTE_APIS = 0x20 + + # Flags1 Mask + FLAGS1_LOCK_AND_READ_OK = 0x01 + FLAGS1_PATHCASELESS = 0x08 + FLAGS1_CANONICALIZED_PATHS = 0x10 + FLAGS1_REPLY = 0x80 + + # Flags2 Mask + FLAGS2_LONG_NAMES = 0x0001 + FLAGS2_EAS = 0x0002 + FLAGS2_SMB_SECURITY_SIGNATURE = 0x0004 + FLAGS2_IS_LONG_NAME = 0x0040 + FLAGS2_DFS = 0x1000 + FLAGS2_PAGING_IO = 0x2000 + FLAGS2_NT_STATUS = 0x4000 + FLAGS2_UNICODE = 0x8000 + FLAGS2_COMPRESSED = 0x0008 + FLAGS2_SMB_SECURITY_SIGNATURE_REQUIRED = 0x0010 + FLAGS2_EXTENDED_SECURITY = 0x0800 + + # Dialect's Security Mode flags + NEGOTIATE_USER_SECURITY = 0x01 + NEGOTIATE_ENCRYPT_PASSWORDS = 0x02 + NEGOTIATE_SECURITY_SIGNATURE_ENABLE = 0x04 + NEGOTIATE_SECURITY_SIGNATURE_REQUIRED = 0x08 + + # Tree Connect AndX Response optionalSuppor flags + SMB_SUPPORT_SEARCH_BITS = 0x01 + SMB_SHARE_IS_IN_DFS = 0x02 + + def __init__(self, remote_name, remote_host, my_name = None, host_type = nmb.TYPE_SERVER, sess_port = 445, timeout=None, UDP = 0, session = None, negPacket = None): + # The uid attribute will be set when the client calls the login() method + self._uid = 0 + self.__server_name = '' + self.__server_os = '' + self.__server_os_major = None + self.__server_os_minor = None + self.__server_os_build = None + self.__server_lanman = '' + self.__server_domain = '' + self.__server_dns_domain_name = '' + self.__remote_name = string.upper(remote_name) + self.__remote_host = remote_host + self.__isNTLMv2 = True + self._dialects_parameters = None + self._dialects_data = None + # Credentials + self.__userName = '' + self.__password = '' + self.__domain = '' + self.__lmhash = '' + self.__nthash = '' + self.__aesKey = '' + self.__kdc = '' + self.__TGT = None + self.__TGS = None + + # Negotiate Protocol Result, used everywhere + # Could be extended or not, flags should be checked before + self._dialect_data = 0 + self._dialect_parameters = 0 + self._action = 0 + self._sess = None + self.encrypt_passwords = True + self.tid = 0 + self.fid = 0 + + # Signing stuff + self._SignSequenceNumber = 0 + self._SigningSessionKey = '' + self._SigningChallengeResponse = '' + self._SignatureEnabled = False + self._SignatureVerificationEnabled = False + self._SignatureRequired = False + + # Base flags (default flags, can be overriden using set_flags()) + self.__flags1 = SMB.FLAGS1_PATHCASELESS | SMB.FLAGS1_CANONICALIZED_PATHS + self.__flags2 = SMB.FLAGS2_EXTENDED_SECURITY | SMB.FLAGS2_NT_STATUS | SMB.FLAGS2_LONG_NAMES + + if timeout is None: + self.__timeout = 60 + else: + self.__timeout = timeout + + # If port 445 and the name sent is *SMBSERVER we're setting the name to the IP. + # This is to help some old applications still believing + # *SMSBSERVER will work against modern OSes. If port is NETBIOS_SESSION_PORT the user better + # know about *SMBSERVER's limitations + if sess_port == 445 and remote_name == '*SMBSERVER': + self.__remote_name = remote_host + + if session is None: + if not my_name: + my_name = socket.gethostname() + i = string.find(my_name, '.') + if i > -1: + my_name = my_name[:i] + + if UDP: + self._sess = nmb.NetBIOSUDPSession(my_name, remote_name, remote_host, host_type, sess_port, self.__timeout) + else: + self._sess = nmb.NetBIOSTCPSession(my_name, remote_name, remote_host, host_type, sess_port, self.__timeout) + + # Initialize session values (_dialect_data and _dialect_parameters) + self.neg_session() + + # Call login() without any authentication information to + # setup a session if the remote server + # is in share mode. + if (self._dialects_parameters['SecurityMode'] & SMB.SECURITY_SHARE_MASK) == SMB.SECURITY_SHARE_SHARE: + self.login('', '') + else: + self._sess = session + self.neg_session(negPacket = negPacket) + # Call login() without any authentication information to + # setup a session if the remote server + # is in share mode. + if (self._dialects_parameters['SecurityMode'] & SMB.SECURITY_SHARE_MASK) == SMB.SECURITY_SHARE_SHARE: + self.login('', '') + + @staticmethod + def ntlm_supported(): + return False + + def get_remote_name(self): + return self.__remote_name + + def get_remote_host(self): + return self.__remote_host + + def get_flags(self): + return self.__flags1, self.__flags2 + + def set_flags(self, flags1=None, flags2=None): + if flags1 is not None: + self.__flags1 = flags1 + if flags2 is not None: + self.__flags2 = flags2 + + def set_timeout(self, timeout): + prev_timeout = self.__timeout + self.__timeout = timeout + return prev_timeout + + def get_timeout(self): + return self.__timeout + + @contextmanager + def use_timeout(self, timeout): + prev_timeout = self.set_timeout(timeout) + try: + yield + finally: + self.set_timeout(prev_timeout) + + def get_session(self): + return self._sess + + def get_tid(self): + return self.tid + + def get_fid(self): + return self.fid + + def isGuestSession(self): + return self._action & SMB_SETUP_GUEST + + def doesSupportNTLMv2(self): + return self.__isNTLMv2 + + def __del__(self): + if self._sess: + self._sess.close() + + def recvSMB(self): + r = self._sess.recv_packet(self.__timeout) + return NewSMBPacket(data = r.get_trailer()) + + @staticmethod + def __decode_trans(params, data): + totparamcnt, totdatacnt, _, paramcnt, paramoffset, paramds, datacnt, dataoffset, datads, setupcnt = unpack('<HHHHHHHHHB', params[:19]) + if paramcnt + paramds < totparamcnt or datacnt + datads < totdatacnt: + has_more = 1 + else: + has_more = 0 + paramoffset = paramoffset - 55 - setupcnt * 2 + dataoffset = dataoffset - 55 - setupcnt * 2 + return has_more, params[20:20 + setupcnt * 2], data[paramoffset:paramoffset + paramcnt], data[dataoffset:dataoffset + datacnt] + + # TODO: Move this to NewSMBPacket, it belongs there + def signSMB(self, packet, signingSessionKey, signingChallengeResponse): + # This logic MUST be applied for messages sent in response to any of the higher-layer actions and in + # compliance with the message sequencing rules. + # * The client or server that sends the message MUST provide the 32-bit sequence number for this + # message, as specified in sections 3.2.4.1 and 3.3.4.1. + # * The SMB_FLAGS2_SMB_SECURITY_SIGNATURE flag in the header MUST be set. + # * To generate the signature, a 32-bit sequence number is copied into the + # least significant 32 bits of the SecuritySignature field and the remaining + # 4 bytes are set to 0x00. + # * The MD5 algorithm, as specified in [RFC1321], MUST be used to generate a hash of the SMB + # message from the start of the SMB Header, which is defined as follows. + # CALL MD5Init( md5context ) + # CALL MD5Update( md5context, Connection.SigningSessionKey ) + # CALL MD5Update( md5context, Connection.SigningChallengeResponse ) + # CALL MD5Update( md5context, SMB message ) + # CALL MD5Final( digest, md5context ) + # SET signature TO the first 8 bytes of the digest + # The resulting 8-byte signature MUST be copied into the SecuritySignature field of the SMB Header, + # after which the message can be transmitted. + + #print "seq(%d) signingSessionKey %r, signingChallengeResponse %r" % (self._SignSequenceNumber, signingSessionKey, signingChallengeResponse) + packet['SecurityFeatures'] = pack('<q',self._SignSequenceNumber) + # Sign with the sequence + m = hashlib.md5() + m.update( signingSessionKey ) + m.update( signingChallengeResponse ) + m.update( str(packet) ) + # Replace sequence with acual hash + packet['SecurityFeatures'] = m.digest()[:8] + if self._SignatureVerificationEnabled: + self._SignSequenceNumber +=1 + else: + self._SignSequenceNumber +=2 + + def checkSignSMB(self, packet, signingSessionKey, signingChallengeResponse): + # Let's check + signature = packet['SecurityFeatures'] + #print "Signature received: %r " % signature + self.signSMB(packet, signingSessionKey, signingChallengeResponse) + #print "Signature calculated: %r" % packet['SecurityFeatures'] + if self._SignatureVerificationEnabled is not True: + self._SignSequenceNumber -= 1 + return packet['SecurityFeatures'] == signature + + def sendSMB(self,smb): + smb['Uid'] = self._uid + #At least on AIX, PIDs can exceed 16 bits, so we mask them out + smb['Pid'] = (os.getpid() & 0xFFFF) + # set flags + smb['Flags1'] |= self.__flags1 + smb['Flags2'] |= self.__flags2 + if self._SignatureEnabled: + smb['Flags2'] |= SMB.FLAGS2_SMB_SECURITY_SIGNATURE + self.signSMB(smb, self._SigningSessionKey, self._SigningChallengeResponse) + + self._sess.send_packet(str(smb)) + + @staticmethod + def isValidAnswer(s, cmd): + while 1: + if s.rawData(): + if s.get_command() == cmd: + if s.get_error_class() == 0x00 and s.get_error_code() == 0x00: + return 1 + else: + raise SessionError, ( "SMB Library Error", s.get_error_class()+ (s.get_reserved() << 8), s.get_error_code() , s.get_flags2() & SMB.FLAGS2_NT_STATUS ) + else: + break + return 0 + + def neg_session(self, extended_security = True, negPacket = None): + def parsePacket(smb): + if smb.isValidAnswer(SMB.SMB_COM_NEGOTIATE): + sessionResponse = SMBCommand(smb['Data'][0]) + self._dialects_parameters = SMBNTLMDialect_Parameters(sessionResponse['Parameters']) + self._dialects_data = SMBNTLMDialect_Data() + self._dialects_data['ChallengeLength'] = self._dialects_parameters['ChallengeLength'] + self._dialects_data.fromString(sessionResponse['Data']) + if self._dialects_parameters['Capabilities'] & SMB.CAP_EXTENDED_SECURITY: + # Whether we choose it or it is enforced by the server, we go for extended security + self._dialects_parameters = SMBExtended_Security_Parameters(sessionResponse['Parameters']) + self._dialects_data = SMBExtended_Security_Data(sessionResponse['Data']) + # Let's setup some variable for later use + if self._dialects_parameters['SecurityMode'] & SMB.SECURITY_SIGNATURES_REQUIRED: + self._SignatureRequired = True + + # Interestingly, the security Blob might be missing sometimes. + #spnego = SPNEGO_NegTokenInit(self._dialects_data['SecurityBlob']) + #for i in spnego['MechTypes']: + # print "Mech Found: %s" % MechTypes[i] + return 1 + + # If not, let's try the old way + else: + if self._dialects_data['ServerName'] is not None: + self.__server_name = self._dialects_data['ServerName'] + + if self._dialects_parameters['DialectIndex'] == 0xffff: + raise UnsupportedFeature,"Remote server does not know NT LM 0.12" + return 1 + else: + return 0 + + if negPacket is None: + smb = NewSMBPacket() + negSession = SMBCommand(SMB.SMB_COM_NEGOTIATE) + flags2 = self.get_flags()[1] + if extended_security is True: + self.set_flags(flags2=flags2|SMB.FLAGS2_EXTENDED_SECURITY) + else: + self.set_flags(flags2=flags2 & (~SMB.FLAGS2_EXTENDED_SECURITY)) + + negSession['Data'] = '\x02NT LM 0.12\x00' + smb.addCommand(negSession) + self.sendSMB(smb) + + while 1: + smb = self.recvSMB() + return parsePacket(smb) + else: + + return parsePacket( NewSMBPacket( data = negPacket)) + + def tree_connect(self, path, password = '', service = SERVICE_ANY): + LOG.warning("[MS-CIFS] This is an original Core Protocol command.This command has been deprecated.Client Implementations SHOULD use SMB_COM_TREE_CONNECT_ANDX") + + # return 0x800 + if password: + # Password is only encrypted if the server passed us an "encryption" during protocol dialect + if self._dialects_parameters['ChallengeLength'] > 0: + # this code is untested + password = self.get_ntlmv1_response(ntlm.compute_lmhash(password)) + + if not unicode_support: + if unicode_convert: + path = str(path) + else: + raise Exception('SMB: Can\t conver path from unicode!') + + smb = NewSMBPacket() + treeConnect = SMBCommand(SMB.SMB_COM_TREE_CONNECT) + treeConnect['Parameters'] = SMBTreeConnect_Parameters() + treeConnect['Data'] = SMBTreeConnect_Data() + treeConnect['Data']['Path'] = path.upper() + treeConnect['Data']['Password'] = password + treeConnect['Data']['Service'] = service + smb.addCommand(treeConnect) + self.sendSMB(smb) + + while 1: + smb = self.recvSMB() + if smb.isValidAnswer(SMB.SMB_COM_TREE_CONNECT): + # XXX Here we are ignoring the rest of the response + return smb['Tid'] + return smb['Tid'] + + def get_uid(self): + return self._uid + + def set_uid(self, uid): + self._uid = uid + + def tree_connect_andx(self, path, password = None, service = SERVICE_ANY, smb_packet=None): + if password: + # Password is only encrypted if the server passed us an "encryption" during protocol dialect + if self._dialects_parameters['ChallengeLength'] > 0: + # this code is untested + password = self.get_ntlmv1_response(ntlm.compute_lmhash(password)) + else: + password = '\x00' + + if not unicode_support: + if unicode_convert: + path = str(path) + else: + raise Exception('SMB: Can\t convert path from unicode!') + + if smb_packet is None: + smb = NewSMBPacket() + else: + smb = smb_packet + + # Just in case this came with the full path ,let's just leave + # the sharename, we'll take care of the rest + + share = path.split('\\')[-1] + try: + _, _, _, _, sockaddr = socket.getaddrinfo(self.get_remote_host(), 80, 0, 0, socket.IPPROTO_TCP)[0] + remote_host = sockaddr[0] + except Exception: + remote_host = self.get_remote_host() + + path = '\\\\' + remote_host + '\\' +share + path = path.upper().encode('utf-16le') if self.__flags2 & SMB.FLAGS2_UNICODE else path + + treeConnect = SMBCommand(SMB.SMB_COM_TREE_CONNECT_ANDX) + treeConnect['Parameters'] = SMBTreeConnectAndX_Parameters() + treeConnect['Data'] = SMBTreeConnectAndX_Data(flags=self.__flags2) + treeConnect['Parameters']['PasswordLength'] = len(password) + treeConnect['Data']['Password'] = password + treeConnect['Data']['Path'] = path + treeConnect['Data']['Service'] = service + + if self.__flags2 & SMB.FLAGS2_UNICODE: + treeConnect['Data']['Pad'] = 0x0 + + smb.addCommand(treeConnect) + + # filename = "\PIPE\epmapper" + + # ntCreate = SMBCommand(SMB.SMB_COM_NT_CREATE_ANDX) + # ntCreate['Parameters'] = SMBNtCreateAndX_Parameters() + # ntCreate['Data'] = SMBNtCreateAndX_Data() + # ntCreate['Parameters']['FileNameLength'] = len(filename) + # ntCreate['Parameters']['CreateFlags'] = 0 + # ntCreate['Parameters']['AccessMask'] = 0x3 + # ntCreate['Parameters']['CreateOptions'] = 0x0 + # ntCreate['Data']['FileName'] = filename + + # smb.addCommand(ntCreate) + self.sendSMB(smb) + + while 1: + smb = self.recvSMB() + if smb.isValidAnswer(SMB.SMB_COM_TREE_CONNECT_ANDX): + # XXX Here we are ignoring the rest of the response + self.tid = smb['Tid'] + return self.tid + self.tid = smb['Tid'] + return self.tid + + # backwars compatibility + connect_tree = tree_connect_andx + + @staticmethod + def getDialect(): + return SMB_DIALECT + + def get_server_name(self): + #return self._dialects_data['ServerName'] + return self.__server_name + + def get_session_key(self): + return self._SigningSessionKey + + def set_session_key(self, key): + self._SigningSessionKey = key + + def get_encryption_key(self): + if self._dialects_data.fields.has_key('Challenge'): + return self._dialects_data['Challenge'] + else: + return None + + def get_server_time(self): + timestamp = self._dialects_parameters['HighDateTime'] + timestamp <<= 32 + timestamp |= self._dialects_parameters['LowDateTime'] + timestamp -= 116444736000000000 + timestamp /= 10000000 + d = datetime.datetime.utcfromtimestamp(timestamp) + return d.strftime("%a, %d %b %Y %H:%M:%S GMT") + + def disconnect_tree(self, tid): + smb = NewSMBPacket() + smb['Tid'] = tid + + smb.addCommand(SMBCommand(SMB.SMB_COM_TREE_DISCONNECT)) + + self.sendSMB(smb) + self.recvSMB() + + def open(self, tid, filename, open_mode, desired_access): + filename = string.replace(filename,'/', '\\') + filename = filename.encode('utf-16le') if self.__flags2 & SMB.FLAGS2_UNICODE else filename + + smb = NewSMBPacket() + smb['Tid'] = tid + + openFile = SMBCommand(SMB.SMB_COM_OPEN) + openFile['Parameters'] = SMBOpen_Parameters() + openFile['Parameters']['DesiredAccess'] = desired_access + openFile['Parameters']['OpenMode'] = open_mode + openFile['Parameters']['SearchAttributes'] = ATTR_READONLY | ATTR_HIDDEN | ATTR_ARCHIVE + openFile['Data'] = SMBOpen_Data(flags=self.__flags2) + openFile['Data']['FileName'] = filename + + if self.__flags2 & SMB.FLAGS2_UNICODE: + openFile['Data']['Pad'] = 0x0 + + smb.addCommand(openFile) + + self.sendSMB(smb) + + smb = self.recvSMB() + if smb.isValidAnswer(SMB.SMB_COM_OPEN): + # XXX Here we are ignoring the rest of the response + openFileResponse = SMBCommand(smb['Data'][0]) + openFileParameters = SMBOpenResponse_Parameters(openFileResponse['Parameters']) + + return ( + openFileParameters['Fid'], + openFileParameters['FileAttributes'], + openFileParameters['LastWriten'], + openFileParameters['FileSize'], + openFileParameters['GrantedAccess'], + ) + + def open_andx(self, tid, filename, open_mode, desired_access): + filename = string.replace(filename,'/', '\\') + filename = filename.encode('utf-16le') if self.__flags2 & SMB.FLAGS2_UNICODE else filename + + smb = NewSMBPacket() + smb['Tid'] = tid + + openFile = SMBCommand(SMB.SMB_COM_OPEN_ANDX) + openFile['Parameters'] = SMBOpenAndX_Parameters() + openFile['Parameters']['DesiredAccess'] = desired_access + openFile['Parameters']['OpenMode'] = open_mode + openFile['Parameters']['SearchAttributes'] = ATTR_READONLY | ATTR_HIDDEN | ATTR_ARCHIVE + openFile['Data'] = SMBOpenAndX_Data(flags=self.__flags2) + openFile['Data']['FileName'] = filename + + if self.__flags2 & SMB.FLAGS2_UNICODE: + openFile['Data']['Pad'] = 0x0 + + smb.addCommand(openFile) + + self.sendSMB(smb) + + smb = self.recvSMB() + if smb.isValidAnswer(SMB.SMB_COM_OPEN_ANDX): + # XXX Here we are ignoring the rest of the response + openFileResponse = SMBCommand(smb['Data'][0]) + openFileParameters = SMBOpenAndXResponse_Parameters(openFileResponse['Parameters']) + + return ( + openFileParameters['Fid'], + openFileParameters['FileAttributes'], + openFileParameters['LastWriten'], + openFileParameters['FileSize'], + openFileParameters['GrantedAccess'], + openFileParameters['FileType'], + openFileParameters['IPCState'], + openFileParameters['Action'], + openFileParameters['ServerFid'], + ) + + def close(self, tid, fid): + smb = NewSMBPacket() + smb['Tid'] = tid + + closeFile = SMBCommand(SMB.SMB_COM_CLOSE) + closeFile['Parameters'] = SMBClose_Parameters() + closeFile['Parameters']['FID'] = fid + smb.addCommand(closeFile) + + self.sendSMB(smb) + smb = self.recvSMB() + if smb.isValidAnswer(SMB.SMB_COM_CLOSE): + return 1 + return 0 + + def send_trans(self, tid, setup, name, param, data, noAnswer = 0): + smb = NewSMBPacket() + smb['Tid'] = tid + + transCommand = SMBCommand(SMB.SMB_COM_TRANSACTION) + transCommand['Parameters'] = SMBTransaction_Parameters() + transCommand['Data'] = SMBTransaction_Data() + + transCommand['Parameters']['Setup'] = setup + transCommand['Parameters']['TotalParameterCount'] = len(param) + transCommand['Parameters']['TotalDataCount'] = len(data) + + transCommand['Parameters']['ParameterCount'] = len(param) + transCommand['Parameters']['ParameterOffset'] = 32+3+28+len(setup)+len(name) + + transCommand['Parameters']['DataCount'] = len(data) + transCommand['Parameters']['DataOffset'] = transCommand['Parameters']['ParameterOffset'] + len(param) + + transCommand['Data']['Name'] = name + transCommand['Data']['Trans_Parameters'] = param + transCommand['Data']['Trans_Data'] = data + + if noAnswer: + transCommand['Parameters']['Flags'] = TRANS_NO_RESPONSE + + smb.addCommand(transCommand) + + self.sendSMB(smb) + + def send_trans2(self, tid, setup, name, param, data): + smb = NewSMBPacket() + smb['Tid'] = tid + + command = pack('<H', setup) + + transCommand = SMBCommand(SMB.SMB_COM_TRANSACTION2) + transCommand['Parameters'] = SMBTransaction2_Parameters() + transCommand['Parameters']['MaxDataCount'] = self._dialects_parameters['MaxBufferSize'] + transCommand['Data'] = SMBTransaction2_Data() + + transCommand['Parameters']['Setup'] = command + transCommand['Parameters']['TotalParameterCount'] = len(param) + transCommand['Parameters']['TotalDataCount'] = len(data) + + if len(param) > 0: + padLen = (4 - (32+2+28 + len(command)) % 4 ) % 4 + padBytes = '\xFF' * padLen + transCommand['Data']['Pad1'] = padBytes + else: + transCommand['Data']['Pad1'] = '' + padLen = 0 + + transCommand['Parameters']['ParameterCount'] = len(param) + transCommand['Parameters']['ParameterOffset'] = 32+2+28+len(command)+len(name) + padLen + + if len(data) > 0: + pad2Len = (4 - (32+2+28 + len(command) + padLen + len(param)) % 4) % 4 + transCommand['Data']['Pad2'] = '\xFF' * pad2Len + else: + transCommand['Data']['Pad2'] = '' + pad2Len = 0 + + transCommand['Parameters']['DataCount'] = len(data) + transCommand['Parameters']['DataOffset'] = transCommand['Parameters']['ParameterOffset'] + len(param) + pad2Len + + transCommand['Data']['Name'] = name + transCommand['Data']['Trans_Parameters'] = param + transCommand['Data']['Trans_Data'] = data + smb.addCommand(transCommand) + + self.sendSMB(smb) + + def query_file_info(self, tid, fid, fileInfoClass = SMB_QUERY_FILE_STANDARD_INFO): + self.send_trans2(tid, SMB.TRANS2_QUERY_FILE_INFORMATION, '\x00', pack('<HH', fid, fileInfoClass), '') + + resp = self.recvSMB() + if resp.isValidAnswer(SMB.SMB_COM_TRANSACTION2): + trans2Response = SMBCommand(resp['Data'][0]) + trans2Parameters = SMBTransaction2Response_Parameters(trans2Response['Parameters']) + # Remove Potential Prefix Padding + return trans2Response['Data'][-trans2Parameters['TotalDataCount']:] + + def __nonraw_retr_file(self, tid, fid, offset, datasize, callback): + if (self._dialects_parameters['Capabilities'] & SMB.CAP_LARGE_READX) and self._SignatureEnabled is False: + max_buf_size = 65000 + else: + max_buf_size = self._dialects_parameters['MaxBufferSize'] & ~0x3ff # Read in multiple KB blocks + + read_offset = offset + while read_offset < datasize: + data = self.read_andx(tid, fid, read_offset, max_buf_size) + + callback(data) + read_offset += len(data) + + def __nonraw_stor_file(self, tid, fid, offset, datasize, callback): + if (self._dialects_parameters['Capabilities'] & SMB.CAP_LARGE_WRITEX) and self._SignatureEnabled is False: + max_buf_size = 65000 + else: + max_buf_size = self._dialects_parameters['MaxBufferSize'] & ~0x3ff # Write in multiple KB blocks + + write_offset = offset + while 1: + data = callback(max_buf_size) + if not data: + break + + smb = self.write_andx(tid,fid,data, write_offset) + writeResponse = SMBCommand(smb['Data'][0]) + writeResponseParameters = SMBWriteAndXResponse_Parameters(writeResponse['Parameters']) + write_offset += writeResponseParameters['Count'] + + def get_server_domain(self): + return self.__server_domain + + def get_server_dns_domain_name(self): + return self.__server_dns_domain_name + + def get_server_os(self): + return self.__server_os + + def get_server_os_major(self): + return self.__server_os_major + + def get_server_os_minor(self): + return self.__server_os_minor + + def get_server_os_build(self): + return self.__server_os_build + + def set_server_os(self, os): + self.__server_os = os + + def get_server_lanman(self): + return self.__server_lanman + + def is_login_required(self): + # Login is required if share mode is user. + # Otherwise only public services or services in share mode + # are allowed. + return (self._dialects_parameters['SecurityMode'] & SMB.SECURITY_SHARE_MASK) == SMB.SECURITY_SHARE_USER + + def is_signing_required(self): + return self._SignatureRequired + + def get_ntlmv1_response(self, key): + challenge = self._dialects_data['Challenge'] + return ntlm.get_ntlmv1_response(key, challenge) + + def kerberos_login(self, user, password, domain = '', lmhash = '', nthash = '', aesKey = '', kdcHost = '', TGT=None, TGS=None): + # Importing down here so pyasn1 is not required if kerberos is not used. + from impacket.krb5.asn1 import AP_REQ, Authenticator, TGS_REP, seq_set + from impacket.krb5.kerberosv5 import getKerberosTGT, getKerberosTGS + from impacket.krb5 import constants + from impacket.krb5.types import Principal, KerberosTime, Ticket + from pyasn1.codec.der import decoder, encoder + import datetime + + # login feature does not support unicode + # disable it if enabled + flags2 = self.__flags2 + if flags2 & SMB.FLAGS2_UNICODE: + self.__flags2 = flags2 & (flags2 ^ SMB.FLAGS2_UNICODE) + + # If TGT or TGS are specified, they are in the form of: + # TGS['KDC_REP'] = the response from the server + # TGS['cipher'] = the cipher used + # TGS['sessionKey'] = the sessionKey + # If we have hashes, normalize them + if lmhash != '' or nthash != '': + if len(lmhash) % 2: lmhash = '0%s' % lmhash + if len(nthash) % 2: nthash = '0%s' % nthash + try: # just in case they were converted already + lmhash = a2b_hex(lmhash) + nthash = a2b_hex(nthash) + except: + pass + + self.__userName = user + self.__password = password + self.__domain = domain + self.__lmhash = lmhash + self.__nthash = nthash + self.__aesKey = aesKey + self.__kdc = kdcHost + self.__TGT = TGT + self.__TGS = TGS + + # First of all, we need to get a TGT for the user + userName = Principal(user, type=constants.PrincipalNameType.NT_PRINCIPAL.value) + if TGT is None: + if TGS is None: + tgt, cipher, oldSessionKey, sessionKey = getKerberosTGT(userName, password, domain, lmhash, nthash, aesKey, kdcHost) + else: + tgt = TGT['KDC_REP'] + cipher = TGT['cipher'] + sessionKey = TGT['sessionKey'] + + # Now that we have the TGT, we should ask for a TGS for cifs + + if TGS is None: + serverName = Principal('cifs/%s' % self.__remote_name, type=constants.PrincipalNameType.NT_SRV_INST.value) + tgs, cipher, oldSessionKey, sessionKey = getKerberosTGS(serverName, domain, kdcHost, tgt, cipher, sessionKey) + else: + tgs = TGS['KDC_REP'] + cipher = TGS['cipher'] + sessionKey = TGS['sessionKey'] + + smb = NewSMBPacket() + + # Are we required to sign SMB? If so we do it, if not we skip it + if self._SignatureRequired: + smb['Flags2'] |= SMB.FLAGS2_SMB_SECURITY_SIGNATURE + + + sessionSetup = SMBCommand(SMB.SMB_COM_SESSION_SETUP_ANDX) + sessionSetup['Parameters'] = SMBSessionSetupAndX_Extended_Parameters() + sessionSetup['Data'] = SMBSessionSetupAndX_Extended_Data() + + sessionSetup['Parameters']['MaxBufferSize'] = 61440 + sessionSetup['Parameters']['MaxMpxCount'] = 2 + sessionSetup['Parameters']['VcNumber'] = 1 + sessionSetup['Parameters']['SessionKey'] = 0 + sessionSetup['Parameters']['Capabilities'] = SMB.CAP_EXTENDED_SECURITY | SMB.CAP_USE_NT_ERRORS | SMB.CAP_UNICODE | SMB.CAP_LARGE_READX | SMB.CAP_LARGE_WRITEX + + + # Let's build a NegTokenInit with the NTLMSSP + # TODO: In the future we should be able to choose different providers + + blob = SPNEGO_NegTokenInit() + + # Kerberos v5 mech + blob['MechTypes'] = [TypesMech['MS KRB5 - Microsoft Kerberos 5']] + + # Let's extract the ticket from the TGS + tgs = decoder.decode(tgs, asn1Spec = TGS_REP())[0] + ticket = Ticket() + ticket.from_asn1(tgs['ticket']) + + # Now let's build the AP_REQ + apReq = AP_REQ() + apReq['pvno'] = 5 + apReq['msg-type'] = int(constants.ApplicationTagNumbers.AP_REQ.value) + + opts = list() + apReq['ap-options'] = constants.encodeFlags(opts) + seq_set(apReq,'ticket', ticket.to_asn1) + + authenticator = Authenticator() + authenticator['authenticator-vno'] = 5 + authenticator['crealm'] = domain + seq_set(authenticator, 'cname', userName.components_to_asn1) + now = datetime.datetime.utcnow() + + authenticator['cusec'] = now.microsecond + authenticator['ctime'] = KerberosTime.to_asn1(now) + + encodedAuthenticator = encoder.encode(authenticator) + + # Key Usage 11 + # AP-REQ Authenticator (includes application authenticator + # subkey), encrypted with the application session key + # (Section 5.5.1) + encryptedEncodedAuthenticator = cipher.encrypt(sessionKey, 11, encodedAuthenticator, None) + + apReq['authenticator'] = None + apReq['authenticator']['etype'] = cipher.enctype + apReq['authenticator']['cipher'] = encryptedEncodedAuthenticator + + blob['MechToken'] = encoder.encode(apReq) + + sessionSetup['Parameters']['SecurityBlobLength'] = len(blob) + sessionSetup['Parameters'].getData() + sessionSetup['Data']['SecurityBlob'] = blob.getData() + + # Fake Data here, don't want to get us fingerprinted + sessionSetup['Data']['NativeOS'] = 'Unix' + sessionSetup['Data']['NativeLanMan'] = 'Samba' + + smb.addCommand(sessionSetup) + self.sendSMB(smb) + + smb = self.recvSMB() + if smb.isValidAnswer(SMB.SMB_COM_SESSION_SETUP_ANDX): + # We will need to use this uid field for all future requests/responses + self._uid = smb['Uid'] + + # Now we have to extract the blob to continue the auth process + sessionResponse = SMBCommand(smb['Data'][0]) + sessionParameters = SMBSessionSetupAndX_Extended_Response_Parameters(sessionResponse['Parameters']) + sessionData = SMBSessionSetupAndX_Extended_Response_Data(flags = smb['Flags2']) + sessionData['SecurityBlobLength'] = sessionParameters['SecurityBlobLength'] + sessionData.fromString(sessionResponse['Data']) + + self._action = sessionParameters['Action'] + # If smb sign required, let's enable it for the rest of the connection + if self._dialects_parameters['SecurityMode'] & SMB.SECURITY_SIGNATURES_REQUIRED: + self._SigningSessionKey = sessionKey.contents + self._SignSequenceNumber = 2 + self._SignatureEnabled = True + + # restore unicode flag if needed + if flags2 & SMB.FLAGS2_UNICODE: + self.__flags2 |= SMB.FLAGS2_UNICODE + + return 1 + else: + raise Exception('Error: Could not login successfully') + + def login_extended(self, user, password, domain = '', lmhash = '', nthash = '', use_ntlmv2 = True ): + + # login feature does not support unicode + # disable it if enabled + flags2 = self.__flags2 + if flags2 & SMB.FLAGS2_UNICODE: + self.__flags2 = flags2 & (flags2 ^ SMB.FLAGS2_UNICODE) + + # Once everything's working we should join login methods into a single one + smb = NewSMBPacket() + # Are we required to sign SMB? If so we do it, if not we skip it + if self._SignatureRequired: + smb['Flags2'] |= SMB.FLAGS2_SMB_SECURITY_SIGNATURE + + sessionSetup = SMBCommand(SMB.SMB_COM_SESSION_SETUP_ANDX) + sessionSetup['Parameters'] = SMBSessionSetupAndX_Extended_Parameters() + sessionSetup['Data'] = SMBSessionSetupAndX_Extended_Data() + + sessionSetup['Parameters']['MaxBufferSize'] = 61440 + sessionSetup['Parameters']['MaxMpxCount'] = 2 + sessionSetup['Parameters']['VcNumber'] = 1 + sessionSetup['Parameters']['SessionKey'] = 0 + sessionSetup['Parameters']['Capabilities'] = SMB.CAP_EXTENDED_SECURITY | SMB.CAP_USE_NT_ERRORS | SMB.CAP_UNICODE | SMB.CAP_LARGE_READX | SMB.CAP_LARGE_WRITEX + + + # Let's build a NegTokenInit with the NTLMSSP + # TODO: In the future we should be able to choose different providers + + blob = SPNEGO_NegTokenInit() + + # NTLMSSP + blob['MechTypes'] = [TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']] + auth = ntlm.getNTLMSSPType1('','',self._SignatureRequired, use_ntlmv2 = use_ntlmv2) + blob['MechToken'] = str(auth) + + sessionSetup['Parameters']['SecurityBlobLength'] = len(blob) + sessionSetup['Parameters'].getData() + sessionSetup['Data']['SecurityBlob'] = blob.getData() + + # Fake Data here, don't want to get us fingerprinted + sessionSetup['Data']['NativeOS'] = 'Unix' + sessionSetup['Data']['NativeLanMan'] = 'Samba' + + smb.addCommand(sessionSetup) + self.sendSMB(smb) + + smb = self.recvSMB() + if smb.isValidAnswer(SMB.SMB_COM_SESSION_SETUP_ANDX): + # We will need to use this uid field for all future requests/responses + self._uid = smb['Uid'] + + # Now we have to extract the blob to continue the auth process + sessionResponse = SMBCommand(smb['Data'][0]) + sessionParameters = SMBSessionSetupAndX_Extended_Response_Parameters(sessionResponse['Parameters']) + sessionData = SMBSessionSetupAndX_Extended_Response_Data(flags = smb['Flags2']) + sessionData['SecurityBlobLength'] = sessionParameters['SecurityBlobLength'] + sessionData.fromString(sessionResponse['Data']) + respToken = SPNEGO_NegTokenResp(sessionData['SecurityBlob']) + + # Let's parse some data and keep it to ourselves in case it is asked + ntlmChallenge = ntlm.NTLMAuthChallenge(respToken['ResponseToken']) + if ntlmChallenge['TargetInfoFields_len'] > 0: + av_pairs = ntlm.AV_PAIRS(ntlmChallenge['TargetInfoFields'][:ntlmChallenge['TargetInfoFields_len']]) + if av_pairs[ntlm.NTLMSSP_AV_HOSTNAME] is not None: + try: + self.__server_name = av_pairs[ntlm.NTLMSSP_AV_HOSTNAME][1].decode('utf-16le') + except: + # For some reason, we couldn't decode Unicode here.. silently discard the operation + pass + if av_pairs[ntlm.NTLMSSP_AV_DOMAINNAME] is not None: + try: + if self.__server_name != av_pairs[ntlm.NTLMSSP_AV_DOMAINNAME][1].decode('utf-16le'): + self.__server_domain = av_pairs[ntlm.NTLMSSP_AV_DOMAINNAME][1].decode('utf-16le') + except: + # For some reason, we couldn't decode Unicode here.. silently discard the operation + pass + if av_pairs[ntlm.NTLMSSP_AV_DNS_DOMAINNAME] is not None: + try: + self.__server_dns_domain_name = av_pairs[ntlm.NTLMSSP_AV_DNS_DOMAINNAME][1].decode('utf-16le') + except: + # For some reason, we couldn't decode Unicode here.. silently discard the operation + pass + + # Parse Version to know the target Operating system name. Not provided elsewhere anymore + if ntlmChallenge.fields.has_key('Version'): + version = ntlmChallenge['Version'] + + if len(version) >= 4: + self.__server_os_major, self.__server_os_minor, self.__server_os_build = unpack('<BBH',version[:4]) + + type3, exportedSessionKey = ntlm.getNTLMSSPType3(auth, respToken['ResponseToken'], user, password, domain, lmhash, nthash, use_ntlmv2 = use_ntlmv2) + + if exportedSessionKey is not None: + self._SigningSessionKey = exportedSessionKey + + smb = NewSMBPacket() + + # Are we required to sign SMB? If so we do it, if not we skip it + if self._SignatureRequired: + smb['Flags2'] |= SMB.FLAGS2_SMB_SECURITY_SIGNATURE + + respToken2 = SPNEGO_NegTokenResp() + respToken2['ResponseToken'] = str(type3) + + # Reusing the previous structure + sessionSetup['Parameters']['SecurityBlobLength'] = len(respToken2) + sessionSetup['Data']['SecurityBlob'] = respToken2.getData() + + # Storing some info for later use + self.__server_os = sessionData['NativeOS'] + self.__server_lanman = sessionData['NativeLanMan'] + + smb.addCommand(sessionSetup) + self.sendSMB(smb) + + smb = self.recvSMB() + self._uid = 0 + if smb.isValidAnswer(SMB.SMB_COM_SESSION_SETUP_ANDX): + self._uid = smb['Uid'] + sessionResponse = SMBCommand(smb['Data'][0]) + sessionParameters = SMBSessionSetupAndXResponse_Parameters(sessionResponse['Parameters']) + + self._action = sessionParameters['Action'] + # If smb sign required, let's enable it for the rest of the connection + if self._dialects_parameters['SecurityMode'] & SMB.SECURITY_SIGNATURES_REQUIRED: + self._SignSequenceNumber = 2 + self._SignatureEnabled = True + + # restore unicode flag if needed + if flags2 & SMB.FLAGS2_UNICODE: + self.__flags2 |= SMB.FLAGS2_UNICODE + + return 1 + else: + raise Exception('Error: Could not login successfully') + + def getCredentials(self): + return ( + self.__userName, + self.__password, + self.__domain, + self.__lmhash, + self.__nthash, + self.__aesKey, + self.__TGT, + self.__TGS) + + def getIOCapabilities(self): + res = dict() + if (self._dialects_parameters['Capabilities'] & SMB.CAP_LARGE_READX) and self._SignatureEnabled is False: + max_size = 65000 + else: + max_size = self._dialects_parameters['MaxBufferSize'] # Read in multiple KB blocks + res['MaxReadSize'] = max_size + res['MaxWriteSize'] = max_size + return res + + def login(self, user, password, domain = '', lmhash = '', nthash = '', ntlm_fallback = True): + + # If we have hashes, normalize them + if lmhash != '' or nthash != '': + if len(lmhash) % 2: lmhash = '0%s' % lmhash + if len(nthash) % 2: nthash = '0%s' % nthash + try: # just in case they were converted already + lmhash = a2b_hex(lmhash) + nthash = a2b_hex(nthash) + except: + pass + + self.__userName = user + self.__password = password + self.__domain = domain + self.__lmhash = lmhash + self.__nthash = nthash + self.__aesKey = '' + self.__TGT = None + self.__TGS = None + + if self._dialects_parameters['Capabilities'] & SMB.CAP_EXTENDED_SECURITY: + try: + self.login_extended(user, password, domain, lmhash, nthash, use_ntlmv2 = True) + except: + # If the target OS is Windows 5.0 or Samba, let's try using NTLMv1 + if ntlm_fallback and ((self.get_server_lanman().find('Windows 2000') != -1) or (self.get_server_lanman().find('Samba') != -1)): + self.login_extended(user, password, domain, lmhash, nthash, use_ntlmv2 = False) + self.__isNTLMv2 = False + else: + raise + elif ntlm_fallback: + self.login_standard(user, password, domain, lmhash, nthash) + self.__isNTLMv2 = False + else: + raise SessionError('Cannot authenticate against target, enable ntlm_fallback') + + def login_standard(self, user, password, domain = '', lmhash = '', nthash = ''): + + # login feature does not support unicode + # disable it if enabled + flags2 = self.__flags2 + if flags2 & SMB.FLAGS2_UNICODE: + self.__flags2 = flags2 & (flags2 ^ SMB.FLAGS2_UNICODE) + + # Only supports NTLMv1 + # Password is only encrypted if the server passed us an "encryption key" during protocol dialect negotiation + if self._dialects_parameters['ChallengeLength'] > 0: + if lmhash != '' or nthash != '': + pwd_ansi = self.get_ntlmv1_response(lmhash) + pwd_unicode = self.get_ntlmv1_response(nthash) + elif password: + lmhash = ntlm.compute_lmhash(password) + nthash = ntlm.compute_nthash(password) + pwd_ansi = self.get_ntlmv1_response(lmhash) + pwd_unicode = self.get_ntlmv1_response(nthash) + else: # NULL SESSION + pwd_ansi = '' + pwd_unicode = '' + else: + pwd_ansi = password + pwd_unicode = '' + + smb = NewSMBPacket() + + sessionSetup = SMBCommand(SMB.SMB_COM_SESSION_SETUP_ANDX) + sessionSetup['Parameters'] = SMBSessionSetupAndX_Parameters() + sessionSetup['Data'] = SMBSessionSetupAndX_Data() + + sessionSetup['Parameters']['MaxBuffer'] = 61440 + sessionSetup['Parameters']['MaxMpxCount'] = 2 + sessionSetup['Parameters']['VCNumber'] = os.getpid() + sessionSetup['Parameters']['SessionKey'] = self._dialects_parameters['SessionKey'] + sessionSetup['Parameters']['AnsiPwdLength'] = len(pwd_ansi) + sessionSetup['Parameters']['UnicodePwdLength'] = len(pwd_unicode) + sessionSetup['Parameters']['Capabilities'] = SMB.CAP_RAW_MODE | SMB.CAP_USE_NT_ERRORS | SMB.CAP_LARGE_READX | SMB.CAP_LARGE_WRITEX + + sessionSetup['Data']['AnsiPwd'] = pwd_ansi + sessionSetup['Data']['UnicodePwd'] = pwd_unicode + sessionSetup['Data']['Account'] = str(user) + sessionSetup['Data']['PrimaryDomain'] = str(domain) + sessionSetup['Data']['NativeOS'] = str(os.name) + sessionSetup['Data']['NativeLanMan'] = 'pysmb' + smb.addCommand(sessionSetup) + + self.sendSMB(smb) + + smb = self.recvSMB() + if smb.isValidAnswer(SMB.SMB_COM_SESSION_SETUP_ANDX): + # We will need to use this uid field for all future requests/responses + self._uid = smb['Uid'] + sessionResponse = SMBCommand(smb['Data'][0]) + sessionParameters = SMBSessionSetupAndXResponse_Parameters(sessionResponse['Parameters']) + sessionData = SMBSessionSetupAndXResponse_Data(flags = smb['Flags2'], data = sessionResponse['Data']) + + self._action = sessionParameters['Action'] + + # Still gotta figure out how to do this with no EXTENDED_SECURITY + if sessionParameters['Action'] & SMB_SETUP_USE_LANMAN_KEY == 0: + self._SigningChallengeResponse = sessionSetup['Data']['UnicodePwd'] + self._SigningSessionKey = nthash + else: + self._SigningChallengeResponse = sessionSetup['Data']['AnsiPwd'] + self._SigningSessionKey = lmhash + + #self._SignSequenceNumber = 1 + #self.checkSignSMB(smb, self._SigningSessionKey ,self._SigningChallengeResponse) + #self._SignatureEnabled = True + self.__server_os = sessionData['NativeOS'] + self.__server_lanman = sessionData['NativeLanMan'] + self.__server_domain = sessionData['PrimaryDomain'] + + # restore unicode flag if needed + if flags2 & SMB.FLAGS2_UNICODE: + self.__flags2 |= SMB.FLAGS2_UNICODE + + return 1 + else: raise Exception('Error: Could not login successfully') + + def waitNamedPipe(self, tid, pipe, timeout = 5, noAnswer = 0): + smb = NewSMBPacket() + smb['Tid'] = tid + + transCommand = SMBCommand(SMB.SMB_COM_TRANSACTION) + transCommand['Parameters'] = SMBTransaction_Parameters() + transCommand['Data'] = SMBTransaction_Data() + + setup = '\x53\x00\x00\x00' + name = '\\PIPE%s\x00' % pipe + transCommand['Parameters']['Setup'] = setup + transCommand['Parameters']['TotalParameterCount'] = 0 + transCommand['Parameters']['TotalDataCount'] = 0 + transCommand['Parameters']['MaxParameterCount'] = 0 + transCommand['Parameters']['MaxDataCount'] = 0 + transCommand['Parameters']['Timeout'] = timeout * 1000 + + transCommand['Parameters']['ParameterCount'] = 0 + transCommand['Parameters']['ParameterOffset'] = 32+3+28+len(setup)+len(name) + + transCommand['Parameters']['DataCount'] = 0 + transCommand['Parameters']['DataOffset'] = 0 + + transCommand['Data']['Name'] = name + transCommand['Data']['Trans_Parameters'] = '' + transCommand['Data']['Trans_Data'] = '' + + if noAnswer: + transCommand['Parameters']['Flags'] = TRANS_NO_RESPONSE + + smb.addCommand(transCommand) + self.sendSMB(smb) + + smb = self.recvSMB() + if smb.isValidAnswer(SMB.SMB_COM_TRANSACTION): + return 1 + return 0 + + def read(self, tid, fid, offset=0, max_size = None, wait_answer=1): + if not max_size: + max_size = self._dialects_parameters['MaxBufferSize'] # Read in multiple KB blocks + + # max_size is not working, because although it would, the server returns an error (More data avail) + + smb = NewSMBPacket() + smb['Tid'] = tid + + read = SMBCommand(SMB.SMB_COM_READ) + read['Parameters'] = SMBRead_Parameters() + read['Parameters']['Fid'] = fid + read['Parameters']['Offset'] = offset + read['Parameters']['Count'] = max_size + smb.addCommand(read) + + if wait_answer: + while 1: + self.sendSMB(smb) + ans = self.recvSMB() + + if ans.isValidAnswer(SMB.SMB_COM_READ): + readResponse = SMBCommand(ans['Data'][0]) + readData = SMBReadResponse_Data(readResponse['Data']) + + return readData['Data'] + + return None + + def read_andx(self, tid, fid, offset=0, max_size = None, wait_answer=1, smb_packet=None): + if not max_size: + if (self._dialects_parameters['Capabilities'] & SMB.CAP_LARGE_READX) and self._SignatureEnabled is False: + max_size = 65000 + else: + max_size = self._dialects_parameters['MaxBufferSize'] # Read in multiple KB blocks + + # max_size is not working, because although it would, the server returns an error (More data avail) + + if smb_packet is None: + smb = NewSMBPacket() + smb['Tid'] = tid + + readAndX = SMBCommand(SMB.SMB_COM_READ_ANDX) + readAndX['Parameters'] = SMBReadAndX_Parameters() + readAndX['Parameters']['Fid'] = fid + readAndX['Parameters']['Offset'] = offset + readAndX['Parameters']['MaxCount'] = max_size + smb.addCommand(readAndX) + else: + smb = smb_packet + + if wait_answer: + answer = '' + while 1: + self.sendSMB(smb) + ans = self.recvSMB() + + if ans.isValidAnswer(SMB.SMB_COM_READ_ANDX): + # XXX Here we are only using a few fields from the response + readAndXResponse = SMBCommand(ans['Data'][0]) + readAndXParameters = SMBReadAndXResponse_Parameters(readAndXResponse['Parameters']) + + offset = readAndXParameters['DataOffset'] + count = readAndXParameters['DataCount']+0x10000*readAndXParameters['DataCount_Hi'] + answer += str(ans)[offset:offset+count] + if not ans.isMoreData(): + return answer + max_size = min(max_size, readAndXParameters['Remaining']) + readAndX['Parameters']['Offset'] += count # XXX Offset is not important (apparently) + else: + self.sendSMB(smb) + ans = self.recvSMB() + + try: + if ans.isValidAnswer(SMB.SMB_COM_READ_ANDX): + return ans + else: + return None + except: + return ans + + return None + + def read_raw(self, tid, fid, offset=0, max_size = None, wait_answer=1): + if not max_size: + max_size = self._dialects_parameters['MaxBufferSize'] # Read in multiple KB blocks + + # max_size is not working, because although it would, the server returns an error (More data avail) + smb = NewSMBPacket() + smb['Tid'] = tid + + readRaw = SMBCommand(SMB.SMB_COM_READ_RAW) + readRaw['Parameters'] = SMBReadRaw_Parameters() + readRaw['Parameters']['Fid'] = fid + readRaw['Parameters']['Offset'] = offset + readRaw['Parameters']['MaxCount'] = max_size + smb.addCommand(readRaw) + + self.sendSMB(smb) + if wait_answer: + data = self._sess.recv_packet(self.__timeout).get_trailer() + if not data: + # If there is no data it means there was an error + data = self.read_andx(tid, fid, offset, max_size) + return data + + return None + + def write(self,tid,fid,data, offset = 0, wait_answer=1): + smb = NewSMBPacket() + smb['Tid'] = tid + + write = SMBCommand(SMB.SMB_COM_WRITE) + write['Parameters'] = SMBWrite_Parameters() + write['Data'] = SMBWrite_Data() + write['Parameters']['Fid'] = fid + write['Parameters']['Count'] = len(data) + write['Parameters']['Offset'] = offset + write['Parameters']['Remaining'] = len(data) + write['Data']['Data'] = data + smb.addCommand(write) + + self.sendSMB(smb) + + if wait_answer: + smb = self.recvSMB() + if smb.isValidAnswer(SMB.SMB_COM_WRITE): + return smb + return None + + def write_andx(self,tid,fid,data, offset = 0, wait_answer=1, write_pipe_mode = False, smb_packet=None): + if smb_packet is None: + smb = NewSMBPacket() + smb['Tid'] = tid + + writeAndX = SMBCommand(SMB.SMB_COM_WRITE_ANDX) + smb.addCommand(writeAndX) + + writeAndX['Parameters'] = SMBWriteAndX_Parameters() + writeAndX['Parameters']['Fid'] = fid + writeAndX['Parameters']['Offset'] = offset + writeAndX['Parameters']['WriteMode'] = 8 + writeAndX['Parameters']['Remaining'] = len(data) + writeAndX['Parameters']['DataLength'] = len(data) + writeAndX['Parameters']['DataOffset'] = len(smb) # this length already includes the parameter + writeAndX['Data'] = data + + if write_pipe_mode is True: + # First of all we gotta know what the MaxBuffSize is + maxBuffSize = self._dialects_parameters['MaxBufferSize'] + if len(data) > maxBuffSize: + chunks_size = maxBuffSize - 60 + writeAndX['Parameters']['WriteMode'] = 0x0c + sendData = '\xff\xff' + data + totalLen = len(sendData) + writeAndX['Parameters']['DataLength'] = chunks_size + writeAndX['Parameters']['Remaining'] = totalLen-2 + writeAndX['Data'] = sendData[:chunks_size] + + self.sendSMB(smb) + if wait_answer: + smbResp = self.recvSMB() + smbResp.isValidAnswer(SMB.SMB_COM_WRITE_ANDX) + + alreadySent = chunks_size + sendData = sendData[chunks_size:] + + while alreadySent < totalLen: + writeAndX['Parameters']['WriteMode'] = 0x04 + writeAndX['Parameters']['DataLength'] = len(sendData[:chunks_size]) + writeAndX['Data'] = sendData[:chunks_size] + self.sendSMB(smb) + if wait_answer: + smbResp = self.recvSMB() + smbResp.isValidAnswer(SMB.SMB_COM_WRITE_ANDX) + alreadySent += writeAndX['Parameters']['DataLength'] + sendData = sendData[chunks_size:] + + return smbResp + + else: + smb = smb_packet + + self.sendSMB(smb) + + if wait_answer: + smb = self.recvSMB() + if smb.isValidAnswer(SMB.SMB_COM_WRITE_ANDX): + return smb + return None + + def write_raw(self,tid,fid,data, offset = 0, wait_answer=1): + LOG.warning("[MS-CIFS] This command was introduced in the CorePlus dialect, but is often listed as part of the LAN Manager 1.0 dialect.This command has been deprecated.Clients SHOULD use SMB_COM_WRITE_ANDX") + smb = NewSMBPacket() + smb['Tid'] = tid + + writeRaw = SMBCommand(SMB.SMB_COM_WRITE_RAW) + writeRaw['Parameters'] = SMBWriteRaw_Parameters() + writeRaw['Parameters']['Fid'] = fid + writeRaw['Parameters']['Offset'] = offset + writeRaw['Parameters']['Count'] = len(data) + writeRaw['Parameters']['DataLength'] = 0 + writeRaw['Parameters']['DataOffset'] = 0 + smb.addCommand(writeRaw) + + self.sendSMB(smb) + self._sess.send_packet(data) + + if wait_answer: + smb = self.recvSMB() + if smb.isValidAnswer(SMB.SMB_COM_WRITE_RAW): + return smb + return None + + def TransactNamedPipe(self, tid, fid, data = '', noAnswer = 0, waitAnswer = 1, offset = 0): + self.send_trans(tid,pack('<HH', 0x26, fid),'\\PIPE\\\x00','',data, noAnswer = noAnswer) + + if noAnswer or not waitAnswer: + return + smb = self.recvSMB() + if smb.isValidAnswer(SMB.SMB_COM_TRANSACTION): + transResponse = SMBCommand(smb['Data'][0]) + transParameters = SMBTransactionResponse_Parameters(transResponse['Parameters']) + return transResponse['Data'][-transParameters['TotalDataCount']:] # Remove Potential Prefix Padding + return None + + def TransactNamedPipeRecv(self): + s = self.recvSMB() + if s.isValidAnswer(SMB.SMB_COM_TRANSACTION): + transResponse = SMBCommand(s['Data'][0]) + transParameters = SMBTransactionResponse_Parameters(transResponse['Parameters']) + return transResponse['Data'][-transParameters['TotalDataCount']:] # Remove Potential Prefix Padding + return None + + def nt_create_andx(self,tid,filename, smb_packet=None, cmd = None, shareAccessMode = FILE_SHARE_READ | FILE_SHARE_WRITE, disposition = FILE_OPEN, accessMask = 0x2019f): + filename = filename.replace('/', '\\') + filename = filename.encode('utf-16le') if self.__flags2 & SMB.FLAGS2_UNICODE else filename + + if smb_packet is None: + smb = NewSMBPacket() + smb['Tid'] = tid + else: + smb = smb_packet + + if cmd is None: + ntCreate = SMBCommand(SMB.SMB_COM_NT_CREATE_ANDX) + ntCreate['Parameters'] = SMBNtCreateAndX_Parameters() + ntCreate['Data'] = SMBNtCreateAndX_Data(flags=self.__flags2) + ntCreate['Parameters']['FileNameLength'] = len(filename) + ntCreate['Parameters']['CreateFlags'] = 0x16 + ntCreate['Parameters']['AccessMask'] = accessMask + ntCreate['Parameters']['CreateOptions'] = 0x40 + ntCreate['Parameters']['ShareAccess'] = shareAccessMode + ntCreate['Parameters']['Disposition'] = disposition + ntCreate['Data']['FileName'] = filename + + if self.__flags2 & SMB.FLAGS2_UNICODE: + ntCreate['Data']['Pad'] = 0x0 + else: + ntCreate = cmd + + smb.addCommand(ntCreate) + + self.sendSMB(smb) + + while 1: + smb = self.recvSMB() + if smb.isValidAnswer(SMB.SMB_COM_NT_CREATE_ANDX): + # XXX Here we are ignoring the rest of the response + ntCreateResponse = SMBCommand(smb['Data'][0]) + ntCreateParameters = SMBNtCreateAndXResponse_Parameters(ntCreateResponse['Parameters']) + + self.fid = ntCreateParameters['Fid'] + return ntCreateParameters['Fid'] + + def logoff(self): + smb = NewSMBPacket() + + logOff = SMBCommand(SMB.SMB_COM_LOGOFF_ANDX) + logOff['Parameters'] = SMBLogOffAndX() + smb.addCommand(logOff) + + self.sendSMB(smb) + self.recvSMB() + # Let's clear some fields so you can login again under the same session + self._uid = 0 + + def list_path(self, service, path = '*', password = None): + path = path.replace('/', '\\') + path = path.encode('utf-16le') if self.__flags2 & SMB.FLAGS2_UNICODE else path + + tid = self.tree_connect_andx('\\\\' + self.__remote_name + '\\' + service, password) + try: + findFirstParameter = SMBFindFirst2_Parameters() + findFirstParameter['SearchAttributes'] = SMB_FILE_ATTRIBUTE_DIRECTORY | SMB_FILE_ATTRIBUTE_HIDDEN | \ + SMB_FILE_ATTRIBUTE_SYSTEM | SMB_FILE_ATTRIBUTE_READONLY | \ + SMB_FILE_ATTRIBUTE_ARCHIVE + findFirstParameter['SearchCount'] = 512 + findFirstParameter['Flags'] = SMB_FIND_RETURN_RESUME_KEYS | SMB_FIND_CLOSE_AT_EOS + findFirstParameter['InformationLevel'] = SMB_FIND_FILE_BOTH_DIRECTORY_INFO + findFirstParameter['SearchStorageType'] = 0 + findFirstParameter['FileName'] = path + ('\x00\x00' if self.__flags2 & SMB.FLAGS2_UNICODE else '\x00') + self.send_trans2(tid, SMB.TRANS2_FIND_FIRST2, '\x00', findFirstParameter, '') + files = [ ] + + totalDataCount = 1 + findData = '' + findFirst2ParameterBlock = '' + while len(findData) < totalDataCount: + resp = self.recvSMB() + + if resp.isValidAnswer(SMB.SMB_COM_TRANSACTION2): + trans2Response = SMBCommand(resp['Data'][0]) + trans2Parameters = SMBTransaction2Response_Parameters(trans2Response['Parameters']) + totalDataCount = trans2Parameters['TotalDataCount'] + findFirst2ParameterBlock += trans2Response['Data'][trans2Parameters['ParameterOffset']-55:][:trans2Parameters['ParameterCount']] + findData += trans2Response['Data'][trans2Parameters['DataOffset']-55:] + + findParameterBlock = SMBFindFirst2Response_Parameters(findFirst2ParameterBlock) + # Save the SID for resume operations + sid = findParameterBlock['SID'] + + while True: + record = SMBFindFileBothDirectoryInfo(data = findData) + + shortname = record['ShortName'].decode('utf-16le') if self.__flags2 & SMB.FLAGS2_UNICODE else record['ShortName'] + filename = record['FileName'].decode('utf-16le') if self.__flags2 & SMB.FLAGS2_UNICODE else record['FileName'] + + fileRecord = SharedFile(record['CreationTime'], record['LastAccessTime'], record['LastChangeTime'], + record['EndOfFile'], record['AllocationSize'], record['ExtFileAttributes'], + shortname, filename) + files.append(fileRecord) + if record['NextEntryOffset'] > 0 and len(findData[record['NextEntryOffset']:]) > 0: + findData = findData[record['NextEntryOffset']:] + else: + # More data to search? + if findParameterBlock['EndOfSearch'] == 0: + resume_filename = record['FileName'] + findNextParameter = SMBFindNext2_Parameters() + findNextParameter['SID'] = sid + findNextParameter['SearchCount'] = 1024 + findNextParameter['InformationLevel'] = SMB_FIND_FILE_BOTH_DIRECTORY_INFO + findNextParameter['ResumeKey'] = 0 + findNextParameter['Flags'] = SMB_FIND_RETURN_RESUME_KEYS | SMB_FIND_CLOSE_AT_EOS + findNextParameter['FileName'] = resume_filename + ('\x00\x00' if self.__flags2 & SMB.FLAGS2_UNICODE else '\x00') + self.send_trans2(tid, SMB.TRANS2_FIND_NEXT2, '\x00', findNextParameter, '') + findData = '' + findNext2ParameterBlock = '' + totalDataCount = 1 + while len(findData) < totalDataCount: + resp = self.recvSMB() + + if resp.isValidAnswer(SMB.SMB_COM_TRANSACTION2): + trans2Response = SMBCommand(resp['Data'][0]) + trans2Parameters = SMBTransaction2Response_Parameters(trans2Response['Parameters']) + totalDataCount = trans2Parameters['TotalDataCount'] + findNext2ParameterBlock += trans2Response['Data'][trans2Parameters['ParameterOffset']-55:][:trans2Parameters['ParameterCount']] + findData += trans2Response['Data'][trans2Parameters['DataOffset']-55:] + findParameterBlock = SMBFindNext2Response_Parameters(findNext2ParameterBlock) + else: + break + finally: + self.disconnect_tree(tid) + + return files + + def retr_file(self, service, filename, callback, mode = FILE_OPEN, offset = 0, password = None, shareAccessMode = SMB_ACCESS_READ): + filename = string.replace(filename, '/', '\\') + + fid = -1 + tid = self.tree_connect_andx('\\\\' + self.__remote_name + '\\' + service, password) + try: + fid = self.nt_create_andx(tid, filename, shareAccessMode = shareAccessMode, accessMask = 0x20089) + + res = self.query_file_info(tid, fid) + datasize = SMBQueryFileStandardInfo(res)['EndOfFile'] + + self.__nonraw_retr_file(tid, fid, offset, datasize, callback) + finally: + if fid >= 0: + self.close(tid, fid) + self.disconnect_tree(tid) + + def stor_file(self, service, filename, callback, mode = FILE_OVERWRITE_IF, offset = 0, password = None, shareAccessMode = SMB_ACCESS_WRITE): + filename = string.replace(filename, '/', '\\') + + fid = -1 + tid = self.tree_connect_andx('\\\\' + self.__remote_name + '\\' + service, password) + try: + fid = self.nt_create_andx(tid, filename, shareAccessMode = shareAccessMode, disposition = mode ) + + self.__nonraw_stor_file(tid, fid, offset, 0, callback) + finally: + if fid >= 0: + self.close(tid, fid) + self.disconnect_tree(tid) + + def stor_file_nonraw(self, service, filename, callback, mode = FILE_OVERWRITE_IF, offset = 0, password = None, shareAccessMode = SMB_ACCESS_WRITE ): + filename = string.replace(filename, '/', '\\') + + fid = -1 + tid = self.tree_connect_andx('\\\\' + self.__remote_name + '\\' + service, password) + try: + fid = self.nt_create_andx(tid, filename, shareAccessMode = shareAccessMode, disposition = mode) + self.__nonraw_stor_file(tid, fid, offset, 0, callback) + finally: + if fid >= 0: + self.close(tid, fid) + self.disconnect_tree(tid) + + def check_dir(self, service, path, password = None): + path = string.replace(path,'/', '\\') + tid = self.tree_connect_andx('\\\\' + self.__remote_name + '\\' + service, password) + try: + smb = NewSMBPacket() + smb['Tid'] = tid + smb['Mid'] = 0 + + cmd = SMBCommand(SMB.SMB_COM_CHECK_DIRECTORY) + cmd['Parameters'] = '' + cmd['Data'] = SMBCheckDirectory_Data(flags = self.__flags2) + cmd['Data']['DirectoryName'] = path.encode('utf-16le') if self.__flags2 & SMB.FLAGS2_UNICODE else path + smb.addCommand(cmd) + + self.sendSMB(smb) + + while 1: + s = self.recvSMB() + if s.isValidAnswer(SMB.SMB_COM_CHECK_DIRECTORY): + return + finally: + self.disconnect_tree(tid) + + def remove(self, service, path, password = None): + path = string.replace(path,'/', '\\') + # Perform a list to ensure the path exists + self.list_path(service, path, password) + + tid = self.tree_connect_andx('\\\\' + self.__remote_name + '\\' + service, password) + try: + smb = NewSMBPacket() + smb['Tid'] = tid + smb['Mid'] = 0 + + cmd = SMBCommand(SMB.SMB_COM_DELETE) + cmd['Parameters'] = SMBDelete_Parameters() + cmd['Parameters']['SearchAttributes'] = ATTR_HIDDEN | ATTR_SYSTEM | ATTR_ARCHIVE + cmd['Data'] = SMBDelete_Data(flags = self.__flags2) + cmd['Data']['FileName'] = (path + '\x00').encode('utf-16le') if self.__flags2 & SMB.FLAGS2_UNICODE else (path + '\x00') + smb.addCommand(cmd) + + self.sendSMB(smb) + + while 1: + s = self.recvSMB() + if s.isValidAnswer(SMB.SMB_COM_DELETE): + return + finally: + self.disconnect_tree(tid) + + def rmdir(self, service, path, password = None): + path = string.replace(path,'/', '\\') + # Check that the directory exists + self.check_dir(service, path, password) + + tid = self.tree_connect_andx('\\\\' + self.__remote_name + '\\' + service, password) + try: + path = path.encode('utf-16le') if self.__flags2 & SMB.FLAGS2_UNICODE else path + + smb = NewSMBPacket() + smb['Tid'] = tid + createDir = SMBCommand(SMB.SMB_COM_DELETE_DIRECTORY) + createDir['Data'] = SMBDeleteDirectory_Data(flags=self.__flags2) + createDir['Data']['DirectoryName'] = path + smb.addCommand(createDir) + + self.sendSMB(smb) + + while 1: + s = self.recvSMB() + if s.isValidAnswer(SMB.SMB_COM_DELETE_DIRECTORY): + return + finally: + self.disconnect_tree(tid) + + def mkdir(self, service, path, password = None): + path = string.replace(path,'/', '\\') + tid = self.tree_connect_andx('\\\\' + self.__remote_name + '\\' + service, password) + try: + path = path.encode('utf-16le') if self.__flags2 & SMB.FLAGS2_UNICODE else path + + smb = NewSMBPacket() + smb['Tid'] = tid + smb['Mid'] = 0 + + createDir = SMBCommand(SMB.SMB_COM_CREATE_DIRECTORY) + createDir['Data'] = SMBCreateDirectory_Data(flags=self.__flags2) + createDir['Data']['DirectoryName'] = path + smb.addCommand(createDir) + + self.sendSMB(smb) + + smb = self.recvSMB() + if smb.isValidAnswer(SMB.SMB_COM_CREATE_DIRECTORY): + return 1 + return 0 + finally: + self.disconnect_tree(tid) + + def rename(self, service, old_path, new_path, password = None): + old_path = string.replace(old_path,'/', '\\') + new_path = string.replace(new_path,'/', '\\') + tid = self.tree_connect_andx('\\\\' + self.__remote_name + '\\' + service, password) + try: + smb = NewSMBPacket() + smb['Tid'] = tid + smb['Mid'] = 0 + + renameCmd = SMBCommand(SMB.SMB_COM_RENAME) + renameCmd['Parameters'] = SMBRename_Parameters() + renameCmd['Parameters']['SearchAttributes'] = ATTR_SYSTEM | ATTR_HIDDEN | ATTR_DIRECTORY + renameCmd['Data'] = SMBRename_Data(flags = self.__flags2) + renameCmd['Data']['OldFileName'] = old_path.encode('utf-16le') if self.__flags2 & SMB.FLAGS2_UNICODE else old_path + renameCmd['Data']['NewFileName'] = new_path.encode('utf-16le') if self.__flags2 & SMB.FLAGS2_UNICODE else new_path + smb.addCommand(renameCmd) + + self.sendSMB(smb) + + smb = self.recvSMB() + if smb.isValidAnswer(SMB.SMB_COM_RENAME): + return 1 + return 0 + finally: + self.disconnect_tree(tid) + + def writeFile(self, treeId, fileId, data, offset = 0): + if (self._dialects_parameters['Capabilities'] & SMB.CAP_LARGE_WRITEX) and self._SignatureEnabled is False: + max_buf_size = 65000 + else: + max_buf_size = self._dialects_parameters['MaxBufferSize'] & ~0x3ff # Write in multiple KB blocks + + write_offset = offset + while 1: + if len(data) == 0: + break + writeData = data[:max_buf_size] + data = data[max_buf_size:] + + smb = self.write_andx(treeId,fileId,writeData, write_offset) + writeResponse = SMBCommand(smb['Data'][0]) + writeResponseParameters = SMBWriteAndXResponse_Parameters(writeResponse['Parameters']) + write_offset += writeResponseParameters['Count'] + + def get_socket(self): + return self._sess.get_socket() + +ERRDOS = { 1: 'Invalid function', + 2: 'File not found', + 3: 'Invalid directory', + 4: 'Too many open files', + 5: 'Access denied', + 6: 'Invalid file handle. Please file a bug report.', + 7: 'Memory control blocks destroyed', + 8: 'Out of memory', + 9: 'Invalid memory block address', + 10: 'Invalid environment', + 11: 'Invalid format', + 12: 'Invalid open mode', + 13: 'Invalid data', + 15: 'Invalid drive', + 16: 'Attempt to remove server\'s current directory', + 17: 'Not the same device', + 18: 'No files found', + 32: 'Sharing mode conflicts detected', + 33: 'Lock request conflicts detected', + 80: 'File already exists' + } + +ERRSRV = { 1: 'Non-specific error', + 2: 'Bad password', + 4: 'Access denied', + 5: 'Invalid tid. Please file a bug report.', + 6: 'Invalid network name', + 7: 'Invalid device', + 49: 'Print queue full', + 50: 'Print queue full', + 51: 'EOF on print queue dump', + 52: 'Invalid print file handle', + 64: 'Command not recognized. Please file a bug report.', + 65: 'Internal server error', + 67: 'Invalid path', + 69: 'Invalid access permissions', + 71: 'Invalid attribute mode', + 81: 'Server is paused', + 82: 'Not receiving messages', + 83: 'No room to buffer messages', + 87: 'Too many remote user names', + 88: 'Operation timeout', + 89: 'Out of resources', + 91: 'Invalid user handle. Please file a bug report.', + 250: 'Temporarily unable to support raw mode for transfer', + 251: 'Temporarily unable to support raw mode for transfer', + 252: 'Continue in MPX mode', + 65535: 'Unsupported function' + } + +ERRHRD = { 19: 'Media is write-protected', + 20: 'Unknown unit', + 21: 'Drive not ready', + 22: 'Unknown command', + 23: 'CRC error', + 24: 'Bad request', + 25: 'Seek error', + 26: 'Unknown media type', + 27: 'Sector not found', + 28: 'Printer out of paper', + 29: 'Write fault', + 30: 'Read fault', + 31: 'General failure', + 32: 'Open conflicts with an existing open', + 33: 'Invalid lock request', + 34: 'Wrong disk in drive', + 35: 'FCBs not available', + 36: 'Sharing buffer exceeded' + } + |