• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
23from __future__ import with_statement
24import calendar
25import socket
26import time
27import datetime
28import struct
29import ConfigParser
30import SocketServer
31import threading
32import logging
33import logging.config
34import ntpath
35import os
36import fnmatch
37import errno
38import sys
39import random
40import shutil
41from binascii import hexlify
42
43# For signing
44from impacket import smb, nmb, ntlm, uuid, LOG
45from impacket import smb3structs as smb2
46from impacket.spnego import SPNEGO_NegTokenInit, TypesMech, MechTypes, SPNEGO_NegTokenResp, ASN1_AID, ASN1_SUPPORTED_MECH
47from 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
54STATUS_SMB_BAD_UID = 0x005B0002
55STATUS_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
63def 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
89def 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
101def decodeSMBString( flags, text ):
102    if flags & smb.SMB.FLAGS2_UNICODE:
103        return text.decode('utf-16le')
104    else:
105        return text
106
107def encodeSMBString( flags, text ):
108    if flags & smb.SMB.FLAGS2_UNICODE:
109        return (text).encode('utf-16le')
110    else:
111        return text
112
113def getFileTime(t):
114    t *= 10000000
115    t += 116444736000000000
116    return t
117
118def getUnixTime(t):
119    t -= 116444736000000000
120    t /= 10000000
121    return t
122
123def 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
130def getSMBTime(t):
131    # TODO: Fix this :P
132    d = datetime.datetime.fromtimestamp(t)
133    return (d.hour << 8) + (d.minute << 4) + d.second
134
135def 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
145def 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
152def 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
193def 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
244def 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
369def queryFileInformation(path, filename, level):
370    #print "queryFileInfo path: %s, filename: %s, level:0x%x" % (path,filename,level)
371    return queryPathInformation(path,filename, level)
372
373def 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
449def 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
457class NTTRANSCommands:
458    def default(self, connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
459        pass
460
461# Here we implement the NT transaction handlers
462class 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
558class 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
841class 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
2497class 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
3467class 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
3513class 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
3566class 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,
3612smb.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
4167VOID_FILE_DESCRIPTOR = -1
4168PIPE_FILE_DESCRIPTOR = -2
4169