Imported Upstream version 7.59.0
[platform/upstream/curl.git] / tests / python_dependencies / impacket / smbserver.py
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