Home | History | Annotate | Download | only in impacket
      1 # Copyright (c) 2003-2016 CORE Security Technologies
      2 #
      3 # This software is provided under under a slightly modified version
      4 # of the Apache Software License. See the accompanying LICENSE file
      5 # for more information.
      6 #
      7 # Author: Alberto Solino (@agsolino)
      8 #
      9 # TODO:
     10 # [-] Functions should return NT error codes
     11 # [-] Handling errors in all situations, right now it's just raising exceptions.
     12 # [*] Standard authentication support
     13 # [ ] Organize the connectionData stuff
     14 # [*] Add capability to send a bad user ID if the user is not authenticated,
     15 #     right now you can ask for any command without actually being authenticated
     16 # [ ] PATH TRAVERSALS EVERYWHERE.. BE WARNED!
     17 # [ ] Check the credentials.. now we're just letting everybody to log in.
     18 # [ ] Check error situation (now many places assume the right data is coming)
     19 # [ ] Implement IPC to the main process so the connectionData is on a single place
     20 # [ ] Hence.. implement locking
     21 # estamos en la B
     22 
     23 from __future__ import with_statement
     24 import calendar
     25 import socket
     26 import time
     27 import datetime
     28 import struct
     29 import ConfigParser
     30 import SocketServer
     31 import threading
     32 import logging
     33 import logging.config
     34 import ntpath
     35 import os
     36 import fnmatch
     37 import errno
     38 import sys
     39 import random
     40 import shutil
     41 from binascii import hexlify
     42 
     43 # For signing
     44 from impacket import smb, nmb, ntlm, uuid, LOG
     45 from impacket import smb3structs as smb2
     46 from impacket.spnego import SPNEGO_NegTokenInit, TypesMech, MechTypes, SPNEGO_NegTokenResp, ASN1_AID, ASN1_SUPPORTED_MECH
     47 from impacket.nt_errors import STATUS_NO_MORE_FILES, STATUS_NETWORK_NAME_DELETED, STATUS_INVALID_PARAMETER, \
     48     STATUS_FILE_CLOSED, STATUS_MORE_PROCESSING_REQUIRED, STATUS_OBJECT_PATH_NOT_FOUND, STATUS_DIRECTORY_NOT_EMPTY, \
     49     STATUS_FILE_IS_A_DIRECTORY, STATUS_NOT_IMPLEMENTED, STATUS_INVALID_HANDLE, STATUS_OBJECT_NAME_COLLISION, \
     50     STATUS_NO_SUCH_FILE, STATUS_CANCELLED, STATUS_OBJECT_NAME_NOT_FOUND, STATUS_SUCCESS, STATUS_ACCESS_DENIED, \
     51     STATUS_NOT_SUPPORTED, STATUS_INVALID_DEVICE_REQUEST, STATUS_FS_DRIVER_REQUIRED, STATUS_INVALID_INFO_CLASS
     52 
     53 # These ones not defined in nt_errors
     54 STATUS_SMB_BAD_UID = 0x005B0002
     55 STATUS_SMB_BAD_TID = 0x00050002
     56 
     57 # Utility functions
     58 # and general functions.
     59 # There are some common functions that can be accessed from more than one SMB
     60 # command (or either TRANSACTION). That's why I'm putting them here
     61 # TODO: Return NT ERROR Codes
     62 
     63 def outputToJohnFormat(challenge, username, domain, lmresponse, ntresponse):
     64 # We don't want to add a possible failure here, since this is an
     65 # extra bonus. We try, if it fails, returns nothing
     66     ret_value = ''
     67     try:
     68         if len(ntresponse) > 24:
     69             # Extended Security - NTLMv2
     70             ret_value = {'hash_string':'%s::%s:%s:%s:%s' % (username.decode('utf-16le'), domain.decode('utf-16le'), hexlify(challenge), hexlify(ntresponse)[:32], hexlify(ntresponse)[32:]), 'hash_version':'ntlmv2'}
     71         else:
     72             # NTLMv1
     73             ret_value = {'hash_string':'%s::%s:%s:%s:%s' % (username.decode('utf-16le'), domain.decode('utf-16le'), hexlify(lmresponse), hexlify(ntresponse), hexlify(challenge)), 'hash_version':'ntlm'}
     74     except:
     75         # Let's try w/o decoding Unicode
     76         try:
     77             if len(ntresponse) > 24:
     78                 # Extended Security - NTLMv2
     79                 ret_value = {'hash_string':'%s::%s:%s:%s:%s' % (username, domain, hexlify(challenge), hexlify(ntresponse)[:32], hexlify(ntresponse)[32:]), 'hash_version':'ntlmv2'}
     80             else:
     81                 # NTLMv1
     82                 ret_value = {'hash_string':'%s::%s:%s:%s:%s' % (username, domain, hexlify(lmresponse), hexlify(ntresponse), hexlify(challenge)), 'hash_version':'ntlm'}
     83         except Exception, e:
     84             LOG.error("outputToJohnFormat: %s" % e)
     85             pass
     86 
     87     return ret_value
     88 
     89 def writeJohnOutputToFile(hash_string, hash_version, file_name):
     90     fn_data = os.path.splitext(file_name)
     91     if hash_version == "ntlmv2":
     92         output_filename = fn_data[0] + "_ntlmv2" + fn_data[1]
     93     else:
     94         output_filename = fn_data[0] + "_ntlm" + fn_data[1]
     95 
     96     with open(output_filename,"a") as f:
     97             f.write(hash_string)
     98             f.write('\n')
     99 
    100 
    101 def decodeSMBString( flags, text ):
    102     if flags & smb.SMB.FLAGS2_UNICODE:
    103         return text.decode('utf-16le')
    104     else:
    105         return text
    106 
    107 def encodeSMBString( flags, text ):
    108     if flags & smb.SMB.FLAGS2_UNICODE:
    109         return (text).encode('utf-16le')
    110     else:
    111         return text
    112 
    113 def getFileTime(t):
    114     t *= 10000000
    115     t += 116444736000000000
    116     return t
    117 
    118 def getUnixTime(t):
    119     t -= 116444736000000000
    120     t /= 10000000
    121     return t
    122 
    123 def getSMBDate(t):
    124     # TODO: Fix this :P
    125     d = datetime.date.fromtimestamp(t)
    126     year = d.year - 1980
    127     ret = (year << 8) + (d.month << 4) + d.day
    128     return ret
    129 
    130 def getSMBTime(t):
    131     # TODO: Fix this :P
    132     d = datetime.datetime.fromtimestamp(t)
    133     return (d.hour << 8) + (d.minute << 4) + d.second
    134 
    135 def getShares(connId, smbServer):
    136     config = smbServer.getServerConfig()
    137     sections = config.sections()
    138     # Remove the global one
    139     del(sections[sections.index('global')])
    140     shares = {}
    141     for i in sections:
    142         shares[i] = dict(config.items(i))
    143     return shares
    144 
    145 def searchShare(connId, share, smbServer):
    146     config = smbServer.getServerConfig()
    147     if config.has_section(share):
    148        return dict(config.items(share))
    149     else:
    150        return None
    151 
    152 def openFile(path,fileName, accessMode, fileAttributes, openMode):
    153     fileName = os.path.normpath(fileName.replace('\\','/'))
    154     errorCode = 0
    155     if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
    156        # strip leading '/'
    157        fileName = fileName[1:]
    158     pathName = os.path.join(path,fileName)
    159     mode = 0
    160     # Check the Open Mode
    161     if openMode & 0x10:
    162         # If the file does not exist, create it.
    163         mode = os.O_CREAT
    164     else:
    165         # If file does not exist, return an error
    166         if os.path.exists(pathName) is not True:
    167             errorCode = STATUS_NO_SUCH_FILE
    168             return 0,mode, pathName, errorCode
    169 
    170     if os.path.isdir(pathName) and (fileAttributes & smb.ATTR_DIRECTORY) == 0:
    171         # Request to open a normal file and this is actually a directory
    172             errorCode = STATUS_FILE_IS_A_DIRECTORY
    173             return 0, mode, pathName, errorCode
    174     # Check the Access Mode
    175     if accessMode & 0x7 == 1:
    176        mode |= os.O_WRONLY
    177     elif accessMode & 0x7 == 2:
    178        mode |= os.O_RDWR
    179     else:
    180        mode = os.O_RDONLY
    181 
    182     try:
    183         if sys.platform == 'win32':
    184             mode |= os.O_BINARY
    185         fid = os.open(pathName, mode)
    186     except Exception, e:
    187         LOG.error("openFile: %s,%s" % (pathName, mode) ,e)
    188         fid = 0
    189         errorCode = STATUS_ACCESS_DENIED
    190 
    191     return fid, mode, pathName, errorCode
    192 
    193 def queryFsInformation(path, filename, level=0):
    194 
    195     if isinstance(filename,unicode):
    196          encoding = 'utf-16le'
    197          flags    = smb.SMB.FLAGS2_UNICODE
    198     else:
    199          encoding = 'ascii'
    200          flags    = 0
    201 
    202     fileName = os.path.normpath(filename.replace('\\','/'))
    203     if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
    204        # strip leading '/'
    205        fileName = fileName[1:]
    206     pathName = os.path.join(path,fileName)
    207     fileSize = os.path.getsize(pathName)
    208     (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(pathName)
    209     if level == smb.SMB_QUERY_FS_ATTRIBUTE_INFO or level == smb2.SMB2_FILESYSTEM_ATTRIBUTE_INFO:
    210         data = smb.SMBQueryFsAttributeInfo()
    211         data['FileSystemAttributes']      = smb.FILE_CASE_SENSITIVE_SEARCH | smb.FILE_CASE_PRESERVED_NAMES
    212         data['MaxFilenNameLengthInBytes'] = 255
    213         data['LengthOfFileSystemName']    = len('XTFS')*2
    214         data['FileSystemName']            = 'XTFS'.encode('utf-16le')
    215         return data.getData()
    216     elif level == smb.SMB_INFO_VOLUME:
    217         data = smb.SMBQueryFsInfoVolume( flags = flags )
    218         data['VolumeLabel']               = 'SHARE'.encode(encoding)
    219         return data.getData()
    220     elif level == smb.SMB_QUERY_FS_VOLUME_INFO or level == smb2.SMB2_FILESYSTEM_VOLUME_INFO:
    221         data = smb.SMBQueryFsVolumeInfo()
    222         data['VolumeLabel']               = ''
    223         data['VolumeCreationTime']        = getFileTime(ctime)
    224         return data.getData()
    225     elif level == smb.SMB_QUERY_FS_SIZE_INFO:
    226         data = smb.SMBQueryFsSizeInfo()
    227         return data.getData()
    228     elif level == smb.FILE_FS_FULL_SIZE_INFORMATION:
    229         data = smb.SMBFileFsFullSizeInformation()
    230         return data.getData()
    231     elif level == smb.FILE_FS_SIZE_INFORMATION:
    232         data = smb.FileFsSizeInformation()
    233         return data.getData()
    234     else:
    235         lastWriteTime = mtime
    236         attribs = 0
    237         if os.path.isdir(pathName):
    238             attribs |= smb.SMB_FILE_ATTRIBUTE_DIRECTORY
    239         if os.path.isfile(pathName):
    240             attribs |= smb.SMB_FILE_ATTRIBUTE_NORMAL
    241         fileAttributes = attribs
    242         return fileSize, lastWriteTime, fileAttributes
    243 
    244 def findFirst2(path, fileName, level, searchAttributes, isSMB2 = False):
    245      # TODO: Depending on the level, this could be done much simpler
    246 
    247      #print "FindFirs2 path:%s, filename:%s" % (path, fileName)
    248      fileName = os.path.normpath(fileName.replace('\\','/'))
    249      # Let's choose the right encoding depending on the request
    250      if isinstance(fileName,unicode):
    251          encoding = 'utf-16le'
    252          flags    = smb.SMB.FLAGS2_UNICODE
    253      else:
    254          encoding = 'ascii'
    255          flags    = 0
    256 
    257      if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
    258         # strip leading '/'
    259         fileName = fileName[1:]
    260 
    261      pathName = os.path.join(path,fileName)
    262      files = []
    263 
    264      if pathName.find('*') == -1 and pathName.find('?') == -1:
    265          # No search patterns
    266          pattern = ''
    267      else:
    268          pattern = os.path.basename(pathName)
    269          dirName = os.path.dirname(pathName)
    270 
    271      # Always add . and .. Not that important for Windows, but Samba whines if
    272      # not present (for * search only)
    273      if pattern == '*':
    274          files.append(os.path.join(dirName,'.'))
    275          files.append(os.path.join(dirName,'..'))
    276 
    277      if pattern != '':
    278          for file in os.listdir(dirName):
    279              if fnmatch.fnmatch(file.lower(),pattern.lower()):
    280                 entry = os.path.join(dirName, file)
    281                 if os.path.isdir(entry):
    282                     if searchAttributes & smb.ATTR_DIRECTORY:
    283                         files.append(entry)
    284                 else:
    285                     files.append(entry)
    286      else:
    287          if os.path.exists(pathName):
    288              files.append(pathName)
    289 
    290      searchResult = []
    291      searchCount = len(files)
    292      errorCode = STATUS_SUCCESS
    293 
    294      for i in files:
    295         if level == smb.SMB_FIND_FILE_BOTH_DIRECTORY_INFO or level == smb2.SMB2_FILE_BOTH_DIRECTORY_INFO:
    296             item = smb.SMBFindFileBothDirectoryInfo( flags = flags )
    297         elif level == smb.SMB_FIND_FILE_DIRECTORY_INFO or level == smb2.SMB2_FILE_DIRECTORY_INFO:
    298             item = smb.SMBFindFileDirectoryInfo( flags = flags )
    299         elif level == smb.SMB_FIND_FILE_FULL_DIRECTORY_INFO or level == smb2.SMB2_FULL_DIRECTORY_INFO:
    300             item = smb.SMBFindFileFullDirectoryInfo( flags = flags )
    301         elif level == smb.SMB_FIND_INFO_STANDARD:
    302             item = smb.SMBFindInfoStandard( flags = flags )
    303         elif level == smb.SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO or level == smb2.SMB2_FILE_ID_FULL_DIRECTORY_INFO:
    304             item = smb.SMBFindFileIdFullDirectoryInfo( flags = flags )
    305         elif level == smb.SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO or level == smb2.SMB2_FILE_ID_BOTH_DIRECTORY_INFO:
    306             item = smb.SMBFindFileIdBothDirectoryInfo( flags = flags )
    307         elif level == smb.SMB_FIND_FILE_NAMES_INFO or level == smb2.SMB2_FILE_NAMES_INFO:
    308             item = smb.SMBFindFileNamesInfo( flags = flags )
    309         else:
    310             LOG.error("Wrong level %d!" % level)
    311             return  searchResult, searchCount, STATUS_NOT_SUPPORTED
    312 
    313         (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(i)
    314         if os.path.isdir(i):
    315            item['ExtFileAttributes'] = smb.ATTR_DIRECTORY
    316         else:
    317            item['ExtFileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE
    318 
    319         item['FileName'] = os.path.basename(i).encode(encoding)
    320 
    321         if level == smb.SMB_FIND_FILE_BOTH_DIRECTORY_INFO or level == smb.SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO or level == smb2.SMB2_FILE_ID_BOTH_DIRECTORY_INFO or level == smb2.SMB2_FILE_BOTH_DIRECTORY_INFO:
    322            item['EaSize']            = 0
    323            item['EndOfFile']         = size
    324            item['AllocationSize']    = size
    325            item['CreationTime']      = getFileTime(ctime)
    326            item['LastAccessTime']    = getFileTime(atime)
    327            item['LastWriteTime']     = getFileTime(mtime)
    328            item['LastChangeTime']    = getFileTime(mtime)
    329            item['ShortName']         = '\x00'*24
    330            item['FileName']          = os.path.basename(i).encode(encoding)
    331            padLen = (8-(len(item) % 8)) % 8
    332            item['NextEntryOffset']   = len(item) + padLen
    333         elif level == smb.SMB_FIND_FILE_DIRECTORY_INFO:
    334            item['EndOfFile']         = size
    335            item['AllocationSize']    = size
    336            item['CreationTime']      = getFileTime(ctime)
    337            item['LastAccessTime']    = getFileTime(atime)
    338            item['LastWriteTime']     = getFileTime(mtime)
    339            item['LastChangeTime']    = getFileTime(mtime)
    340            item['FileName']          = os.path.basename(i).encode(encoding)
    341            padLen = (8-(len(item) % 8)) % 8
    342            item['NextEntryOffset']   = len(item) + padLen
    343         elif level == smb.SMB_FIND_FILE_FULL_DIRECTORY_INFO or level == smb.SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO or level == smb2.SMB2_FULL_DIRECTORY_INFO:
    344            item['EaSize']            = 0
    345            item['EndOfFile']         = size
    346            item['AllocationSize']    = size
    347            item['CreationTime']      = getFileTime(ctime)
    348            item['LastAccessTime']    = getFileTime(atime)
    349            item['LastWriteTime']     = getFileTime(mtime)
    350            item['LastChangeTime']    = getFileTime(mtime)
    351            padLen = (8-(len(item) % 8)) % 8
    352            item['NextEntryOffset']   = len(item) + padLen
    353         elif level == smb.SMB_FIND_INFO_STANDARD:
    354            item['EaSize']            = size
    355            item['CreationDate']      = getSMBDate(ctime)
    356            item['CreationTime']      = getSMBTime(ctime)
    357            item['LastAccessDate']    = getSMBDate(atime)
    358            item['LastAccessTime']    = getSMBTime(atime)
    359            item['LastWriteDate']     = getSMBDate(mtime)
    360            item['LastWriteTime']     = getSMBTime(mtime)
    361         searchResult.append(item)
    362 
    363      # No more files
    364      if (level >= smb.SMB_FIND_FILE_DIRECTORY_INFO or isSMB2 == True) and searchCount > 0:
    365          searchResult[-1]['NextEntryOffset'] = 0
    366 
    367      return searchResult, searchCount, errorCode
    368 
    369 def queryFileInformation(path, filename, level):
    370     #print "queryFileInfo path: %s, filename: %s, level:0x%x" % (path,filename,level)
    371     return queryPathInformation(path,filename, level)
    372 
    373 def queryPathInformation(path, filename, level):
    374     # TODO: Depending on the level, this could be done much simpler
    375   #print "queryPathInfo path: %s, filename: %s, level:0x%x" % (path,filename,level)
    376   try:
    377     errorCode = 0
    378     fileName = os.path.normpath(filename.replace('\\','/'))
    379     if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\') and path != '':
    380        # strip leading '/'
    381        fileName = fileName[1:]
    382     pathName = os.path.join(path,fileName)
    383     if os.path.exists(pathName):
    384         (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(pathName)
    385         if level == smb.SMB_QUERY_FILE_BASIC_INFO:
    386             infoRecord = smb.SMBQueryFileBasicInfo()
    387             infoRecord['CreationTime']         = getFileTime(ctime)
    388             infoRecord['LastAccessTime']       = getFileTime(atime)
    389             infoRecord['LastWriteTime']        = getFileTime(mtime)
    390             infoRecord['LastChangeTime']       = getFileTime(mtime)
    391             if os.path.isdir(pathName):
    392                infoRecord['ExtFileAttributes'] = smb.ATTR_DIRECTORY
    393             else:
    394                infoRecord['ExtFileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE
    395         elif level == smb.SMB_QUERY_FILE_STANDARD_INFO:
    396             infoRecord = smb.SMBQueryFileStandardInfo()
    397             infoRecord['AllocationSize']       = size
    398             infoRecord['EndOfFile']            = size
    399             if os.path.isdir(pathName):
    400                infoRecord['Directory']         = 1
    401             else:
    402                infoRecord['Directory']         = 0
    403         elif level == smb.SMB_QUERY_FILE_ALL_INFO or level == smb2.SMB2_FILE_ALL_INFO:
    404             infoRecord = smb.SMBQueryFileAllInfo()
    405             infoRecord['CreationTime']         = getFileTime(ctime)
    406             infoRecord['LastAccessTime']       = getFileTime(atime)
    407             infoRecord['LastWriteTime']        = getFileTime(mtime)
    408             infoRecord['LastChangeTime']       = getFileTime(mtime)
    409             if os.path.isdir(pathName):
    410                infoRecord['ExtFileAttributes'] = smb.ATTR_DIRECTORY
    411             else:
    412                infoRecord['ExtFileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE
    413             infoRecord['AllocationSize']       = size
    414             infoRecord['EndOfFile']            = size
    415             if os.path.isdir(pathName):
    416                infoRecord['Directory']         = 1
    417             else:
    418                infoRecord['Directory']         = 0
    419             infoRecord['FileName']             = filename.encode('utf-16le')
    420         elif level == smb2.SMB2_FILE_NETWORK_OPEN_INFO:
    421             infoRecord = smb.SMBFileNetworkOpenInfo()
    422             infoRecord['CreationTime']         = getFileTime(ctime)
    423             infoRecord['LastAccessTime']       = getFileTime(atime)
    424             infoRecord['LastWriteTime']        = getFileTime(mtime)
    425             infoRecord['ChangeTime']           = getFileTime(mtime)
    426             infoRecord['AllocationSize']       = size
    427             infoRecord['EndOfFile']            = size
    428             if os.path.isdir(pathName):
    429                infoRecord['FileAttributes'] = smb.ATTR_DIRECTORY
    430             else:
    431                infoRecord['FileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE
    432         elif level == smb.SMB_QUERY_FILE_EA_INFO or level == smb2.SMB2_FILE_EA_INFO:
    433             infoRecord = smb.SMBQueryFileEaInfo()
    434         elif level == smb2.SMB2_FILE_STREAM_INFO:
    435             infoRecord = smb.SMBFileStreamInformation()
    436         else:
    437             LOG.error('Unknown level for query path info! 0x%x' % level)
    438             # UNSUPPORTED
    439             return None, STATUS_NOT_SUPPORTED
    440 
    441         return infoRecord, errorCode
    442     else:
    443         # NOT FOUND
    444         return None, STATUS_OBJECT_NAME_NOT_FOUND
    445   except Exception, e:
    446       LOG.error('queryPathInfo: %s' % e)
    447       raise
    448 
    449 def queryDiskInformation(path):
    450 # TODO: Do something useful here :)
    451 # For now we just return fake values
    452    totalUnits = 65535
    453    freeUnits = 65535
    454    return totalUnits, freeUnits
    455 
    456 # Here we implement the NT transaction handlers
    457 class NTTRANSCommands:
    458     def default(self, connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
    459         pass
    460 
    461 # Here we implement the NT transaction handlers
    462 class TRANSCommands:
    463     @staticmethod
    464     def lanMan(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
    465         # Minimal [MS-RAP] implementation, just to return the shares
    466         connData = smbServer.getConnectionData(connId)
    467 
    468         respSetup = ''
    469         respParameters = ''
    470         respData = ''
    471         errorCode = STATUS_SUCCESS
    472         if struct.unpack('<H',parameters[:2])[0] == 0:
    473             # NetShareEnum Request
    474             netShareEnum = smb.SMBNetShareEnum(parameters)
    475             if netShareEnum['InfoLevel'] == 1:
    476                 shares = getShares(connId, smbServer)
    477                 respParameters = smb.SMBNetShareEnumResponse()
    478                 respParameters['EntriesReturned']  = len(shares)
    479                 respParameters['EntriesAvailable'] = len(shares)
    480                 tailData = ''
    481                 for i in shares:
    482                     # NetShareInfo1 len == 20
    483                     entry = smb.NetShareInfo1()
    484                     entry['NetworkName'] = i + '\x00'*(13-len(i))
    485                     entry['Type']        = int(shares[i]['share type'])
    486                     # (beto) If offset == 0 it crashes explorer.exe on windows 7
    487                     entry['RemarkOffsetLow'] = 20 * len(shares) + len(tailData)
    488                     respData += entry.getData()
    489                     if shares[i].has_key('comment'):
    490                         tailData += shares[i]['comment'] + '\x00'
    491                     else:
    492                         tailData += '\x00'
    493                 respData += tailData
    494             else:
    495                 # We don't support other info levels
    496                 errorCode = STATUS_NOT_SUPPORTED
    497         elif struct.unpack('<H',parameters[:2])[0] == 13:
    498             # NetrServerGetInfo Request
    499             respParameters = smb.SMBNetServerGetInfoResponse()
    500             netServerInfo = smb.SMBNetServerInfo1()
    501             netServerInfo['ServerName'] = smbServer.getServerName()
    502             respData = str(netServerInfo)
    503             respParameters['TotalBytesAvailable'] = len(respData)
    504         elif struct.unpack('<H',parameters[:2])[0] == 1:
    505             # NetrShareGetInfo Request
    506             request = smb.SMBNetShareGetInfo(parameters)
    507             respParameters = smb.SMBNetShareGetInfoResponse()
    508             shares = getShares(connId, smbServer)
    509             share = shares[request['ShareName'].upper()]
    510             shareInfo = smb.NetShareInfo1()
    511             shareInfo['NetworkName'] = request['ShareName'].upper() + '\x00'
    512             shareInfo['Type']        = int(share['share type'])
    513             respData = shareInfo.getData()
    514             if share.has_key('comment'):
    515                 shareInfo['RemarkOffsetLow'] = len(respData)
    516                 respData += share['comment'] + '\x00'
    517             respParameters['TotalBytesAvailable'] = len(respData)
    518 
    519         else:
    520             # We don't know how to handle anything else
    521             errorCode = STATUS_NOT_SUPPORTED
    522 
    523         smbServer.setConnectionData(connId, connData)
    524 
    525         return respSetup, respParameters, respData, errorCode
    526 
    527     @staticmethod
    528     def transactNamedPipe(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
    529         connData = smbServer.getConnectionData(connId)
    530 
    531         respSetup = ''
    532         respParameters = ''
    533         respData = ''
    534         errorCode = STATUS_SUCCESS
    535         SMBCommand  = smb.SMBCommand(recvPacket['Data'][0])
    536         transParameters= smb.SMBTransaction_Parameters(SMBCommand['Parameters'])
    537 
    538         # Extract the FID
    539         fid = struct.unpack('<H', transParameters['Setup'][2:])[0]
    540 
    541         if connData['OpenedFiles'].has_key(fid):
    542             fileHandle = connData['OpenedFiles'][fid]['FileHandle']
    543             if fileHandle != PIPE_FILE_DESCRIPTOR:
    544                 os.write(fileHandle,data)
    545                 respData = os.read(fileHandle,data)
    546             else:
    547                 sock = connData['OpenedFiles'][fid]['Socket']
    548                 sock.send(data)
    549                 respData = sock.recv(maxDataCount)
    550         else:
    551             errorCode = STATUS_INVALID_HANDLE
    552 
    553         smbServer.setConnectionData(connId, connData)
    554 
    555         return respSetup, respParameters, respData, errorCode
    556 
    557 # Here we implement the transaction2 handlers
    558 class TRANS2Commands:
    559     # All these commands return setup, parameters, data, errorCode
    560     @staticmethod
    561     def setPathInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
    562         connData = smbServer.getConnectionData(connId)
    563 
    564         respSetup = ''
    565         respParameters = ''
    566         respData = ''
    567         errorCode = STATUS_SUCCESS
    568         setPathInfoParameters = smb.SMBSetPathInformation_Parameters(flags = recvPacket['Flags2'], data = parameters)
    569         if connData['ConnectedShares'].has_key(recvPacket['Tid']):
    570             path     = connData['ConnectedShares'][recvPacket['Tid']]['path']
    571             fileName = decodeSMBString(recvPacket['Flags2'], setPathInfoParameters['FileName'])
    572             fileName = os.path.normpath(fileName.replace('\\','/'))
    573             if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\') and path != '':
    574                # strip leading '/'
    575                fileName = fileName[1:]
    576             pathName = os.path.join(path,fileName)
    577             if os.path.exists(pathName):
    578                 informationLevel = setPathInfoParameters['InformationLevel']
    579                 if informationLevel == smb.SMB_SET_FILE_BASIC_INFO:
    580                     infoRecord = smb.SMBSetFileBasicInfo(data)
    581                     # Creation time won't be set,  the other ones we play with.
    582                     atime = infoRecord['LastAccessTime']
    583                     if atime == 0:
    584                         atime = -1
    585                     else:
    586                         atime = getUnixTime(atime)
    587                     mtime = infoRecord['LastWriteTime']
    588                     if mtime == 0:
    589                         mtime = -1
    590                     else:
    591                         mtime = getUnixTime(mtime)
    592                     if mtime != -1 or atime != -1:
    593                         os.utime(pathName,(atime,mtime))
    594                 else:
    595                     smbServer.log('Unknown level for set path info! 0x%x' % setPathInfoParameters['InformationLevel'], logging.ERROR)
    596                     # UNSUPPORTED
    597                     errorCode =  STATUS_NOT_SUPPORTED
    598             else:
    599                 errorCode = STATUS_OBJECT_NAME_NOT_FOUND
    600 
    601             if errorCode == STATUS_SUCCESS:
    602                 respParameters = smb.SMBSetPathInformationResponse_Parameters()
    603 
    604         else:
    605             errorCode = STATUS_SMB_BAD_TID
    606 
    607         smbServer.setConnectionData(connId, connData)
    608 
    609         return respSetup, respParameters, respData, errorCode
    610 
    611 
    612     @staticmethod
    613     def setFileInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
    614         connData = smbServer.getConnectionData(connId)
    615 
    616         respSetup = ''
    617         respParameters = ''
    618         respData = ''
    619         errorCode = STATUS_SUCCESS
    620         setFileInfoParameters = smb.SMBSetFileInformation_Parameters(parameters)
    621 
    622         if connData['ConnectedShares'].has_key(recvPacket['Tid']):
    623             if connData['OpenedFiles'].has_key(setFileInfoParameters['FID']):
    624                 fileName = connData['OpenedFiles'][setFileInfoParameters['FID']]['FileName']
    625                 informationLevel = setFileInfoParameters['InformationLevel']
    626                 if informationLevel == smb.SMB_SET_FILE_DISPOSITION_INFO:
    627                     infoRecord = smb.SMBSetFileDispositionInfo(parameters)
    628                     if infoRecord['DeletePending'] > 0:
    629                        # Mark this file for removal after closed
    630                        connData['OpenedFiles'][setFileInfoParameters['FID']]['DeleteOnClose'] = True
    631                        respParameters = smb.SMBSetFileInformationResponse_Parameters()
    632                 elif informationLevel == smb.SMB_SET_FILE_BASIC_INFO:
    633                     infoRecord = smb.SMBSetFileBasicInfo(data)
    634                     # Creation time won't be set,  the other ones we play with.
    635                     atime = infoRecord['LastAccessTime']
    636                     if atime == 0:
    637                         atime = -1
    638                     else:
    639                         atime = getUnixTime(atime)
    640                     mtime = infoRecord['LastWriteTime']
    641                     if mtime == 0:
    642                         mtime = -1
    643                     else:
    644                         mtime = getUnixTime(mtime)
    645                     os.utime(fileName,(atime,mtime))
    646                 elif informationLevel == smb.SMB_SET_FILE_END_OF_FILE_INFO:
    647                     fileHandle = connData['OpenedFiles'][setFileInfoParameters['FID']]['FileHandle']
    648                     infoRecord = smb.SMBSetFileEndOfFileInfo(data)
    649                     if infoRecord['EndOfFile'] > 0:
    650                         os.lseek(fileHandle, infoRecord['EndOfFile']-1, 0)
    651                         os.write(fileHandle, '\x00')
    652                 else:
    653                     smbServer.log('Unknown level for set file info! 0x%x' % setFileInfoParameters['InformationLevel'], logging.ERROR)
    654                     # UNSUPPORTED
    655                     errorCode =  STATUS_NOT_SUPPORTED
    656             else:
    657                 errorCode = STATUS_NO_SUCH_FILE
    658 
    659             if errorCode == STATUS_SUCCESS:
    660                 respParameters = smb.SMBSetFileInformationResponse_Parameters()
    661         else:
    662             errorCode = STATUS_SMB_BAD_TID
    663 
    664         smbServer.setConnectionData(connId, connData)
    665 
    666         return respSetup, respParameters, respData, errorCode
    667 
    668     @staticmethod
    669     def queryFileInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
    670         connData = smbServer.getConnectionData(connId)
    671 
    672         respSetup = ''
    673         respParameters = ''
    674         respData = ''
    675 
    676         queryFileInfoParameters = smb.SMBQueryFileInformation_Parameters(parameters)
    677 
    678         if connData['ConnectedShares'].has_key(recvPacket['Tid']):
    679             if connData['OpenedFiles'].has_key(queryFileInfoParameters['FID']):
    680                 fileName = connData['OpenedFiles'][queryFileInfoParameters['FID']]['FileName']
    681 
    682                 infoRecord, errorCode = queryFileInformation('', fileName, queryFileInfoParameters['InformationLevel'])
    683 
    684                 if infoRecord is not None:
    685                     respParameters = smb.SMBQueryFileInformationResponse_Parameters()
    686                     respData = infoRecord
    687             else:
    688                 errorCode = STATUS_INVALID_HANDLE
    689         else:
    690             errorCode = STATUS_SMB_BAD_TID
    691 
    692         smbServer.setConnectionData(connId, connData)
    693 
    694         return respSetup, respParameters, respData, errorCode
    695 
    696     @staticmethod
    697     def queryPathInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
    698         connData = smbServer.getConnectionData(connId)
    699 
    700         respSetup = ''
    701         respParameters = ''
    702         respData = ''
    703         errorCode = 0
    704 
    705         queryPathInfoParameters = smb.SMBQueryPathInformation_Parameters(flags = recvPacket['Flags2'], data = parameters)
    706 
    707         if connData['ConnectedShares'].has_key(recvPacket['Tid']):
    708             path = connData['ConnectedShares'][recvPacket['Tid']]['path']
    709             try:
    710                infoRecord, errorCode = queryPathInformation(path, decodeSMBString(recvPacket['Flags2'], queryPathInfoParameters['FileName']), queryPathInfoParameters['InformationLevel'])
    711             except Exception, e:
    712                smbServer.log("queryPathInformation: %s" % e,logging.ERROR)
    713 
    714             if infoRecord is not None:
    715                 respParameters = smb.SMBQueryPathInformationResponse_Parameters()
    716                 respData = infoRecord
    717         else:
    718             errorCode = STATUS_SMB_BAD_TID
    719 
    720         smbServer.setConnectionData(connId, connData)
    721 
    722         return respSetup, respParameters, respData, errorCode
    723 
    724     @staticmethod
    725     def queryFsInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
    726         connData = smbServer.getConnectionData(connId)
    727         errorCode = 0
    728         # Get the Tid associated
    729         if connData['ConnectedShares'].has_key(recvPacket['Tid']):
    730             data = queryFsInformation(connData['ConnectedShares'][recvPacket['Tid']]['path'], '', struct.unpack('<H',parameters)[0])
    731 
    732         smbServer.setConnectionData(connId, connData)
    733 
    734         return '','', data, errorCode
    735 
    736     @staticmethod
    737     def findNext2(connId, smbServer, recvPacket, parameters, data, maxDataCount):
    738         connData = smbServer.getConnectionData(connId)
    739 
    740         respSetup = ''
    741         respParameters = ''
    742         respData = ''
    743         errorCode = STATUS_SUCCESS
    744         findNext2Parameters = smb.SMBFindNext2_Parameters(flags = recvPacket['Flags2'], data = parameters)
    745 
    746         sid = findNext2Parameters['SID']
    747         if connData['ConnectedShares'].has_key(recvPacket['Tid']):
    748             if connData['SIDs'].has_key(sid):
    749                 searchResult = connData['SIDs'][sid]
    750                 respParameters = smb.SMBFindNext2Response_Parameters()
    751                 endOfSearch = 1
    752                 searchCount = 1
    753                 totalData = 0
    754                 for i in enumerate(searchResult):
    755                     data = i[1].getData()
    756                     lenData = len(data)
    757                     if (totalData+lenData) >= maxDataCount or (i[0]+1) >= findNext2Parameters['SearchCount']:
    758                         # We gotta stop here and continue on a find_next2
    759                         endOfSearch = 0
    760                         connData['SIDs'][sid] = searchResult[i[0]:]
    761                         respParameters['LastNameOffset'] = totalData
    762                         break
    763                     else:
    764                         searchCount +=1
    765                         respData += data
    766                         totalData += lenData
    767 
    768                 # Have we reached the end of the search or still stuff to send?
    769                 if endOfSearch > 0:
    770                     # Let's remove the SID from our ConnData
    771                     del(connData['SIDs'][sid])
    772 
    773                 respParameters['EndOfSearch'] = endOfSearch
    774                 respParameters['SearchCount'] = searchCount
    775             else:
    776                 errorCode = STATUS_INVALID_HANDLE
    777         else:
    778             errorCode = STATUS_SMB_BAD_TID
    779 
    780         smbServer.setConnectionData(connId, connData)
    781 
    782         return respSetup, respParameters, respData, errorCode
    783 
    784     @staticmethod
    785     def findFirst2(connId, smbServer, recvPacket, parameters, data, maxDataCount):
    786         connData = smbServer.getConnectionData(connId)
    787 
    788         respSetup = ''
    789         respParameters = ''
    790         respData = ''
    791         findFirst2Parameters = smb.SMBFindFirst2_Parameters( recvPacket['Flags2'], data = parameters)
    792 
    793         if connData['ConnectedShares'].has_key(recvPacket['Tid']):
    794             path = connData['ConnectedShares'][recvPacket['Tid']]['path']
    795 
    796             searchResult, searchCount, errorCode = findFirst2(path,
    797                           decodeSMBString( recvPacket['Flags2'], findFirst2Parameters['FileName'] ),
    798                           findFirst2Parameters['InformationLevel'],
    799                           findFirst2Parameters['SearchAttributes'] )
    800 
    801             respParameters = smb.SMBFindFirst2Response_Parameters()
    802             endOfSearch = 1
    803             sid = 0x80 # default SID
    804             searchCount = 0
    805             totalData = 0
    806             for i in enumerate(searchResult):
    807                 #i[1].dump()
    808                 data = i[1].getData()
    809                 lenData = len(data)
    810                 if (totalData+lenData) >= maxDataCount or (i[0]+1) > findFirst2Parameters['SearchCount']:
    811                     # We gotta stop here and continue on a find_next2
    812                     endOfSearch = 0
    813                     # Simple way to generate a fid
    814                     if len(connData['SIDs']) == 0:
    815                        sid = 1
    816                     else:
    817                        sid = connData['SIDs'].keys()[-1] + 1
    818                     # Store the remaining search results in the ConnData SID
    819                     connData['SIDs'][sid] = searchResult[i[0]:]
    820                     respParameters['LastNameOffset'] = totalData
    821                     break
    822                 else:
    823                     searchCount +=1
    824                     respData += data
    825 
    826                     padLen = (8-(lenData % 8)) %8
    827                     respData += '\xaa'*padLen
    828                     totalData += lenData + padLen
    829 
    830             respParameters['SID'] = sid
    831             respParameters['EndOfSearch'] = endOfSearch
    832             respParameters['SearchCount'] = searchCount
    833         else:
    834             errorCode = STATUS_SMB_BAD_TID
    835 
    836         smbServer.setConnectionData(connId, connData)
    837 
    838         return respSetup, respParameters, respData, errorCode
    839 
    840 # Here we implement the commands handlers
    841 class SMBCommands:
    842 
    843     @staticmethod
    844     def smbTransaction(connId, smbServer, SMBCommand, recvPacket, transCommands):
    845         connData = smbServer.getConnectionData(connId)
    846 
    847         respSMBCommand = smb.SMBCommand(recvPacket['Command'])
    848 
    849         transParameters= smb.SMBTransaction_Parameters(SMBCommand['Parameters'])
    850 
    851         # Do the stuff
    852         if transParameters['ParameterCount'] != transParameters['TotalParameterCount']:
    853             # TODO: Handle partial parameters
    854             raise Exception("Unsupported partial parameters in TRANSACT2!")
    855         else:
    856             transData = smb.SMBTransaction_SData(flags = recvPacket['Flags2'])
    857             # Standard says servers shouldn't trust Parameters and Data comes
    858             # in order, so we have to parse the offsets, ugly
    859 
    860             paramCount = transParameters['ParameterCount']
    861             transData['Trans_ParametersLength'] = paramCount
    862             dataCount = transParameters['DataCount']
    863             transData['Trans_DataLength'] = dataCount
    864             transData.fromString(SMBCommand['Data'])
    865             if transParameters['ParameterOffset'] > 0:
    866                 paramOffset = transParameters['ParameterOffset'] - 63 - transParameters['SetupLength']
    867                 transData['Trans_Parameters'] = SMBCommand['Data'][paramOffset:paramOffset+paramCount]
    868             else:
    869                 transData['Trans_Parameters'] = ''
    870 
    871             if transParameters['DataOffset'] > 0:
    872                 dataOffset = transParameters['DataOffset'] - 63 - transParameters['SetupLength']
    873                 transData['Trans_Data'] = SMBCommand['Data'][dataOffset:dataOffset + dataCount]
    874             else:
    875                 transData['Trans_Data'] = ''
    876 
    877             # Call the handler for this TRANSACTION
    878             if transParameters['SetupCount'] == 0:
    879                 # No subcommand, let's play with the Name
    880                 command = decodeSMBString(recvPacket['Flags2'],transData['Name'])
    881             else:
    882                 command = struct.unpack('<H', transParameters['Setup'][:2])[0]
    883 
    884             if transCommands.has_key(command):
    885                # Call the TRANS subcommand
    886                setup = ''
    887                parameters = ''
    888                data = ''
    889                try:
    890                    setup, parameters, data, errorCode = transCommands[command](connId,
    891                                 smbServer,
    892                                 recvPacket,
    893                                 transData['Trans_Parameters'],
    894                                 transData['Trans_Data'],
    895                                 transParameters['MaxDataCount'])
    896                except Exception, e:
    897                    #print 'Transaction: %s' % e,e
    898                    smbServer.log('Transaction: (%r,%s)' % (command, e), logging.ERROR)
    899                    errorCode = STATUS_ACCESS_DENIED
    900                    #raise
    901 
    902                if setup == '' and parameters == '' and data == '':
    903                    # Something wen't wrong
    904                    respParameters = ''
    905                    respData = ''
    906                else:
    907                    # Build the answer
    908                    data = str(data)
    909                    remainingData = len(data)
    910                    parameters = str(parameters)
    911                    remainingParameters = len(parameters)
    912                    commands = []
    913                    dataDisplacement = 0
    914                    while remainingData > 0 or remainingParameters > 0:
    915                        respSMBCommand = smb.SMBCommand(recvPacket['Command'])
    916                        respParameters = smb.SMBTransactionResponse_Parameters()
    917                        respData       = smb.SMBTransaction2Response_Data()
    918 
    919                        respParameters['TotalParameterCount'] = len(parameters)
    920                        respParameters['ParameterCount']      = len(parameters)
    921                        respData['Trans_ParametersLength']    = len(parameters)
    922                        respParameters['TotalDataCount']      = len(data)
    923                        respParameters['DataDisplacement']    = dataDisplacement
    924 
    925                        # TODO: Do the same for parameters
    926                        if len(data) >  transParameters['MaxDataCount']:
    927                            # Answer doesn't fit in this packet
    928                            LOG.debug("Lowering answer from %d to %d" % (len(data),transParameters['MaxDataCount']) )
    929                            respParameters['DataCount'] = transParameters['MaxDataCount']
    930                        else:
    931                            respParameters['DataCount'] = len(data)
    932 
    933                        respData['Trans_DataLength']          = respParameters['DataCount']
    934                        respParameters['SetupCount']          = len(setup)
    935                        respParameters['Setup']               = setup
    936                        # TODO: Make sure we're calculating the pad right
    937                        if len(parameters) > 0:
    938                            #padLen = 4 - (55 + len(setup)) % 4
    939                            padLen = (4 - (55 + len(setup)) % 4 ) % 4
    940                            padBytes = '\xFF' * padLen
    941                            respData['Pad1'] = padBytes
    942                            respParameters['ParameterOffset'] = 55 + len(setup) + padLen
    943                        else:
    944                            padLen = 0
    945                            respParameters['ParameterOffset'] = 0
    946                            respData['Pad1']                  = ''
    947 
    948                        if len(data) > 0:
    949                            #pad2Len = 4 - (55 + len(setup) + padLen + len(parameters)) % 4
    950                            pad2Len = (4 - (55 + len(setup) + padLen + len(parameters)) % 4) % 4
    951                            respData['Pad2'] = '\xFF' * pad2Len
    952                            respParameters['DataOffset'] = 55 + len(setup) + padLen + len(parameters) + pad2Len
    953                        else:
    954                            respParameters['DataOffset'] = 0
    955                            respData['Pad2']             = ''
    956 
    957                        respData['Trans_Parameters'] = parameters[:respParameters['ParameterCount']]
    958                        respData['Trans_Data']       = data[:respParameters['DataCount']]
    959                        respSMBCommand['Parameters'] = respParameters
    960                        respSMBCommand['Data']       = respData
    961 
    962                        data = data[respParameters['DataCount']:]
    963                        remainingData -= respParameters['DataCount']
    964                        dataDisplacement += respParameters['DataCount'] + 1
    965 
    966                        parameters = parameters[respParameters['ParameterCount']:]
    967                        remainingParameters -= respParameters['ParameterCount']
    968                        commands.append(respSMBCommand)
    969 
    970                    smbServer.setConnectionData(connId, connData)
    971                    return commands, None, errorCode
    972 
    973             else:
    974                smbServer.log("Unsupported Transact command %r" % command, logging.ERROR)
    975                respParameters = ''
    976                respData = ''
    977                errorCode = STATUS_NOT_IMPLEMENTED
    978 
    979         respSMBCommand['Parameters']             = respParameters
    980         respSMBCommand['Data']                   = respData
    981         smbServer.setConnectionData(connId, connData)
    982 
    983         return [respSMBCommand], None, errorCode
    984 
    985 
    986     @staticmethod
    987     def smbNTTransact(connId, smbServer, SMBCommand, recvPacket, transCommands):
    988         connData = smbServer.getConnectionData(connId)
    989 
    990         respSMBCommand = smb.SMBCommand(recvPacket['Command'])
    991 
    992         NTTransParameters= smb.SMBNTTransaction_Parameters(SMBCommand['Parameters'])
    993         # Do the stuff
    994         if NTTransParameters['ParameterCount'] != NTTransParameters['TotalParameterCount']:
    995             # TODO: Handle partial parameters
    996             raise Exception("Unsupported partial parameters in NTTrans!")
    997         else:
    998             NTTransData = smb.SMBNTTransaction_Data()
    999             # Standard says servers shouldn't trust Parameters and Data comes
   1000             # in order, so we have to parse the offsets, ugly
   1001 
   1002             paramCount = NTTransParameters['ParameterCount']
   1003             NTTransData['NT_Trans_ParametersLength'] = paramCount
   1004             dataCount = NTTransParameters['DataCount']
   1005             NTTransData['NT_Trans_DataLength'] = dataCount
   1006 
   1007             if NTTransParameters['ParameterOffset'] > 0:
   1008                 paramOffset = NTTransParameters['ParameterOffset'] - 73 - NTTransParameters['SetupLength']
   1009                 NTTransData['NT_Trans_Parameters'] = SMBCommand['Data'][paramOffset:paramOffset+paramCount]
   1010             else:
   1011                 NTTransData['NT_Trans_Parameters'] = ''
   1012 
   1013             if NTTransParameters['DataOffset'] > 0:
   1014                 dataOffset = NTTransParameters['DataOffset'] - 73 - NTTransParameters['SetupLength']
   1015                 NTTransData['NT_Trans_Data'] = SMBCommand['Data'][dataOffset:dataOffset + dataCount]
   1016             else:
   1017                 NTTransData['NT_Trans_Data'] = ''
   1018 
   1019             # Call the handler for this TRANSACTION
   1020             command = NTTransParameters['Function']
   1021             if transCommands.has_key(command):
   1022                # Call the NT TRANS subcommand
   1023                setup = ''
   1024                parameters = ''
   1025                data = ''
   1026                try:
   1027                    setup, parameters, data, errorCode = transCommands[command](connId,
   1028                                 smbServer,
   1029                                 recvPacket,
   1030                                 NTTransData['NT_Trans_Parameters'],
   1031                                 NTTransData['NT_Trans_Data'],
   1032                                 NTTransParameters['MaxDataCount'])
   1033                except Exception, e:
   1034                    smbServer.log('NTTransaction: (0x%x,%s)' % (command, e), logging.ERROR)
   1035                    errorCode = STATUS_ACCESS_DENIED
   1036                    #raise
   1037 
   1038                if setup == '' and parameters == '' and data == '':
   1039                    # Something wen't wrong
   1040                    respParameters = ''
   1041                    respData = ''
   1042                    if errorCode == STATUS_SUCCESS:
   1043                        errorCode = STATUS_ACCESS_DENIED
   1044                else:
   1045                    # Build the answer
   1046                    data = str(data)
   1047                    remainingData = len(data)
   1048                    parameters = str(parameters)
   1049                    remainingParameters = len(parameters)
   1050                    commands = []
   1051                    dataDisplacement = 0
   1052                    while remainingData > 0 or remainingParameters > 0:
   1053                        respSMBCommand = smb.SMBCommand(recvPacket['Command'])
   1054                        respParameters = smb.SMBNTTransactionResponse_Parameters()
   1055                        respData       = smb.SMBNTTransactionResponse_Data()
   1056 
   1057                        respParameters['TotalParameterCount'] = len(parameters)
   1058                        respParameters['ParameterCount']      = len(parameters)
   1059                        respData['Trans_ParametersLength']    = len(parameters)
   1060                        respParameters['TotalDataCount']      = len(data)
   1061                        respParameters['DataDisplacement']    = dataDisplacement
   1062                        # TODO: Do the same for parameters
   1063                        if len(data) >  NTTransParameters['MaxDataCount']:
   1064                            # Answer doesn't fit in this packet
   1065                            LOG.debug("Lowering answer from %d to %d" % (len(data),NTTransParameters['MaxDataCount']) )
   1066                            respParameters['DataCount'] = NTTransParameters['MaxDataCount']
   1067                        else:
   1068                            respParameters['DataCount'] = len(data)
   1069 
   1070                        respData['NT_Trans_DataLength']          = respParameters['DataCount']
   1071                        respParameters['SetupCount']          = len(setup)
   1072                        respParameters['Setup']               = setup
   1073                        # TODO: Make sure we're calculating the pad right
   1074                        if len(parameters) > 0:
   1075                            #padLen = 4 - (71 + len(setup)) % 4
   1076                            padLen = (4 - (73 + len(setup)) % 4 ) % 4
   1077                            padBytes = '\xFF' * padLen
   1078                            respData['Pad1'] = padBytes
   1079                            respParameters['ParameterOffset'] = 73 + len(setup) + padLen
   1080                        else:
   1081                            padLen = 0
   1082                            respParameters['ParameterOffset'] = 0
   1083                            respData['Pad1']                  = ''
   1084 
   1085                        if len(data) > 0:
   1086                            #pad2Len = 4 - (71 + len(setup) + padLen + len(parameters)) % 4
   1087                            pad2Len = (4 - (73 + len(setup) + padLen + len(parameters)) % 4) % 4
   1088                            respData['Pad2'] = '\xFF' * pad2Len
   1089                            respParameters['DataOffset'] = 73 + len(setup) + padLen + len(parameters) + pad2Len
   1090                        else:
   1091                            respParameters['DataOffset'] = 0
   1092                            respData['Pad2']             = ''
   1093 
   1094                        respData['NT_Trans_Parameters'] = parameters[:respParameters['ParameterCount']]
   1095                        respData['NT_Trans_Data']       = data[:respParameters['DataCount']]
   1096                        respSMBCommand['Parameters'] = respParameters
   1097                        respSMBCommand['Data']       = respData
   1098 
   1099                        data = data[respParameters['DataCount']:]
   1100                        remainingData -= respParameters['DataCount']
   1101                        dataDisplacement += respParameters['DataCount'] + 1
   1102 
   1103                        parameters = parameters[respParameters['ParameterCount']:]
   1104                        remainingParameters -= respParameters['ParameterCount']
   1105                        commands.append(respSMBCommand)
   1106 
   1107                    smbServer.setConnectionData(connId, connData)
   1108                    return commands, None, errorCode
   1109 
   1110             else:
   1111                #smbServer.log("Unsupported NTTransact command 0x%x" % command, logging.ERROR)
   1112                respParameters = ''
   1113                respData = ''
   1114                errorCode = STATUS_NOT_IMPLEMENTED
   1115 
   1116         respSMBCommand['Parameters']             = respParameters
   1117         respSMBCommand['Data']                   = respData
   1118 
   1119         smbServer.setConnectionData(connId, connData)
   1120         return [respSMBCommand], None, errorCode
   1121 
   1122 
   1123     @staticmethod
   1124     def smbTransaction2(connId, smbServer, SMBCommand, recvPacket, transCommands):
   1125         connData = smbServer.getConnectionData(connId)
   1126 
   1127         respSMBCommand = smb.SMBCommand(recvPacket['Command'])
   1128 
   1129         trans2Parameters= smb.SMBTransaction2_Parameters(SMBCommand['Parameters'])
   1130 
   1131         # Do the stuff
   1132         if trans2Parameters['ParameterCount'] != trans2Parameters['TotalParameterCount']:
   1133             # TODO: Handle partial parameters
   1134             #print "Unsupported partial parameters in TRANSACT2!"
   1135             raise Exception("Unsupported partial parameters in TRANSACT2!")
   1136         else:
   1137             trans2Data = smb.SMBTransaction2_Data()
   1138             # Standard says servers shouldn't trust Parameters and Data comes
   1139             # in order, so we have to parse the offsets, ugly
   1140 
   1141             paramCount = trans2Parameters['ParameterCount']
   1142             trans2Data['Trans_ParametersLength'] = paramCount
   1143             dataCount = trans2Parameters['DataCount']
   1144             trans2Data['Trans_DataLength'] = dataCount
   1145 
   1146             if trans2Parameters['ParameterOffset'] > 0:
   1147                 paramOffset = trans2Parameters['ParameterOffset'] - 63 - trans2Parameters['SetupLength']
   1148                 trans2Data['Trans_Parameters'] = SMBCommand['Data'][paramOffset:paramOffset+paramCount]
   1149             else:
   1150                 trans2Data['Trans_Parameters'] = ''
   1151 
   1152             if trans2Parameters['DataOffset'] > 0:
   1153                 dataOffset = trans2Parameters['DataOffset'] - 63 - trans2Parameters['SetupLength']
   1154                 trans2Data['Trans_Data'] = SMBCommand['Data'][dataOffset:dataOffset + dataCount]
   1155             else:
   1156                 trans2Data['Trans_Data'] = ''
   1157 
   1158             # Call the handler for this TRANSACTION
   1159             command = struct.unpack('<H', trans2Parameters['Setup'])[0]
   1160             if transCommands.has_key(command):
   1161                # Call the TRANS2 subcommand
   1162                try:
   1163                    setup, parameters, data, errorCode = transCommands[command](connId,
   1164                                 smbServer,
   1165                                 recvPacket,
   1166                                 trans2Data['Trans_Parameters'],
   1167                                 trans2Data['Trans_Data'],
   1168                                 trans2Parameters['MaxDataCount'])
   1169                except Exception, e:
   1170                    smbServer.log('Transaction2: (0x%x,%s)' % (command, e), logging.ERROR)
   1171                    #import traceback
   1172                    #traceback.print_exc()
   1173                    raise
   1174 
   1175                if setup == '' and parameters == '' and data == '':
   1176                    # Something wen't wrong
   1177                    respParameters = ''
   1178                    respData = ''
   1179                else:
   1180                    # Build the answer
   1181                    data = str(data)
   1182                    remainingData = len(data)
   1183                    parameters = str(parameters)
   1184                    remainingParameters = len(parameters)
   1185                    commands = []
   1186                    dataDisplacement = 0
   1187                    while remainingData > 0 or remainingParameters > 0:
   1188                        respSMBCommand = smb.SMBCommand(recvPacket['Command'])
   1189                        respParameters = smb.SMBTransaction2Response_Parameters()
   1190                        respData       = smb.SMBTransaction2Response_Data()
   1191 
   1192                        respParameters['TotalParameterCount'] = len(parameters)
   1193                        respParameters['ParameterCount']      = len(parameters)
   1194                        respData['Trans_ParametersLength']    = len(parameters)
   1195                        respParameters['TotalDataCount']      = len(data)
   1196                        respParameters['DataDisplacement']    = dataDisplacement
   1197                        # TODO: Do the same for parameters
   1198                        if len(data) >  trans2Parameters['MaxDataCount']:
   1199                            # Answer doesn't fit in this packet
   1200                            LOG.debug("Lowering answer from %d to %d" % (len(data),trans2Parameters['MaxDataCount']) )
   1201                            respParameters['DataCount'] = trans2Parameters['MaxDataCount']
   1202                        else:
   1203                            respParameters['DataCount'] = len(data)
   1204 
   1205                        respData['Trans_DataLength']          = respParameters['DataCount']
   1206                        respParameters['SetupCount']          = len(setup)
   1207                        respParameters['Setup']               = setup
   1208                        # TODO: Make sure we're calculating the pad right
   1209                        if len(parameters) > 0:
   1210                            #padLen = 4 - (55 + len(setup)) % 4
   1211                            padLen = (4 - (55 + len(setup)) % 4 ) % 4
   1212                            padBytes = '\xFF' * padLen
   1213                            respData['Pad1'] = padBytes
   1214                            respParameters['ParameterOffset'] = 55 + len(setup) + padLen
   1215                        else:
   1216                            padLen = 0
   1217                            respParameters['ParameterOffset'] = 0
   1218                            respData['Pad1']                  = ''
   1219 
   1220                        if len(data) > 0:
   1221                            #pad2Len = 4 - (55 + len(setup) + padLen + len(parameters)) % 4
   1222                            pad2Len = (4 - (55 + len(setup) + padLen + len(parameters)) % 4) % 4
   1223                            respData['Pad2'] = '\xFF' * pad2Len
   1224                            respParameters['DataOffset'] = 55 + len(setup) + padLen + len(parameters) + pad2Len
   1225                        else:
   1226                            respParameters['DataOffset'] = 0
   1227                            respData['Pad2']             = ''
   1228 
   1229                        respData['Trans_Parameters'] = parameters[:respParameters['ParameterCount']]
   1230                        respData['Trans_Data']       = data[:respParameters['DataCount']]
   1231                        respSMBCommand['Parameters'] = respParameters
   1232                        respSMBCommand['Data']       = respData
   1233 
   1234                        data = data[respParameters['DataCount']:]
   1235                        remainingData -= respParameters['DataCount']
   1236                        dataDisplacement += respParameters['DataCount'] + 1
   1237 
   1238                        parameters = parameters[respParameters['ParameterCount']:]
   1239                        remainingParameters -= respParameters['ParameterCount']
   1240                        commands.append(respSMBCommand)
   1241 
   1242                    smbServer.setConnectionData(connId, connData)
   1243                    return commands, None, errorCode
   1244 
   1245             else:
   1246                smbServer.log("Unsupported Transact/2 command 0x%x" % command, logging.ERROR)
   1247                respParameters = ''
   1248                respData = ''
   1249                errorCode = STATUS_NOT_IMPLEMENTED
   1250 
   1251         respSMBCommand['Parameters']             = respParameters
   1252         respSMBCommand['Data']                   = respData
   1253 
   1254         smbServer.setConnectionData(connId, connData)
   1255         return [respSMBCommand], None, errorCode
   1256 
   1257     @staticmethod
   1258     def smbComLockingAndX(connId, smbServer, SMBCommand, recvPacket):
   1259         connData = smbServer.getConnectionData(connId)
   1260 
   1261         respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_LOCKING_ANDX)
   1262         respParameters        = ''
   1263         respData              = ''
   1264 
   1265         # I'm actually doing nothing.. just make MacOS happy ;)
   1266         errorCode = STATUS_SUCCESS
   1267 
   1268         respSMBCommand['Parameters']             = respParameters
   1269         respSMBCommand['Data']                   = respData
   1270         smbServer.setConnectionData(connId, connData)
   1271 
   1272         return [respSMBCommand], None, errorCode
   1273 
   1274 
   1275     @staticmethod
   1276     def smbComClose(connId, smbServer, SMBCommand, recvPacket):
   1277         connData = smbServer.getConnectionData(connId)
   1278 
   1279         respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_CLOSE)
   1280         respParameters        = ''
   1281         respData              = ''
   1282 
   1283         comClose =  smb.SMBClose_Parameters(SMBCommand['Parameters'])
   1284 
   1285         if connData['OpenedFiles'].has_key(comClose['FID']):
   1286              errorCode = STATUS_SUCCESS
   1287              fileHandle = connData['OpenedFiles'][comClose['FID']]['FileHandle']
   1288              try:
   1289                  if fileHandle == PIPE_FILE_DESCRIPTOR:
   1290                      connData['OpenedFiles'][comClose['FID']]['Socket'].close()
   1291                  elif fileHandle != VOID_FILE_DESCRIPTOR:
   1292                      os.close(fileHandle)
   1293              except Exception, e:
   1294                  smbServer.log("comClose %s" % e, logging.ERROR)
   1295                  errorCode = STATUS_ACCESS_DENIED
   1296              else:
   1297                  # Check if the file was marked for removal
   1298                  if connData['OpenedFiles'][comClose['FID']]['DeleteOnClose'] is True:
   1299                      try:
   1300                          os.remove(connData['OpenedFiles'][comClose['FID']]['FileName'])
   1301                      except Exception, e:
   1302                          smbServer.log("comClose %s" % e, logging.ERROR)
   1303                          errorCode = STATUS_ACCESS_DENIED
   1304                  del(connData['OpenedFiles'][comClose['FID']])
   1305         else:
   1306             errorCode = STATUS_INVALID_HANDLE
   1307 
   1308         if errorCode > 0:
   1309             respParameters = ''
   1310             respData       = ''
   1311 
   1312         respSMBCommand['Parameters']             = respParameters
   1313         respSMBCommand['Data']                   = respData
   1314         smbServer.setConnectionData(connId, connData)
   1315 
   1316         return [respSMBCommand], None, errorCode
   1317 
   1318     @staticmethod
   1319     def smbComWrite(connId, smbServer, SMBCommand, recvPacket):
   1320         connData = smbServer.getConnectionData(connId)
   1321 
   1322         respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_WRITE)
   1323         respParameters        = smb.SMBWriteResponse_Parameters()
   1324         respData              = ''
   1325 
   1326         comWriteParameters =  smb.SMBWrite_Parameters(SMBCommand['Parameters'])
   1327         comWriteData = smb.SMBWrite_Data(SMBCommand['Data'])
   1328 
   1329         if connData['OpenedFiles'].has_key(comWriteParameters['Fid']):
   1330              fileHandle = connData['OpenedFiles'][comWriteParameters['Fid']]['FileHandle']
   1331              errorCode = STATUS_SUCCESS
   1332              try:
   1333                  if fileHandle != PIPE_FILE_DESCRIPTOR:
   1334                      # TODO: Handle big size files
   1335                      # If we're trying to write past the file end we just skip the write call (Vista does this)
   1336                      if os.lseek(fileHandle, 0, 2) >= comWriteParameters['Offset']:
   1337                          os.lseek(fileHandle,comWriteParameters['Offset'],0)
   1338                          os.write(fileHandle,comWriteData['Data'])
   1339                  else:
   1340                      sock = connData['OpenedFiles'][comWriteParameters['Fid']]['Socket']
   1341                      sock.send(comWriteData['Data'])
   1342                  respParameters['Count']    = comWriteParameters['Count']
   1343              except Exception, e:
   1344                  smbServer.log('smbComWrite: %s' % e, logging.ERROR)
   1345                  errorCode = STATUS_ACCESS_DENIED
   1346         else:
   1347             errorCode = STATUS_INVALID_HANDLE
   1348 
   1349 
   1350         if errorCode > 0:
   1351             respParameters = ''
   1352             respData       = ''
   1353 
   1354         respSMBCommand['Parameters']             = respParameters
   1355         respSMBCommand['Data']                   = respData
   1356         smbServer.setConnectionData(connId, connData)
   1357 
   1358         return [respSMBCommand], None, errorCode
   1359 
   1360     @staticmethod
   1361     def smbComFlush(connId, smbServer, SMBCommand,recvPacket ):
   1362         connData = smbServer.getConnectionData(connId)
   1363 
   1364         respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_FLUSH)
   1365         respParameters        = ''
   1366         respData              = ''
   1367 
   1368         comFlush =  smb.SMBFlush_Parameters(SMBCommand['Parameters'])
   1369 
   1370         if connData['OpenedFiles'].has_key(comFlush['FID']):
   1371              errorCode = STATUS_SUCCESS
   1372              fileHandle = connData['OpenedFiles'][comFlush['FID']]['FileHandle']
   1373              try:
   1374                  os.fsync(fileHandle)
   1375              except Exception, e:
   1376                  smbServer.log("comFlush %s" % e, logging.ERROR)
   1377                  errorCode = STATUS_ACCESS_DENIED
   1378         else:
   1379             errorCode = STATUS_INVALID_HANDLE
   1380 
   1381         if errorCode > 0:
   1382             respParameters = ''
   1383             respData       = ''
   1384 
   1385         respSMBCommand['Parameters']             = respParameters
   1386         respSMBCommand['Data']                   = respData
   1387         smbServer.setConnectionData(connId, connData)
   1388 
   1389         return [respSMBCommand], None, errorCode
   1390 
   1391 
   1392     @staticmethod
   1393     def smbComCreateDirectory(connId, smbServer, SMBCommand,recvPacket ):
   1394         connData = smbServer.getConnectionData(connId)
   1395 
   1396         respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_CREATE_DIRECTORY)
   1397         respParameters        = ''
   1398         respData              = ''
   1399 
   1400         comCreateDirectoryData=  smb.SMBCreateDirectory_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
   1401 
   1402         # Get the Tid associated
   1403         if connData['ConnectedShares'].has_key(recvPacket['Tid']):
   1404              errorCode = STATUS_SUCCESS
   1405              path = connData['ConnectedShares'][recvPacket['Tid']]['path']
   1406              fileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comCreateDirectoryData['DirectoryName']).replace('\\','/'))
   1407              if len(fileName) > 0:
   1408                 if fileName[0] == '/' or fileName[0] == '\\':
   1409                     # strip leading '/'
   1410                     fileName = fileName[1:]
   1411              pathName = os.path.join(path,fileName)
   1412              if os.path.exists(pathName):
   1413                 errorCode = STATUS_OBJECT_NAME_COLLISION
   1414 
   1415              # TODO: More checks here in the future.. Specially when we support
   1416              # user access
   1417              else:
   1418                  try:
   1419                      os.mkdir(pathName)
   1420                  except Exception, e:
   1421                      smbServer.log("smbComCreateDirectory: %s" % e, logging.ERROR)
   1422                      errorCode = STATUS_ACCESS_DENIED
   1423         else:
   1424             errorCode = STATUS_SMB_BAD_TID
   1425 
   1426 
   1427         if errorCode > 0:
   1428             respParameters = ''
   1429             respData       = ''
   1430 
   1431         respSMBCommand['Parameters']             = respParameters
   1432         respSMBCommand['Data']                   = respData
   1433         smbServer.setConnectionData(connId, connData)
   1434 
   1435         return [respSMBCommand], None, errorCode
   1436 
   1437     @staticmethod
   1438     def smbComRename(connId, smbServer, SMBCommand, recvPacket ):
   1439         connData = smbServer.getConnectionData(connId)
   1440 
   1441         respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_RENAME)
   1442         respParameters        = ''
   1443         respData              = ''
   1444 
   1445         comRenameData      =  smb.SMBRename_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
   1446         # Get the Tid associated
   1447         if connData['ConnectedShares'].has_key(recvPacket['Tid']):
   1448              errorCode = STATUS_SUCCESS
   1449              path = connData['ConnectedShares'][recvPacket['Tid']]['path']
   1450              oldFileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comRenameData['OldFileName']).replace('\\','/'))
   1451              newFileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comRenameData['NewFileName']).replace('\\','/'))
   1452              if len(oldFileName) > 0 and (oldFileName[0] == '/' or oldFileName[0] == '\\'):
   1453                 # strip leading '/'
   1454                 oldFileName = oldFileName[1:]
   1455              oldPathName = os.path.join(path,oldFileName)
   1456              if len(newFileName) > 0 and (newFileName[0] == '/' or newFileName[0] == '\\'):
   1457                 # strip leading '/'
   1458                 newFileName = newFileName[1:]
   1459              newPathName = os.path.join(path,newFileName)
   1460 
   1461              if os.path.exists(oldPathName) is not True:
   1462                 errorCode = STATUS_NO_SUCH_FILE
   1463 
   1464              # TODO: More checks here in the future.. Specially when we support
   1465              # user access
   1466              else:
   1467                  try:
   1468                      os.rename(oldPathName,newPathName)
   1469                  except OSError, e:
   1470                      smbServer.log("smbComRename: %s" % e, logging.ERROR)
   1471                      errorCode = STATUS_ACCESS_DENIED
   1472         else:
   1473             errorCode = STATUS_SMB_BAD_TID
   1474 
   1475 
   1476         if errorCode > 0:
   1477             respParameters = ''
   1478             respData       = ''
   1479 
   1480         respSMBCommand['Parameters']             = respParameters
   1481         respSMBCommand['Data']                   = respData
   1482         smbServer.setConnectionData(connId, connData)
   1483 
   1484         return [respSMBCommand], None, errorCode
   1485 
   1486     @staticmethod
   1487     def smbComDelete(connId, smbServer, SMBCommand, recvPacket ):
   1488         connData = smbServer.getConnectionData(connId)
   1489 
   1490         respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_DELETE)
   1491         respParameters        = ''
   1492         respData              = ''
   1493 
   1494         comDeleteData         =  smb.SMBDelete_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
   1495 
   1496         # Get the Tid associated
   1497         if connData['ConnectedShares'].has_key(recvPacket['Tid']):
   1498              errorCode = STATUS_SUCCESS
   1499              path = connData['ConnectedShares'][recvPacket['Tid']]['path']
   1500              fileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comDeleteData['FileName']).replace('\\','/'))
   1501              if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
   1502                 # strip leading '/'
   1503                 fileName = fileName[1:]
   1504              pathName = os.path.join(path,fileName)
   1505              if os.path.exists(pathName) is not True:
   1506                 errorCode = STATUS_NO_SUCH_FILE
   1507 
   1508              # TODO: More checks here in the future.. Specially when we support
   1509              # user access
   1510              else:
   1511                  try:
   1512                      os.remove(pathName)
   1513                  except OSError, e:
   1514                      smbServer.log("smbComDelete: %s" % e, logging.ERROR)
   1515                      errorCode = STATUS_ACCESS_DENIED
   1516         else:
   1517             errorCode = STATUS_SMB_BAD_TID
   1518 
   1519         if errorCode > 0:
   1520             respParameters = ''
   1521             respData       = ''
   1522 
   1523         respSMBCommand['Parameters']             = respParameters
   1524         respSMBCommand['Data']                   = respData
   1525         smbServer.setConnectionData(connId, connData)
   1526 
   1527         return [respSMBCommand], None, errorCode
   1528 
   1529 
   1530     @staticmethod
   1531     def smbComDeleteDirectory(connId, smbServer, SMBCommand, recvPacket ):
   1532         connData = smbServer.getConnectionData(connId)
   1533 
   1534         respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_DELETE_DIRECTORY)
   1535         respParameters        = ''
   1536         respData              = ''
   1537 
   1538         comDeleteDirectoryData=  smb.SMBDeleteDirectory_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
   1539 
   1540         # Get the Tid associated
   1541         if connData['ConnectedShares'].has_key(recvPacket['Tid']):
   1542              errorCode = STATUS_SUCCESS
   1543              path = connData['ConnectedShares'][recvPacket['Tid']]['path']
   1544              fileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comDeleteDirectoryData['DirectoryName']).replace('\\','/'))
   1545              if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
   1546                 # strip leading '/'
   1547                 fileName = fileName[1:]
   1548              pathName = os.path.join(path,fileName)
   1549              if os.path.exists(pathName) is not True:
   1550                 errorCode = STATUS_NO_SUCH_FILE
   1551 
   1552              # TODO: More checks here in the future.. Specially when we support
   1553              # user access
   1554              else:
   1555                  try:
   1556                      os.rmdir(pathName)
   1557                  except OSError, e:
   1558                      smbServer.log("smbComDeleteDirectory: %s" % e,logging.ERROR)
   1559                      if e.errno == errno.ENOTEMPTY:
   1560                          errorCode = STATUS_DIRECTORY_NOT_EMPTY
   1561                      else:
   1562                          errorCode = STATUS_ACCESS_DENIED
   1563         else:
   1564             errorCode = STATUS_SMB_BAD_TID
   1565 
   1566         if errorCode > 0:
   1567             respParameters = ''
   1568             respData       = ''
   1569 
   1570         respSMBCommand['Parameters']             = respParameters
   1571         respSMBCommand['Data']                   = respData
   1572         smbServer.setConnectionData(connId, connData)
   1573 
   1574         return [respSMBCommand], None, errorCode
   1575 
   1576 
   1577     @staticmethod
   1578     def smbComWriteAndX(connId, smbServer, SMBCommand, recvPacket):
   1579         connData = smbServer.getConnectionData(connId)
   1580 
   1581         respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_WRITE_ANDX)
   1582         respParameters        = smb.SMBWriteAndXResponse_Parameters()
   1583         respData              = ''
   1584 
   1585         if SMBCommand['WordCount'] == 0x0C:
   1586             writeAndX =  smb.SMBWriteAndX_Parameters_Short(SMBCommand['Parameters'])
   1587             writeAndXData = smb.SMBWriteAndX_Data_Short()
   1588         else:
   1589             writeAndX =  smb.SMBWriteAndX_Parameters(SMBCommand['Parameters'])
   1590             writeAndXData = smb.SMBWriteAndX_Data()
   1591         writeAndXData['DataLength'] = writeAndX['DataLength']
   1592         writeAndXData['DataOffset'] = writeAndX['DataOffset']
   1593         writeAndXData.fromString(SMBCommand['Data'])
   1594 
   1595 
   1596         if connData['OpenedFiles'].has_key(writeAndX['Fid']):
   1597              fileHandle = connData['OpenedFiles'][writeAndX['Fid']]['FileHandle']
   1598              errorCode = STATUS_SUCCESS
   1599              try:
   1600                  if fileHandle != PIPE_FILE_DESCRIPTOR:
   1601                      offset = writeAndX['Offset']
   1602                      if writeAndX.fields.has_key('HighOffset'):
   1603                          offset += (writeAndX['HighOffset'] << 32)
   1604                      # If we're trying to write past the file end we just skip the write call (Vista does this)
   1605                      if os.lseek(fileHandle, 0, 2) >= offset:
   1606                          os.lseek(fileHandle,offset,0)
   1607                          os.write(fileHandle,writeAndXData['Data'])
   1608                  else:
   1609                      sock = connData['OpenedFiles'][writeAndX['Fid']]['Socket']
   1610                      sock.send(writeAndXData['Data'])
   1611 
   1612                  respParameters['Count']    = writeAndX['DataLength']
   1613                  respParameters['Available']= 0xff
   1614              except Exception, e:
   1615                  smbServer.log('smbComWriteAndx: %s' % e, logging.ERROR)
   1616                  errorCode = STATUS_ACCESS_DENIED
   1617         else:
   1618             errorCode = STATUS_INVALID_HANDLE
   1619 
   1620         if errorCode > 0:
   1621             respParameters = ''
   1622             respData       = ''
   1623 
   1624         respSMBCommand['Parameters']             = respParameters
   1625         respSMBCommand['Data']                   = respData
   1626         smbServer.setConnectionData(connId, connData)
   1627 
   1628         return [respSMBCommand], None, errorCode
   1629 
   1630     @staticmethod
   1631     def smbComRead(connId, smbServer, SMBCommand, recvPacket):
   1632         connData = smbServer.getConnectionData(connId)
   1633 
   1634         respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_READ)
   1635         respParameters        = smb.SMBReadResponse_Parameters()
   1636         respData              = smb.SMBReadResponse_Data()
   1637 
   1638         comReadParameters =  smb.SMBRead_Parameters(SMBCommand['Parameters'])
   1639 
   1640         if connData['OpenedFiles'].has_key(comReadParameters['Fid']):
   1641              fileHandle = connData['OpenedFiles'][comReadParameters['Fid']]['FileHandle']
   1642              errorCode = STATUS_SUCCESS
   1643              try:
   1644                  if fileHandle != PIPE_FILE_DESCRIPTOR:
   1645                      # TODO: Handle big size files
   1646                      os.lseek(fileHandle,comReadParameters['Offset'],0)
   1647                      content = os.read(fileHandle,comReadParameters['Count'])
   1648                  else:
   1649                      sock = connData['OpenedFiles'][comReadParameters['Fid']]['Socket']
   1650                      content = sock.recv(comReadParameters['Count'])
   1651                  respParameters['Count']    = len(content)
   1652                  respData['DataLength']     = len(content)
   1653                  respData['Data']           = content
   1654              except Exception, e:
   1655                  smbServer.log('smbComRead: %s ' % e, logging.ERROR)
   1656                  errorCode = STATUS_ACCESS_DENIED
   1657         else:
   1658             errorCode = STATUS_INVALID_HANDLE
   1659 
   1660         if errorCode > 0:
   1661             respParameters = ''
   1662             respData       = ''
   1663 
   1664         respSMBCommand['Parameters']             = respParameters
   1665         respSMBCommand['Data']                   = respData
   1666         smbServer.setConnectionData(connId, connData)
   1667 
   1668         return [respSMBCommand], None, errorCode
   1669 
   1670     @staticmethod
   1671     def smbComReadAndX(connId, smbServer, SMBCommand, recvPacket):
   1672         connData = smbServer.getConnectionData(connId)
   1673 
   1674         respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_READ_ANDX)
   1675         respParameters        = smb.SMBReadAndXResponse_Parameters()
   1676         respData              = ''
   1677 
   1678         if SMBCommand['WordCount'] == 0x0A:
   1679             readAndX =  smb.SMBReadAndX_Parameters2(SMBCommand['Parameters'])
   1680         else:
   1681             readAndX =  smb.SMBReadAndX_Parameters(SMBCommand['Parameters'])
   1682 
   1683         if connData['OpenedFiles'].has_key(readAndX['Fid']):
   1684              fileHandle = connData['OpenedFiles'][readAndX['Fid']]['FileHandle']
   1685              errorCode = 0
   1686              try:
   1687                  if fileHandle != PIPE_FILE_DESCRIPTOR:
   1688                      offset = readAndX['Offset']
   1689                      if readAndX.fields.has_key('HighOffset'):
   1690                          offset += (readAndX['HighOffset'] << 32)
   1691                      os.lseek(fileHandle,offset,0)
   1692                      content = os.read(fileHandle,readAndX['MaxCount'])
   1693                  else:
   1694                      sock = connData['OpenedFiles'][readAndX['Fid']]['Socket']
   1695                      content = sock.recv(readAndX['MaxCount'])
   1696                  respParameters['Remaining']    = 0xffff
   1697                  respParameters['DataCount']    = len(content)
   1698                  respParameters['DataOffset']   = 59
   1699                  respParameters['DataCount_Hi'] = 0
   1700                  respData = content
   1701              except Exception, e:
   1702                  smbServer.log('smbComReadAndX: %s ' % e, logging.ERROR)
   1703                  errorCode = STATUS_ACCESS_DENIED
   1704         else:
   1705             errorCode = STATUS_INVALID_HANDLE
   1706 
   1707         if errorCode > 0:
   1708             respParameters = ''
   1709             respData       = ''
   1710 
   1711         respSMBCommand['Parameters']             = respParameters
   1712         respSMBCommand['Data']                   = respData
   1713         smbServer.setConnectionData(connId, connData)
   1714 
   1715         return [respSMBCommand], None, errorCode
   1716 
   1717     @staticmethod
   1718     def smbQueryInformation(connId, smbServer, SMBCommand, recvPacket):
   1719         connData = smbServer.getConnectionData(connId)
   1720 
   1721         respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_QUERY_INFORMATION)
   1722         respParameters = smb.SMBQueryInformationResponse_Parameters()
   1723         respData       = ''
   1724 
   1725         queryInformation= smb.SMBQueryInformation_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
   1726 
   1727         # Get the Tid associated
   1728         if connData['ConnectedShares'].has_key(recvPacket['Tid']):
   1729             fileSize, lastWriteTime, fileAttributes = queryFsInformation(
   1730                 connData['ConnectedShares'][recvPacket['Tid']]['path'],
   1731                 decodeSMBString(recvPacket['Flags2'],queryInformation['FileName']))
   1732 
   1733             respParameters['FileSize']       = fileSize
   1734             respParameters['LastWriteTime']  = lastWriteTime
   1735             respParameters['FileAttributes'] = fileAttributes
   1736             errorCode = STATUS_SUCCESS
   1737         else:
   1738             # STATUS_SMB_BAD_TID
   1739             errorCode = STATUS_SMB_BAD_TID
   1740             respParameters  = ''
   1741             respData        = ''
   1742 
   1743         respSMBCommand['Parameters']             = respParameters
   1744         respSMBCommand['Data']                   = respData
   1745 
   1746         smbServer.setConnectionData(connId, connData)
   1747         return [respSMBCommand], None, errorCode
   1748 
   1749     @staticmethod
   1750     def smbQueryInformationDisk(connId, smbServer, SMBCommand, recvPacket):
   1751         connData = smbServer.getConnectionData(connId)
   1752 
   1753         respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_QUERY_INFORMATION_DISK)
   1754         respParameters = smb.SMBQueryInformationDiskResponse_Parameters()
   1755         respData       = ''
   1756 
   1757         # Get the Tid associated
   1758         if connData['ConnectedShares'].has_key(recvPacket['Tid']):
   1759             totalUnits, freeUnits = queryDiskInformation(
   1760                         connData['ConnectedShares'][recvPacket['Tid']]['path'])
   1761 
   1762             respParameters['TotalUnits']    = totalUnits
   1763             respParameters['BlocksPerUnit'] = 1
   1764             respParameters['BlockSize']     = 1
   1765             respParameters['FreeUnits']     = freeUnits
   1766             errorCode = STATUS_SUCCESS
   1767         else:
   1768             # STATUS_SMB_BAD_TID
   1769             respData  = ''
   1770             respParameters = ''
   1771             errorCode = STATUS_SMB_BAD_TID
   1772 
   1773 
   1774         respSMBCommand['Parameters']             = respParameters
   1775         respSMBCommand['Data']                   = respData
   1776 
   1777         smbServer.setConnectionData(connId, connData)
   1778         return [respSMBCommand], None, errorCode
   1779 
   1780     @staticmethod
   1781     def smbComEcho(connId, smbServer, SMBCommand, recvPacket):
   1782         connData = smbServer.getConnectionData(connId)
   1783 
   1784         respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_ECHO)
   1785         respParameters = smb.SMBEchoResponse_Parameters()
   1786         respData       = smb.SMBEchoResponse_Data()
   1787 
   1788         echoData       = smb.SMBEcho_Data(SMBCommand['Data'])
   1789 
   1790         respParameters['SequenceNumber'] = 1
   1791         respData['Data']                 = echoData['Data']
   1792 
   1793         respSMBCommand['Parameters']     = respParameters
   1794         respSMBCommand['Data']           = respData
   1795 
   1796         errorCode = STATUS_SUCCESS
   1797         smbServer.setConnectionData(connId, connData)
   1798         return [respSMBCommand], None, errorCode
   1799 
   1800     @staticmethod
   1801     def smbComTreeDisconnect(connId, smbServer, SMBCommand, recvPacket):
   1802         connData = smbServer.getConnectionData(connId)
   1803 
   1804         respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_TREE_DISCONNECT)
   1805 
   1806         # Check if the Tid matches the Tid trying to disconnect
   1807         respParameters = ''
   1808         respData = ''
   1809 
   1810         if connData['ConnectedShares'].has_key(recvPacket['Tid']):
   1811             smbServer.log("Disconnecting Share(%d:%s)" % (recvPacket['Tid'],connData['ConnectedShares'][recvPacket['Tid']]['shareName']))
   1812             del(connData['ConnectedShares'][recvPacket['Tid']])
   1813             errorCode = STATUS_SUCCESS
   1814         else:
   1815             # STATUS_SMB_BAD_TID
   1816             errorCode = STATUS_SMB_BAD_TID
   1817 
   1818         respSMBCommand['Parameters'] = respParameters
   1819         respSMBCommand['Data']       = respData
   1820 
   1821         smbServer.setConnectionData(connId, connData)
   1822         return [respSMBCommand], None, errorCode
   1823 
   1824     @staticmethod
   1825     def smbComLogOffAndX(connId, smbServer, SMBCommand, recvPacket):
   1826         connData = smbServer.getConnectionData(connId)
   1827 
   1828         respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_LOGOFF_ANDX)
   1829 
   1830         # Check if the Uid matches the user trying to logoff
   1831         respParameters = ''
   1832         respData = ''
   1833         if recvPacket['Uid'] != connData['Uid']:
   1834             # STATUS_SMB_BAD_UID
   1835             errorCode = STATUS_SMB_BAD_UID
   1836         else:
   1837             errorCode = STATUS_SUCCESS
   1838 
   1839         respSMBCommand['Parameters']   = respParameters
   1840         respSMBCommand['Data']         = respData
   1841         connData['Uid'] = 0
   1842 
   1843         smbServer.setConnectionData(connId, connData)
   1844 
   1845         return [respSMBCommand], None, errorCode
   1846 
   1847     @staticmethod
   1848     def smbComQueryInformation2(connId, smbServer, SMBCommand, recvPacket):
   1849         connData = smbServer.getConnectionData(connId)
   1850 
   1851         respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_QUERY_INFORMATION2)
   1852         respParameters        = smb.SMBQueryInformation2Response_Parameters()
   1853         respData              = ''
   1854 
   1855         queryInformation2 = smb.SMBQueryInformation2_Parameters(SMBCommand['Parameters'])
   1856         errorCode = 0xFF
   1857         if connData['OpenedFiles'].has_key(queryInformation2['Fid']):
   1858              errorCode = STATUS_SUCCESS
   1859              pathName = connData['OpenedFiles'][queryInformation2['Fid']]['FileName']
   1860              try:
   1861                  (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(pathName)
   1862                  respParameters['CreateDate']         = getSMBDate(ctime)
   1863                  respParameters['CreationTime']       = getSMBTime(ctime)
   1864                  respParameters['LastAccessDate']     = getSMBDate(atime)
   1865                  respParameters['LastAccessTime']     = getSMBTime(atime)
   1866                  respParameters['LastWriteDate']      = getSMBDate(mtime)
   1867                  respParameters['LastWriteTime']      = getSMBTime(mtime)
   1868                  respParameters['FileDataSize']       = size
   1869                  respParameters['FileAllocationSize'] = size
   1870                  attribs = 0
   1871                  if os.path.isdir(pathName):
   1872                      attribs = smb.SMB_FILE_ATTRIBUTE_DIRECTORY
   1873                  if os.path.isfile(pathName):
   1874                      attribs = smb.SMB_FILE_ATTRIBUTE_NORMAL
   1875                  respParameters['FileAttributes'] = attribs
   1876              except Exception, e:
   1877                  smbServer.log('smbComQueryInformation2 %s' % e,logging.ERROR)
   1878                  errorCode = STATUS_ACCESS_DENIED
   1879 
   1880         if errorCode > 0:
   1881             respParameters = ''
   1882             respData       = ''
   1883 
   1884         respSMBCommand['Parameters']             = respParameters
   1885         respSMBCommand['Data']                   = respData
   1886         smbServer.setConnectionData(connId, connData)
   1887 
   1888         return [respSMBCommand], None, errorCode
   1889 
   1890     @staticmethod
   1891     def smbComNtCreateAndX(connId, smbServer, SMBCommand, recvPacket):
   1892         # TODO: Fully implement this
   1893         connData = smbServer.getConnectionData(connId)
   1894 
   1895         respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_NT_CREATE_ANDX)
   1896         respParameters        = smb.SMBNtCreateAndXResponse_Parameters()
   1897         respData              = ''
   1898 
   1899         ntCreateAndXParameters = smb.SMBNtCreateAndX_Parameters(SMBCommand['Parameters'])
   1900         ntCreateAndXData       = smb.SMBNtCreateAndX_Data( flags = recvPacket['Flags2'], data = SMBCommand['Data'])
   1901 
   1902         #if ntCreateAndXParameters['CreateFlags'] & 0x10:  # NT_CREATE_REQUEST_EXTENDED_RESPONSE
   1903         #    respParameters        = smb.SMBNtCreateAndXExtendedResponse_Parameters()
   1904         #    respParameters['VolumeGUID'] = '\x00'
   1905 
   1906         # Get the Tid associated
   1907         if connData['ConnectedShares'].has_key(recvPacket['Tid']):
   1908              # If we have a rootFid, the path is relative to that fid
   1909              errorCode = STATUS_SUCCESS
   1910              if ntCreateAndXParameters['RootFid'] > 0:
   1911                  path = connData['OpenedFiles'][ntCreateAndXParameters['RootFid']]['FileName']
   1912                  LOG.debug("RootFid present %s!" % path)
   1913              else:
   1914                  if connData['ConnectedShares'][recvPacket['Tid']].has_key('path'):
   1915                      path = connData['ConnectedShares'][recvPacket['Tid']]['path']
   1916                  else:
   1917                      path = 'NONE'
   1918                      errorCode = STATUS_ACCESS_DENIED
   1919 
   1920              deleteOnClose = False
   1921 
   1922              fileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],ntCreateAndXData['FileName']).replace('\\','/'))
   1923              if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
   1924                 # strip leading '/'
   1925                 fileName = fileName[1:]
   1926              pathName = os.path.join(path,fileName)
   1927              createDisposition = ntCreateAndXParameters['Disposition']
   1928              mode = 0
   1929 
   1930              if createDisposition == smb.FILE_SUPERSEDE:
   1931                  mode |= os.O_TRUNC | os.O_CREAT
   1932              elif createDisposition & smb.FILE_OVERWRITE_IF == smb.FILE_OVERWRITE_IF:
   1933                  mode |= os.O_TRUNC | os.O_CREAT
   1934              elif createDisposition & smb.FILE_OVERWRITE == smb.FILE_OVERWRITE:
   1935                  if os.path.exists(pathName) is True:
   1936                      mode |= os.O_TRUNC
   1937                  else:
   1938                      errorCode = STATUS_NO_SUCH_FILE
   1939              elif createDisposition & smb.FILE_OPEN_IF == smb.FILE_OPEN_IF:
   1940                  if os.path.exists(pathName) is True:
   1941                      mode |= os.O_TRUNC
   1942                  else:
   1943                      mode |= os.O_TRUNC | os.O_CREAT
   1944              elif createDisposition & smb.FILE_CREATE == smb.FILE_CREATE:
   1945                  if os.path.exists(pathName) is True:
   1946                      errorCode = STATUS_OBJECT_NAME_COLLISION
   1947                  else:
   1948                      mode |= os.O_CREAT
   1949              elif createDisposition & smb.FILE_OPEN == smb.FILE_OPEN:
   1950                  if os.path.exists(pathName) is not True and smbServer.getRegisteredNamedPipes().has_key(unicode(pathName)) is not True:
   1951                      errorCode = STATUS_NO_SUCH_FILE
   1952 
   1953              if errorCode == STATUS_SUCCESS:
   1954                  desiredAccess = ntCreateAndXParameters['AccessMask']
   1955                  if (desiredAccess & smb.FILE_READ_DATA) or (desiredAccess & smb.GENERIC_READ):
   1956                      mode |= os.O_RDONLY
   1957                  if (desiredAccess & smb.FILE_WRITE_DATA) or (desiredAccess & smb.GENERIC_WRITE):
   1958                      if (desiredAccess & smb.FILE_READ_DATA) or (desiredAccess & smb.GENERIC_READ):
   1959                          mode |= os.O_RDWR #| os.O_APPEND
   1960                      else:
   1961                          mode |= os.O_WRONLY #| os.O_APPEND
   1962                  if desiredAccess & smb.GENERIC_ALL:
   1963                      mode |= os.O_RDWR #| os.O_APPEND
   1964 
   1965                  createOptions =  ntCreateAndXParameters['CreateOptions']
   1966                  if mode & os.O_CREAT == os.O_CREAT:
   1967                      if createOptions & smb.FILE_DIRECTORY_FILE == smb.FILE_DIRECTORY_FILE:
   1968                          try:
   1969                              # Let's create the directory
   1970                              os.mkdir(pathName)
   1971                              mode = os.O_RDONLY
   1972                          except Exception, e:
   1973                              smbServer.log("NTCreateAndX: %s,%s,%s" % (pathName,mode,e),logging.ERROR)
   1974                              errorCode = STATUS_ACCESS_DENIED
   1975                  if createOptions & smb.FILE_NON_DIRECTORY_FILE == smb.FILE_NON_DIRECTORY_FILE:
   1976                      # If the file being opened is a directory, the server MUST fail the request with
   1977                      # STATUS_FILE_IS_A_DIRECTORY in the Status field of the SMB Header in the server
   1978                      # response.
   1979                      if os.path.isdir(pathName) is True:
   1980                         errorCode = STATUS_FILE_IS_A_DIRECTORY
   1981 
   1982                  if createOptions & smb.FILE_DELETE_ON_CLOSE == smb.FILE_DELETE_ON_CLOSE:
   1983                      deleteOnClose = True
   1984 
   1985                  if errorCode == STATUS_SUCCESS:
   1986                      try:
   1987                          if os.path.isdir(pathName) and sys.platform == 'win32':
   1988                             fid = VOID_FILE_DESCRIPTOR
   1989                          else:
   1990                             if sys.platform == 'win32':
   1991                                mode |= os.O_BINARY
   1992                             if smbServer.getRegisteredNamedPipes().has_key(unicode(pathName)):
   1993                                 fid = PIPE_FILE_DESCRIPTOR
   1994                                 sock = socket.socket()
   1995                                 sock.connect(smbServer.getRegisteredNamedPipes()[unicode(pathName)])
   1996                             else:
   1997                                 fid = os.open(pathName, mode)
   1998                      except Exception, e:
   1999                          smbServer.log("NTCreateAndX: %s,%s,%s" % (pathName,mode,e),logging.ERROR)
   2000                          #print e
   2001                          fid = 0
   2002                          errorCode = STATUS_ACCESS_DENIED
   2003         else:
   2004             errorCode = STATUS_SMB_BAD_TID
   2005 
   2006         if errorCode == STATUS_SUCCESS:
   2007             # Simple way to generate a fid
   2008             if len(connData['OpenedFiles']) == 0:
   2009                fakefid = 1
   2010             else:
   2011                fakefid = connData['OpenedFiles'].keys()[-1] + 1
   2012             respParameters['Fid'] = fakefid
   2013             respParameters['CreateAction'] = createDisposition
   2014             if fid == PIPE_FILE_DESCRIPTOR:
   2015                 respParameters['FileAttributes'] = 0x80
   2016                 respParameters['IsDirectory'] = 0
   2017                 respParameters['CreateTime']     = 0
   2018                 respParameters['LastAccessTime'] = 0
   2019                 respParameters['LastWriteTime']  = 0
   2020                 respParameters['LastChangeTime'] = 0
   2021                 respParameters['AllocationSize'] = 4096
   2022                 respParameters['EndOfFile']      = 0
   2023                 respParameters['FileType']       = 2
   2024                 respParameters['IPCState']       = 0x5ff
   2025             else:
   2026                 if os.path.isdir(pathName):
   2027                     respParameters['FileAttributes'] = smb.SMB_FILE_ATTRIBUTE_DIRECTORY
   2028                     respParameters['IsDirectory'] = 1
   2029                 else:
   2030                     respParameters['IsDirectory'] = 0
   2031                     respParameters['FileAttributes'] = ntCreateAndXParameters['FileAttributes']
   2032                 # Let's get this file's information
   2033                 respInfo, errorCode = queryPathInformation('',pathName,level= smb.SMB_QUERY_FILE_ALL_INFO)
   2034                 if errorCode == STATUS_SUCCESS:
   2035                     respParameters['CreateTime']     = respInfo['CreationTime']
   2036                     respParameters['LastAccessTime'] = respInfo['LastAccessTime']
   2037                     respParameters['LastWriteTime']  = respInfo['LastWriteTime']
   2038                     respParameters['LastChangeTime'] = respInfo['LastChangeTime']
   2039                     respParameters['FileAttributes'] = respInfo['ExtFileAttributes']
   2040                     respParameters['AllocationSize'] = respInfo['AllocationSize']
   2041                     respParameters['EndOfFile']      = respInfo['EndOfFile']
   2042                 else:
   2043                     respParameters = ''
   2044                     respData       = ''
   2045 
   2046             if errorCode == STATUS_SUCCESS:
   2047                 # Let's store the fid for the connection
   2048                 # smbServer.log('Create file %s, mode:0x%x' % (pathName, mode))
   2049                 connData['OpenedFiles'][fakefid] = {}
   2050                 connData['OpenedFiles'][fakefid]['FileHandle'] = fid
   2051                 connData['OpenedFiles'][fakefid]['FileName'] = pathName
   2052                 connData['OpenedFiles'][fakefid]['DeleteOnClose']  = deleteOnClose
   2053                 if fid == PIPE_FILE_DESCRIPTOR:
   2054                     connData['OpenedFiles'][fakefid]['Socket'] = sock
   2055         else:
   2056             respParameters = ''
   2057             respData       = ''
   2058 
   2059         respSMBCommand['Parameters']             = respParameters
   2060         respSMBCommand['Data']                   = respData
   2061         smbServer.setConnectionData(connId, connData)
   2062 
   2063         return [respSMBCommand], None, errorCode
   2064 
   2065     @staticmethod
   2066     def smbComOpenAndX(connId, smbServer, SMBCommand, recvPacket):
   2067         connData = smbServer.getConnectionData(connId)
   2068 
   2069         respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_OPEN_ANDX)
   2070         respParameters        = smb.SMBOpenAndXResponse_Parameters()
   2071         respData              = ''
   2072 
   2073         openAndXParameters = smb.SMBOpenAndX_Parameters(SMBCommand['Parameters'])
   2074         openAndXData       = smb.SMBOpenAndX_Data( flags = recvPacket['Flags2'], data = SMBCommand['Data'])
   2075 
   2076         # Get the Tid associated
   2077         if connData['ConnectedShares'].has_key(recvPacket['Tid']):
   2078              path = connData['ConnectedShares'][recvPacket['Tid']]['path']
   2079              openedFile, mode, pathName, errorCode = openFile(path,
   2080                      decodeSMBString(recvPacket['Flags2'],openAndXData['FileName']),
   2081                      openAndXParameters['DesiredAccess'],
   2082                      openAndXParameters['FileAttributes'],
   2083                      openAndXParameters['OpenMode'])
   2084         else:
   2085            errorCode = STATUS_SMB_BAD_TID
   2086 
   2087         if errorCode == STATUS_SUCCESS:
   2088             # Simple way to generate a fid
   2089             fid = len(connData['OpenedFiles']) + 1
   2090             if len(connData['OpenedFiles']) == 0:
   2091                fid = 1
   2092             else:
   2093                fid = connData['OpenedFiles'].keys()[-1] + 1
   2094             respParameters['Fid'] = fid
   2095             if mode & os.O_CREAT:
   2096                 # File did not exist and was created
   2097                 respParameters['Action'] = 0x2
   2098             elif mode & os.O_RDONLY:
   2099                 # File existed and was opened
   2100                 respParameters['Action'] = 0x1
   2101             elif mode & os.O_APPEND:
   2102                 # File existed and was opened
   2103                 respParameters['Action'] = 0x1
   2104             else:
   2105                 # File existed and was truncated
   2106                 respParameters['Action'] = 0x3
   2107 
   2108             # Let's store the fid for the connection
   2109             #smbServer.log('Opening file %s' % pathName)
   2110             connData['OpenedFiles'][fid] = {}
   2111             connData['OpenedFiles'][fid]['FileHandle'] = openedFile
   2112             connData['OpenedFiles'][fid]['FileName'] = pathName
   2113             connData['OpenedFiles'][fid]['DeleteOnClose']  = False
   2114         else:
   2115             respParameters = ''
   2116             respData       = ''
   2117 
   2118         respSMBCommand['Parameters']             = respParameters
   2119         respSMBCommand['Data']                   = respData
   2120         smbServer.setConnectionData(connId, connData)
   2121 
   2122         return [respSMBCommand], None, errorCode
   2123 
   2124     @staticmethod
   2125     def smbComTreeConnectAndX(connId, smbServer, SMBCommand, recvPacket):
   2126         connData = smbServer.getConnectionData(connId)
   2127 
   2128         resp = smb.NewSMBPacket()
   2129         resp['Flags1'] = smb.SMB.FLAGS1_REPLY
   2130         resp['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES | recvPacket['Flags2'] & smb.SMB.FLAGS2_UNICODE
   2131 
   2132         resp['Tid'] = recvPacket['Tid']
   2133         resp['Mid'] = recvPacket['Mid']
   2134         resp['Pid'] = connData['Pid']
   2135 
   2136         respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_TREE_CONNECT_ANDX)
   2137         respParameters        = smb.SMBTreeConnectAndXResponse_Parameters()
   2138         respData              = smb.SMBTreeConnectAndXResponse_Data()
   2139 
   2140         treeConnectAndXParameters = smb.SMBTreeConnectAndX_Parameters(SMBCommand['Parameters'])
   2141 
   2142         if treeConnectAndXParameters['Flags'] & 0x8:
   2143             respParameters        = smb.SMBTreeConnectAndXExtendedResponse_Parameters()
   2144 
   2145         treeConnectAndXData                    = smb.SMBTreeConnectAndX_Data( flags = recvPacket['Flags2'] )
   2146         treeConnectAndXData['_PasswordLength'] = treeConnectAndXParameters['PasswordLength']
   2147         treeConnectAndXData.fromString(SMBCommand['Data'])
   2148 
   2149         errorCode = STATUS_SUCCESS
   2150 
   2151         ## Process here the request, does the share exist?
   2152         UNCOrShare = decodeSMBString(recvPacket['Flags2'], treeConnectAndXData['Path'])
   2153 
   2154         # Is this a UNC?
   2155         if ntpath.ismount(UNCOrShare):
   2156             path = UNCOrShare.split('\\')[3]
   2157         else:
   2158             path = ntpath.basename(UNCOrShare)
   2159 
   2160         share = searchShare(connId, path, smbServer)
   2161         if share is not None:
   2162             # Simple way to generate a Tid
   2163             if len(connData['ConnectedShares']) == 0:
   2164                tid = 1
   2165             else:
   2166                tid = connData['ConnectedShares'].keys()[-1] + 1
   2167             connData['ConnectedShares'][tid] = share
   2168             connData['ConnectedShares'][tid]['shareName'] = path
   2169             resp['Tid'] = tid
   2170             #smbServer.log("Connecting Share(%d:%s)" % (tid,path))
   2171         else:
   2172             smbServer.log("TreeConnectAndX not found %s" % path, logging.ERROR)
   2173             errorCode = STATUS_OBJECT_PATH_NOT_FOUND
   2174             resp['ErrorCode']   = errorCode >> 16
   2175             resp['ErrorClass']  = errorCode & 0xff
   2176         ##
   2177         respParameters['OptionalSupport'] = smb.SMB.SMB_SUPPORT_SEARCH_BITS
   2178 
   2179         if path == 'IPC$':
   2180             respData['Service']               = 'IPC'
   2181         else:
   2182             respData['Service']               = path
   2183         respData['PadLen']                = 0
   2184         respData['NativeFileSystem']      = encodeSMBString(recvPacket['Flags2'], 'NTFS' )
   2185 
   2186         respSMBCommand['Parameters']             = respParameters
   2187         respSMBCommand['Data']                   = respData
   2188 
   2189         resp['Uid'] = connData['Uid']
   2190         resp.addCommand(respSMBCommand)
   2191         smbServer.setConnectionData(connId, connData)
   2192 
   2193         return None, [resp], errorCode
   2194 
   2195     @staticmethod
   2196     def smbComSessionSetupAndX(connId, smbServer, SMBCommand, recvPacket):
   2197         connData = smbServer.getConnectionData(connId, checkStatus = False)
   2198 
   2199         respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_SESSION_SETUP_ANDX)
   2200 
   2201         # From [MS-SMB]
   2202         # When extended security is being used (see section 3.2.4.2.4), the
   2203         # request MUST take the following form
   2204         # [..]
   2205         # WordCount (1 byte): The value of this field MUST be 0x0C.
   2206         if SMBCommand['WordCount'] == 12:
   2207             # Extended security. Here we deal with all SPNEGO stuff
   2208             respParameters = smb.SMBSessionSetupAndX_Extended_Response_Parameters()
   2209             respData       = smb.SMBSessionSetupAndX_Extended_Response_Data(flags = recvPacket['Flags2'])
   2210             sessionSetupParameters = smb.SMBSessionSetupAndX_Extended_Parameters(SMBCommand['Parameters'])
   2211             sessionSetupData = smb.SMBSessionSetupAndX_Extended_Data()
   2212             sessionSetupData['SecurityBlobLength'] = sessionSetupParameters['SecurityBlobLength']
   2213             sessionSetupData.fromString(SMBCommand['Data'])
   2214             connData['Capabilities'] = sessionSetupParameters['Capabilities']
   2215 
   2216             rawNTLM = False
   2217             if struct.unpack('B',sessionSetupData['SecurityBlob'][0])[0] == ASN1_AID:
   2218                # NEGOTIATE packet
   2219                blob =  SPNEGO_NegTokenInit(sessionSetupData['SecurityBlob'])
   2220                token = blob['MechToken']
   2221                if len(blob['MechTypes'][0]) > 0:
   2222                    # Is this GSSAPI NTLM or something else we don't support?
   2223                    mechType = blob['MechTypes'][0]
   2224                    if mechType != TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']:
   2225                        # Nope, do we know it?
   2226                        if MechTypes.has_key(mechType):
   2227                            mechStr = MechTypes[mechType]
   2228                        else:
   2229                            mechStr = hexlify(mechType)
   2230                        smbServer.log("Unsupported MechType '%s'" % mechStr, logging.CRITICAL)
   2231                        # We don't know the token, we answer back again saying
   2232                        # we just support NTLM.
   2233                        # ToDo: Build this into a SPNEGO_NegTokenResp()
   2234                        respToken = '\xa1\x15\x30\x13\xa0\x03\x0a\x01\x03\xa1\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a'
   2235                        respParameters['SecurityBlobLength'] = len(respToken)
   2236                        respData['SecurityBlobLength'] = respParameters['SecurityBlobLength']
   2237                        respData['SecurityBlob']       = respToken
   2238                        respData['NativeOS']     = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS())
   2239                        respData['NativeLanMan'] = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS())
   2240                        respSMBCommand['Parameters'] = respParameters
   2241                        respSMBCommand['Data']       = respData
   2242                        return [respSMBCommand], None, STATUS_MORE_PROCESSING_REQUIRED
   2243 
   2244             elif struct.unpack('B',sessionSetupData['SecurityBlob'][0])[0] == ASN1_SUPPORTED_MECH:
   2245                # AUTH packet
   2246                blob = SPNEGO_NegTokenResp(sessionSetupData['SecurityBlob'])
   2247                token = blob['ResponseToken']
   2248             else:
   2249                # No GSSAPI stuff, raw NTLMSSP
   2250                rawNTLM = True
   2251                token = sessionSetupData['SecurityBlob']
   2252 
   2253             # Here we only handle NTLMSSP, depending on what stage of the
   2254             # authentication we are, we act on it
   2255             messageType = struct.unpack('<L',token[len('NTLMSSP\x00'):len('NTLMSSP\x00')+4])[0]
   2256 
   2257             if messageType == 0x01:
   2258                 # NEGOTIATE_MESSAGE
   2259                 negotiateMessage = ntlm.NTLMAuthNegotiate()
   2260                 negotiateMessage.fromString(token)
   2261                 # Let's store it in the connection data
   2262                 connData['NEGOTIATE_MESSAGE'] = negotiateMessage
   2263                 # Let's build the answer flags
   2264                 # TODO: Parse all the flags. With this we're leaving some clients out
   2265 
   2266                 ansFlags = 0
   2267 
   2268                 if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_56:
   2269                    ansFlags |= ntlm.NTLMSSP_NEGOTIATE_56
   2270                 if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_128:
   2271                    ansFlags |= ntlm.NTLMSSP_NEGOTIATE_128
   2272                 if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH:
   2273                    ansFlags |= ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH
   2274                 if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
   2275                    ansFlags |= ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
   2276                 if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_UNICODE:
   2277                    ansFlags |= ntlm.NTLMSSP_NEGOTIATE_UNICODE
   2278                 if negotiateMessage['flags'] & ntlm.NTLM_NEGOTIATE_OEM:
   2279                    ansFlags |= ntlm.NTLM_NEGOTIATE_OEM
   2280 
   2281                 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_VERSION | ntlm.NTLMSSP_NEGOTIATE_TARGET_INFO | ntlm.NTLMSSP_TARGET_TYPE_SERVER | ntlm.NTLMSSP_NEGOTIATE_NTLM | ntlm.NTLMSSP_REQUEST_TARGET
   2282 
   2283                 # Generate the AV_PAIRS
   2284                 av_pairs = ntlm.AV_PAIRS()
   2285                 # TODO: Put the proper data from SMBSERVER config
   2286                 av_pairs[ntlm.NTLMSSP_AV_HOSTNAME] = av_pairs[ntlm.NTLMSSP_AV_DNS_HOSTNAME] = smbServer.getServerName().encode('utf-16le')
   2287                 av_pairs[ntlm.NTLMSSP_AV_DOMAINNAME] = av_pairs[ntlm.NTLMSSP_AV_DNS_DOMAINNAME] = smbServer.getServerDomain().encode('utf-16le')
   2288                 av_pairs[ntlm.NTLMSSP_AV_TIME] = struct.pack('<q', (116444736000000000 + calendar.timegm(time.gmtime()) * 10000000) )
   2289 
   2290                 challengeMessage = ntlm.NTLMAuthChallenge()
   2291                 challengeMessage['flags']            = ansFlags
   2292                 challengeMessage['domain_len']       = len(smbServer.getServerDomain().encode('utf-16le'))
   2293                 challengeMessage['domain_max_len']   = challengeMessage['domain_len']
   2294                 challengeMessage['domain_offset']    = 40 + 16
   2295                 challengeMessage['challenge']        = smbServer.getSMBChallenge()
   2296                 challengeMessage['domain_name']      = smbServer.getServerDomain().encode('utf-16le')
   2297                 challengeMessage['TargetInfoFields_len']     = len(av_pairs)
   2298                 challengeMessage['TargetInfoFields_max_len'] = len(av_pairs)
   2299                 challengeMessage['TargetInfoFields'] = av_pairs
   2300                 challengeMessage['TargetInfoFields_offset']  = 40 + 16 + len(challengeMessage['domain_name'])
   2301                 challengeMessage['Version']          = '\xff'*8
   2302                 challengeMessage['VersionLen']       = 8
   2303 
   2304                 if rawNTLM is False:
   2305                     respToken = SPNEGO_NegTokenResp()
   2306                     # accept-incomplete. We want more data
   2307                     respToken['NegResult'] = '\x01'
   2308                     respToken['SupportedMech'] = TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']
   2309 
   2310                     respToken['ResponseToken'] = challengeMessage.getData()
   2311                 else:
   2312                     respToken = challengeMessage
   2313 
   2314                 # Setting the packet to STATUS_MORE_PROCESSING
   2315                 errorCode = STATUS_MORE_PROCESSING_REQUIRED
   2316                 # Let's set up an UID for this connection and store it
   2317                 # in the connection's data
   2318                 # Picking a fixed value
   2319                 # TODO: Manage more UIDs for the same session
   2320                 connData['Uid'] = 10
   2321                 # Let's store it in the connection data
   2322                 connData['CHALLENGE_MESSAGE'] = challengeMessage
   2323 
   2324             elif messageType == 0x02:
   2325                 # CHALLENGE_MESSAGE
   2326                 raise Exception('Challenge Message raise, not implemented!')
   2327             elif messageType == 0x03:
   2328                 # AUTHENTICATE_MESSAGE, here we deal with authentication
   2329                 authenticateMessage = ntlm.NTLMAuthChallengeResponse()
   2330                 authenticateMessage.fromString(token)
   2331                 smbServer.log("AUTHENTICATE_MESSAGE (%s\\%s,%s)" % (authenticateMessage['domain_name'], authenticateMessage['user_name'], authenticateMessage['host_name']))
   2332                 # TODO: Check the credentials! Now granting permissions
   2333 
   2334                 respToken = SPNEGO_NegTokenResp()
   2335                 # accept-completed
   2336                 respToken['NegResult'] = '\x00'
   2337 
   2338                 # Status SUCCESS
   2339                 errorCode = STATUS_SUCCESS
   2340                 smbServer.log('User %s\\%s authenticated successfully' % (authenticateMessage['user_name'], authenticateMessage['host_name']))
   2341                 # Let's store it in the connection data
   2342                 connData['AUTHENTICATE_MESSAGE'] = authenticateMessage
   2343                 try:
   2344                     jtr_dump_path = smbServer.getJTRdumpPath()
   2345                     ntlm_hash_data = outputToJohnFormat( connData['CHALLENGE_MESSAGE']['challenge'], authenticateMessage['user_name'], authenticateMessage['domain_name'], authenticateMessage['lanman'], authenticateMessage['ntlm'] )
   2346                     smbServer.log(ntlm_hash_data['hash_string'])
   2347                     if jtr_dump_path is not '':
   2348                         writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], jtr_dump_path)
   2349                 except:
   2350                     smbServer.log("Could not write NTLM Hashes to the specified JTR_Dump_Path %s" % jtr_dump_path)
   2351             else:
   2352                 raise Exception("Unknown NTLMSSP MessageType %d" % messageType)
   2353 
   2354             respParameters['SecurityBlobLength'] = len(respToken)
   2355             respData['SecurityBlobLength'] = respParameters['SecurityBlobLength']
   2356             respData['SecurityBlob']       = respToken.getData()
   2357 
   2358         else:
   2359             # Process Standard Security
   2360             respParameters = smb.SMBSessionSetupAndXResponse_Parameters()
   2361             respData       = smb.SMBSessionSetupAndXResponse_Data()
   2362             sessionSetupParameters = smb.SMBSessionSetupAndX_Parameters(SMBCommand['Parameters'])
   2363             sessionSetupData = smb.SMBSessionSetupAndX_Data()
   2364             sessionSetupData['AnsiPwdLength'] = sessionSetupParameters['AnsiPwdLength']
   2365             sessionSetupData['UnicodePwdLength'] = sessionSetupParameters['UnicodePwdLength']
   2366             sessionSetupData.fromString(SMBCommand['Data'])
   2367             connData['Capabilities'] = sessionSetupParameters['Capabilities']
   2368             # Do the verification here, for just now we grant access
   2369             # TODO: Manage more UIDs for the same session
   2370             errorCode = STATUS_SUCCESS
   2371             connData['Uid'] = 10
   2372             respParameters['Action'] = 0
   2373             smbServer.log('User %s\\%s authenticated successfully (basic)' % (sessionSetupData['PrimaryDomain'], sessionSetupData['Account']))
   2374             try:
   2375                 jtr_dump_path = smbServer.getJTRdumpPath()
   2376                 ntlm_hash_data = outputToJohnFormat( '', sessionSetupData['Account'], sessionSetupData['PrimaryDomain'], sessionSetupData['AnsiPwd'], sessionSetupData['UnicodePwd'] )
   2377                 smbServer.log(ntlm_hash_data['hash_string'])
   2378                 if jtr_dump_path is not '':
   2379                     writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], jtr_dump_path)
   2380             except:
   2381                 smbServer.log("Could not write NTLM Hashes to the specified JTR_Dump_Path %s" % jtr_dump_path)
   2382 
   2383         respData['NativeOS']     = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS())
   2384         respData['NativeLanMan'] = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS())
   2385         respSMBCommand['Parameters'] = respParameters
   2386         respSMBCommand['Data']       = respData
   2387 
   2388         # From now on, the client can ask for other commands
   2389         connData['Authenticated'] = True
   2390         # For now, just switching to nobody
   2391         #os.setregid(65534,65534)
   2392         #os.setreuid(65534,65534)
   2393         smbServer.setConnectionData(connId, connData)
   2394 
   2395         return [respSMBCommand], None, errorCode
   2396 
   2397     @staticmethod
   2398     def smbComNegotiate(connId, smbServer, SMBCommand, recvPacket ):
   2399         connData = smbServer.getConnectionData(connId, checkStatus = False)
   2400         connData['Pid'] = recvPacket['Pid']
   2401 
   2402         SMBCommand = smb.SMBCommand(recvPacket['Data'][0])
   2403         respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_NEGOTIATE)
   2404 
   2405         resp = smb.NewSMBPacket()
   2406         resp['Flags1'] = smb.SMB.FLAGS1_REPLY
   2407         resp['Pid'] = connData['Pid']
   2408         resp['Tid'] = recvPacket['Tid']
   2409         resp['Mid'] = recvPacket['Mid']
   2410 
   2411         # TODO: We support more dialects, and parse them accordingly
   2412         dialects = SMBCommand['Data'].split('\x02')
   2413         try:
   2414            index = dialects.index('NT LM 0.12\x00') - 1
   2415            # Let's fill the data for NTLM
   2416            if recvPacket['Flags2'] & smb.SMB.FLAGS2_EXTENDED_SECURITY:
   2417                     resp['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_UNICODE
   2418                     #resp['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS
   2419                     _dialects_data = smb.SMBExtended_Security_Data()
   2420                     _dialects_data['ServerGUID'] = 'A'*16
   2421                     blob = SPNEGO_NegTokenInit()
   2422                     blob['MechTypes'] = [TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']]
   2423                     _dialects_data['SecurityBlob'] = blob.getData()
   2424 
   2425                     _dialects_parameters = smb.SMBExtended_Security_Parameters()
   2426                     _dialects_parameters['Capabilities']    = smb.SMB.CAP_EXTENDED_SECURITY | smb.SMB.CAP_USE_NT_ERRORS | smb.SMB.CAP_NT_SMBS | smb.SMB.CAP_UNICODE
   2427                     _dialects_parameters['ChallengeLength'] = 0
   2428 
   2429            else:
   2430                     resp['Flags2'] = smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_UNICODE
   2431                     _dialects_parameters = smb.SMBNTLMDialect_Parameters()
   2432                     _dialects_data= smb.SMBNTLMDialect_Data()
   2433                     _dialects_data['Payload'] = ''
   2434                     if connData.has_key('EncryptionKey'):
   2435                         _dialects_data['Challenge'] = connData['EncryptionKey']
   2436                         _dialects_parameters['ChallengeLength'] = len(str(_dialects_data))
   2437                     else:
   2438                         # TODO: Handle random challenges, now one that can be used with rainbow tables
   2439                         _dialects_data['Challenge'] = '\x11\x22\x33\x44\x55\x66\x77\x88'
   2440                         _dialects_parameters['ChallengeLength'] = 8
   2441                     _dialects_parameters['Capabilities']    = smb.SMB.CAP_USE_NT_ERRORS | smb.SMB.CAP_NT_SMBS
   2442 
   2443            # Let's see if we need to support RPC_REMOTE_APIS
   2444            config = smbServer.getServerConfig()
   2445            if config.has_option('global','rpc_apis'):
   2446                if config.getboolean('global', 'rpc_apis') is True:
   2447                   _dialects_parameters['Capabilities'] |= smb.SMB.CAP_RPC_REMOTE_APIS
   2448 
   2449            _dialects_parameters['DialectIndex']    = index
   2450            _dialects_parameters['SecurityMode']    = smb.SMB.SECURITY_AUTH_ENCRYPTED | smb.SMB.SECURITY_SHARE_USER
   2451            _dialects_parameters['MaxMpxCount']     = 1
   2452            _dialects_parameters['MaxNumberVcs']    = 1
   2453            _dialects_parameters['MaxBufferSize']   = 64000
   2454            _dialects_parameters['MaxRawSize']      = 65536
   2455            _dialects_parameters['SessionKey']      = 0
   2456            _dialects_parameters['LowDateTime']     = 0
   2457            _dialects_parameters['HighDateTime']    = 0
   2458            _dialects_parameters['ServerTimeZone']  = 0
   2459 
   2460 
   2461            respSMBCommand['Data']           = _dialects_data
   2462            respSMBCommand['Parameters']     = _dialects_parameters
   2463            connData['_dialects_data']       = _dialects_data
   2464            connData['_dialects_parameters'] = _dialects_parameters
   2465 
   2466         except Exception, e:
   2467            # No NTLM throw an error
   2468            smbServer.log('smbComNegotiate: %s' % e, logging.ERROR)
   2469            respSMBCommand['Data'] = struct.pack('<H',0xffff)
   2470 
   2471 
   2472         smbServer.setConnectionData(connId, connData)
   2473 
   2474         resp.addCommand(respSMBCommand)
   2475 
   2476         return None, [resp], STATUS_SUCCESS
   2477 
   2478     @staticmethod
   2479     def default(connId, smbServer, SMBCommand, recvPacket):
   2480         # By default we return an SMB Packet with error not implemented
   2481         smbServer.log("Not implemented command: 0x%x" % recvPacket['Command'],logging.DEBUG)
   2482         packet = smb.NewSMBPacket()
   2483         packet['Flags1']  = smb.SMB.FLAGS1_REPLY
   2484         packet['Flags2']  = smb.SMB.FLAGS2_NT_STATUS
   2485         packet['Command'] = recvPacket['Command']
   2486         packet['Pid']     = recvPacket['Pid']
   2487         packet['Tid']     = recvPacket['Tid']
   2488         packet['Mid']     = recvPacket['Mid']
   2489         packet['Uid']     = recvPacket['Uid']
   2490         packet['Data']    = '\x00\x00\x00'
   2491         errorCode = STATUS_NOT_IMPLEMENTED
   2492         packet['ErrorCode']   = errorCode >> 16
   2493         packet['ErrorClass']  = errorCode & 0xff
   2494 
   2495         return None, [packet], errorCode
   2496 
   2497 class SMB2Commands:
   2498     @staticmethod
   2499     def smb2Negotiate(connId, smbServer, recvPacket, isSMB1 = False):
   2500         connData = smbServer.getConnectionData(connId, checkStatus = False)
   2501 
   2502         respPacket = smb2.SMB2Packet()
   2503         respPacket['Flags']     = smb2.SMB2_FLAGS_SERVER_TO_REDIR
   2504         respPacket['Status']    = STATUS_SUCCESS
   2505         respPacket['CreditRequestResponse'] = 1
   2506         respPacket['Command']   = smb2.SMB2_NEGOTIATE
   2507         respPacket['SessionID'] = 0
   2508         if isSMB1 is False:
   2509             respPacket['MessageID'] = recvPacket['MessageID']
   2510         else:
   2511             respPacket['MessageID'] = 0
   2512         respPacket['TreeID']    = 0
   2513 
   2514 
   2515         respSMBCommand = smb2.SMB2Negotiate_Response()
   2516 
   2517         respSMBCommand['SecurityMode'] = 1
   2518         if isSMB1 is True:
   2519             # Let's first parse the packet to see if the client supports SMB2
   2520             SMBCommand = smb.SMBCommand(recvPacket['Data'][0])
   2521 
   2522             dialects = SMBCommand['Data'].split('\x02')
   2523             if 'SMB 2.002\x00' in dialects or 'SMB 2.???\x00' in dialects:
   2524                 respSMBCommand['DialectRevision'] = smb2.SMB2_DIALECT_002
   2525             else:
   2526                 # Client does not support SMB2 fallbacking
   2527                 raise Exception('SMB2 not supported, fallbacking')
   2528         else:
   2529             respSMBCommand['DialectRevision'] = smb2.SMB2_DIALECT_002
   2530         respSMBCommand['ServerGuid'] = 'A'*16
   2531         respSMBCommand['Capabilities'] = 0
   2532         respSMBCommand['MaxTransactSize'] = 65536
   2533         respSMBCommand['MaxReadSize'] = 65536
   2534         respSMBCommand['MaxWriteSize'] = 65536
   2535         respSMBCommand['SystemTime'] = getFileTime(calendar.timegm(time.gmtime()))
   2536         respSMBCommand['ServerStartTime'] = getFileTime(calendar.timegm(time.gmtime()))
   2537         respSMBCommand['SecurityBufferOffset'] = 0x80
   2538 
   2539         blob = SPNEGO_NegTokenInit()
   2540         blob['MechTypes'] = [TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']]
   2541 
   2542         respSMBCommand['Buffer'] = blob.getData()
   2543         respSMBCommand['SecurityBufferLength'] = len(respSMBCommand['Buffer'])
   2544 
   2545         respPacket['Data']      = respSMBCommand
   2546 
   2547         smbServer.setConnectionData(connId, connData)
   2548 
   2549         return None, [respPacket], STATUS_SUCCESS
   2550 
   2551     @staticmethod
   2552     def smb2SessionSetup(connId, smbServer, recvPacket):
   2553         connData = smbServer.getConnectionData(connId, checkStatus = False)
   2554 
   2555         respSMBCommand = smb2.SMB2SessionSetup_Response()
   2556 
   2557         sessionSetupData = smb2.SMB2SessionSetup(recvPacket['Data'])
   2558 
   2559         connData['Capabilities'] = sessionSetupData['Capabilities']
   2560 
   2561         securityBlob = sessionSetupData['Buffer']
   2562 
   2563         rawNTLM = False
   2564         if struct.unpack('B',securityBlob[0])[0] == ASN1_AID:
   2565            # NEGOTIATE packet
   2566            blob =  SPNEGO_NegTokenInit(securityBlob)
   2567            token = blob['MechToken']
   2568            if len(blob['MechTypes'][0]) > 0:
   2569                # Is this GSSAPI NTLM or something else we don't support?
   2570                mechType = blob['MechTypes'][0]
   2571                if mechType != TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']:
   2572                    # Nope, do we know it?
   2573                    if MechTypes.has_key(mechType):
   2574                        mechStr = MechTypes[mechType]
   2575                    else:
   2576                        mechStr = hexlify(mechType)
   2577                    smbServer.log("Unsupported MechType '%s'" % mechStr, logging.CRITICAL)
   2578                    # We don't know the token, we answer back again saying
   2579                    # we just support NTLM.
   2580                    # ToDo: Build this into a SPNEGO_NegTokenResp()
   2581                    respToken = '\xa1\x15\x30\x13\xa0\x03\x0a\x01\x03\xa1\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a'
   2582                    respSMBCommand['SecurityBufferOffset'] = 0x48
   2583                    respSMBCommand['SecurityBufferLength'] = len(respToken)
   2584                    respSMBCommand['Buffer'] = respToken
   2585 
   2586                    return [respSMBCommand], None, STATUS_MORE_PROCESSING_REQUIRED
   2587         elif struct.unpack('B',securityBlob[0])[0] == ASN1_SUPPORTED_MECH:
   2588            # AUTH packet
   2589            blob = SPNEGO_NegTokenResp(securityBlob)
   2590            token = blob['ResponseToken']
   2591         else:
   2592            # No GSSAPI stuff, raw NTLMSSP
   2593            rawNTLM = True
   2594            token = securityBlob
   2595 
   2596         # Here we only handle NTLMSSP, depending on what stage of the
   2597         # authentication we are, we act on it
   2598         messageType = struct.unpack('<L',token[len('NTLMSSP\x00'):len('NTLMSSP\x00')+4])[0]
   2599 
   2600         if messageType == 0x01:
   2601             # NEGOTIATE_MESSAGE
   2602             negotiateMessage = ntlm.NTLMAuthNegotiate()
   2603             negotiateMessage.fromString(token)
   2604             # Let's store it in the connection data
   2605             connData['NEGOTIATE_MESSAGE'] = negotiateMessage
   2606             # Let's build the answer flags
   2607             # TODO: Parse all the flags. With this we're leaving some clients out
   2608 
   2609             ansFlags = 0
   2610 
   2611             if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_56:
   2612                ansFlags |= ntlm.NTLMSSP_NEGOTIATE_56
   2613             if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_128:
   2614                ansFlags |= ntlm.NTLMSSP_NEGOTIATE_128
   2615             if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH:
   2616                ansFlags |= ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH
   2617             if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
   2618                ansFlags |= ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
   2619             if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_UNICODE:
   2620                ansFlags |= ntlm.NTLMSSP_NEGOTIATE_UNICODE
   2621             if negotiateMessage['flags'] & ntlm.NTLM_NEGOTIATE_OEM:
   2622                ansFlags |= ntlm.NTLM_NEGOTIATE_OEM
   2623 
   2624             ansFlags |= ntlm.NTLMSSP_NEGOTIATE_VERSION | ntlm.NTLMSSP_NEGOTIATE_TARGET_INFO | ntlm.NTLMSSP_TARGET_TYPE_SERVER | ntlm.NTLMSSP_NEGOTIATE_NTLM | ntlm.NTLMSSP_REQUEST_TARGET
   2625 
   2626             # Generate the AV_PAIRS
   2627             av_pairs = ntlm.AV_PAIRS()
   2628             # TODO: Put the proper data from SMBSERVER config
   2629             av_pairs[ntlm.NTLMSSP_AV_HOSTNAME] = av_pairs[ntlm.NTLMSSP_AV_DNS_HOSTNAME] = smbServer.getServerName().encode('utf-16le')
   2630             av_pairs[ntlm.NTLMSSP_AV_DOMAINNAME] = av_pairs[ntlm.NTLMSSP_AV_DNS_DOMAINNAME] = smbServer.getServerDomain().encode('utf-16le')
   2631             av_pairs[ntlm.NTLMSSP_AV_TIME] = struct.pack('<q', (116444736000000000 + calendar.timegm(time.gmtime()) * 10000000) )
   2632 
   2633             challengeMessage = ntlm.NTLMAuthChallenge()
   2634             challengeMessage['flags']            = ansFlags
   2635             challengeMessage['domain_len']       = len(smbServer.getServerDomain().encode('utf-16le'))
   2636             challengeMessage['domain_max_len']   = challengeMessage['domain_len']
   2637             challengeMessage['domain_offset']    = 40 + 16
   2638             challengeMessage['challenge']        = smbServer.getSMBChallenge()
   2639             challengeMessage['domain_name']      = smbServer.getServerDomain().encode('utf-16le')
   2640             challengeMessage['TargetInfoFields_len']     = len(av_pairs)
   2641             challengeMessage['TargetInfoFields_max_len'] = len(av_pairs)
   2642             challengeMessage['TargetInfoFields'] = av_pairs
   2643             challengeMessage['TargetInfoFields_offset']  = 40 + 16 + len(challengeMessage['domain_name'])
   2644             challengeMessage['Version']          = '\xff'*8
   2645             challengeMessage['VersionLen']       = 8
   2646 
   2647             if rawNTLM is False:
   2648                 respToken = SPNEGO_NegTokenResp()
   2649                 # accept-incomplete. We want more data
   2650                 respToken['NegResult'] = '\x01'
   2651                 respToken['SupportedMech'] = TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']
   2652 
   2653                 respToken['ResponseToken'] = challengeMessage.getData()
   2654             else:
   2655                 respToken = challengeMessage
   2656 
   2657             # Setting the packet to STATUS_MORE_PROCESSING
   2658             errorCode = STATUS_MORE_PROCESSING_REQUIRED
   2659             # Let's set up an UID for this connection and store it
   2660             # in the connection's data
   2661             # Picking a fixed value
   2662             # TODO: Manage more UIDs for the same session
   2663             connData['Uid'] = random.randint(1,0xffffffff)
   2664             # Let's store it in the connection data
   2665             connData['CHALLENGE_MESSAGE'] = challengeMessage
   2666 
   2667         elif messageType == 0x02:
   2668             # CHALLENGE_MESSAGE
   2669             raise Exception('Challenge Message raise, not implemented!')
   2670         elif messageType == 0x03:
   2671             # AUTHENTICATE_MESSAGE, here we deal with authentication
   2672             authenticateMessage = ntlm.NTLMAuthChallengeResponse()
   2673             authenticateMessage.fromString(token)
   2674             smbServer.log("AUTHENTICATE_MESSAGE (%s\\%s,%s)" % (authenticateMessage['domain_name'], authenticateMessage['user_name'], authenticateMessage['host_name']))
   2675             # TODO: Check the credentials! Now granting permissions
   2676 
   2677             respToken = SPNEGO_NegTokenResp()
   2678             # accept-completed
   2679             respToken['NegResult'] = '\x00'
   2680 
   2681             # Status SUCCESS
   2682             errorCode = STATUS_SUCCESS
   2683             smbServer.log('User %s\\%s authenticated successfully' % (authenticateMessage['user_name'], authenticateMessage['host_name']))
   2684             # Let's store it in the connection data
   2685             connData['AUTHENTICATE_MESSAGE'] = authenticateMessage
   2686             try:
   2687                 jtr_dump_path = smbServer.getJTRdumpPath()
   2688                 ntlm_hash_data = outputToJohnFormat( connData['CHALLENGE_MESSAGE']['challenge'], authenticateMessage['user_name'], authenticateMessage['domain_name'], authenticateMessage['lanman'], authenticateMessage['ntlm'] )
   2689                 smbServer.log(ntlm_hash_data['hash_string'])
   2690                 if jtr_dump_path is not '':
   2691                     writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], jtr_dump_path)
   2692             except:
   2693                 smbServer.log("Could not write NTLM Hashes to the specified JTR_Dump_Path %s" % jtr_dump_path)
   2694             respSMBCommand['SessionFlags'] = 1
   2695         else:
   2696             raise Exception("Unknown NTLMSSP MessageType %d" % messageType)
   2697 
   2698         respSMBCommand['SecurityBufferOffset'] = 0x48
   2699         respSMBCommand['SecurityBufferLength'] = len(respToken)
   2700         respSMBCommand['Buffer'] = respToken.getData()
   2701 
   2702         # From now on, the client can ask for other commands
   2703         connData['Authenticated'] = True
   2704         # For now, just switching to nobody
   2705         #os.setregid(65534,65534)
   2706         #os.setreuid(65534,65534)
   2707         smbServer.setConnectionData(connId, connData)
   2708 
   2709         return [respSMBCommand], None, errorCode
   2710 
   2711     @staticmethod
   2712     def smb2TreeConnect(connId, smbServer, recvPacket):
   2713         connData = smbServer.getConnectionData(connId)
   2714 
   2715         respPacket = smb2.SMB2Packet()
   2716         respPacket['Flags']     = smb2.SMB2_FLAGS_SERVER_TO_REDIR
   2717         respPacket['Status']    = STATUS_SUCCESS
   2718         respPacket['CreditRequestResponse'] = 1
   2719         respPacket['Command']   = recvPacket['Command']
   2720         respPacket['SessionID'] = connData['Uid']
   2721         respPacket['Reserved']  = recvPacket['Reserved']
   2722         respPacket['MessageID'] = recvPacket['MessageID']
   2723         respPacket['TreeID']    = recvPacket['TreeID']
   2724 
   2725         respSMBCommand        = smb2.SMB2TreeConnect_Response()
   2726 
   2727         treeConnectRequest = smb2.SMB2TreeConnect(recvPacket['Data'])
   2728 
   2729         errorCode = STATUS_SUCCESS
   2730 
   2731         ## Process here the request, does the share exist?
   2732         path = str(recvPacket)[treeConnectRequest['PathOffset']:][:treeConnectRequest['PathLength']]
   2733         UNCOrShare = path.decode('utf-16le')
   2734 
   2735         # Is this a UNC?
   2736         if ntpath.ismount(UNCOrShare):
   2737             path = UNCOrShare.split('\\')[3]
   2738         else:
   2739             path = ntpath.basename(UNCOrShare)
   2740 
   2741         share = searchShare(connId, path.upper(), smbServer)
   2742         if share is not None:
   2743             # Simple way to generate a Tid
   2744             if len(connData['ConnectedShares']) == 0:
   2745                tid = 1
   2746             else:
   2747                tid = connData['ConnectedShares'].keys()[-1] + 1
   2748             connData['ConnectedShares'][tid] = share
   2749             connData['ConnectedShares'][tid]['shareName'] = path
   2750             respPacket['TreeID']    = tid
   2751             smbServer.log("Connecting Share(%d:%s)" % (tid,path))
   2752         else:
   2753             smbServer.log("SMB2_TREE_CONNECT not found %s" % path, logging.ERROR)
   2754             errorCode = STATUS_OBJECT_PATH_NOT_FOUND
   2755             respPacket['Status'] = errorCode
   2756         ##
   2757 
   2758         if path == 'IPC$':
   2759             respSMBCommand['ShareType'] = smb2.SMB2_SHARE_TYPE_PIPE
   2760             respSMBCommand['ShareFlags'] = 0x30
   2761         else:
   2762             respSMBCommand['ShareType'] = smb2.SMB2_SHARE_TYPE_DISK
   2763             respSMBCommand['ShareFlags'] = 0x0
   2764 
   2765         respSMBCommand['Capabilities'] = 0
   2766         respSMBCommand['MaximalAccess'] = 0x000f01ff
   2767 
   2768         respPacket['Data'] = respSMBCommand
   2769 
   2770         smbServer.setConnectionData(connId, connData)
   2771 
   2772         return None, [respPacket], errorCode
   2773 
   2774     @staticmethod
   2775     def smb2Create(connId, smbServer, recvPacket):
   2776         connData = smbServer.getConnectionData(connId)
   2777 
   2778         respSMBCommand        = smb2.SMB2Create_Response()
   2779 
   2780         ntCreateRequest       = smb2.SMB2Create(recvPacket['Data'])
   2781 
   2782         respSMBCommand['Buffer'] = '\x00'
   2783         # Get the Tid associated
   2784         if connData['ConnectedShares'].has_key(recvPacket['TreeID']):
   2785              # If we have a rootFid, the path is relative to that fid
   2786              errorCode = STATUS_SUCCESS
   2787              if connData['ConnectedShares'][recvPacket['TreeID']].has_key('path'):
   2788                  path = connData['ConnectedShares'][recvPacket['TreeID']]['path']
   2789              else:
   2790                  path = 'NONE'
   2791                  errorCode = STATUS_ACCESS_DENIED
   2792 
   2793              deleteOnClose = False
   2794 
   2795              fileName = os.path.normpath(ntCreateRequest['Buffer'][:ntCreateRequest['NameLength']].decode('utf-16le').replace('\\','/'))
   2796              if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
   2797                 # strip leading '/'
   2798                 fileName = fileName[1:]
   2799              pathName = os.path.join(path,fileName)
   2800              createDisposition = ntCreateRequest['CreateDisposition']
   2801              mode = 0
   2802 
   2803              if createDisposition == smb2.FILE_SUPERSEDE:
   2804                  mode |= os.O_TRUNC | os.O_CREAT
   2805              elif createDisposition & smb2.FILE_OVERWRITE_IF == smb2.FILE_OVERWRITE_IF:
   2806                  mode |= os.O_TRUNC | os.O_CREAT
   2807              elif createDisposition & smb2.FILE_OVERWRITE == smb2.FILE_OVERWRITE:
   2808                  if os.path.exists(pathName) is True:
   2809                      mode |= os.O_TRUNC
   2810                  else:
   2811                      errorCode = STATUS_NO_SUCH_FILE
   2812              elif createDisposition & smb2.FILE_OPEN_IF == smb2.FILE_OPEN_IF:
   2813                  if os.path.exists(pathName) is True:
   2814                      mode |= os.O_TRUNC
   2815                  else:
   2816                      mode |= os.O_TRUNC | os.O_CREAT
   2817              elif createDisposition & smb2.FILE_CREATE == smb2.FILE_CREATE:
   2818                  if os.path.exists(pathName) is True:
   2819                      errorCode = STATUS_OBJECT_NAME_COLLISION
   2820                  else:
   2821                      mode |= os.O_CREAT
   2822              elif createDisposition & smb2.FILE_OPEN == smb2.FILE_OPEN:
   2823                  if os.path.exists(pathName) is not True and smbServer.getRegisteredNamedPipes().has_key(unicode(pathName)) is not True:
   2824                      errorCode = STATUS_NO_SUCH_FILE
   2825 
   2826              if errorCode == STATUS_SUCCESS:
   2827                  desiredAccess = ntCreateRequest['DesiredAccess']
   2828                  if (desiredAccess & smb2.FILE_READ_DATA) or (desiredAccess & smb2.GENERIC_READ):
   2829                      mode |= os.O_RDONLY
   2830                  if (desiredAccess & smb2.FILE_WRITE_DATA) or (desiredAccess & smb2.GENERIC_WRITE):
   2831                      if (desiredAccess & smb2.FILE_READ_DATA) or (desiredAccess & smb2.GENERIC_READ):
   2832                          mode |= os.O_RDWR #| os.O_APPEND
   2833                      else:
   2834                          mode |= os.O_WRONLY #| os.O_APPEND
   2835                  if desiredAccess & smb2.GENERIC_ALL:
   2836                      mode |= os.O_RDWR #| os.O_APPEND
   2837 
   2838                  createOptions =  ntCreateRequest['CreateOptions']
   2839                  if mode & os.O_CREAT == os.O_CREAT:
   2840                      if createOptions & smb2.FILE_DIRECTORY_FILE == smb2.FILE_DIRECTORY_FILE:
   2841                          try:
   2842                              # Let's create the directory
   2843                              os.mkdir(pathName)
   2844                              mode = os.O_RDONLY
   2845                          except Exception, e:
   2846                              smbServer.log("SMB2_CREATE: %s,%s,%s" % (pathName,mode,e),logging.ERROR)
   2847                              errorCode = STATUS_ACCESS_DENIED
   2848                  if createOptions & smb2.FILE_NON_DIRECTORY_FILE == smb2.FILE_NON_DIRECTORY_FILE:
   2849                      # If the file being opened is a directory, the server MUST fail the request with
   2850                      # STATUS_FILE_IS_A_DIRECTORY in the Status field of the SMB Header in the server
   2851                      # response.
   2852                      if os.path.isdir(pathName) is True:
   2853                         errorCode = STATUS_FILE_IS_A_DIRECTORY
   2854 
   2855                  if createOptions & smb2.FILE_DELETE_ON_CLOSE == smb2.FILE_DELETE_ON_CLOSE:
   2856                      deleteOnClose = True
   2857 
   2858                  if errorCode == STATUS_SUCCESS:
   2859                      try:
   2860                          if os.path.isdir(pathName) and sys.platform == 'win32':
   2861                             fid = VOID_FILE_DESCRIPTOR
   2862                          else:
   2863                             if sys.platform == 'win32':
   2864                                mode |= os.O_BINARY
   2865                             if smbServer.getRegisteredNamedPipes().has_key(unicode(pathName)):
   2866                                 fid = PIPE_FILE_DESCRIPTOR
   2867                                 sock = socket.socket()
   2868                                 sock.connect(smbServer.getRegisteredNamedPipes()[unicode(pathName)])
   2869                             else:
   2870                                 fid = os.open(pathName, mode)
   2871                      except Exception, e:
   2872                          smbServer.log("SMB2_CREATE: %s,%s,%s" % (pathName,mode,e),logging.ERROR)
   2873                          #print e
   2874                          fid = 0
   2875                          errorCode = STATUS_ACCESS_DENIED
   2876         else:
   2877             errorCode = STATUS_SMB_BAD_TID
   2878 
   2879         if errorCode == STATUS_SUCCESS:
   2880             # Simple way to generate a fid
   2881             fakefid = uuid.generate()
   2882 
   2883             respSMBCommand['FileID'] = fakefid
   2884             respSMBCommand['CreateAction'] = createDisposition
   2885 
   2886             if fid == PIPE_FILE_DESCRIPTOR:
   2887                 respSMBCommand['CreationTime']   = 0
   2888                 respSMBCommand['LastAccessTime'] = 0
   2889                 respSMBCommand['LastWriteTime']  = 0
   2890                 respSMBCommand['ChangeTime']     = 0
   2891                 respSMBCommand['AllocationSize'] = 4096
   2892                 respSMBCommand['EndOfFile']      = 0
   2893                 respSMBCommand['FileAttributes'] = 0x80
   2894 
   2895             else:
   2896                 if os.path.isdir(pathName):
   2897                     respSMBCommand['FileAttributes'] = smb.SMB_FILE_ATTRIBUTE_DIRECTORY
   2898                 else:
   2899                     respSMBCommand['FileAttributes'] = ntCreateRequest['FileAttributes']
   2900                 # Let's get this file's information
   2901                 respInfo, errorCode = queryPathInformation('',pathName,level= smb.SMB_QUERY_FILE_ALL_INFO)
   2902                 if errorCode == STATUS_SUCCESS:
   2903                     respSMBCommand['CreationTime']   = respInfo['CreationTime']
   2904                     respSMBCommand['LastAccessTime'] = respInfo['LastAccessTime']
   2905                     respSMBCommand['LastWriteTime']  = respInfo['LastWriteTime']
   2906                     respSMBCommand['LastChangeTime'] = respInfo['LastChangeTime']
   2907                     respSMBCommand['FileAttributes'] = respInfo['ExtFileAttributes']
   2908                     respSMBCommand['AllocationSize'] = respInfo['AllocationSize']
   2909                     respSMBCommand['EndOfFile']      = respInfo['EndOfFile']
   2910 
   2911             if errorCode == STATUS_SUCCESS:
   2912                 # Let's store the fid for the connection
   2913                 # smbServer.log('Create file %s, mode:0x%x' % (pathName, mode))
   2914                 connData['OpenedFiles'][fakefid] = {}
   2915                 connData['OpenedFiles'][fakefid]['FileHandle'] = fid
   2916                 connData['OpenedFiles'][fakefid]['FileName'] = pathName
   2917                 connData['OpenedFiles'][fakefid]['DeleteOnClose']  = deleteOnClose
   2918                 connData['OpenedFiles'][fakefid]['Open']  = {}
   2919                 connData['OpenedFiles'][fakefid]['Open']['EnumerationLocation'] = 0
   2920                 connData['OpenedFiles'][fakefid]['Open']['EnumerationSearchPattern'] = ''
   2921                 if fid == PIPE_FILE_DESCRIPTOR:
   2922                     connData['OpenedFiles'][fakefid]['Socket'] = sock
   2923         else:
   2924             respSMBCommand = smb2.SMB2Error()
   2925 
   2926         if errorCode == STATUS_SUCCESS:
   2927             connData['LastRequest']['SMB2_CREATE'] = respSMBCommand
   2928         smbServer.setConnectionData(connId, connData)
   2929 
   2930         return [respSMBCommand], None, errorCode
   2931 
   2932     @staticmethod
   2933     def smb2Close(connId, smbServer, recvPacket):
   2934         connData = smbServer.getConnectionData(connId)
   2935 
   2936         respSMBCommand        = smb2.SMB2Close_Response()
   2937 
   2938         closeRequest = smb2.SMB2Close(recvPacket['Data'])
   2939 
   2940         if str(closeRequest['FileID']) == '\xff'*16:
   2941             # Let's take the data from the lastRequest
   2942             if  connData['LastRequest'].has_key('SMB2_CREATE'):
   2943                 fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
   2944             else:
   2945                 fileID = str(closeRequest['FileID'])
   2946         else:
   2947             fileID = str(closeRequest['FileID'])
   2948 
   2949         if connData['OpenedFiles'].has_key(fileID):
   2950              errorCode = STATUS_SUCCESS
   2951              fileHandle = connData['OpenedFiles'][fileID]['FileHandle']
   2952              pathName = connData['OpenedFiles'][fileID]['FileName']
   2953              infoRecord = None
   2954              try:
   2955                  if fileHandle == PIPE_FILE_DESCRIPTOR:
   2956                      connData['OpenedFiles'][fileID]['Socket'].close()
   2957                  elif fileHandle != VOID_FILE_DESCRIPTOR:
   2958                      os.close(fileHandle)
   2959                      infoRecord, errorCode = queryFileInformation(os.path.dirname(pathName), os.path.basename(pathName), smb2.SMB2_FILE_NETWORK_OPEN_INFO)
   2960              except Exception, e:
   2961                  smbServer.log("SMB2_CLOSE %s" % e, logging.ERROR)
   2962                  errorCode = STATUS_INVALID_HANDLE
   2963              else:
   2964                  # Check if the file was marked for removal
   2965                  if connData['OpenedFiles'][fileID]['DeleteOnClose'] is True:
   2966                      try:
   2967                          if os.path.isdir(pathName):
   2968                              shutil.rmtree(connData['OpenedFiles'][fileID]['FileName'])
   2969                          else:
   2970                              os.remove(connData['OpenedFiles'][fileID]['FileName'])
   2971                      except Exception, e:
   2972                          smbServer.log("SMB2_CLOSE %s" % e, logging.ERROR)
   2973                          errorCode = STATUS_ACCESS_DENIED
   2974 
   2975                  # Now fill out the response
   2976                  if infoRecord is not None:
   2977                      respSMBCommand['CreationTime']   = infoRecord['CreationTime']
   2978                      respSMBCommand['LastAccessTime'] = infoRecord['LastAccessTime']
   2979                      respSMBCommand['LastWriteTime']  = infoRecord['LastWriteTime']
   2980                      respSMBCommand['ChangeTime']     = infoRecord['ChangeTime']
   2981                      respSMBCommand['AllocationSize'] = infoRecord['AllocationSize']
   2982                      respSMBCommand['EndofFile']      = infoRecord['EndOfFile']
   2983                      respSMBCommand['FileAttributes'] = infoRecord['FileAttributes']
   2984                  if errorCode == STATUS_SUCCESS:
   2985                      del(connData['OpenedFiles'][fileID])
   2986         else:
   2987             errorCode = STATUS_INVALID_HANDLE
   2988 
   2989         smbServer.setConnectionData(connId, connData)
   2990         return [respSMBCommand], None, errorCode
   2991 
   2992     @staticmethod
   2993     def smb2QueryInfo(connId, smbServer, recvPacket):
   2994         connData = smbServer.getConnectionData(connId)
   2995 
   2996         respSMBCommand        = smb2.SMB2QueryInfo_Response()
   2997 
   2998         queryInfo = smb2.SMB2QueryInfo(recvPacket['Data'])
   2999 
   3000         errorCode = STATUS_SUCCESS
   3001 
   3002         respSMBCommand['OutputBufferOffset'] = 0x48
   3003         respSMBCommand['Buffer'] = '\x00'
   3004 
   3005         if str(queryInfo['FileID']) == '\xff'*16:
   3006             # Let's take the data from the lastRequest
   3007             if  connData['LastRequest'].has_key('SMB2_CREATE'):
   3008                 fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
   3009             else:
   3010                 fileID = str(queryInfo['FileID'])
   3011         else:
   3012             fileID = str(queryInfo['FileID'])
   3013 
   3014         if connData['ConnectedShares'].has_key(recvPacket['TreeID']):
   3015             if connData['OpenedFiles'].has_key(fileID):
   3016                 fileName = connData['OpenedFiles'][fileID]['FileName']
   3017 
   3018                 if queryInfo['InfoType'] == smb2.SMB2_0_INFO_FILE:
   3019                     if queryInfo['FileInfoClass'] == smb2.SMB2_FILE_INTERNAL_INFO:
   3020                         # No need to call queryFileInformation, we have the data here
   3021                         infoRecord = smb2.FileInternalInformation()
   3022                         infoRecord['IndexNumber'] = fileID
   3023                     else:
   3024                         infoRecord, errorCode = queryFileInformation(os.path.dirname(fileName), os.path.basename(fileName), queryInfo['FileInfoClass'])
   3025                 elif queryInfo['InfoType'] == smb2.SMB2_0_INFO_FILESYSTEM:
   3026                     infoRecord = queryFsInformation(os.path.dirname(fileName), os.path.basename(fileName), queryInfo['FileInfoClass'])
   3027                 elif queryInfo['InfoType'] == smb2.SMB2_0_INFO_SECURITY:
   3028                     # Failing for now, until we support it
   3029                     infoRecord = None
   3030                     errorCode = STATUS_ACCESS_DENIED
   3031                 else:
   3032                     smbServer.log("queryInfo not supported (%x)" %  queryInfo['InfoType'], logging.ERROR)
   3033 
   3034                 if infoRecord is not None:
   3035                     respSMBCommand['OutputBufferLength'] = len(infoRecord)
   3036                     respSMBCommand['Buffer'] = infoRecord
   3037             else:
   3038                 errorCode = STATUS_INVALID_HANDLE
   3039         else:
   3040             errorCode = STATUS_SMB_BAD_TID
   3041 
   3042 
   3043         smbServer.setConnectionData(connId, connData)
   3044         return [respSMBCommand], None, errorCode
   3045 
   3046     @staticmethod
   3047     def smb2SetInfo(connId, smbServer, recvPacket):
   3048         connData = smbServer.getConnectionData(connId)
   3049 
   3050         respSMBCommand        = smb2.SMB2SetInfo_Response()
   3051 
   3052         setInfo = smb2.SMB2SetInfo(recvPacket['Data'])
   3053 
   3054         errorCode = STATUS_SUCCESS
   3055 
   3056         if str(setInfo['FileID']) == '\xff'*16:
   3057             # Let's take the data from the lastRequest
   3058             if  connData['LastRequest'].has_key('SMB2_CREATE'):
   3059                 fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
   3060             else:
   3061                 fileID = str(setInfo['FileID'])
   3062         else:
   3063             fileID = str(setInfo['FileID'])
   3064 
   3065         if connData['ConnectedShares'].has_key(recvPacket['TreeID']):
   3066             path     = connData['ConnectedShares'][recvPacket['TreeID']]['path']
   3067             if connData['OpenedFiles'].has_key(fileID):
   3068                 pathName = connData['OpenedFiles'][fileID]['FileName']
   3069 
   3070                 if setInfo['InfoType'] == smb2.SMB2_0_INFO_FILE:
   3071                     # The file information is being set
   3072                     informationLevel = setInfo['FileInfoClass']
   3073                     if informationLevel == smb2.SMB2_FILE_DISPOSITION_INFO:
   3074                         infoRecord = smb.SMBSetFileDispositionInfo(setInfo['Buffer'])
   3075                         if infoRecord['DeletePending'] > 0:
   3076                            # Mark this file for removal after closed
   3077                            connData['OpenedFiles'][fileID]['DeleteOnClose'] = True
   3078                     elif informationLevel == smb2.SMB2_FILE_BASIC_INFO:
   3079                         infoRecord = smb.SMBSetFileBasicInfo(setInfo['Buffer'])
   3080                         # Creation time won't be set,  the other ones we play with.
   3081                         atime = infoRecord['LastWriteTime']
   3082                         if atime == 0:
   3083                             atime = -1
   3084                         else:
   3085                             atime = getUnixTime(atime)
   3086                         mtime = infoRecord['ChangeTime']
   3087                         if mtime == 0:
   3088                             mtime = -1
   3089                         else:
   3090                             mtime = getUnixTime(mtime)
   3091                         if atime > 0 and mtime > 0:
   3092                             os.utime(pathName,(atime,mtime))
   3093                     elif informationLevel == smb2.SMB2_FILE_END_OF_FILE_INFO:
   3094                         fileHandle = connData['OpenedFiles'][fileID]['FileHandle']
   3095                         infoRecord = smb.SMBSetFileEndOfFileInfo(setInfo['Buffer'])
   3096                         if infoRecord['EndOfFile'] > 0:
   3097                             os.lseek(fileHandle, infoRecord['EndOfFile']-1, 0)
   3098                             os.write(fileHandle, '\x00')
   3099                     elif informationLevel == smb2.SMB2_FILE_RENAME_INFO:
   3100                         renameInfo = smb2.FILE_RENAME_INFORMATION_TYPE_2(setInfo['Buffer'])
   3101                         newPathName = os.path.join(path,renameInfo['FileName'].decode('utf-16le').replace('\\', '/'))
   3102                         if renameInfo['ReplaceIfExists'] == 0 and os.path.exists(newPathName):
   3103                             return [smb2.SMB2Error()], None, STATUS_OBJECT_NAME_COLLISION
   3104                         try:
   3105                              os.rename(pathName,newPathName)
   3106                              connData['OpenedFiles'][fileID]['FileName'] = newPathName
   3107                         except Exception, e:
   3108                              smbServer.log("smb2SetInfo: %s" % e, logging.ERROR)
   3109                              errorCode = STATUS_ACCESS_DENIED
   3110                     else:
   3111                         smbServer.log('Unknown level for set file info! 0x%x' % informationLevel, logging.ERROR)
   3112                         # UNSUPPORTED
   3113                         errorCode =  STATUS_NOT_SUPPORTED
   3114                 #elif setInfo['InfoType'] == smb2.SMB2_0_INFO_FILESYSTEM:
   3115                 #    # The underlying object store information is being set.
   3116                 #    setInfo = queryFsInformation('/', fileName, queryInfo['FileInfoClass'])
   3117                 #elif setInfo['InfoType'] == smb2.SMB2_0_INFO_SECURITY:
   3118                 #    # The security information is being set.
   3119                 #    # Failing for now, until we support it
   3120                 #    infoRecord = None
   3121                 #    errorCode = STATUS_ACCESS_DENIED
   3122                 #elif setInfo['InfoType'] == smb2.SMB2_0_INFO_QUOTA:
   3123                 #    # The underlying object store quota information is being set.
   3124                 #    setInfo = queryFsInformation('/', fileName, queryInfo['FileInfoClass'])
   3125                 else:
   3126                     smbServer.log("setInfo not supported (%x)" %  setInfo['InfoType'], logging.ERROR)
   3127 
   3128             else:
   3129                 errorCode = STATUS_INVALID_HANDLE
   3130         else:
   3131             errorCode = STATUS_SMB_BAD_TID
   3132 
   3133 
   3134         smbServer.setConnectionData(connId, connData)
   3135         return [respSMBCommand], None, errorCode
   3136 
   3137     @staticmethod
   3138     def smb2Write(connId, smbServer, recvPacket):
   3139         connData = smbServer.getConnectionData(connId)
   3140 
   3141         respSMBCommand = smb2.SMB2Write_Response()
   3142         writeRequest   = smb2.SMB2Write(recvPacket['Data'])
   3143 
   3144         respSMBCommand['Buffer'] = '\x00'
   3145 
   3146         if str(writeRequest['FileID']) == '\xff'*16:
   3147             # Let's take the data from the lastRequest
   3148             if  connData['LastRequest'].has_key('SMB2_CREATE'):
   3149                 fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
   3150             else:
   3151                 fileID = str(writeRequest['FileID'])
   3152         else:
   3153             fileID = str(writeRequest['FileID'])
   3154 
   3155         if connData['OpenedFiles'].has_key(fileID):
   3156              fileHandle = connData['OpenedFiles'][fileID]['FileHandle']
   3157              errorCode = STATUS_SUCCESS
   3158              try:
   3159                  if fileHandle != PIPE_FILE_DESCRIPTOR:
   3160                      offset = writeRequest['Offset']
   3161                      # If we're trying to write past the file end we just skip the write call (Vista does this)
   3162                      if os.lseek(fileHandle, 0, 2) >= offset:
   3163                          os.lseek(fileHandle,offset,0)
   3164                          os.write(fileHandle,writeRequest['Buffer'])
   3165                  else:
   3166                      sock = connData['OpenedFiles'][fileID]['Socket']
   3167                      sock.send(writeRequest['Buffer'])
   3168 
   3169                  respSMBCommand['Count']    = writeRequest['Length']
   3170                  respSMBCommand['Remaining']= 0xff
   3171              except Exception, e:
   3172                  smbServer.log('SMB2_WRITE: %s' % e, logging.ERROR)
   3173                  errorCode = STATUS_ACCESS_DENIED
   3174         else:
   3175             errorCode = STATUS_INVALID_HANDLE
   3176 
   3177         smbServer.setConnectionData(connId, connData)
   3178         return [respSMBCommand], None, errorCode
   3179 
   3180     @staticmethod
   3181     def smb2Read(connId, smbServer, recvPacket):
   3182         connData = smbServer.getConnectionData(connId)
   3183 
   3184         respSMBCommand = smb2.SMB2Read_Response()
   3185         readRequest   = smb2.SMB2Read(recvPacket['Data'])
   3186 
   3187         respSMBCommand['Buffer'] = '\x00'
   3188 
   3189         if str(readRequest['FileID']) == '\xff'*16:
   3190             # Let's take the data from the lastRequest
   3191             if  connData['LastRequest'].has_key('SMB2_CREATE'):
   3192                 fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
   3193             else:
   3194                 fileID = str(readRequest['FileID'])
   3195         else:
   3196             fileID = str(readRequest['FileID'])
   3197 
   3198         if connData['OpenedFiles'].has_key(fileID):
   3199              fileHandle = connData['OpenedFiles'][fileID]['FileHandle']
   3200              errorCode = 0
   3201              try:
   3202                  if fileHandle != PIPE_FILE_DESCRIPTOR:
   3203                      offset = readRequest['Offset']
   3204                      os.lseek(fileHandle,offset,0)
   3205                      content = os.read(fileHandle,readRequest['Length'])
   3206                  else:
   3207                      sock = connData['OpenedFiles'][fileID]['Socket']
   3208                      content = sock.recv(readRequest['Length'])
   3209 
   3210                  respSMBCommand['DataOffset']   = 0x50
   3211                  respSMBCommand['DataLength']   = len(content)
   3212                  respSMBCommand['DataRemaining']= 0
   3213                  respSMBCommand['Buffer']       = content
   3214              except Exception, e:
   3215                  smbServer.log('SMB2_READ: %s ' % e, logging.ERROR)
   3216                  errorCode = STATUS_ACCESS_DENIED
   3217         else:
   3218             errorCode = STATUS_INVALID_HANDLE
   3219 
   3220         smbServer.setConnectionData(connId, connData)
   3221         return [respSMBCommand], None, errorCode
   3222 
   3223     @staticmethod
   3224     def smb2Flush(connId, smbServer, recvPacket):
   3225         connData = smbServer.getConnectionData(connId)
   3226 
   3227         respSMBCommand = smb2.SMB2Flush_Response()
   3228         flushRequest   = smb2.SMB2Flush(recvPacket['Data'])
   3229 
   3230         if connData['OpenedFiles'].has_key(str(flushRequest['FileID'])):
   3231              fileHandle = connData['OpenedFiles'][str(flushRequest['FileID'])]['FileHandle']
   3232              errorCode = STATUS_SUCCESS
   3233              try:
   3234                  os.fsync(fileHandle)
   3235              except Exception, e:
   3236                  smbServer.log("SMB2_FLUSH %s" % e, logging.ERROR)
   3237                  errorCode = STATUS_ACCESS_DENIED
   3238         else:
   3239             errorCode = STATUS_INVALID_HANDLE
   3240 
   3241         smbServer.setConnectionData(connId, connData)
   3242         return [respSMBCommand], None, errorCode
   3243 
   3244 
   3245     @staticmethod
   3246     def smb2QueryDirectory(connId, smbServer, recvPacket):
   3247         connData = smbServer.getConnectionData(connId)
   3248         respSMBCommand = smb2.SMB2QueryDirectory_Response()
   3249         queryDirectoryRequest   = smb2.SMB2QueryDirectory(recvPacket['Data'])
   3250 
   3251         respSMBCommand['Buffer'] = '\x00'
   3252 
   3253         # The server MUST locate the tree connection, as specified in section 3.3.5.2.11.
   3254         if connData['ConnectedShares'].has_key(recvPacket['TreeID']) is False:
   3255             return [smb2.SMB2Error()], None, STATUS_NETWORK_NAME_DELETED
   3256 
   3257         # Next, the server MUST locate the open for the directory to be queried
   3258         # If no open is found, the server MUST fail the request with STATUS_FILE_CLOSED
   3259         if str(queryDirectoryRequest['FileID']) == '\xff'*16:
   3260             # Let's take the data from the lastRequest
   3261             if  connData['LastRequest'].has_key('SMB2_CREATE'):
   3262                 fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
   3263             else:
   3264                 fileID = str(queryDirectoryRequest['FileID'])
   3265         else:
   3266             fileID = str(queryDirectoryRequest['FileID'])
   3267 
   3268         if connData['OpenedFiles'].has_key(fileID) is False:
   3269             return [smb2.SMB2Error()], None, STATUS_FILE_CLOSED
   3270 
   3271         # If the open is not an open to a directory, the request MUST be failed
   3272         # with STATUS_INVALID_PARAMETER.
   3273         if os.path.isdir(connData['OpenedFiles'][fileID]['FileName']) is False:
   3274             return [smb2.SMB2Error()], None, STATUS_INVALID_PARAMETER
   3275 
   3276         # If any other information class is specified in the FileInformationClass
   3277         # field of the SMB2 QUERY_DIRECTORY Request, the server MUST fail the
   3278         # operation with STATUS_INVALID_INFO_CLASS.
   3279         if queryDirectoryRequest['FileInformationClass'] not in (
   3280         smb2.FILE_DIRECTORY_INFORMATION, smb2.FILE_FULL_DIRECTORY_INFORMATION, smb2.FILEID_FULL_DIRECTORY_INFORMATION,
   3281         smb2.FILE_BOTH_DIRECTORY_INFORMATION, smb2.FILEID_BOTH_DIRECTORY_INFORMATION, smb2.FILENAMES_INFORMATION):
   3282             return [smb2.SMB2Error()], None, STATUS_INVALID_INFO_CLASS
   3283 
   3284         # If SMB2_REOPEN is set in the Flags field of the SMB2 QUERY_DIRECTORY
   3285         # Request, the server SHOULD<326> set Open.EnumerationLocation to 0
   3286         # and Open.EnumerationSearchPattern to an empty string.
   3287         if queryDirectoryRequest['Flags'] & smb2.SMB2_REOPEN:
   3288             connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] = 0
   3289             connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] = ''
   3290 
   3291         # If SMB2_RESTART_SCANS is set in the Flags field of the SMB2
   3292         # QUERY_DIRECTORY Request, the server MUST set
   3293         # Open.EnumerationLocation to 0.
   3294         if queryDirectoryRequest['Flags'] & smb2.SMB2_RESTART_SCANS:
   3295             connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] = 0
   3296 
   3297         # If Open.EnumerationLocation is 0 and Open.EnumerationSearchPattern
   3298         # is an empty string, then Open.EnumerationSearchPattern MUST be set
   3299         # to the search pattern specified in the SMB2 QUERY_DIRECTORY by
   3300         # FileNameOffset and FileNameLength. If FileNameLength is 0, the server
   3301         # SHOULD<327> set Open.EnumerationSearchPattern as "*" to search all entries.
   3302 
   3303         pattern = queryDirectoryRequest['Buffer'].decode('utf-16le')
   3304         if  connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] == 0 and \
   3305             connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] == '':
   3306             if pattern == '':
   3307                 pattern = '*'
   3308             connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] = pattern
   3309 
   3310         # If SMB2_INDEX_SPECIFIED is set and FileNameLength is not zero,
   3311         # the server MUST set Open.EnumerationSearchPattern to the search pattern
   3312         # specified in the request by FileNameOffset and FileNameLength.
   3313         if queryDirectoryRequest['Flags'] & smb2.SMB2_INDEX_SPECIFIED and \
   3314            queryDirectoryRequest['FileNameLength'] > 0:
   3315             connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] = pattern
   3316 
   3317         pathName = os.path.join(os.path.normpath(connData['OpenedFiles'][fileID]['FileName']),pattern)
   3318         searchResult, searchCount, errorCode = findFirst2(os.path.dirname(pathName),
   3319                   os.path.basename(pathName),
   3320                   queryDirectoryRequest['FileInformationClass'],
   3321                   smb.ATTR_DIRECTORY, isSMB2 = True )
   3322 
   3323         if errorCode != STATUS_SUCCESS:
   3324             return [smb2.SMB2Error()], None, errorCode
   3325 
   3326         if searchCount > 2 and pattern == '*':
   3327             # strip . and ..
   3328             searchCount -= 2
   3329             searchResult = searchResult[2:]
   3330 
   3331         if searchCount == 0 and connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] == 0:
   3332             return [smb2.SMB2Error()], None, STATUS_NO_SUCH_FILE
   3333 
   3334         if  connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] < 0:
   3335             return [smb2.SMB2Error()], None, STATUS_NO_MORE_FILES
   3336 
   3337         totalData = 0
   3338         respData = ''
   3339         for nItem in range(connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'], searchCount):
   3340             connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] += 1
   3341             if queryDirectoryRequest['Flags'] & smb2.SL_RETURN_SINGLE_ENTRY:
   3342                 # If single entry is requested we must clear the NextEntryOffset
   3343                 searchResult[nItem]['NextEntryOffset'] = 0
   3344             data = searchResult[nItem].getData()
   3345             lenData = len(data)
   3346             padLen = (8-(lenData % 8)) %8
   3347 
   3348             if (totalData+lenData) >= queryDirectoryRequest['OutputBufferLength']:
   3349                 connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] -= 1
   3350                 break
   3351             else:
   3352                 respData += data + '\x00'*padLen
   3353                 totalData += lenData + padLen
   3354 
   3355             if queryDirectoryRequest['Flags'] & smb2.SL_RETURN_SINGLE_ENTRY:
   3356                 break
   3357 
   3358         if connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] >= searchCount:
   3359              connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] = -1
   3360 
   3361         respSMBCommand['OutputBufferOffset'] = 0x48
   3362         respSMBCommand['OutputBufferLength'] = totalData
   3363         respSMBCommand['Buffer'] = respData
   3364 
   3365         smbServer.setConnectionData(connId, connData)
   3366         return [respSMBCommand], None, errorCode
   3367 
   3368     @staticmethod
   3369     def smb2ChangeNotify(connId, smbServer, recvPacket):
   3370 
   3371         return [smb2.SMB2Error()], None, STATUS_NOT_SUPPORTED
   3372 
   3373     @staticmethod
   3374     def smb2Echo(connId, smbServer, recvPacket):
   3375 
   3376         respSMBCommand = smb2.SMB2Echo_Response()
   3377 
   3378         return [respSMBCommand], None, STATUS_SUCCESS
   3379 
   3380     @staticmethod
   3381     def smb2TreeDisconnect(connId, smbServer, recvPacket):
   3382         connData = smbServer.getConnectionData(connId)
   3383 
   3384         respSMBCommand = smb2.SMB2TreeDisconnect_Response()
   3385 
   3386         if connData['ConnectedShares'].has_key(recvPacket['TreeID']):
   3387             smbServer.log("Disconnecting Share(%d:%s)" % (recvPacket['TreeID'],connData['ConnectedShares'][recvPacket['TreeID']]['shareName']))
   3388             del(connData['ConnectedShares'][recvPacket['TreeID']])
   3389             errorCode = STATUS_SUCCESS
   3390         else:
   3391             # STATUS_SMB_BAD_TID
   3392             errorCode = STATUS_SMB_BAD_TID
   3393 
   3394 
   3395         smbServer.setConnectionData(connId, connData)
   3396         return [respSMBCommand], None, errorCode
   3397 
   3398     @staticmethod
   3399     def smb2Logoff(connId, smbServer, recvPacket):
   3400         connData = smbServer.getConnectionData(connId)
   3401 
   3402         respSMBCommand = smb2.SMB2Logoff_Response()
   3403 
   3404         if recvPacket['SessionID'] != connData['Uid']:
   3405             # STATUS_SMB_BAD_UID
   3406             errorCode = STATUS_SMB_BAD_UID
   3407         else:
   3408             errorCode = STATUS_SUCCESS
   3409 
   3410         connData['Uid'] = 0
   3411 
   3412         smbServer.setConnectionData(connId, connData)
   3413         return [respSMBCommand], None, errorCode
   3414 
   3415     @staticmethod
   3416     def smb2Ioctl(connId, smbServer, recvPacket):
   3417         connData = smbServer.getConnectionData(connId)
   3418 
   3419         respSMBCommand = smb2.SMB2Ioctl_Response()
   3420         ioctlRequest   = smb2.SMB2Ioctl(recvPacket['Data'])
   3421 
   3422         ioctls = smbServer.getIoctls()
   3423         if ioctls.has_key(ioctlRequest['CtlCode']):
   3424             outputData, errorCode = ioctls[ioctlRequest['CtlCode']](connId, smbServer, ioctlRequest)
   3425             if errorCode == STATUS_SUCCESS:
   3426                 respSMBCommand['CtlCode']      = ioctlRequest['CtlCode']
   3427                 respSMBCommand['FileID']       = ioctlRequest['FileID']
   3428                 respSMBCommand['InputOffset']  = 0
   3429                 respSMBCommand['InputCount']   = 0
   3430                 respSMBCommand['OutputOffset'] = 0x70
   3431                 respSMBCommand['OutputCount']  = len(outputData)
   3432                 respSMBCommand['Flags']        = 0
   3433                 respSMBCommand['Buffer']       = outputData
   3434             else:
   3435                 respSMBCommand = outputData
   3436         else:
   3437             smbServer.log("Ioctl not implemented command: 0x%x" % ioctlRequest['CtlCode'],logging.DEBUG)
   3438             errorCode = STATUS_INVALID_DEVICE_REQUEST
   3439             respSMBCommand = smb2.SMB2Error()
   3440 
   3441         smbServer.setConnectionData(connId, connData)
   3442         return [respSMBCommand], None, errorCode
   3443 
   3444     @staticmethod
   3445     def smb2Lock(connId, smbServer, recvPacket):
   3446         connData = smbServer.getConnectionData(connId)
   3447 
   3448         respSMBCommand = smb2.SMB2Lock_Response()
   3449 
   3450         # I'm actually doing nothing.. just make MacOS happy ;)
   3451         errorCode = STATUS_SUCCESS
   3452 
   3453         smbServer.setConnectionData(connId, connData)
   3454         return [respSMBCommand], None, errorCode
   3455 
   3456     @staticmethod
   3457     def smb2Cancel(connId, smbServer, recvPacket):
   3458         # I'm actually doing nothing
   3459         return [smb2.SMB2Error()], None, STATUS_CANCELLED
   3460 
   3461     @staticmethod
   3462     def default(connId, smbServer, recvPacket):
   3463         # By default we return an SMB Packet with error not implemented
   3464         smbServer.log("Not implemented command: 0x%x" % recvPacket['Command'],logging.DEBUG)
   3465         return [smb2.SMB2Error()], None, STATUS_NOT_SUPPORTED
   3466 
   3467 class Ioctls:
   3468    @staticmethod
   3469    def fsctlDfsGetReferrals(connId, smbServer, ioctlRequest):
   3470         return smb2.SMB2Error(), STATUS_FS_DRIVER_REQUIRED
   3471 
   3472    @staticmethod
   3473    def fsctlPipeTransceive(connId, smbServer, ioctlRequest):
   3474         connData = smbServer.getConnectionData(connId)
   3475 
   3476         ioctlResponse = ''
   3477 
   3478         if connData['OpenedFiles'].has_key(str(ioctlRequest['FileID'])):
   3479              fileHandle = connData['OpenedFiles'][str(ioctlRequest['FileID'])]['FileHandle']
   3480              errorCode = STATUS_SUCCESS
   3481              try:
   3482                  if fileHandle != PIPE_FILE_DESCRIPTOR:
   3483                      errorCode = STATUS_INVALID_DEVICE_REQUEST
   3484                  else:
   3485                      sock = connData['OpenedFiles'][str(ioctlRequest['FileID'])]['Socket']
   3486                      sock.sendall(ioctlRequest['Buffer'])
   3487                      ioctlResponse = sock.recv(ioctlRequest['MaxOutputResponse'])
   3488              except Exception, e:
   3489                  smbServer.log('fsctlPipeTransceive: %s ' % e, logging.ERROR)
   3490                  errorCode = STATUS_ACCESS_DENIED
   3491         else:
   3492             errorCode = STATUS_INVALID_DEVICE_REQUEST
   3493 
   3494         smbServer.setConnectionData(connId, connData)
   3495         return ioctlResponse, errorCode
   3496 
   3497    @staticmethod
   3498    def fsctlValidateNegotiateInfo(connId, smbServer, ioctlRequest):
   3499         connData = smbServer.getConnectionData(connId)
   3500 
   3501         errorCode = STATUS_SUCCESS
   3502 
   3503         validateNegotiateInfo = smb2.VALIDATE_NEGOTIATE_INFO(ioctlRequest['Buffer'])
   3504         validateNegotiateInfo['Capabilities'] = 0
   3505         validateNegotiateInfo['Guid'] = 'A'*16
   3506         validateNegotiateInfo['SecurityMode'] = 1
   3507         validateNegotiateInfo['Dialects'] = (smb2.SMB2_DIALECT_002,)
   3508 
   3509         smbServer.setConnectionData(connId, connData)
   3510         return validateNegotiateInfo.getData(), errorCode
   3511 
   3512 
   3513 class SMBSERVERHandler(SocketServer.BaseRequestHandler):
   3514     def __init__(self, request, client_address, server, select_poll = False):
   3515         self.__SMB = server
   3516         self.__ip, self.__port = client_address
   3517         self.__request = request
   3518         self.__connId = threading.currentThread().getName()
   3519         self.__timeOut = 60*5
   3520         self.__select_poll = select_poll
   3521         #self.__connId = os.getpid()
   3522         SocketServer.BaseRequestHandler.__init__(self, request, client_address, server)
   3523 
   3524     def handle(self):
   3525         self.__SMB.log("Incoming connection (%s,%d)" % (self.__ip, self.__port))
   3526         self.__SMB.addConnection(self.__connId, self.__ip, self.__port)
   3527         while True:
   3528             try:
   3529                 # Firt of all let's get the NETBIOS packet
   3530                 session = nmb.NetBIOSTCPSession(self.__SMB.getServerName(),'HOST', self.__ip, sess_port = self.__port, sock = self.__request, select_poll = self.__select_poll)
   3531                 try:
   3532                     p = session.recv_packet(self.__timeOut)
   3533                 except nmb.NetBIOSTimeout:
   3534                     raise
   3535                 except nmb.NetBIOSError:
   3536                     break
   3537 
   3538                 if p.get_type() == nmb.NETBIOS_SESSION_REQUEST:
   3539                    # Someone is requesting a session, we're gonna accept them all :)
   3540                    _, rn, my = p.get_trailer().split(' ')
   3541                    remote_name = nmb.decode_name('\x20'+rn)
   3542                    myname = nmb.decode_name('\x20'+my)
   3543                    self.__SMB.log("NetBIOS Session request (%s,%s,%s)" % (self.__ip, remote_name[1].strip(), myname[1]))
   3544                    r = nmb.NetBIOSSessionPacket()
   3545                    r.set_type(nmb.NETBIOS_SESSION_POSITIVE_RESPONSE)
   3546                    r.set_trailer(p.get_trailer())
   3547                    self.__request.send(r.rawData())
   3548                 else:
   3549                    resp = self.__SMB.processRequest(self.__connId, p.get_trailer())
   3550                    # Send all the packets recevied. Except for big transactions this should be
   3551                    # a single packet
   3552                    for i in resp:
   3553                        session.send_packet(str(i))
   3554             except Exception, e:
   3555                 self.__SMB.log("Handle: %s" % e)
   3556                 #import traceback
   3557                 #traceback.print_exc()
   3558                 break
   3559 
   3560     def finish(self):
   3561         # Thread/process is dying, we should tell the main SMB thread to remove all this thread data
   3562         self.__SMB.log("Closing down connection (%s,%d)" % (self.__ip, self.__port))
   3563         self.__SMB.removeConnection(self.__connId)
   3564         return SocketServer.BaseRequestHandler.finish(self)
   3565 
   3566 class SMBSERVER(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
   3567 #class SMBSERVER(SocketServer.ForkingMixIn, SocketServer.TCPServer):
   3568     def __init__(self, server_address, handler_class=SMBSERVERHandler, config_parser = None):
   3569         SocketServer.TCPServer.allow_reuse_address = True
   3570         SocketServer.TCPServer.__init__(self, server_address, handler_class)
   3571 
   3572         # Server name and OS to be presented whenever is necessary
   3573         self.__serverName   = ''
   3574         self.__serverOS     = ''
   3575         self.__serverDomain = ''
   3576         self.__challenge    = ''
   3577         self.__log          = None
   3578 
   3579         # Our ConfigParser data
   3580         self.__serverConfig = config_parser
   3581 
   3582         # Our credentials to be used during the server's lifetime
   3583         self.__credentials = {}
   3584 
   3585         # Our log file
   3586         self.__logFile = ''
   3587 
   3588         # Registered Named Pipes, format is PipeName,Socket
   3589         self.__registeredNamedPipes = {}
   3590 
   3591         # JTR dump path
   3592         self.__jtr_dump_path = ''
   3593 
   3594         # SMB2 Support flag = default not active
   3595         self.__SMB2Support = False
   3596 
   3597         # Our list of commands we will answer, by default the NOT IMPLEMENTED one
   3598         self.__smbCommandsHandler = SMBCommands()
   3599         self.__smbTrans2Handler   = TRANS2Commands()
   3600         self.__smbTransHandler    = TRANSCommands()
   3601         self.__smbNTTransHandler  = NTTRANSCommands()
   3602         self.__smb2CommandsHandler = SMB2Commands()
   3603         self.__IoctlHandler       = Ioctls()
   3604 
   3605         self.__smbNTTransCommands = {
   3606         # NT IOCTL, can't find doc for this
   3607         0xff                               :self.__smbNTTransHandler.default
   3608         }
   3609 
   3610         self.__smbTransCommands  = {
   3611 '\\PIPE\\LANMAN'                       :self.__smbTransHandler.lanMan,
   3612 smb.SMB.TRANS_TRANSACT_NMPIPE          :self.__smbTransHandler.transactNamedPipe,
   3613         }
   3614         self.__smbTrans2Commands = {
   3615  smb.SMB.TRANS2_FIND_FIRST2            :self.__smbTrans2Handler.findFirst2,
   3616  smb.SMB.TRANS2_FIND_NEXT2             :self.__smbTrans2Handler.findNext2,
   3617  smb.SMB.TRANS2_QUERY_FS_INFORMATION   :self.__smbTrans2Handler.queryFsInformation,
   3618  smb.SMB.TRANS2_QUERY_PATH_INFORMATION :self.__smbTrans2Handler.queryPathInformation,
   3619  smb.SMB.TRANS2_QUERY_FILE_INFORMATION :self.__smbTrans2Handler.queryFileInformation,
   3620  smb.SMB.TRANS2_SET_FILE_INFORMATION   :self.__smbTrans2Handler.setFileInformation,
   3621  smb.SMB.TRANS2_SET_PATH_INFORMATION   :self.__smbTrans2Handler.setPathInformation
   3622         }
   3623 
   3624         self.__smbCommands = {
   3625  #smb.SMB.SMB_COM_FLUSH:              self.__smbCommandsHandler.smbComFlush,
   3626  smb.SMB.SMB_COM_CREATE_DIRECTORY:   self.__smbCommandsHandler.smbComCreateDirectory,
   3627  smb.SMB.SMB_COM_DELETE_DIRECTORY:   self.__smbCommandsHandler.smbComDeleteDirectory,
   3628  smb.SMB.SMB_COM_RENAME:             self.__smbCommandsHandler.smbComRename,
   3629  smb.SMB.SMB_COM_DELETE:             self.__smbCommandsHandler.smbComDelete,
   3630  smb.SMB.SMB_COM_NEGOTIATE:          self.__smbCommandsHandler.smbComNegotiate,
   3631  smb.SMB.SMB_COM_SESSION_SETUP_ANDX: self.__smbCommandsHandler.smbComSessionSetupAndX,
   3632  smb.SMB.SMB_COM_LOGOFF_ANDX:        self.__smbCommandsHandler.smbComLogOffAndX,
   3633  smb.SMB.SMB_COM_TREE_CONNECT_ANDX:  self.__smbCommandsHandler.smbComTreeConnectAndX,
   3634  smb.SMB.SMB_COM_TREE_DISCONNECT:    self.__smbCommandsHandler.smbComTreeDisconnect,
   3635  smb.SMB.SMB_COM_ECHO:               self.__smbCommandsHandler.smbComEcho,
   3636  smb.SMB.SMB_COM_QUERY_INFORMATION:  self.__smbCommandsHandler.smbQueryInformation,
   3637  smb.SMB.SMB_COM_TRANSACTION2:       self.__smbCommandsHandler.smbTransaction2,
   3638  smb.SMB.SMB_COM_TRANSACTION:        self.__smbCommandsHandler.smbTransaction,
   3639  # Not needed for now
   3640  smb.SMB.SMB_COM_NT_TRANSACT:        self.__smbCommandsHandler.smbNTTransact,
   3641  smb.SMB.SMB_COM_QUERY_INFORMATION_DISK: self.__smbCommandsHandler.smbQueryInformationDisk,
   3642  smb.SMB.SMB_COM_OPEN_ANDX:          self.__smbCommandsHandler.smbComOpenAndX,
   3643  smb.SMB.SMB_COM_QUERY_INFORMATION2: self.__smbCommandsHandler.smbComQueryInformation2,
   3644  smb.SMB.SMB_COM_READ_ANDX:          self.__smbCommandsHandler.smbComReadAndX,
   3645  smb.SMB.SMB_COM_READ:               self.__smbCommandsHandler.smbComRead,
   3646  smb.SMB.SMB_COM_WRITE_ANDX:         self.__smbCommandsHandler.smbComWriteAndX,
   3647  smb.SMB.SMB_COM_WRITE:              self.__smbCommandsHandler.smbComWrite,
   3648  smb.SMB.SMB_COM_CLOSE:              self.__smbCommandsHandler.smbComClose,
   3649  smb.SMB.SMB_COM_LOCKING_ANDX:       self.__smbCommandsHandler.smbComLockingAndX,
   3650  smb.SMB.SMB_COM_NT_CREATE_ANDX:     self.__smbCommandsHandler.smbComNtCreateAndX,
   3651  0xFF:                               self.__smbCommandsHandler.default
   3652 }
   3653 
   3654         self.__smb2Ioctls = {
   3655  smb2.FSCTL_DFS_GET_REFERRALS:            self.__IoctlHandler.fsctlDfsGetReferrals,
   3656 # smb2.FSCTL_PIPE_PEEK:                    self.__IoctlHandler.fsctlPipePeek,
   3657 # smb2.FSCTL_PIPE_WAIT:                    self.__IoctlHandler.fsctlPipeWait,
   3658  smb2.FSCTL_PIPE_TRANSCEIVE:              self.__IoctlHandler.fsctlPipeTransceive,
   3659 # smb2.FSCTL_SRV_COPYCHUNK:                self.__IoctlHandler.fsctlSrvCopyChunk,
   3660 # smb2.FSCTL_SRV_ENUMERATE_SNAPSHOTS:      self.__IoctlHandler.fsctlSrvEnumerateSnapshots,
   3661 # smb2.FSCTL_SRV_REQUEST_RESUME_KEY:       self.__IoctlHandler.fsctlSrvRequestResumeKey,
   3662 # smb2.FSCTL_SRV_READ_HASH:                self.__IoctlHandler.fsctlSrvReadHash,
   3663 # smb2.FSCTL_SRV_COPYCHUNK_WRITE:          self.__IoctlHandler.fsctlSrvCopyChunkWrite,
   3664 # smb2.FSCTL_LMR_REQUEST_RESILIENCY:       self.__IoctlHandler.fsctlLmrRequestResiliency,
   3665 # smb2.FSCTL_QUERY_NETWORK_INTERFACE_INFO: self.__IoctlHandler.fsctlQueryNetworkInterfaceInfo,
   3666 # smb2.FSCTL_SET_REPARSE_POINT:            self.__IoctlHandler.fsctlSetReparsePoint,
   3667 # smb2.FSCTL_DFS_GET_REFERRALS_EX:         self.__IoctlHandler.fsctlDfsGetReferralsEx,
   3668 # smb2.FSCTL_FILE_LEVEL_TRIM:              self.__IoctlHandler.fsctlFileLevelTrim,
   3669  smb2.FSCTL_VALIDATE_NEGOTIATE_INFO:      self.__IoctlHandler.fsctlValidateNegotiateInfo,
   3670 }
   3671 
   3672         self.__smb2Commands = {
   3673  smb2.SMB2_NEGOTIATE:       self.__smb2CommandsHandler.smb2Negotiate,
   3674  smb2.SMB2_SESSION_SETUP:   self.__smb2CommandsHandler.smb2SessionSetup,
   3675  smb2.SMB2_LOGOFF:          self.__smb2CommandsHandler.smb2Logoff,
   3676  smb2.SMB2_TREE_CONNECT:    self.__smb2CommandsHandler.smb2TreeConnect,
   3677  smb2.SMB2_TREE_DISCONNECT: self.__smb2CommandsHandler.smb2TreeDisconnect,
   3678  smb2.SMB2_CREATE:          self.__smb2CommandsHandler.smb2Create,
   3679  smb2.SMB2_CLOSE:           self.__smb2CommandsHandler.smb2Close,
   3680  smb2.SMB2_FLUSH:           self.__smb2CommandsHandler.smb2Flush,
   3681  smb2.SMB2_READ:            self.__smb2CommandsHandler.smb2Read,
   3682  smb2.SMB2_WRITE:           self.__smb2CommandsHandler.smb2Write,
   3683  smb2.SMB2_LOCK:            self.__smb2CommandsHandler.smb2Lock,
   3684  smb2.SMB2_IOCTL:           self.__smb2CommandsHandler.smb2Ioctl,
   3685  smb2.SMB2_CANCEL:          self.__smb2CommandsHandler.smb2Cancel,
   3686  smb2.SMB2_ECHO:            self.__smb2CommandsHandler.smb2Echo,
   3687  smb2.SMB2_QUERY_DIRECTORY: self.__smb2CommandsHandler.smb2QueryDirectory,
   3688  smb2.SMB2_CHANGE_NOTIFY:   self.__smb2CommandsHandler.smb2ChangeNotify,
   3689  smb2.SMB2_QUERY_INFO:      self.__smb2CommandsHandler.smb2QueryInfo,
   3690  smb2.SMB2_SET_INFO:        self.__smb2CommandsHandler.smb2SetInfo,
   3691 # smb2.SMB2_OPLOCK_BREAK:    self.__smb2CommandsHandler.smb2SessionSetup,
   3692  0xFF:                      self.__smb2CommandsHandler.default
   3693 }
   3694 
   3695         # List of active connections
   3696         self.__activeConnections = {}
   3697 
   3698     def getIoctls(self):
   3699         return self.__smb2Ioctls
   3700 
   3701     def getCredentials(self):
   3702         return self.__credentials
   3703 
   3704     def removeConnection(self, name):
   3705         try:
   3706            del(self.__activeConnections[name])
   3707         except:
   3708            pass
   3709         self.log("Remaining connections %s" % self.__activeConnections.keys())
   3710 
   3711     def addConnection(self, name, ip, port):
   3712         self.__activeConnections[name] = {}
   3713         # Let's init with some know stuff we will need to have
   3714         # TODO: Document what's in there
   3715         #print "Current Connections", self.__activeConnections.keys()
   3716         self.__activeConnections[name]['PacketNum']       = 0
   3717         self.__activeConnections[name]['ClientIP']        = ip
   3718         self.__activeConnections[name]['ClientPort']      = port
   3719         self.__activeConnections[name]['Uid']             = 0
   3720         self.__activeConnections[name]['ConnectedShares'] = {}
   3721         self.__activeConnections[name]['OpenedFiles']     = {}
   3722         # SID results for findfirst2
   3723         self.__activeConnections[name]['SIDs']            = {}
   3724         self.__activeConnections[name]['LastRequest']     = {}
   3725 
   3726     def getActiveConnections(self):
   3727         return self.__activeConnections
   3728 
   3729     def setConnectionData(self, connId, data):
   3730         self.__activeConnections[connId] = data
   3731         #print "setConnectionData"
   3732         #print self.__activeConnections
   3733 
   3734     def getConnectionData(self, connId, checkStatus = True):
   3735         conn = self.__activeConnections[connId]
   3736         if checkStatus is True:
   3737             if conn.has_key('Authenticated') is not True:
   3738                 # Can't keep going further
   3739                 raise Exception("User not Authenticated!")
   3740         return conn
   3741 
   3742     def getRegisteredNamedPipes(self):
   3743         return self.__registeredNamedPipes
   3744 
   3745     def registerNamedPipe(self, pipeName, address):
   3746         self.__registeredNamedPipes[unicode(pipeName)] = address
   3747         return True
   3748 
   3749     def unregisterNamedPipe(self, pipeName):
   3750         if self.__registeredNamedPipes.has_key(pipeName):
   3751             del(self.__registeredNamedPipes[unicode(pipeName)])
   3752             return True
   3753         return False
   3754 
   3755     def unregisterTransaction(self, transCommand):
   3756         if self.__smbTransCommands.has_key(transCommand):
   3757            del(self.__smbTransCommands[transCommand])
   3758 
   3759     def hookTransaction(self, transCommand, callback):
   3760         # If you call this function, callback will replace
   3761         # the current Transaction sub command.
   3762         # (don't get confused with the Transaction smbCommand)
   3763         # If the transaction sub command doesn't not exist, it is added
   3764         # If the transaction sub command exists, it returns the original function         # replaced
   3765         #
   3766         # callback MUST be declared as:
   3767         # callback(connId, smbServer, recvPacket, parameters, data, maxDataCount=0)
   3768         #
   3769         # WHERE:
   3770         #
   3771         # connId      : the connection Id, used to grab/update information about
   3772         #               the current connection
   3773         # smbServer   : the SMBServer instance available for you to ask
   3774         #               configuration data
   3775         # recvPacket  : the full SMBPacket that triggered this command
   3776         # parameters  : the transaction parameters
   3777         # data        : the transaction data
   3778         # maxDataCount: the max amount of data that can be transfered agreed
   3779         #               with the client
   3780         #
   3781         # and MUST return:
   3782         # respSetup, respParameters, respData, errorCode
   3783         #
   3784         # WHERE:
   3785         #
   3786         # respSetup: the setup response of the transaction
   3787         # respParameters: the parameters response of the transaction
   3788         # respData: the data reponse of the transaction
   3789         # errorCode: the NT error code
   3790 
   3791         if self.__smbTransCommands.has_key(transCommand):
   3792            originalCommand = self.__smbTransCommands[transCommand]
   3793         else:
   3794            originalCommand = None
   3795 
   3796         self.__smbTransCommands[transCommand] = callback
   3797         return originalCommand
   3798 
   3799     def unregisterTransaction2(self, transCommand):
   3800         if self.__smbTrans2Commands.has_key(transCommand):
   3801            del(self.__smbTrans2Commands[transCommand])
   3802 
   3803     def hookTransaction2(self, transCommand, callback):
   3804         # Here we should add to __smbTrans2Commands
   3805         # Same description as Transaction
   3806         if self.__smbTrans2Commands.has_key(transCommand):
   3807            originalCommand = self.__smbTrans2Commands[transCommand]
   3808         else:
   3809            originalCommand = None
   3810 
   3811         self.__smbTrans2Commands[transCommand] = callback
   3812         return originalCommand
   3813 
   3814     def unregisterNTTransaction(self, transCommand):
   3815         if self.__smbNTTransCommands.has_key(transCommand):
   3816            del(self.__smbNTTransCommands[transCommand])
   3817 
   3818     def hookNTTransaction(self, transCommand, callback):
   3819         # Here we should add to __smbNTTransCommands
   3820         # Same description as Transaction
   3821         if self.__smbNTTransCommands.has_key(transCommand):
   3822            originalCommand = self.__smbNTTransCommands[transCommand]
   3823         else:
   3824            originalCommand = None
   3825 
   3826         self.__smbNTTransCommands[transCommand] = callback
   3827         return originalCommand
   3828 
   3829     def unregisterSmbCommand(self, smbCommand):
   3830         if self.__smbCommands.has_key(smbCommand):
   3831            del(self.__smbCommands[smbCommand])
   3832 
   3833     def hookSmbCommand(self, smbCommand, callback):
   3834         # Here we should add to self.__smbCommands
   3835         # If you call this function, callback will replace
   3836         # the current smbCommand.
   3837         # If smbCommand doesn't not exist, it is added
   3838         # If SMB command exists, it returns the original function replaced
   3839         #
   3840         # callback MUST be declared as:
   3841         # callback(connId, smbServer, SMBCommand, recvPacket)
   3842         #
   3843         # WHERE:
   3844         #
   3845         # connId    : the connection Id, used to grab/update information about
   3846         #             the current connection
   3847         # smbServer : the SMBServer instance available for you to ask
   3848         #             configuration data
   3849         # SMBCommand: the SMBCommand itself, with its data and parameters.
   3850         #             Check smb.py:SMBCommand() for a reference
   3851         # recvPacket: the full SMBPacket that triggered this command
   3852         #
   3853         # and MUST return:
   3854         # <list of respSMBCommands>, <list of packets>, errorCode
   3855         # <list of packets> has higher preference over commands, in case you
   3856         # want to change the whole packet
   3857         # errorCode: the NT error code
   3858         #
   3859         # For SMB_COM_TRANSACTION2, SMB_COM_TRANSACTION and SMB_COM_NT_TRANSACT
   3860         # the callback function is slightly different:
   3861         #
   3862         # callback(connId, smbServer, SMBCommand, recvPacket, transCommands)
   3863         #
   3864         # WHERE:
   3865         #
   3866         # transCommands: a list of transaction subcommands already registered
   3867         #
   3868 
   3869         if self.__smbCommands.has_key(smbCommand):
   3870            originalCommand = self.__smbCommands[smbCommand]
   3871         else:
   3872            originalCommand = None
   3873 
   3874         self.__smbCommands[smbCommand] = callback
   3875         return originalCommand
   3876 
   3877     def unregisterSmb2Command(self, smb2Command):
   3878         if self.__smb2Commands.has_key(smb2Command):
   3879            del(self.__smb2Commands[smb2Command])
   3880 
   3881     def hookSmb2Command(self, smb2Command, callback):
   3882         if self.__smb2Commands.has_key(smb2Command):
   3883            originalCommand = self.__smb2Commands[smb2Command]
   3884         else:
   3885            originalCommand = None
   3886 
   3887         self.__smb2Commands[smb2Command] = callback
   3888         return originalCommand
   3889 
   3890     def log(self, msg, level=logging.INFO):
   3891         self.__log.log(level,msg)
   3892 
   3893     def getServerName(self):
   3894         return self.__serverName
   3895 
   3896     def getServerOS(self):
   3897         return self.__serverOS
   3898 
   3899     def getServerDomain(self):
   3900         return self.__serverDomain
   3901 
   3902     def getSMBChallenge(self):
   3903         return self.__challenge
   3904 
   3905     def getServerConfig(self):
   3906         return self.__serverConfig
   3907 
   3908     def setServerConfig(self, config):
   3909         self.__serverConfig = config
   3910 
   3911     def getJTRdumpPath(self):
   3912         return self.__jtr_dump_path
   3913 
   3914     def verify_request(self, request, client_address):
   3915         # TODO: Control here the max amount of processes we want to launch
   3916         # returning False, closes the connection
   3917         return True
   3918 
   3919     def processRequest(self, connId, data):
   3920 
   3921         # TODO: Process batched commands.
   3922         isSMB2      = False
   3923         SMBCommand  = None
   3924         try:
   3925             packet = smb.NewSMBPacket(data = data)
   3926             SMBCommand  = smb.SMBCommand(packet['Data'][0])
   3927         except:
   3928             # Maybe a SMB2 packet?
   3929             packet = smb2.SMB2Packet(data = data)
   3930             isSMB2 = True
   3931 
   3932         # We might have compound requests
   3933         compoundedPacketsResponse = []
   3934         compoundedPackets         = []
   3935         try:
   3936             # Search out list of implemented commands
   3937             # We provide them with:
   3938             # connId      : representing the data for this specific connection
   3939             # self        : the SMBSERVER if they want to ask data to it
   3940             # SMBCommand  : the SMBCommand they are expecting to process
   3941             # packet      : the received packet itself, in case they need more data than the actual command
   3942             # Only for Transactions
   3943             # transCommand: a list of transaction subcommands
   3944             # We expect to get:
   3945             # respCommands: a list of answers for the commands processed
   3946             # respPacket  : if the commands chose to directly craft packet/s, we use this and not the previous
   3947             #               this MUST be a list
   3948             # errorCode   : self explanatory
   3949             if isSMB2 is False:
   3950                 if packet['Command'] == smb.SMB.SMB_COM_TRANSACTION2:
   3951                     respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
   3952                                   connId,
   3953                                   self,
   3954                                   SMBCommand,
   3955                                   packet,
   3956                                   self.__smbTrans2Commands)
   3957                 elif packet['Command'] == smb.SMB.SMB_COM_NT_TRANSACT:
   3958                     respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
   3959                                   connId,
   3960                                   self,
   3961                                   SMBCommand,
   3962                                   packet,
   3963                                   self.__smbNTTransCommands)
   3964                 elif packet['Command'] == smb.SMB.SMB_COM_TRANSACTION:
   3965                     respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
   3966                                   connId,
   3967                                   self,
   3968                                   SMBCommand,
   3969                                   packet,
   3970                                   self.__smbTransCommands)
   3971                 else:
   3972                     if self.__smbCommands.has_key(packet['Command']):
   3973                        if self.__SMB2Support is True:
   3974                            if packet['Command'] == smb.SMB.SMB_COM_NEGOTIATE:
   3975                                try:
   3976                                    respCommands, respPackets, errorCode = self.__smb2Commands[smb2.SMB2_NEGOTIATE](connId, self, packet, True)
   3977                                    isSMB2 = True
   3978                                except Exception, e:
   3979                                    self.log('SMB2_NEGOTIATE: %s' % e, logging.ERROR)
   3980                                    # If something went wrong, let's fallback to SMB1
   3981                                    respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
   3982                                        connId,
   3983                                        self,
   3984                                        SMBCommand,
   3985                                        packet)
   3986                                    #self.__SMB2Support = False
   3987                                    pass
   3988                            else:
   3989                                respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
   3990                                        connId,
   3991                                        self,
   3992                                        SMBCommand,
   3993                                        packet)
   3994                        else:
   3995                            respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
   3996                                        connId,
   3997                                        self,
   3998                                        SMBCommand,
   3999                                        packet)
   4000                     else:
   4001                        respCommands, respPackets, errorCode = self.__smbCommands[255](connId, self, SMBCommand, packet)
   4002 
   4003                 compoundedPacketsResponse.append((respCommands, respPackets, errorCode))
   4004                 compoundedPackets.append(packet)
   4005 
   4006             else:
   4007                 done = False
   4008                 while not done:
   4009                     if self.__smb2Commands.has_key(packet['Command']):
   4010                        if self.__SMB2Support is True:
   4011                            respCommands, respPackets, errorCode = self.__smb2Commands[packet['Command']](
   4012                                    connId,
   4013                                    self,
   4014                                    packet)
   4015                        else:
   4016                            respCommands, respPackets, errorCode = self.__smb2Commands[255](connId, self, packet)
   4017                     else:
   4018                        respCommands, respPackets, errorCode = self.__smb2Commands[255](connId, self, packet)
   4019                     # Let's store the result for this compounded packet
   4020                     compoundedPacketsResponse.append((respCommands, respPackets, errorCode))
   4021                     compoundedPackets.append(packet)
   4022                     if packet['NextCommand'] != 0:
   4023                         data = data[packet['NextCommand']:]
   4024                         packet = smb2.SMB2Packet(data = data)
   4025                     else:
   4026                         done = True
   4027 
   4028         except Exception, e:
   4029             #import traceback
   4030             #traceback.print_exc()
   4031             # Something wen't wrong, defaulting to Bad user ID
   4032             self.log('processRequest (0x%x,%s)' % (packet['Command'],e), logging.ERROR)
   4033             raise
   4034 
   4035         # We prepare the response packet to commands don't need to bother about that.
   4036         connData    = self.getConnectionData(connId, False)
   4037 
   4038         # Force reconnection loop.. This is just a test.. client will send me back credentials :)
   4039         #connData['PacketNum'] += 1
   4040         #if connData['PacketNum'] == 15:
   4041         #    connData['PacketNum'] = 0
   4042         #    # Something wen't wrong, defaulting to Bad user ID
   4043         #    self.log('Sending BAD USER ID!', logging.ERROR)
   4044         #    #raise
   4045         #    packet['Flags1'] |= smb.SMB.FLAGS1_REPLY
   4046         #    packet['Flags2'] = 0
   4047         #    errorCode = STATUS_SMB_BAD_UID
   4048         #    packet['ErrorCode']   = errorCode >> 16
   4049         #    packet['ErrorClass']  = errorCode & 0xff
   4050         #    return [packet]
   4051 
   4052         self.setConnectionData(connId, connData)
   4053 
   4054         packetsToSend = []
   4055         for packetNum in range(len(compoundedPacketsResponse)):
   4056             respCommands, respPackets, errorCode = compoundedPacketsResponse[packetNum]
   4057             packet = compoundedPackets[packetNum]
   4058             if respPackets is None:
   4059                 for respCommand in respCommands:
   4060                     if isSMB2 is False:
   4061                         respPacket           = smb.NewSMBPacket()
   4062                         respPacket['Flags1'] = smb.SMB.FLAGS1_REPLY
   4063 
   4064                         # TODO this should come from a per session configuration
   4065                         respPacket['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES | packet['Flags2'] & smb.SMB.FLAGS2_UNICODE
   4066                         #respPacket['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES
   4067                         #respPacket['Flags1'] = 0x98
   4068                         #respPacket['Flags2'] = 0xc807
   4069 
   4070 
   4071                         respPacket['Tid']    = packet['Tid']
   4072                         respPacket['Mid']    = packet['Mid']
   4073                         respPacket['Pid']    = packet['Pid']
   4074                         respPacket['Uid']    = connData['Uid']
   4075 
   4076                         respPacket['ErrorCode']   = errorCode >> 16
   4077                         respPacket['_reserved']   = errorCode >> 8 & 0xff
   4078                         respPacket['ErrorClass']  = errorCode & 0xff
   4079                         respPacket.addCommand(respCommand)
   4080 
   4081                         packetsToSend.append(respPacket)
   4082                     else:
   4083                         respPacket = smb2.SMB2Packet()
   4084                         respPacket['Flags']     = smb2.SMB2_FLAGS_SERVER_TO_REDIR
   4085                         if packetNum > 0:
   4086                             respPacket['Flags'] |= smb2.SMB2_FLAGS_RELATED_OPERATIONS
   4087                         respPacket['Status']    = errorCode
   4088                         respPacket['CreditRequestResponse'] = packet['CreditRequestResponse']
   4089                         respPacket['Command']   = packet['Command']
   4090                         respPacket['CreditCharge'] = packet['CreditCharge']
   4091                         #respPacket['CreditCharge'] = 0
   4092                         respPacket['Reserved']  = packet['Reserved']
   4093                         respPacket['SessionID'] = connData['Uid']
   4094                         respPacket['MessageID'] = packet['MessageID']
   4095                         respPacket['TreeID']    = packet['TreeID']
   4096                         respPacket['Data']      = str(respCommand)
   4097                         packetsToSend.append(respPacket)
   4098             else:
   4099                 # The SMBCommand took care of building the packet
   4100                 packetsToSend = respPackets
   4101 
   4102         if isSMB2 is True:
   4103             # Let's build a compound answer
   4104             finalData = ''
   4105             i = 0
   4106             for i in range(len(packetsToSend)-1):
   4107                 packet = packetsToSend[i]
   4108                 # Align to 8-bytes
   4109                 padLen = (8 - (len(packet) % 8) ) % 8
   4110                 packet['NextCommand'] = len(packet) + padLen
   4111                 finalData += str(packet) + padLen*'\x00'
   4112 
   4113             # Last one
   4114             finalData += str(packetsToSend[len(packetsToSend)-1])
   4115             packetsToSend = [finalData]
   4116 
   4117         # We clear the compound requests
   4118         connData['LastRequest'] = {}
   4119 
   4120         return packetsToSend
   4121 
   4122     def processConfigFile(self, configFile = None):
   4123         # TODO: Do a real config parser
   4124         if self.__serverConfig is None:
   4125             if configFile is None:
   4126                 configFile = 'smb.conf'
   4127             self.__serverConfig = ConfigParser.ConfigParser()
   4128             self.__serverConfig.read(configFile)
   4129 
   4130         self.__serverName   = self.__serverConfig.get('global','server_name')
   4131         self.__serverOS     = self.__serverConfig.get('global','server_os')
   4132         self.__serverDomain = self.__serverConfig.get('global','server_domain')
   4133         self.__logFile      = self.__serverConfig.get('global','log_file')
   4134         if self.__serverConfig.has_option('global', 'challenge'):
   4135             self.__challenge    = self.__serverConfig.get('global', 'challenge')
   4136         else:
   4137             self.__challenge    = 'A'*8
   4138 
   4139         if self.__serverConfig.has_option("global", "jtr_dump_path"):
   4140             self.__jtr_dump_path = self.__serverConfig.get("global", "jtr_dump_path")
   4141 
   4142         if self.__serverConfig.has_option("global", "SMB2Support"):
   4143             self.__SMB2Support = self.__serverConfig.getboolean("global","SMB2Support")
   4144         else:
   4145             self.__SMB2Support = False
   4146 
   4147         if self.__logFile != 'None':
   4148             logging.basicConfig(filename = self.__logFile,
   4149                              level = logging.DEBUG,
   4150                              format="%(asctime)s: %(levelname)s: %(message)s",
   4151                              datefmt = '%m/%d/%Y %I:%M:%S %p')
   4152         self.__log        = LOG
   4153 
   4154         # Process the credentials
   4155         credentials_fname = self.__serverConfig.get('global','credentials_file')
   4156         if credentials_fname is not "":
   4157             cred = open(credentials_fname)
   4158             line = cred.readline()
   4159             while line:
   4160                 name, domain, lmhash, nthash = line.split(':')
   4161                 self.__credentials[name] = (domain, lmhash, nthash.strip('\r\n'))
   4162                 line = cred.readline()
   4163             cred.close()
   4164         self.log('Config file parsed')
   4165 
   4166 # For windows platforms, opening a directory is not an option, so we set a void FD
   4167 VOID_FILE_DESCRIPTOR = -1
   4168 PIPE_FILE_DESCRIPTOR = -2
   4169