Files correlati : utilma verione di curl git-svn-id: svn://10.65.10.50/branches/R_10_00@24159 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			4169 lines
		
	
	
		
			190 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			4169 lines
		
	
	
		
			190 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
# Copyright (c) 2003-2016 CORE Security Technologies
 | 
						|
#
 | 
						|
# This software is provided under under a slightly modified version
 | 
						|
# of the Apache Software License. See the accompanying LICENSE file
 | 
						|
# for more information.
 | 
						|
#
 | 
						|
# Author: Alberto Solino (@agsolino)
 | 
						|
#
 | 
						|
# TODO:
 | 
						|
# [-] Functions should return NT error codes
 | 
						|
# [-] Handling errors in all situations, right now it's just raising exceptions.
 | 
						|
# [*] Standard authentication support
 | 
						|
# [ ] Organize the connectionData stuff
 | 
						|
# [*] Add capability to send a bad user ID if the user is not authenticated,
 | 
						|
#     right now you can ask for any command without actually being authenticated
 | 
						|
# [ ] PATH TRAVERSALS EVERYWHERE.. BE WARNED!
 | 
						|
# [ ] Check the credentials.. now we're just letting everybody to log in.
 | 
						|
# [ ] Check error situation (now many places assume the right data is coming)
 | 
						|
# [ ] Implement IPC to the main process so the connectionData is on a single place
 | 
						|
# [ ] Hence.. implement locking
 | 
						|
# estamos en la B
 | 
						|
 | 
						|
from __future__ import with_statement
 | 
						|
import calendar
 | 
						|
import socket
 | 
						|
import time
 | 
						|
import datetime
 | 
						|
import struct
 | 
						|
import ConfigParser
 | 
						|
import SocketServer
 | 
						|
import threading
 | 
						|
import logging
 | 
						|
import logging.config
 | 
						|
import ntpath
 | 
						|
import os
 | 
						|
import fnmatch
 | 
						|
import errno
 | 
						|
import sys
 | 
						|
import random
 | 
						|
import shutil
 | 
						|
from binascii import hexlify
 | 
						|
 | 
						|
# For signing
 | 
						|
from impacket import smb, nmb, ntlm, uuid, LOG
 | 
						|
from impacket import smb3structs as smb2
 | 
						|
from impacket.spnego import SPNEGO_NegTokenInit, TypesMech, MechTypes, SPNEGO_NegTokenResp, ASN1_AID, ASN1_SUPPORTED_MECH
 | 
						|
from impacket.nt_errors import STATUS_NO_MORE_FILES, STATUS_NETWORK_NAME_DELETED, STATUS_INVALID_PARAMETER, \
 | 
						|
    STATUS_FILE_CLOSED, STATUS_MORE_PROCESSING_REQUIRED, STATUS_OBJECT_PATH_NOT_FOUND, STATUS_DIRECTORY_NOT_EMPTY, \
 | 
						|
    STATUS_FILE_IS_A_DIRECTORY, STATUS_NOT_IMPLEMENTED, STATUS_INVALID_HANDLE, STATUS_OBJECT_NAME_COLLISION, \
 | 
						|
    STATUS_NO_SUCH_FILE, STATUS_CANCELLED, STATUS_OBJECT_NAME_NOT_FOUND, STATUS_SUCCESS, STATUS_ACCESS_DENIED, \
 | 
						|
    STATUS_NOT_SUPPORTED, STATUS_INVALID_DEVICE_REQUEST, STATUS_FS_DRIVER_REQUIRED, STATUS_INVALID_INFO_CLASS
 | 
						|
 | 
						|
# These ones not defined in nt_errors
 | 
						|
STATUS_SMB_BAD_UID = 0x005B0002
 | 
						|
STATUS_SMB_BAD_TID = 0x00050002
 | 
						|
 | 
						|
# Utility functions
 | 
						|
# and general functions.
 | 
						|
# There are some common functions that can be accessed from more than one SMB
 | 
						|
# command (or either TRANSACTION). That's why I'm putting them here
 | 
						|
# TODO: Return NT ERROR Codes
 | 
						|
 | 
						|
def outputToJohnFormat(challenge, username, domain, lmresponse, ntresponse):
 | 
						|
# We don't want to add a possible failure here, since this is an
 | 
						|
# extra bonus. We try, if it fails, returns nothing
 | 
						|
    ret_value = ''
 | 
						|
    try:
 | 
						|
        if len(ntresponse) > 24:
 | 
						|
            # Extended Security - NTLMv2
 | 
						|
            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'}
 | 
						|
        else:
 | 
						|
            # NTLMv1
 | 
						|
            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'}
 | 
						|
    except:
 | 
						|
        # Let's try w/o decoding Unicode
 | 
						|
        try:
 | 
						|
            if len(ntresponse) > 24:
 | 
						|
                # Extended Security - NTLMv2
 | 
						|
                ret_value = {'hash_string':'%s::%s:%s:%s:%s' % (username, domain, hexlify(challenge), hexlify(ntresponse)[:32], hexlify(ntresponse)[32:]), 'hash_version':'ntlmv2'}
 | 
						|
            else:
 | 
						|
                # NTLMv1
 | 
						|
                ret_value = {'hash_string':'%s::%s:%s:%s:%s' % (username, domain, hexlify(lmresponse), hexlify(ntresponse), hexlify(challenge)), 'hash_version':'ntlm'}
 | 
						|
        except Exception, e:
 | 
						|
            LOG.error("outputToJohnFormat: %s" % e)
 | 
						|
            pass
 | 
						|
 | 
						|
    return ret_value
 | 
						|
 | 
						|
def writeJohnOutputToFile(hash_string, hash_version, file_name):
 | 
						|
    fn_data = os.path.splitext(file_name)
 | 
						|
    if hash_version == "ntlmv2":
 | 
						|
        output_filename = fn_data[0] + "_ntlmv2" + fn_data[1]
 | 
						|
    else:
 | 
						|
        output_filename = fn_data[0] + "_ntlm" + fn_data[1]
 | 
						|
 | 
						|
    with open(output_filename,"a") as f:
 | 
						|
            f.write(hash_string)
 | 
						|
            f.write('\n')
 | 
						|
 | 
						|
 | 
						|
def decodeSMBString( flags, text ):
 | 
						|
    if flags & smb.SMB.FLAGS2_UNICODE:
 | 
						|
        return text.decode('utf-16le')
 | 
						|
    else:
 | 
						|
        return text
 | 
						|
 | 
						|
def encodeSMBString( flags, text ):
 | 
						|
    if flags & smb.SMB.FLAGS2_UNICODE:
 | 
						|
        return (text).encode('utf-16le')
 | 
						|
    else:
 | 
						|
        return text
 | 
						|
 | 
						|
def getFileTime(t):
 | 
						|
    t *= 10000000
 | 
						|
    t += 116444736000000000
 | 
						|
    return t
 | 
						|
 | 
						|
def getUnixTime(t):
 | 
						|
    t -= 116444736000000000
 | 
						|
    t /= 10000000
 | 
						|
    return t
 | 
						|
 | 
						|
def getSMBDate(t):
 | 
						|
    # TODO: Fix this :P
 | 
						|
    d = datetime.date.fromtimestamp(t)
 | 
						|
    year = d.year - 1980
 | 
						|
    ret = (year << 8) + (d.month << 4) + d.day
 | 
						|
    return ret
 | 
						|
 | 
						|
def getSMBTime(t):
 | 
						|
    # TODO: Fix this :P
 | 
						|
    d = datetime.datetime.fromtimestamp(t)
 | 
						|
    return (d.hour << 8) + (d.minute << 4) + d.second
 | 
						|
 | 
						|
def getShares(connId, smbServer):
 | 
						|
    config = smbServer.getServerConfig()
 | 
						|
    sections = config.sections()
 | 
						|
    # Remove the global one
 | 
						|
    del(sections[sections.index('global')])
 | 
						|
    shares = {}
 | 
						|
    for i in sections:
 | 
						|
        shares[i] = dict(config.items(i))
 | 
						|
    return shares
 | 
						|
 | 
						|
def searchShare(connId, share, smbServer):
 | 
						|
    config = smbServer.getServerConfig()
 | 
						|
    if config.has_section(share):
 | 
						|
       return dict(config.items(share))
 | 
						|
    else:
 | 
						|
       return None
 | 
						|
 | 
						|
def openFile(path,fileName, accessMode, fileAttributes, openMode):
 | 
						|
    fileName = os.path.normpath(fileName.replace('\\','/'))
 | 
						|
    errorCode = 0
 | 
						|
    if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
 | 
						|
       # strip leading '/'
 | 
						|
       fileName = fileName[1:]
 | 
						|
    pathName = os.path.join(path,fileName)
 | 
						|
    mode = 0
 | 
						|
    # Check the Open Mode
 | 
						|
    if openMode & 0x10:
 | 
						|
        # If the file does not exist, create it.
 | 
						|
        mode = os.O_CREAT
 | 
						|
    else:
 | 
						|
        # If file does not exist, return an error
 | 
						|
        if os.path.exists(pathName) is not True:
 | 
						|
            errorCode = STATUS_NO_SUCH_FILE
 | 
						|
            return 0,mode, pathName, errorCode
 | 
						|
 | 
						|
    if os.path.isdir(pathName) and (fileAttributes & smb.ATTR_DIRECTORY) == 0:
 | 
						|
        # Request to open a normal file and this is actually a directory
 | 
						|
            errorCode = STATUS_FILE_IS_A_DIRECTORY
 | 
						|
            return 0, mode, pathName, errorCode
 | 
						|
    # Check the Access Mode
 | 
						|
    if accessMode & 0x7 == 1:
 | 
						|
       mode |= os.O_WRONLY
 | 
						|
    elif accessMode & 0x7 == 2:
 | 
						|
       mode |= os.O_RDWR
 | 
						|
    else:
 | 
						|
       mode = os.O_RDONLY
 | 
						|
 | 
						|
    try:
 | 
						|
        if sys.platform == 'win32':
 | 
						|
            mode |= os.O_BINARY
 | 
						|
        fid = os.open(pathName, mode)
 | 
						|
    except Exception, e:
 | 
						|
        LOG.error("openFile: %s,%s" % (pathName, mode) ,e)
 | 
						|
        fid = 0
 | 
						|
        errorCode = STATUS_ACCESS_DENIED
 | 
						|
 | 
						|
    return fid, mode, pathName, errorCode
 | 
						|
 | 
						|
def queryFsInformation(path, filename, level=0):
 | 
						|
 | 
						|
    if isinstance(filename,unicode):
 | 
						|
         encoding = 'utf-16le'
 | 
						|
         flags    = smb.SMB.FLAGS2_UNICODE
 | 
						|
    else:
 | 
						|
         encoding = 'ascii'
 | 
						|
         flags    = 0
 | 
						|
 | 
						|
    fileName = os.path.normpath(filename.replace('\\','/'))
 | 
						|
    if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
 | 
						|
       # strip leading '/'
 | 
						|
       fileName = fileName[1:]
 | 
						|
    pathName = os.path.join(path,fileName)
 | 
						|
    fileSize = os.path.getsize(pathName)
 | 
						|
    (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(pathName)
 | 
						|
    if level == smb.SMB_QUERY_FS_ATTRIBUTE_INFO or level == smb2.SMB2_FILESYSTEM_ATTRIBUTE_INFO:
 | 
						|
        data = smb.SMBQueryFsAttributeInfo()
 | 
						|
        data['FileSystemAttributes']      = smb.FILE_CASE_SENSITIVE_SEARCH | smb.FILE_CASE_PRESERVED_NAMES
 | 
						|
        data['MaxFilenNameLengthInBytes'] = 255
 | 
						|
        data['LengthOfFileSystemName']    = len('XTFS')*2
 | 
						|
        data['FileSystemName']            = 'XTFS'.encode('utf-16le')
 | 
						|
        return data.getData()
 | 
						|
    elif level == smb.SMB_INFO_VOLUME:
 | 
						|
        data = smb.SMBQueryFsInfoVolume( flags = flags )
 | 
						|
        data['VolumeLabel']               = 'SHARE'.encode(encoding)
 | 
						|
        return data.getData()
 | 
						|
    elif level == smb.SMB_QUERY_FS_VOLUME_INFO or level == smb2.SMB2_FILESYSTEM_VOLUME_INFO:
 | 
						|
        data = smb.SMBQueryFsVolumeInfo()
 | 
						|
        data['VolumeLabel']               = ''
 | 
						|
        data['VolumeCreationTime']        = getFileTime(ctime)
 | 
						|
        return data.getData()
 | 
						|
    elif level == smb.SMB_QUERY_FS_SIZE_INFO:
 | 
						|
        data = smb.SMBQueryFsSizeInfo()
 | 
						|
        return data.getData()
 | 
						|
    elif level == smb.FILE_FS_FULL_SIZE_INFORMATION:
 | 
						|
        data = smb.SMBFileFsFullSizeInformation()
 | 
						|
        return data.getData()
 | 
						|
    elif level == smb.FILE_FS_SIZE_INFORMATION:
 | 
						|
        data = smb.FileFsSizeInformation()
 | 
						|
        return data.getData()
 | 
						|
    else:
 | 
						|
        lastWriteTime = mtime
 | 
						|
        attribs = 0
 | 
						|
        if os.path.isdir(pathName):
 | 
						|
            attribs |= smb.SMB_FILE_ATTRIBUTE_DIRECTORY
 | 
						|
        if os.path.isfile(pathName):
 | 
						|
            attribs |= smb.SMB_FILE_ATTRIBUTE_NORMAL
 | 
						|
        fileAttributes = attribs
 | 
						|
        return fileSize, lastWriteTime, fileAttributes
 | 
						|
 | 
						|
def findFirst2(path, fileName, level, searchAttributes, isSMB2 = False):
 | 
						|
     # TODO: Depending on the level, this could be done much simpler
 | 
						|
 | 
						|
     #print "FindFirs2 path:%s, filename:%s" % (path, fileName)
 | 
						|
     fileName = os.path.normpath(fileName.replace('\\','/'))
 | 
						|
     # Let's choose the right encoding depending on the request
 | 
						|
     if isinstance(fileName,unicode):
 | 
						|
         encoding = 'utf-16le'
 | 
						|
         flags    = smb.SMB.FLAGS2_UNICODE
 | 
						|
     else:
 | 
						|
         encoding = 'ascii'
 | 
						|
         flags    = 0
 | 
						|
 | 
						|
     if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
 | 
						|
        # strip leading '/'
 | 
						|
        fileName = fileName[1:]
 | 
						|
 | 
						|
     pathName = os.path.join(path,fileName)
 | 
						|
     files = []
 | 
						|
 | 
						|
     if pathName.find('*') == -1 and pathName.find('?') == -1:
 | 
						|
         # No search patterns
 | 
						|
         pattern = ''
 | 
						|
     else:
 | 
						|
         pattern = os.path.basename(pathName)
 | 
						|
         dirName = os.path.dirname(pathName)
 | 
						|
 | 
						|
     # Always add . and .. Not that important for Windows, but Samba whines if
 | 
						|
     # not present (for * search only)
 | 
						|
     if pattern == '*':
 | 
						|
         files.append(os.path.join(dirName,'.'))
 | 
						|
         files.append(os.path.join(dirName,'..'))
 | 
						|
 | 
						|
     if pattern != '':
 | 
						|
         for file in os.listdir(dirName):
 | 
						|
             if fnmatch.fnmatch(file.lower(),pattern.lower()):
 | 
						|
                entry = os.path.join(dirName, file)
 | 
						|
                if os.path.isdir(entry):
 | 
						|
                    if searchAttributes & smb.ATTR_DIRECTORY:
 | 
						|
                        files.append(entry)
 | 
						|
                else:
 | 
						|
                    files.append(entry)
 | 
						|
     else:
 | 
						|
         if os.path.exists(pathName):
 | 
						|
             files.append(pathName)
 | 
						|
 | 
						|
     searchResult = []
 | 
						|
     searchCount = len(files)
 | 
						|
     errorCode = STATUS_SUCCESS
 | 
						|
 | 
						|
     for i in files:
 | 
						|
        if level == smb.SMB_FIND_FILE_BOTH_DIRECTORY_INFO or level == smb2.SMB2_FILE_BOTH_DIRECTORY_INFO:
 | 
						|
            item = smb.SMBFindFileBothDirectoryInfo( flags = flags )
 | 
						|
        elif level == smb.SMB_FIND_FILE_DIRECTORY_INFO or level == smb2.SMB2_FILE_DIRECTORY_INFO:
 | 
						|
            item = smb.SMBFindFileDirectoryInfo( flags = flags )
 | 
						|
        elif level == smb.SMB_FIND_FILE_FULL_DIRECTORY_INFO or level == smb2.SMB2_FULL_DIRECTORY_INFO:
 | 
						|
            item = smb.SMBFindFileFullDirectoryInfo( flags = flags )
 | 
						|
        elif level == smb.SMB_FIND_INFO_STANDARD:
 | 
						|
            item = smb.SMBFindInfoStandard( flags = flags )
 | 
						|
        elif level == smb.SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO or level == smb2.SMB2_FILE_ID_FULL_DIRECTORY_INFO:
 | 
						|
            item = smb.SMBFindFileIdFullDirectoryInfo( flags = flags )
 | 
						|
        elif level == smb.SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO or level == smb2.SMB2_FILE_ID_BOTH_DIRECTORY_INFO:
 | 
						|
            item = smb.SMBFindFileIdBothDirectoryInfo( flags = flags )
 | 
						|
        elif level == smb.SMB_FIND_FILE_NAMES_INFO or level == smb2.SMB2_FILE_NAMES_INFO:
 | 
						|
            item = smb.SMBFindFileNamesInfo( flags = flags )
 | 
						|
        else:
 | 
						|
            LOG.error("Wrong level %d!" % level)
 | 
						|
            return  searchResult, searchCount, STATUS_NOT_SUPPORTED
 | 
						|
 | 
						|
        (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(i)
 | 
						|
        if os.path.isdir(i):
 | 
						|
           item['ExtFileAttributes'] = smb.ATTR_DIRECTORY
 | 
						|
        else:
 | 
						|
           item['ExtFileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE
 | 
						|
 | 
						|
        item['FileName'] = os.path.basename(i).encode(encoding)
 | 
						|
 | 
						|
        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:
 | 
						|
           item['EaSize']            = 0
 | 
						|
           item['EndOfFile']         = size
 | 
						|
           item['AllocationSize']    = size
 | 
						|
           item['CreationTime']      = getFileTime(ctime)
 | 
						|
           item['LastAccessTime']    = getFileTime(atime)
 | 
						|
           item['LastWriteTime']     = getFileTime(mtime)
 | 
						|
           item['LastChangeTime']    = getFileTime(mtime)
 | 
						|
           item['ShortName']         = '\x00'*24
 | 
						|
           item['FileName']          = os.path.basename(i).encode(encoding)
 | 
						|
           padLen = (8-(len(item) % 8)) % 8
 | 
						|
           item['NextEntryOffset']   = len(item) + padLen
 | 
						|
        elif level == smb.SMB_FIND_FILE_DIRECTORY_INFO:
 | 
						|
           item['EndOfFile']         = size
 | 
						|
           item['AllocationSize']    = size
 | 
						|
           item['CreationTime']      = getFileTime(ctime)
 | 
						|
           item['LastAccessTime']    = getFileTime(atime)
 | 
						|
           item['LastWriteTime']     = getFileTime(mtime)
 | 
						|
           item['LastChangeTime']    = getFileTime(mtime)
 | 
						|
           item['FileName']          = os.path.basename(i).encode(encoding)
 | 
						|
           padLen = (8-(len(item) % 8)) % 8
 | 
						|
           item['NextEntryOffset']   = len(item) + padLen
 | 
						|
        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:
 | 
						|
           item['EaSize']            = 0
 | 
						|
           item['EndOfFile']         = size
 | 
						|
           item['AllocationSize']    = size
 | 
						|
           item['CreationTime']      = getFileTime(ctime)
 | 
						|
           item['LastAccessTime']    = getFileTime(atime)
 | 
						|
           item['LastWriteTime']     = getFileTime(mtime)
 | 
						|
           item['LastChangeTime']    = getFileTime(mtime)
 | 
						|
           padLen = (8-(len(item) % 8)) % 8
 | 
						|
           item['NextEntryOffset']   = len(item) + padLen
 | 
						|
        elif level == smb.SMB_FIND_INFO_STANDARD:
 | 
						|
           item['EaSize']            = size
 | 
						|
           item['CreationDate']      = getSMBDate(ctime)
 | 
						|
           item['CreationTime']      = getSMBTime(ctime)
 | 
						|
           item['LastAccessDate']    = getSMBDate(atime)
 | 
						|
           item['LastAccessTime']    = getSMBTime(atime)
 | 
						|
           item['LastWriteDate']     = getSMBDate(mtime)
 | 
						|
           item['LastWriteTime']     = getSMBTime(mtime)
 | 
						|
        searchResult.append(item)
 | 
						|
 | 
						|
     # No more files
 | 
						|
     if (level >= smb.SMB_FIND_FILE_DIRECTORY_INFO or isSMB2 == True) and searchCount > 0:
 | 
						|
         searchResult[-1]['NextEntryOffset'] = 0
 | 
						|
 | 
						|
     return searchResult, searchCount, errorCode
 | 
						|
 | 
						|
def queryFileInformation(path, filename, level):
 | 
						|
    #print "queryFileInfo path: %s, filename: %s, level:0x%x" % (path,filename,level)
 | 
						|
    return queryPathInformation(path,filename, level)
 | 
						|
 | 
						|
def queryPathInformation(path, filename, level):
 | 
						|
    # TODO: Depending on the level, this could be done much simpler
 | 
						|
  #print "queryPathInfo path: %s, filename: %s, level:0x%x" % (path,filename,level)
 | 
						|
  try:
 | 
						|
    errorCode = 0
 | 
						|
    fileName = os.path.normpath(filename.replace('\\','/'))
 | 
						|
    if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\') and path != '':
 | 
						|
       # strip leading '/'
 | 
						|
       fileName = fileName[1:]
 | 
						|
    pathName = os.path.join(path,fileName)
 | 
						|
    if os.path.exists(pathName):
 | 
						|
        (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(pathName)
 | 
						|
        if level == smb.SMB_QUERY_FILE_BASIC_INFO:
 | 
						|
            infoRecord = smb.SMBQueryFileBasicInfo()
 | 
						|
            infoRecord['CreationTime']         = getFileTime(ctime)
 | 
						|
            infoRecord['LastAccessTime']       = getFileTime(atime)
 | 
						|
            infoRecord['LastWriteTime']        = getFileTime(mtime)
 | 
						|
            infoRecord['LastChangeTime']       = getFileTime(mtime)
 | 
						|
            if os.path.isdir(pathName):
 | 
						|
               infoRecord['ExtFileAttributes'] = smb.ATTR_DIRECTORY
 | 
						|
            else:
 | 
						|
               infoRecord['ExtFileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE
 | 
						|
        elif level == smb.SMB_QUERY_FILE_STANDARD_INFO:
 | 
						|
            infoRecord = smb.SMBQueryFileStandardInfo()
 | 
						|
            infoRecord['AllocationSize']       = size
 | 
						|
            infoRecord['EndOfFile']            = size
 | 
						|
            if os.path.isdir(pathName):
 | 
						|
               infoRecord['Directory']         = 1
 | 
						|
            else:
 | 
						|
               infoRecord['Directory']         = 0
 | 
						|
        elif level == smb.SMB_QUERY_FILE_ALL_INFO or level == smb2.SMB2_FILE_ALL_INFO:
 | 
						|
            infoRecord = smb.SMBQueryFileAllInfo()
 | 
						|
            infoRecord['CreationTime']         = getFileTime(ctime)
 | 
						|
            infoRecord['LastAccessTime']       = getFileTime(atime)
 | 
						|
            infoRecord['LastWriteTime']        = getFileTime(mtime)
 | 
						|
            infoRecord['LastChangeTime']       = getFileTime(mtime)
 | 
						|
            if os.path.isdir(pathName):
 | 
						|
               infoRecord['ExtFileAttributes'] = smb.ATTR_DIRECTORY
 | 
						|
            else:
 | 
						|
               infoRecord['ExtFileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE
 | 
						|
            infoRecord['AllocationSize']       = size
 | 
						|
            infoRecord['EndOfFile']            = size
 | 
						|
            if os.path.isdir(pathName):
 | 
						|
               infoRecord['Directory']         = 1
 | 
						|
            else:
 | 
						|
               infoRecord['Directory']         = 0
 | 
						|
            infoRecord['FileName']             = filename.encode('utf-16le')
 | 
						|
        elif level == smb2.SMB2_FILE_NETWORK_OPEN_INFO:
 | 
						|
            infoRecord = smb.SMBFileNetworkOpenInfo()
 | 
						|
            infoRecord['CreationTime']         = getFileTime(ctime)
 | 
						|
            infoRecord['LastAccessTime']       = getFileTime(atime)
 | 
						|
            infoRecord['LastWriteTime']        = getFileTime(mtime)
 | 
						|
            infoRecord['ChangeTime']           = getFileTime(mtime)
 | 
						|
            infoRecord['AllocationSize']       = size
 | 
						|
            infoRecord['EndOfFile']            = size
 | 
						|
            if os.path.isdir(pathName):
 | 
						|
               infoRecord['FileAttributes'] = smb.ATTR_DIRECTORY
 | 
						|
            else:
 | 
						|
               infoRecord['FileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE
 | 
						|
        elif level == smb.SMB_QUERY_FILE_EA_INFO or level == smb2.SMB2_FILE_EA_INFO:
 | 
						|
            infoRecord = smb.SMBQueryFileEaInfo()
 | 
						|
        elif level == smb2.SMB2_FILE_STREAM_INFO:
 | 
						|
            infoRecord = smb.SMBFileStreamInformation()
 | 
						|
        else:
 | 
						|
            LOG.error('Unknown level for query path info! 0x%x' % level)
 | 
						|
            # UNSUPPORTED
 | 
						|
            return None, STATUS_NOT_SUPPORTED
 | 
						|
 | 
						|
        return infoRecord, errorCode
 | 
						|
    else:
 | 
						|
        # NOT FOUND
 | 
						|
        return None, STATUS_OBJECT_NAME_NOT_FOUND
 | 
						|
  except Exception, e:
 | 
						|
      LOG.error('queryPathInfo: %s' % e)
 | 
						|
      raise
 | 
						|
 | 
						|
def queryDiskInformation(path):
 | 
						|
# TODO: Do something useful here :)
 | 
						|
# For now we just return fake values
 | 
						|
   totalUnits = 65535
 | 
						|
   freeUnits = 65535
 | 
						|
   return totalUnits, freeUnits
 | 
						|
 | 
						|
# Here we implement the NT transaction handlers
 | 
						|
class NTTRANSCommands:
 | 
						|
    def default(self, connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
 | 
						|
        pass
 | 
						|
 | 
						|
# Here we implement the NT transaction handlers
 | 
						|
class TRANSCommands:
 | 
						|
    @staticmethod
 | 
						|
    def lanMan(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
 | 
						|
        # Minimal [MS-RAP] implementation, just to return the shares
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSetup = ''
 | 
						|
        respParameters = ''
 | 
						|
        respData = ''
 | 
						|
        errorCode = STATUS_SUCCESS
 | 
						|
        if struct.unpack('<H',parameters[:2])[0] == 0:
 | 
						|
            # NetShareEnum Request
 | 
						|
            netShareEnum = smb.SMBNetShareEnum(parameters)
 | 
						|
            if netShareEnum['InfoLevel'] == 1:
 | 
						|
                shares = getShares(connId, smbServer)
 | 
						|
                respParameters = smb.SMBNetShareEnumResponse()
 | 
						|
                respParameters['EntriesReturned']  = len(shares)
 | 
						|
                respParameters['EntriesAvailable'] = len(shares)
 | 
						|
                tailData = ''
 | 
						|
                for i in shares:
 | 
						|
                    # NetShareInfo1 len == 20
 | 
						|
                    entry = smb.NetShareInfo1()
 | 
						|
                    entry['NetworkName'] = i + '\x00'*(13-len(i))
 | 
						|
                    entry['Type']        = int(shares[i]['share type'])
 | 
						|
                    # (beto) If offset == 0 it crashes explorer.exe on windows 7
 | 
						|
                    entry['RemarkOffsetLow'] = 20 * len(shares) + len(tailData)
 | 
						|
                    respData += entry.getData()
 | 
						|
                    if shares[i].has_key('comment'):
 | 
						|
                        tailData += shares[i]['comment'] + '\x00'
 | 
						|
                    else:
 | 
						|
                        tailData += '\x00'
 | 
						|
                respData += tailData
 | 
						|
            else:
 | 
						|
                # We don't support other info levels
 | 
						|
                errorCode = STATUS_NOT_SUPPORTED
 | 
						|
        elif struct.unpack('<H',parameters[:2])[0] == 13:
 | 
						|
            # NetrServerGetInfo Request
 | 
						|
            respParameters = smb.SMBNetServerGetInfoResponse()
 | 
						|
            netServerInfo = smb.SMBNetServerInfo1()
 | 
						|
            netServerInfo['ServerName'] = smbServer.getServerName()
 | 
						|
            respData = str(netServerInfo)
 | 
						|
            respParameters['TotalBytesAvailable'] = len(respData)
 | 
						|
        elif struct.unpack('<H',parameters[:2])[0] == 1:
 | 
						|
            # NetrShareGetInfo Request
 | 
						|
            request = smb.SMBNetShareGetInfo(parameters)
 | 
						|
            respParameters = smb.SMBNetShareGetInfoResponse()
 | 
						|
            shares = getShares(connId, smbServer)
 | 
						|
            share = shares[request['ShareName'].upper()]
 | 
						|
            shareInfo = smb.NetShareInfo1()
 | 
						|
            shareInfo['NetworkName'] = request['ShareName'].upper() + '\x00'
 | 
						|
            shareInfo['Type']        = int(share['share type'])
 | 
						|
            respData = shareInfo.getData()
 | 
						|
            if share.has_key('comment'):
 | 
						|
                shareInfo['RemarkOffsetLow'] = len(respData)
 | 
						|
                respData += share['comment'] + '\x00'
 | 
						|
            respParameters['TotalBytesAvailable'] = len(respData)
 | 
						|
 | 
						|
        else:
 | 
						|
            # We don't know how to handle anything else
 | 
						|
            errorCode = STATUS_NOT_SUPPORTED
 | 
						|
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        return respSetup, respParameters, respData, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def transactNamedPipe(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSetup = ''
 | 
						|
        respParameters = ''
 | 
						|
        respData = ''
 | 
						|
        errorCode = STATUS_SUCCESS
 | 
						|
        SMBCommand  = smb.SMBCommand(recvPacket['Data'][0])
 | 
						|
        transParameters= smb.SMBTransaction_Parameters(SMBCommand['Parameters'])
 | 
						|
 | 
						|
        # Extract the FID
 | 
						|
        fid = struct.unpack('<H', transParameters['Setup'][2:])[0]
 | 
						|
 | 
						|
        if connData['OpenedFiles'].has_key(fid):
 | 
						|
            fileHandle = connData['OpenedFiles'][fid]['FileHandle']
 | 
						|
            if fileHandle != PIPE_FILE_DESCRIPTOR:
 | 
						|
                os.write(fileHandle,data)
 | 
						|
                respData = os.read(fileHandle,data)
 | 
						|
            else:
 | 
						|
                sock = connData['OpenedFiles'][fid]['Socket']
 | 
						|
                sock.send(data)
 | 
						|
                respData = sock.recv(maxDataCount)
 | 
						|
        else:
 | 
						|
            errorCode = STATUS_INVALID_HANDLE
 | 
						|
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        return respSetup, respParameters, respData, errorCode
 | 
						|
 | 
						|
# Here we implement the transaction2 handlers
 | 
						|
class TRANS2Commands:
 | 
						|
    # All these commands return setup, parameters, data, errorCode
 | 
						|
    @staticmethod
 | 
						|
    def setPathInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSetup = ''
 | 
						|
        respParameters = ''
 | 
						|
        respData = ''
 | 
						|
        errorCode = STATUS_SUCCESS
 | 
						|
        setPathInfoParameters = smb.SMBSetPathInformation_Parameters(flags = recvPacket['Flags2'], data = parameters)
 | 
						|
        if connData['ConnectedShares'].has_key(recvPacket['Tid']):
 | 
						|
            path     = connData['ConnectedShares'][recvPacket['Tid']]['path']
 | 
						|
            fileName = decodeSMBString(recvPacket['Flags2'], setPathInfoParameters['FileName'])
 | 
						|
            fileName = os.path.normpath(fileName.replace('\\','/'))
 | 
						|
            if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\') and path != '':
 | 
						|
               # strip leading '/'
 | 
						|
               fileName = fileName[1:]
 | 
						|
            pathName = os.path.join(path,fileName)
 | 
						|
            if os.path.exists(pathName):
 | 
						|
                informationLevel = setPathInfoParameters['InformationLevel']
 | 
						|
                if informationLevel == smb.SMB_SET_FILE_BASIC_INFO:
 | 
						|
                    infoRecord = smb.SMBSetFileBasicInfo(data)
 | 
						|
                    # Creation time won't be set,  the other ones we play with.
 | 
						|
                    atime = infoRecord['LastAccessTime']
 | 
						|
                    if atime == 0:
 | 
						|
                        atime = -1
 | 
						|
                    else:
 | 
						|
                        atime = getUnixTime(atime)
 | 
						|
                    mtime = infoRecord['LastWriteTime']
 | 
						|
                    if mtime == 0:
 | 
						|
                        mtime = -1
 | 
						|
                    else:
 | 
						|
                        mtime = getUnixTime(mtime)
 | 
						|
                    if mtime != -1 or atime != -1:
 | 
						|
                        os.utime(pathName,(atime,mtime))
 | 
						|
                else:
 | 
						|
                    smbServer.log('Unknown level for set path info! 0x%x' % setPathInfoParameters['InformationLevel'], logging.ERROR)
 | 
						|
                    # UNSUPPORTED
 | 
						|
                    errorCode =  STATUS_NOT_SUPPORTED
 | 
						|
            else:
 | 
						|
                errorCode = STATUS_OBJECT_NAME_NOT_FOUND
 | 
						|
 | 
						|
            if errorCode == STATUS_SUCCESS:
 | 
						|
                respParameters = smb.SMBSetPathInformationResponse_Parameters()
 | 
						|
 | 
						|
        else:
 | 
						|
            errorCode = STATUS_SMB_BAD_TID
 | 
						|
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        return respSetup, respParameters, respData, errorCode
 | 
						|
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def setFileInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSetup = ''
 | 
						|
        respParameters = ''
 | 
						|
        respData = ''
 | 
						|
        errorCode = STATUS_SUCCESS
 | 
						|
        setFileInfoParameters = smb.SMBSetFileInformation_Parameters(parameters)
 | 
						|
 | 
						|
        if connData['ConnectedShares'].has_key(recvPacket['Tid']):
 | 
						|
            if connData['OpenedFiles'].has_key(setFileInfoParameters['FID']):
 | 
						|
                fileName = connData['OpenedFiles'][setFileInfoParameters['FID']]['FileName']
 | 
						|
                informationLevel = setFileInfoParameters['InformationLevel']
 | 
						|
                if informationLevel == smb.SMB_SET_FILE_DISPOSITION_INFO:
 | 
						|
                    infoRecord = smb.SMBSetFileDispositionInfo(parameters)
 | 
						|
                    if infoRecord['DeletePending'] > 0:
 | 
						|
                       # Mark this file for removal after closed
 | 
						|
                       connData['OpenedFiles'][setFileInfoParameters['FID']]['DeleteOnClose'] = True
 | 
						|
                       respParameters = smb.SMBSetFileInformationResponse_Parameters()
 | 
						|
                elif informationLevel == smb.SMB_SET_FILE_BASIC_INFO:
 | 
						|
                    infoRecord = smb.SMBSetFileBasicInfo(data)
 | 
						|
                    # Creation time won't be set,  the other ones we play with.
 | 
						|
                    atime = infoRecord['LastAccessTime']
 | 
						|
                    if atime == 0:
 | 
						|
                        atime = -1
 | 
						|
                    else:
 | 
						|
                        atime = getUnixTime(atime)
 | 
						|
                    mtime = infoRecord['LastWriteTime']
 | 
						|
                    if mtime == 0:
 | 
						|
                        mtime = -1
 | 
						|
                    else:
 | 
						|
                        mtime = getUnixTime(mtime)
 | 
						|
                    os.utime(fileName,(atime,mtime))
 | 
						|
                elif informationLevel == smb.SMB_SET_FILE_END_OF_FILE_INFO:
 | 
						|
                    fileHandle = connData['OpenedFiles'][setFileInfoParameters['FID']]['FileHandle']
 | 
						|
                    infoRecord = smb.SMBSetFileEndOfFileInfo(data)
 | 
						|
                    if infoRecord['EndOfFile'] > 0:
 | 
						|
                        os.lseek(fileHandle, infoRecord['EndOfFile']-1, 0)
 | 
						|
                        os.write(fileHandle, '\x00')
 | 
						|
                else:
 | 
						|
                    smbServer.log('Unknown level for set file info! 0x%x' % setFileInfoParameters['InformationLevel'], logging.ERROR)
 | 
						|
                    # UNSUPPORTED
 | 
						|
                    errorCode =  STATUS_NOT_SUPPORTED
 | 
						|
            else:
 | 
						|
                errorCode = STATUS_NO_SUCH_FILE
 | 
						|
 | 
						|
            if errorCode == STATUS_SUCCESS:
 | 
						|
                respParameters = smb.SMBSetFileInformationResponse_Parameters()
 | 
						|
        else:
 | 
						|
            errorCode = STATUS_SMB_BAD_TID
 | 
						|
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        return respSetup, respParameters, respData, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def queryFileInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSetup = ''
 | 
						|
        respParameters = ''
 | 
						|
        respData = ''
 | 
						|
 | 
						|
        queryFileInfoParameters = smb.SMBQueryFileInformation_Parameters(parameters)
 | 
						|
 | 
						|
        if connData['ConnectedShares'].has_key(recvPacket['Tid']):
 | 
						|
            if connData['OpenedFiles'].has_key(queryFileInfoParameters['FID']):
 | 
						|
                fileName = connData['OpenedFiles'][queryFileInfoParameters['FID']]['FileName']
 | 
						|
 | 
						|
                infoRecord, errorCode = queryFileInformation('', fileName, queryFileInfoParameters['InformationLevel'])
 | 
						|
 | 
						|
                if infoRecord is not None:
 | 
						|
                    respParameters = smb.SMBQueryFileInformationResponse_Parameters()
 | 
						|
                    respData = infoRecord
 | 
						|
            else:
 | 
						|
                errorCode = STATUS_INVALID_HANDLE
 | 
						|
        else:
 | 
						|
            errorCode = STATUS_SMB_BAD_TID
 | 
						|
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        return respSetup, respParameters, respData, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def queryPathInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSetup = ''
 | 
						|
        respParameters = ''
 | 
						|
        respData = ''
 | 
						|
        errorCode = 0
 | 
						|
 | 
						|
        queryPathInfoParameters = smb.SMBQueryPathInformation_Parameters(flags = recvPacket['Flags2'], data = parameters)
 | 
						|
 | 
						|
        if connData['ConnectedShares'].has_key(recvPacket['Tid']):
 | 
						|
            path = connData['ConnectedShares'][recvPacket['Tid']]['path']
 | 
						|
            try:
 | 
						|
               infoRecord, errorCode = queryPathInformation(path, decodeSMBString(recvPacket['Flags2'], queryPathInfoParameters['FileName']), queryPathInfoParameters['InformationLevel'])
 | 
						|
            except Exception, e:
 | 
						|
               smbServer.log("queryPathInformation: %s" % e,logging.ERROR)
 | 
						|
 | 
						|
            if infoRecord is not None:
 | 
						|
                respParameters = smb.SMBQueryPathInformationResponse_Parameters()
 | 
						|
                respData = infoRecord
 | 
						|
        else:
 | 
						|
            errorCode = STATUS_SMB_BAD_TID
 | 
						|
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        return respSetup, respParameters, respData, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def queryFsInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
        errorCode = 0
 | 
						|
        # Get the Tid associated
 | 
						|
        if connData['ConnectedShares'].has_key(recvPacket['Tid']):
 | 
						|
            data = queryFsInformation(connData['ConnectedShares'][recvPacket['Tid']]['path'], '', struct.unpack('<H',parameters)[0])
 | 
						|
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        return '','', data, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def findNext2(connId, smbServer, recvPacket, parameters, data, maxDataCount):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSetup = ''
 | 
						|
        respParameters = ''
 | 
						|
        respData = ''
 | 
						|
        errorCode = STATUS_SUCCESS
 | 
						|
        findNext2Parameters = smb.SMBFindNext2_Parameters(flags = recvPacket['Flags2'], data = parameters)
 | 
						|
 | 
						|
        sid = findNext2Parameters['SID']
 | 
						|
        if connData['ConnectedShares'].has_key(recvPacket['Tid']):
 | 
						|
            if connData['SIDs'].has_key(sid):
 | 
						|
                searchResult = connData['SIDs'][sid]
 | 
						|
                respParameters = smb.SMBFindNext2Response_Parameters()
 | 
						|
                endOfSearch = 1
 | 
						|
                searchCount = 1
 | 
						|
                totalData = 0
 | 
						|
                for i in enumerate(searchResult):
 | 
						|
                    data = i[1].getData()
 | 
						|
                    lenData = len(data)
 | 
						|
                    if (totalData+lenData) >= maxDataCount or (i[0]+1) >= findNext2Parameters['SearchCount']:
 | 
						|
                        # We gotta stop here and continue on a find_next2
 | 
						|
                        endOfSearch = 0
 | 
						|
                        connData['SIDs'][sid] = searchResult[i[0]:]
 | 
						|
                        respParameters['LastNameOffset'] = totalData
 | 
						|
                        break
 | 
						|
                    else:
 | 
						|
                        searchCount +=1
 | 
						|
                        respData += data
 | 
						|
                        totalData += lenData
 | 
						|
 | 
						|
                # Have we reached the end of the search or still stuff to send?
 | 
						|
                if endOfSearch > 0:
 | 
						|
                    # Let's remove the SID from our ConnData
 | 
						|
                    del(connData['SIDs'][sid])
 | 
						|
 | 
						|
                respParameters['EndOfSearch'] = endOfSearch
 | 
						|
                respParameters['SearchCount'] = searchCount
 | 
						|
            else:
 | 
						|
                errorCode = STATUS_INVALID_HANDLE
 | 
						|
        else:
 | 
						|
            errorCode = STATUS_SMB_BAD_TID
 | 
						|
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        return respSetup, respParameters, respData, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def findFirst2(connId, smbServer, recvPacket, parameters, data, maxDataCount):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSetup = ''
 | 
						|
        respParameters = ''
 | 
						|
        respData = ''
 | 
						|
        findFirst2Parameters = smb.SMBFindFirst2_Parameters( recvPacket['Flags2'], data = parameters)
 | 
						|
 | 
						|
        if connData['ConnectedShares'].has_key(recvPacket['Tid']):
 | 
						|
            path = connData['ConnectedShares'][recvPacket['Tid']]['path']
 | 
						|
 | 
						|
            searchResult, searchCount, errorCode = findFirst2(path,
 | 
						|
                          decodeSMBString( recvPacket['Flags2'], findFirst2Parameters['FileName'] ),
 | 
						|
                          findFirst2Parameters['InformationLevel'],
 | 
						|
                          findFirst2Parameters['SearchAttributes'] )
 | 
						|
 | 
						|
            respParameters = smb.SMBFindFirst2Response_Parameters()
 | 
						|
            endOfSearch = 1
 | 
						|
            sid = 0x80 # default SID
 | 
						|
            searchCount = 0
 | 
						|
            totalData = 0
 | 
						|
            for i in enumerate(searchResult):
 | 
						|
                #i[1].dump()
 | 
						|
                data = i[1].getData()
 | 
						|
                lenData = len(data)
 | 
						|
                if (totalData+lenData) >= maxDataCount or (i[0]+1) > findFirst2Parameters['SearchCount']:
 | 
						|
                    # We gotta stop here and continue on a find_next2
 | 
						|
                    endOfSearch = 0
 | 
						|
                    # Simple way to generate a fid
 | 
						|
                    if len(connData['SIDs']) == 0:
 | 
						|
                       sid = 1
 | 
						|
                    else:
 | 
						|
                       sid = connData['SIDs'].keys()[-1] + 1
 | 
						|
                    # Store the remaining search results in the ConnData SID
 | 
						|
                    connData['SIDs'][sid] = searchResult[i[0]:]
 | 
						|
                    respParameters['LastNameOffset'] = totalData
 | 
						|
                    break
 | 
						|
                else:
 | 
						|
                    searchCount +=1
 | 
						|
                    respData += data
 | 
						|
 | 
						|
                    padLen = (8-(lenData % 8)) %8
 | 
						|
                    respData += '\xaa'*padLen
 | 
						|
                    totalData += lenData + padLen
 | 
						|
 | 
						|
            respParameters['SID'] = sid
 | 
						|
            respParameters['EndOfSearch'] = endOfSearch
 | 
						|
            respParameters['SearchCount'] = searchCount
 | 
						|
        else:
 | 
						|
            errorCode = STATUS_SMB_BAD_TID
 | 
						|
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        return respSetup, respParameters, respData, errorCode
 | 
						|
 | 
						|
# Here we implement the commands handlers
 | 
						|
class SMBCommands:
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smbTransaction(connId, smbServer, SMBCommand, recvPacket, transCommands):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand = smb.SMBCommand(recvPacket['Command'])
 | 
						|
 | 
						|
        transParameters= smb.SMBTransaction_Parameters(SMBCommand['Parameters'])
 | 
						|
 | 
						|
        # Do the stuff
 | 
						|
        if transParameters['ParameterCount'] != transParameters['TotalParameterCount']:
 | 
						|
            # TODO: Handle partial parameters
 | 
						|
            raise Exception("Unsupported partial parameters in TRANSACT2!")
 | 
						|
        else:
 | 
						|
            transData = smb.SMBTransaction_SData(flags = recvPacket['Flags2'])
 | 
						|
            # Standard says servers shouldn't trust Parameters and Data comes
 | 
						|
            # in order, so we have to parse the offsets, ugly
 | 
						|
 | 
						|
            paramCount = transParameters['ParameterCount']
 | 
						|
            transData['Trans_ParametersLength'] = paramCount
 | 
						|
            dataCount = transParameters['DataCount']
 | 
						|
            transData['Trans_DataLength'] = dataCount
 | 
						|
            transData.fromString(SMBCommand['Data'])
 | 
						|
            if transParameters['ParameterOffset'] > 0:
 | 
						|
                paramOffset = transParameters['ParameterOffset'] - 63 - transParameters['SetupLength']
 | 
						|
                transData['Trans_Parameters'] = SMBCommand['Data'][paramOffset:paramOffset+paramCount]
 | 
						|
            else:
 | 
						|
                transData['Trans_Parameters'] = ''
 | 
						|
 | 
						|
            if transParameters['DataOffset'] > 0:
 | 
						|
                dataOffset = transParameters['DataOffset'] - 63 - transParameters['SetupLength']
 | 
						|
                transData['Trans_Data'] = SMBCommand['Data'][dataOffset:dataOffset + dataCount]
 | 
						|
            else:
 | 
						|
                transData['Trans_Data'] = ''
 | 
						|
 | 
						|
            # Call the handler for this TRANSACTION
 | 
						|
            if transParameters['SetupCount'] == 0:
 | 
						|
                # No subcommand, let's play with the Name
 | 
						|
                command = decodeSMBString(recvPacket['Flags2'],transData['Name'])
 | 
						|
            else:
 | 
						|
                command = struct.unpack('<H', transParameters['Setup'][:2])[0]
 | 
						|
 | 
						|
            if transCommands.has_key(command):
 | 
						|
               # Call the TRANS subcommand
 | 
						|
               setup = ''
 | 
						|
               parameters = ''
 | 
						|
               data = ''
 | 
						|
               try:
 | 
						|
                   setup, parameters, data, errorCode = transCommands[command](connId,
 | 
						|
                                smbServer,
 | 
						|
                                recvPacket,
 | 
						|
                                transData['Trans_Parameters'],
 | 
						|
                                transData['Trans_Data'],
 | 
						|
                                transParameters['MaxDataCount'])
 | 
						|
               except Exception, e:
 | 
						|
                   #print 'Transaction: %s' % e,e
 | 
						|
                   smbServer.log('Transaction: (%r,%s)' % (command, e), logging.ERROR)
 | 
						|
                   errorCode = STATUS_ACCESS_DENIED
 | 
						|
                   #raise
 | 
						|
 | 
						|
               if setup == '' and parameters == '' and data == '':
 | 
						|
                   # Something wen't wrong
 | 
						|
                   respParameters = ''
 | 
						|
                   respData = ''
 | 
						|
               else:
 | 
						|
                   # Build the answer
 | 
						|
                   data = str(data)
 | 
						|
                   remainingData = len(data)
 | 
						|
                   parameters = str(parameters)
 | 
						|
                   remainingParameters = len(parameters)
 | 
						|
                   commands = []
 | 
						|
                   dataDisplacement = 0
 | 
						|
                   while remainingData > 0 or remainingParameters > 0:
 | 
						|
                       respSMBCommand = smb.SMBCommand(recvPacket['Command'])
 | 
						|
                       respParameters = smb.SMBTransactionResponse_Parameters()
 | 
						|
                       respData       = smb.SMBTransaction2Response_Data()
 | 
						|
 | 
						|
                       respParameters['TotalParameterCount'] = len(parameters)
 | 
						|
                       respParameters['ParameterCount']      = len(parameters)
 | 
						|
                       respData['Trans_ParametersLength']    = len(parameters)
 | 
						|
                       respParameters['TotalDataCount']      = len(data)
 | 
						|
                       respParameters['DataDisplacement']    = dataDisplacement
 | 
						|
 | 
						|
                       # TODO: Do the same for parameters
 | 
						|
                       if len(data) >  transParameters['MaxDataCount']:
 | 
						|
                           # Answer doesn't fit in this packet
 | 
						|
                           LOG.debug("Lowering answer from %d to %d" % (len(data),transParameters['MaxDataCount']) )
 | 
						|
                           respParameters['DataCount'] = transParameters['MaxDataCount']
 | 
						|
                       else:
 | 
						|
                           respParameters['DataCount'] = len(data)
 | 
						|
 | 
						|
                       respData['Trans_DataLength']          = respParameters['DataCount']
 | 
						|
                       respParameters['SetupCount']          = len(setup)
 | 
						|
                       respParameters['Setup']               = setup
 | 
						|
                       # TODO: Make sure we're calculating the pad right
 | 
						|
                       if len(parameters) > 0:
 | 
						|
                           #padLen = 4 - (55 + len(setup)) % 4
 | 
						|
                           padLen = (4 - (55 + len(setup)) % 4 ) % 4
 | 
						|
                           padBytes = '\xFF' * padLen
 | 
						|
                           respData['Pad1'] = padBytes
 | 
						|
                           respParameters['ParameterOffset'] = 55 + len(setup) + padLen
 | 
						|
                       else:
 | 
						|
                           padLen = 0
 | 
						|
                           respParameters['ParameterOffset'] = 0
 | 
						|
                           respData['Pad1']                  = ''
 | 
						|
 | 
						|
                       if len(data) > 0:
 | 
						|
                           #pad2Len = 4 - (55 + len(setup) + padLen + len(parameters)) % 4
 | 
						|
                           pad2Len = (4 - (55 + len(setup) + padLen + len(parameters)) % 4) % 4
 | 
						|
                           respData['Pad2'] = '\xFF' * pad2Len
 | 
						|
                           respParameters['DataOffset'] = 55 + len(setup) + padLen + len(parameters) + pad2Len
 | 
						|
                       else:
 | 
						|
                           respParameters['DataOffset'] = 0
 | 
						|
                           respData['Pad2']             = ''
 | 
						|
 | 
						|
                       respData['Trans_Parameters'] = parameters[:respParameters['ParameterCount']]
 | 
						|
                       respData['Trans_Data']       = data[:respParameters['DataCount']]
 | 
						|
                       respSMBCommand['Parameters'] = respParameters
 | 
						|
                       respSMBCommand['Data']       = respData
 | 
						|
 | 
						|
                       data = data[respParameters['DataCount']:]
 | 
						|
                       remainingData -= respParameters['DataCount']
 | 
						|
                       dataDisplacement += respParameters['DataCount'] + 1
 | 
						|
 | 
						|
                       parameters = parameters[respParameters['ParameterCount']:]
 | 
						|
                       remainingParameters -= respParameters['ParameterCount']
 | 
						|
                       commands.append(respSMBCommand)
 | 
						|
 | 
						|
                   smbServer.setConnectionData(connId, connData)
 | 
						|
                   return commands, None, errorCode
 | 
						|
 | 
						|
            else:
 | 
						|
               smbServer.log("Unsupported Transact command %r" % command, logging.ERROR)
 | 
						|
               respParameters = ''
 | 
						|
               respData = ''
 | 
						|
               errorCode = STATUS_NOT_IMPLEMENTED
 | 
						|
 | 
						|
        respSMBCommand['Parameters']             = respParameters
 | 
						|
        respSMBCommand['Data']                   = respData
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smbNTTransact(connId, smbServer, SMBCommand, recvPacket, transCommands):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand = smb.SMBCommand(recvPacket['Command'])
 | 
						|
 | 
						|
        NTTransParameters= smb.SMBNTTransaction_Parameters(SMBCommand['Parameters'])
 | 
						|
        # Do the stuff
 | 
						|
        if NTTransParameters['ParameterCount'] != NTTransParameters['TotalParameterCount']:
 | 
						|
            # TODO: Handle partial parameters
 | 
						|
            raise Exception("Unsupported partial parameters in NTTrans!")
 | 
						|
        else:
 | 
						|
            NTTransData = smb.SMBNTTransaction_Data()
 | 
						|
            # Standard says servers shouldn't trust Parameters and Data comes
 | 
						|
            # in order, so we have to parse the offsets, ugly
 | 
						|
 | 
						|
            paramCount = NTTransParameters['ParameterCount']
 | 
						|
            NTTransData['NT_Trans_ParametersLength'] = paramCount
 | 
						|
            dataCount = NTTransParameters['DataCount']
 | 
						|
            NTTransData['NT_Trans_DataLength'] = dataCount
 | 
						|
 | 
						|
            if NTTransParameters['ParameterOffset'] > 0:
 | 
						|
                paramOffset = NTTransParameters['ParameterOffset'] - 73 - NTTransParameters['SetupLength']
 | 
						|
                NTTransData['NT_Trans_Parameters'] = SMBCommand['Data'][paramOffset:paramOffset+paramCount]
 | 
						|
            else:
 | 
						|
                NTTransData['NT_Trans_Parameters'] = ''
 | 
						|
 | 
						|
            if NTTransParameters['DataOffset'] > 0:
 | 
						|
                dataOffset = NTTransParameters['DataOffset'] - 73 - NTTransParameters['SetupLength']
 | 
						|
                NTTransData['NT_Trans_Data'] = SMBCommand['Data'][dataOffset:dataOffset + dataCount]
 | 
						|
            else:
 | 
						|
                NTTransData['NT_Trans_Data'] = ''
 | 
						|
 | 
						|
            # Call the handler for this TRANSACTION
 | 
						|
            command = NTTransParameters['Function']
 | 
						|
            if transCommands.has_key(command):
 | 
						|
               # Call the NT TRANS subcommand
 | 
						|
               setup = ''
 | 
						|
               parameters = ''
 | 
						|
               data = ''
 | 
						|
               try:
 | 
						|
                   setup, parameters, data, errorCode = transCommands[command](connId,
 | 
						|
                                smbServer,
 | 
						|
                                recvPacket,
 | 
						|
                                NTTransData['NT_Trans_Parameters'],
 | 
						|
                                NTTransData['NT_Trans_Data'],
 | 
						|
                                NTTransParameters['MaxDataCount'])
 | 
						|
               except Exception, e:
 | 
						|
                   smbServer.log('NTTransaction: (0x%x,%s)' % (command, e), logging.ERROR)
 | 
						|
                   errorCode = STATUS_ACCESS_DENIED
 | 
						|
                   #raise
 | 
						|
 | 
						|
               if setup == '' and parameters == '' and data == '':
 | 
						|
                   # Something wen't wrong
 | 
						|
                   respParameters = ''
 | 
						|
                   respData = ''
 | 
						|
                   if errorCode == STATUS_SUCCESS:
 | 
						|
                       errorCode = STATUS_ACCESS_DENIED
 | 
						|
               else:
 | 
						|
                   # Build the answer
 | 
						|
                   data = str(data)
 | 
						|
                   remainingData = len(data)
 | 
						|
                   parameters = str(parameters)
 | 
						|
                   remainingParameters = len(parameters)
 | 
						|
                   commands = []
 | 
						|
                   dataDisplacement = 0
 | 
						|
                   while remainingData > 0 or remainingParameters > 0:
 | 
						|
                       respSMBCommand = smb.SMBCommand(recvPacket['Command'])
 | 
						|
                       respParameters = smb.SMBNTTransactionResponse_Parameters()
 | 
						|
                       respData       = smb.SMBNTTransactionResponse_Data()
 | 
						|
 | 
						|
                       respParameters['TotalParameterCount'] = len(parameters)
 | 
						|
                       respParameters['ParameterCount']      = len(parameters)
 | 
						|
                       respData['Trans_ParametersLength']    = len(parameters)
 | 
						|
                       respParameters['TotalDataCount']      = len(data)
 | 
						|
                       respParameters['DataDisplacement']    = dataDisplacement
 | 
						|
                       # TODO: Do the same for parameters
 | 
						|
                       if len(data) >  NTTransParameters['MaxDataCount']:
 | 
						|
                           # Answer doesn't fit in this packet
 | 
						|
                           LOG.debug("Lowering answer from %d to %d" % (len(data),NTTransParameters['MaxDataCount']) )
 | 
						|
                           respParameters['DataCount'] = NTTransParameters['MaxDataCount']
 | 
						|
                       else:
 | 
						|
                           respParameters['DataCount'] = len(data)
 | 
						|
 | 
						|
                       respData['NT_Trans_DataLength']          = respParameters['DataCount']
 | 
						|
                       respParameters['SetupCount']          = len(setup)
 | 
						|
                       respParameters['Setup']               = setup
 | 
						|
                       # TODO: Make sure we're calculating the pad right
 | 
						|
                       if len(parameters) > 0:
 | 
						|
                           #padLen = 4 - (71 + len(setup)) % 4
 | 
						|
                           padLen = (4 - (73 + len(setup)) % 4 ) % 4
 | 
						|
                           padBytes = '\xFF' * padLen
 | 
						|
                           respData['Pad1'] = padBytes
 | 
						|
                           respParameters['ParameterOffset'] = 73 + len(setup) + padLen
 | 
						|
                       else:
 | 
						|
                           padLen = 0
 | 
						|
                           respParameters['ParameterOffset'] = 0
 | 
						|
                           respData['Pad1']                  = ''
 | 
						|
 | 
						|
                       if len(data) > 0:
 | 
						|
                           #pad2Len = 4 - (71 + len(setup) + padLen + len(parameters)) % 4
 | 
						|
                           pad2Len = (4 - (73 + len(setup) + padLen + len(parameters)) % 4) % 4
 | 
						|
                           respData['Pad2'] = '\xFF' * pad2Len
 | 
						|
                           respParameters['DataOffset'] = 73 + len(setup) + padLen + len(parameters) + pad2Len
 | 
						|
                       else:
 | 
						|
                           respParameters['DataOffset'] = 0
 | 
						|
                           respData['Pad2']             = ''
 | 
						|
 | 
						|
                       respData['NT_Trans_Parameters'] = parameters[:respParameters['ParameterCount']]
 | 
						|
                       respData['NT_Trans_Data']       = data[:respParameters['DataCount']]
 | 
						|
                       respSMBCommand['Parameters'] = respParameters
 | 
						|
                       respSMBCommand['Data']       = respData
 | 
						|
 | 
						|
                       data = data[respParameters['DataCount']:]
 | 
						|
                       remainingData -= respParameters['DataCount']
 | 
						|
                       dataDisplacement += respParameters['DataCount'] + 1
 | 
						|
 | 
						|
                       parameters = parameters[respParameters['ParameterCount']:]
 | 
						|
                       remainingParameters -= respParameters['ParameterCount']
 | 
						|
                       commands.append(respSMBCommand)
 | 
						|
 | 
						|
                   smbServer.setConnectionData(connId, connData)
 | 
						|
                   return commands, None, errorCode
 | 
						|
 | 
						|
            else:
 | 
						|
               #smbServer.log("Unsupported NTTransact command 0x%x" % command, logging.ERROR)
 | 
						|
               respParameters = ''
 | 
						|
               respData = ''
 | 
						|
               errorCode = STATUS_NOT_IMPLEMENTED
 | 
						|
 | 
						|
        respSMBCommand['Parameters']             = respParameters
 | 
						|
        respSMBCommand['Data']                   = respData
 | 
						|
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smbTransaction2(connId, smbServer, SMBCommand, recvPacket, transCommands):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand = smb.SMBCommand(recvPacket['Command'])
 | 
						|
 | 
						|
        trans2Parameters= smb.SMBTransaction2_Parameters(SMBCommand['Parameters'])
 | 
						|
 | 
						|
        # Do the stuff
 | 
						|
        if trans2Parameters['ParameterCount'] != trans2Parameters['TotalParameterCount']:
 | 
						|
            # TODO: Handle partial parameters
 | 
						|
            #print "Unsupported partial parameters in TRANSACT2!"
 | 
						|
            raise Exception("Unsupported partial parameters in TRANSACT2!")
 | 
						|
        else:
 | 
						|
            trans2Data = smb.SMBTransaction2_Data()
 | 
						|
            # Standard says servers shouldn't trust Parameters and Data comes
 | 
						|
            # in order, so we have to parse the offsets, ugly
 | 
						|
 | 
						|
            paramCount = trans2Parameters['ParameterCount']
 | 
						|
            trans2Data['Trans_ParametersLength'] = paramCount
 | 
						|
            dataCount = trans2Parameters['DataCount']
 | 
						|
            trans2Data['Trans_DataLength'] = dataCount
 | 
						|
 | 
						|
            if trans2Parameters['ParameterOffset'] > 0:
 | 
						|
                paramOffset = trans2Parameters['ParameterOffset'] - 63 - trans2Parameters['SetupLength']
 | 
						|
                trans2Data['Trans_Parameters'] = SMBCommand['Data'][paramOffset:paramOffset+paramCount]
 | 
						|
            else:
 | 
						|
                trans2Data['Trans_Parameters'] = ''
 | 
						|
 | 
						|
            if trans2Parameters['DataOffset'] > 0:
 | 
						|
                dataOffset = trans2Parameters['DataOffset'] - 63 - trans2Parameters['SetupLength']
 | 
						|
                trans2Data['Trans_Data'] = SMBCommand['Data'][dataOffset:dataOffset + dataCount]
 | 
						|
            else:
 | 
						|
                trans2Data['Trans_Data'] = ''
 | 
						|
 | 
						|
            # Call the handler for this TRANSACTION
 | 
						|
            command = struct.unpack('<H', trans2Parameters['Setup'])[0]
 | 
						|
            if transCommands.has_key(command):
 | 
						|
               # Call the TRANS2 subcommand
 | 
						|
               try:
 | 
						|
                   setup, parameters, data, errorCode = transCommands[command](connId,
 | 
						|
                                smbServer,
 | 
						|
                                recvPacket,
 | 
						|
                                trans2Data['Trans_Parameters'],
 | 
						|
                                trans2Data['Trans_Data'],
 | 
						|
                                trans2Parameters['MaxDataCount'])
 | 
						|
               except Exception, e:
 | 
						|
                   smbServer.log('Transaction2: (0x%x,%s)' % (command, e), logging.ERROR)
 | 
						|
                   #import traceback
 | 
						|
                   #traceback.print_exc()
 | 
						|
                   raise
 | 
						|
 | 
						|
               if setup == '' and parameters == '' and data == '':
 | 
						|
                   # Something wen't wrong
 | 
						|
                   respParameters = ''
 | 
						|
                   respData = ''
 | 
						|
               else:
 | 
						|
                   # Build the answer
 | 
						|
                   data = str(data)
 | 
						|
                   remainingData = len(data)
 | 
						|
                   parameters = str(parameters)
 | 
						|
                   remainingParameters = len(parameters)
 | 
						|
                   commands = []
 | 
						|
                   dataDisplacement = 0
 | 
						|
                   while remainingData > 0 or remainingParameters > 0:
 | 
						|
                       respSMBCommand = smb.SMBCommand(recvPacket['Command'])
 | 
						|
                       respParameters = smb.SMBTransaction2Response_Parameters()
 | 
						|
                       respData       = smb.SMBTransaction2Response_Data()
 | 
						|
 | 
						|
                       respParameters['TotalParameterCount'] = len(parameters)
 | 
						|
                       respParameters['ParameterCount']      = len(parameters)
 | 
						|
                       respData['Trans_ParametersLength']    = len(parameters)
 | 
						|
                       respParameters['TotalDataCount']      = len(data)
 | 
						|
                       respParameters['DataDisplacement']    = dataDisplacement
 | 
						|
                       # TODO: Do the same for parameters
 | 
						|
                       if len(data) >  trans2Parameters['MaxDataCount']:
 | 
						|
                           # Answer doesn't fit in this packet
 | 
						|
                           LOG.debug("Lowering answer from %d to %d" % (len(data),trans2Parameters['MaxDataCount']) )
 | 
						|
                           respParameters['DataCount'] = trans2Parameters['MaxDataCount']
 | 
						|
                       else:
 | 
						|
                           respParameters['DataCount'] = len(data)
 | 
						|
 | 
						|
                       respData['Trans_DataLength']          = respParameters['DataCount']
 | 
						|
                       respParameters['SetupCount']          = len(setup)
 | 
						|
                       respParameters['Setup']               = setup
 | 
						|
                       # TODO: Make sure we're calculating the pad right
 | 
						|
                       if len(parameters) > 0:
 | 
						|
                           #padLen = 4 - (55 + len(setup)) % 4
 | 
						|
                           padLen = (4 - (55 + len(setup)) % 4 ) % 4
 | 
						|
                           padBytes = '\xFF' * padLen
 | 
						|
                           respData['Pad1'] = padBytes
 | 
						|
                           respParameters['ParameterOffset'] = 55 + len(setup) + padLen
 | 
						|
                       else:
 | 
						|
                           padLen = 0
 | 
						|
                           respParameters['ParameterOffset'] = 0
 | 
						|
                           respData['Pad1']                  = ''
 | 
						|
 | 
						|
                       if len(data) > 0:
 | 
						|
                           #pad2Len = 4 - (55 + len(setup) + padLen + len(parameters)) % 4
 | 
						|
                           pad2Len = (4 - (55 + len(setup) + padLen + len(parameters)) % 4) % 4
 | 
						|
                           respData['Pad2'] = '\xFF' * pad2Len
 | 
						|
                           respParameters['DataOffset'] = 55 + len(setup) + padLen + len(parameters) + pad2Len
 | 
						|
                       else:
 | 
						|
                           respParameters['DataOffset'] = 0
 | 
						|
                           respData['Pad2']             = ''
 | 
						|
 | 
						|
                       respData['Trans_Parameters'] = parameters[:respParameters['ParameterCount']]
 | 
						|
                       respData['Trans_Data']       = data[:respParameters['DataCount']]
 | 
						|
                       respSMBCommand['Parameters'] = respParameters
 | 
						|
                       respSMBCommand['Data']       = respData
 | 
						|
 | 
						|
                       data = data[respParameters['DataCount']:]
 | 
						|
                       remainingData -= respParameters['DataCount']
 | 
						|
                       dataDisplacement += respParameters['DataCount'] + 1
 | 
						|
 | 
						|
                       parameters = parameters[respParameters['ParameterCount']:]
 | 
						|
                       remainingParameters -= respParameters['ParameterCount']
 | 
						|
                       commands.append(respSMBCommand)
 | 
						|
 | 
						|
                   smbServer.setConnectionData(connId, connData)
 | 
						|
                   return commands, None, errorCode
 | 
						|
 | 
						|
            else:
 | 
						|
               smbServer.log("Unsupported Transact/2 command 0x%x" % command, logging.ERROR)
 | 
						|
               respParameters = ''
 | 
						|
               respData = ''
 | 
						|
               errorCode = STATUS_NOT_IMPLEMENTED
 | 
						|
 | 
						|
        respSMBCommand['Parameters']             = respParameters
 | 
						|
        respSMBCommand['Data']                   = respData
 | 
						|
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smbComLockingAndX(connId, smbServer, SMBCommand, recvPacket):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_LOCKING_ANDX)
 | 
						|
        respParameters        = ''
 | 
						|
        respData              = ''
 | 
						|
 | 
						|
        # I'm actually doing nothing.. just make MacOS happy ;)
 | 
						|
        errorCode = STATUS_SUCCESS
 | 
						|
 | 
						|
        respSMBCommand['Parameters']             = respParameters
 | 
						|
        respSMBCommand['Data']                   = respData
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smbComClose(connId, smbServer, SMBCommand, recvPacket):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_CLOSE)
 | 
						|
        respParameters        = ''
 | 
						|
        respData              = ''
 | 
						|
 | 
						|
        comClose =  smb.SMBClose_Parameters(SMBCommand['Parameters'])
 | 
						|
 | 
						|
        if connData['OpenedFiles'].has_key(comClose['FID']):
 | 
						|
             errorCode = STATUS_SUCCESS
 | 
						|
             fileHandle = connData['OpenedFiles'][comClose['FID']]['FileHandle']
 | 
						|
             try:
 | 
						|
                 if fileHandle == PIPE_FILE_DESCRIPTOR:
 | 
						|
                     connData['OpenedFiles'][comClose['FID']]['Socket'].close()
 | 
						|
                 elif fileHandle != VOID_FILE_DESCRIPTOR:
 | 
						|
                     os.close(fileHandle)
 | 
						|
             except Exception, e:
 | 
						|
                 smbServer.log("comClose %s" % e, logging.ERROR)
 | 
						|
                 errorCode = STATUS_ACCESS_DENIED
 | 
						|
             else:
 | 
						|
                 # Check if the file was marked for removal
 | 
						|
                 if connData['OpenedFiles'][comClose['FID']]['DeleteOnClose'] is True:
 | 
						|
                     try:
 | 
						|
                         os.remove(connData['OpenedFiles'][comClose['FID']]['FileName'])
 | 
						|
                     except Exception, e:
 | 
						|
                         smbServer.log("comClose %s" % e, logging.ERROR)
 | 
						|
                         errorCode = STATUS_ACCESS_DENIED
 | 
						|
                 del(connData['OpenedFiles'][comClose['FID']])
 | 
						|
        else:
 | 
						|
            errorCode = STATUS_INVALID_HANDLE
 | 
						|
 | 
						|
        if errorCode > 0:
 | 
						|
            respParameters = ''
 | 
						|
            respData       = ''
 | 
						|
 | 
						|
        respSMBCommand['Parameters']             = respParameters
 | 
						|
        respSMBCommand['Data']                   = respData
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smbComWrite(connId, smbServer, SMBCommand, recvPacket):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_WRITE)
 | 
						|
        respParameters        = smb.SMBWriteResponse_Parameters()
 | 
						|
        respData              = ''
 | 
						|
 | 
						|
        comWriteParameters =  smb.SMBWrite_Parameters(SMBCommand['Parameters'])
 | 
						|
        comWriteData = smb.SMBWrite_Data(SMBCommand['Data'])
 | 
						|
 | 
						|
        if connData['OpenedFiles'].has_key(comWriteParameters['Fid']):
 | 
						|
             fileHandle = connData['OpenedFiles'][comWriteParameters['Fid']]['FileHandle']
 | 
						|
             errorCode = STATUS_SUCCESS
 | 
						|
             try:
 | 
						|
                 if fileHandle != PIPE_FILE_DESCRIPTOR:
 | 
						|
                     # TODO: Handle big size files
 | 
						|
                     # If we're trying to write past the file end we just skip the write call (Vista does this)
 | 
						|
                     if os.lseek(fileHandle, 0, 2) >= comWriteParameters['Offset']:
 | 
						|
                         os.lseek(fileHandle,comWriteParameters['Offset'],0)
 | 
						|
                         os.write(fileHandle,comWriteData['Data'])
 | 
						|
                 else:
 | 
						|
                     sock = connData['OpenedFiles'][comWriteParameters['Fid']]['Socket']
 | 
						|
                     sock.send(comWriteData['Data'])
 | 
						|
                 respParameters['Count']    = comWriteParameters['Count']
 | 
						|
             except Exception, e:
 | 
						|
                 smbServer.log('smbComWrite: %s' % e, logging.ERROR)
 | 
						|
                 errorCode = STATUS_ACCESS_DENIED
 | 
						|
        else:
 | 
						|
            errorCode = STATUS_INVALID_HANDLE
 | 
						|
 | 
						|
 | 
						|
        if errorCode > 0:
 | 
						|
            respParameters = ''
 | 
						|
            respData       = ''
 | 
						|
 | 
						|
        respSMBCommand['Parameters']             = respParameters
 | 
						|
        respSMBCommand['Data']                   = respData
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smbComFlush(connId, smbServer, SMBCommand,recvPacket ):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_FLUSH)
 | 
						|
        respParameters        = ''
 | 
						|
        respData              = ''
 | 
						|
 | 
						|
        comFlush =  smb.SMBFlush_Parameters(SMBCommand['Parameters'])
 | 
						|
 | 
						|
        if connData['OpenedFiles'].has_key(comFlush['FID']):
 | 
						|
             errorCode = STATUS_SUCCESS
 | 
						|
             fileHandle = connData['OpenedFiles'][comFlush['FID']]['FileHandle']
 | 
						|
             try:
 | 
						|
                 os.fsync(fileHandle)
 | 
						|
             except Exception, e:
 | 
						|
                 smbServer.log("comFlush %s" % e, logging.ERROR)
 | 
						|
                 errorCode = STATUS_ACCESS_DENIED
 | 
						|
        else:
 | 
						|
            errorCode = STATUS_INVALID_HANDLE
 | 
						|
 | 
						|
        if errorCode > 0:
 | 
						|
            respParameters = ''
 | 
						|
            respData       = ''
 | 
						|
 | 
						|
        respSMBCommand['Parameters']             = respParameters
 | 
						|
        respSMBCommand['Data']                   = respData
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smbComCreateDirectory(connId, smbServer, SMBCommand,recvPacket ):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_CREATE_DIRECTORY)
 | 
						|
        respParameters        = ''
 | 
						|
        respData              = ''
 | 
						|
 | 
						|
        comCreateDirectoryData=  smb.SMBCreateDirectory_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
 | 
						|
 | 
						|
        # Get the Tid associated
 | 
						|
        if connData['ConnectedShares'].has_key(recvPacket['Tid']):
 | 
						|
             errorCode = STATUS_SUCCESS
 | 
						|
             path = connData['ConnectedShares'][recvPacket['Tid']]['path']
 | 
						|
             fileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comCreateDirectoryData['DirectoryName']).replace('\\','/'))
 | 
						|
             if len(fileName) > 0:
 | 
						|
                if fileName[0] == '/' or fileName[0] == '\\':
 | 
						|
                    # strip leading '/'
 | 
						|
                    fileName = fileName[1:]
 | 
						|
             pathName = os.path.join(path,fileName)
 | 
						|
             if os.path.exists(pathName):
 | 
						|
                errorCode = STATUS_OBJECT_NAME_COLLISION
 | 
						|
 | 
						|
             # TODO: More checks here in the future.. Specially when we support
 | 
						|
             # user access
 | 
						|
             else:
 | 
						|
                 try:
 | 
						|
                     os.mkdir(pathName)
 | 
						|
                 except Exception, e:
 | 
						|
                     smbServer.log("smbComCreateDirectory: %s" % e, logging.ERROR)
 | 
						|
                     errorCode = STATUS_ACCESS_DENIED
 | 
						|
        else:
 | 
						|
            errorCode = STATUS_SMB_BAD_TID
 | 
						|
 | 
						|
 | 
						|
        if errorCode > 0:
 | 
						|
            respParameters = ''
 | 
						|
            respData       = ''
 | 
						|
 | 
						|
        respSMBCommand['Parameters']             = respParameters
 | 
						|
        respSMBCommand['Data']                   = respData
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smbComRename(connId, smbServer, SMBCommand, recvPacket ):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_RENAME)
 | 
						|
        respParameters        = ''
 | 
						|
        respData              = ''
 | 
						|
 | 
						|
        comRenameData      =  smb.SMBRename_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
 | 
						|
        # Get the Tid associated
 | 
						|
        if connData['ConnectedShares'].has_key(recvPacket['Tid']):
 | 
						|
             errorCode = STATUS_SUCCESS
 | 
						|
             path = connData['ConnectedShares'][recvPacket['Tid']]['path']
 | 
						|
             oldFileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comRenameData['OldFileName']).replace('\\','/'))
 | 
						|
             newFileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comRenameData['NewFileName']).replace('\\','/'))
 | 
						|
             if len(oldFileName) > 0 and (oldFileName[0] == '/' or oldFileName[0] == '\\'):
 | 
						|
                # strip leading '/'
 | 
						|
                oldFileName = oldFileName[1:]
 | 
						|
             oldPathName = os.path.join(path,oldFileName)
 | 
						|
             if len(newFileName) > 0 and (newFileName[0] == '/' or newFileName[0] == '\\'):
 | 
						|
                # strip leading '/'
 | 
						|
                newFileName = newFileName[1:]
 | 
						|
             newPathName = os.path.join(path,newFileName)
 | 
						|
 | 
						|
             if os.path.exists(oldPathName) is not True:
 | 
						|
                errorCode = STATUS_NO_SUCH_FILE
 | 
						|
 | 
						|
             # TODO: More checks here in the future.. Specially when we support
 | 
						|
             # user access
 | 
						|
             else:
 | 
						|
                 try:
 | 
						|
                     os.rename(oldPathName,newPathName)
 | 
						|
                 except OSError, e:
 | 
						|
                     smbServer.log("smbComRename: %s" % e, logging.ERROR)
 | 
						|
                     errorCode = STATUS_ACCESS_DENIED
 | 
						|
        else:
 | 
						|
            errorCode = STATUS_SMB_BAD_TID
 | 
						|
 | 
						|
 | 
						|
        if errorCode > 0:
 | 
						|
            respParameters = ''
 | 
						|
            respData       = ''
 | 
						|
 | 
						|
        respSMBCommand['Parameters']             = respParameters
 | 
						|
        respSMBCommand['Data']                   = respData
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smbComDelete(connId, smbServer, SMBCommand, recvPacket ):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_DELETE)
 | 
						|
        respParameters        = ''
 | 
						|
        respData              = ''
 | 
						|
 | 
						|
        comDeleteData         =  smb.SMBDelete_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
 | 
						|
 | 
						|
        # Get the Tid associated
 | 
						|
        if connData['ConnectedShares'].has_key(recvPacket['Tid']):
 | 
						|
             errorCode = STATUS_SUCCESS
 | 
						|
             path = connData['ConnectedShares'][recvPacket['Tid']]['path']
 | 
						|
             fileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comDeleteData['FileName']).replace('\\','/'))
 | 
						|
             if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
 | 
						|
                # strip leading '/'
 | 
						|
                fileName = fileName[1:]
 | 
						|
             pathName = os.path.join(path,fileName)
 | 
						|
             if os.path.exists(pathName) is not True:
 | 
						|
                errorCode = STATUS_NO_SUCH_FILE
 | 
						|
 | 
						|
             # TODO: More checks here in the future.. Specially when we support
 | 
						|
             # user access
 | 
						|
             else:
 | 
						|
                 try:
 | 
						|
                     os.remove(pathName)
 | 
						|
                 except OSError, e:
 | 
						|
                     smbServer.log("smbComDelete: %s" % e, logging.ERROR)
 | 
						|
                     errorCode = STATUS_ACCESS_DENIED
 | 
						|
        else:
 | 
						|
            errorCode = STATUS_SMB_BAD_TID
 | 
						|
 | 
						|
        if errorCode > 0:
 | 
						|
            respParameters = ''
 | 
						|
            respData       = ''
 | 
						|
 | 
						|
        respSMBCommand['Parameters']             = respParameters
 | 
						|
        respSMBCommand['Data']                   = respData
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smbComDeleteDirectory(connId, smbServer, SMBCommand, recvPacket ):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_DELETE_DIRECTORY)
 | 
						|
        respParameters        = ''
 | 
						|
        respData              = ''
 | 
						|
 | 
						|
        comDeleteDirectoryData=  smb.SMBDeleteDirectory_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
 | 
						|
 | 
						|
        # Get the Tid associated
 | 
						|
        if connData['ConnectedShares'].has_key(recvPacket['Tid']):
 | 
						|
             errorCode = STATUS_SUCCESS
 | 
						|
             path = connData['ConnectedShares'][recvPacket['Tid']]['path']
 | 
						|
             fileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comDeleteDirectoryData['DirectoryName']).replace('\\','/'))
 | 
						|
             if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
 | 
						|
                # strip leading '/'
 | 
						|
                fileName = fileName[1:]
 | 
						|
             pathName = os.path.join(path,fileName)
 | 
						|
             if os.path.exists(pathName) is not True:
 | 
						|
                errorCode = STATUS_NO_SUCH_FILE
 | 
						|
 | 
						|
             # TODO: More checks here in the future.. Specially when we support
 | 
						|
             # user access
 | 
						|
             else:
 | 
						|
                 try:
 | 
						|
                     os.rmdir(pathName)
 | 
						|
                 except OSError, e:
 | 
						|
                     smbServer.log("smbComDeleteDirectory: %s" % e,logging.ERROR)
 | 
						|
                     if e.errno == errno.ENOTEMPTY:
 | 
						|
                         errorCode = STATUS_DIRECTORY_NOT_EMPTY
 | 
						|
                     else:
 | 
						|
                         errorCode = STATUS_ACCESS_DENIED
 | 
						|
        else:
 | 
						|
            errorCode = STATUS_SMB_BAD_TID
 | 
						|
 | 
						|
        if errorCode > 0:
 | 
						|
            respParameters = ''
 | 
						|
            respData       = ''
 | 
						|
 | 
						|
        respSMBCommand['Parameters']             = respParameters
 | 
						|
        respSMBCommand['Data']                   = respData
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smbComWriteAndX(connId, smbServer, SMBCommand, recvPacket):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_WRITE_ANDX)
 | 
						|
        respParameters        = smb.SMBWriteAndXResponse_Parameters()
 | 
						|
        respData              = ''
 | 
						|
 | 
						|
        if SMBCommand['WordCount'] == 0x0C:
 | 
						|
            writeAndX =  smb.SMBWriteAndX_Parameters_Short(SMBCommand['Parameters'])
 | 
						|
            writeAndXData = smb.SMBWriteAndX_Data_Short()
 | 
						|
        else:
 | 
						|
            writeAndX =  smb.SMBWriteAndX_Parameters(SMBCommand['Parameters'])
 | 
						|
            writeAndXData = smb.SMBWriteAndX_Data()
 | 
						|
        writeAndXData['DataLength'] = writeAndX['DataLength']
 | 
						|
        writeAndXData['DataOffset'] = writeAndX['DataOffset']
 | 
						|
        writeAndXData.fromString(SMBCommand['Data'])
 | 
						|
 | 
						|
 | 
						|
        if connData['OpenedFiles'].has_key(writeAndX['Fid']):
 | 
						|
             fileHandle = connData['OpenedFiles'][writeAndX['Fid']]['FileHandle']
 | 
						|
             errorCode = STATUS_SUCCESS
 | 
						|
             try:
 | 
						|
                 if fileHandle != PIPE_FILE_DESCRIPTOR:
 | 
						|
                     offset = writeAndX['Offset']
 | 
						|
                     if writeAndX.fields.has_key('HighOffset'):
 | 
						|
                         offset += (writeAndX['HighOffset'] << 32)
 | 
						|
                     # If we're trying to write past the file end we just skip the write call (Vista does this)
 | 
						|
                     if os.lseek(fileHandle, 0, 2) >= offset:
 | 
						|
                         os.lseek(fileHandle,offset,0)
 | 
						|
                         os.write(fileHandle,writeAndXData['Data'])
 | 
						|
                 else:
 | 
						|
                     sock = connData['OpenedFiles'][writeAndX['Fid']]['Socket']
 | 
						|
                     sock.send(writeAndXData['Data'])
 | 
						|
 | 
						|
                 respParameters['Count']    = writeAndX['DataLength']
 | 
						|
                 respParameters['Available']= 0xff
 | 
						|
             except Exception, e:
 | 
						|
                 smbServer.log('smbComWriteAndx: %s' % e, logging.ERROR)
 | 
						|
                 errorCode = STATUS_ACCESS_DENIED
 | 
						|
        else:
 | 
						|
            errorCode = STATUS_INVALID_HANDLE
 | 
						|
 | 
						|
        if errorCode > 0:
 | 
						|
            respParameters = ''
 | 
						|
            respData       = ''
 | 
						|
 | 
						|
        respSMBCommand['Parameters']             = respParameters
 | 
						|
        respSMBCommand['Data']                   = respData
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smbComRead(connId, smbServer, SMBCommand, recvPacket):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_READ)
 | 
						|
        respParameters        = smb.SMBReadResponse_Parameters()
 | 
						|
        respData              = smb.SMBReadResponse_Data()
 | 
						|
 | 
						|
        comReadParameters =  smb.SMBRead_Parameters(SMBCommand['Parameters'])
 | 
						|
 | 
						|
        if connData['OpenedFiles'].has_key(comReadParameters['Fid']):
 | 
						|
             fileHandle = connData['OpenedFiles'][comReadParameters['Fid']]['FileHandle']
 | 
						|
             errorCode = STATUS_SUCCESS
 | 
						|
             try:
 | 
						|
                 if fileHandle != PIPE_FILE_DESCRIPTOR:
 | 
						|
                     # TODO: Handle big size files
 | 
						|
                     os.lseek(fileHandle,comReadParameters['Offset'],0)
 | 
						|
                     content = os.read(fileHandle,comReadParameters['Count'])
 | 
						|
                 else:
 | 
						|
                     sock = connData['OpenedFiles'][comReadParameters['Fid']]['Socket']
 | 
						|
                     content = sock.recv(comReadParameters['Count'])
 | 
						|
                 respParameters['Count']    = len(content)
 | 
						|
                 respData['DataLength']     = len(content)
 | 
						|
                 respData['Data']           = content
 | 
						|
             except Exception, e:
 | 
						|
                 smbServer.log('smbComRead: %s ' % e, logging.ERROR)
 | 
						|
                 errorCode = STATUS_ACCESS_DENIED
 | 
						|
        else:
 | 
						|
            errorCode = STATUS_INVALID_HANDLE
 | 
						|
 | 
						|
        if errorCode > 0:
 | 
						|
            respParameters = ''
 | 
						|
            respData       = ''
 | 
						|
 | 
						|
        respSMBCommand['Parameters']             = respParameters
 | 
						|
        respSMBCommand['Data']                   = respData
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smbComReadAndX(connId, smbServer, SMBCommand, recvPacket):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_READ_ANDX)
 | 
						|
        respParameters        = smb.SMBReadAndXResponse_Parameters()
 | 
						|
        respData              = ''
 | 
						|
 | 
						|
        if SMBCommand['WordCount'] == 0x0A:
 | 
						|
            readAndX =  smb.SMBReadAndX_Parameters2(SMBCommand['Parameters'])
 | 
						|
        else:
 | 
						|
            readAndX =  smb.SMBReadAndX_Parameters(SMBCommand['Parameters'])
 | 
						|
 | 
						|
        if connData['OpenedFiles'].has_key(readAndX['Fid']):
 | 
						|
             fileHandle = connData['OpenedFiles'][readAndX['Fid']]['FileHandle']
 | 
						|
             errorCode = 0
 | 
						|
             try:
 | 
						|
                 if fileHandle != PIPE_FILE_DESCRIPTOR:
 | 
						|
                     offset = readAndX['Offset']
 | 
						|
                     if readAndX.fields.has_key('HighOffset'):
 | 
						|
                         offset += (readAndX['HighOffset'] << 32)
 | 
						|
                     os.lseek(fileHandle,offset,0)
 | 
						|
                     content = os.read(fileHandle,readAndX['MaxCount'])
 | 
						|
                 else:
 | 
						|
                     sock = connData['OpenedFiles'][readAndX['Fid']]['Socket']
 | 
						|
                     content = sock.recv(readAndX['MaxCount'])
 | 
						|
                 respParameters['Remaining']    = 0xffff
 | 
						|
                 respParameters['DataCount']    = len(content)
 | 
						|
                 respParameters['DataOffset']   = 59
 | 
						|
                 respParameters['DataCount_Hi'] = 0
 | 
						|
                 respData = content
 | 
						|
             except Exception, e:
 | 
						|
                 smbServer.log('smbComReadAndX: %s ' % e, logging.ERROR)
 | 
						|
                 errorCode = STATUS_ACCESS_DENIED
 | 
						|
        else:
 | 
						|
            errorCode = STATUS_INVALID_HANDLE
 | 
						|
 | 
						|
        if errorCode > 0:
 | 
						|
            respParameters = ''
 | 
						|
            respData       = ''
 | 
						|
 | 
						|
        respSMBCommand['Parameters']             = respParameters
 | 
						|
        respSMBCommand['Data']                   = respData
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smbQueryInformation(connId, smbServer, SMBCommand, recvPacket):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_QUERY_INFORMATION)
 | 
						|
        respParameters = smb.SMBQueryInformationResponse_Parameters()
 | 
						|
        respData       = ''
 | 
						|
 | 
						|
        queryInformation= smb.SMBQueryInformation_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
 | 
						|
 | 
						|
        # Get the Tid associated
 | 
						|
        if connData['ConnectedShares'].has_key(recvPacket['Tid']):
 | 
						|
            fileSize, lastWriteTime, fileAttributes = queryFsInformation(
 | 
						|
                connData['ConnectedShares'][recvPacket['Tid']]['path'],
 | 
						|
                decodeSMBString(recvPacket['Flags2'],queryInformation['FileName']))
 | 
						|
 | 
						|
            respParameters['FileSize']       = fileSize
 | 
						|
            respParameters['LastWriteTime']  = lastWriteTime
 | 
						|
            respParameters['FileAttributes'] = fileAttributes
 | 
						|
            errorCode = STATUS_SUCCESS
 | 
						|
        else:
 | 
						|
            # STATUS_SMB_BAD_TID
 | 
						|
            errorCode = STATUS_SMB_BAD_TID
 | 
						|
            respParameters  = ''
 | 
						|
            respData        = ''
 | 
						|
 | 
						|
        respSMBCommand['Parameters']             = respParameters
 | 
						|
        respSMBCommand['Data']                   = respData
 | 
						|
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smbQueryInformationDisk(connId, smbServer, SMBCommand, recvPacket):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_QUERY_INFORMATION_DISK)
 | 
						|
        respParameters = smb.SMBQueryInformationDiskResponse_Parameters()
 | 
						|
        respData       = ''
 | 
						|
 | 
						|
        # Get the Tid associated
 | 
						|
        if connData['ConnectedShares'].has_key(recvPacket['Tid']):
 | 
						|
            totalUnits, freeUnits = queryDiskInformation(
 | 
						|
                        connData['ConnectedShares'][recvPacket['Tid']]['path'])
 | 
						|
 | 
						|
            respParameters['TotalUnits']    = totalUnits
 | 
						|
            respParameters['BlocksPerUnit'] = 1
 | 
						|
            respParameters['BlockSize']     = 1
 | 
						|
            respParameters['FreeUnits']     = freeUnits
 | 
						|
            errorCode = STATUS_SUCCESS
 | 
						|
        else:
 | 
						|
            # STATUS_SMB_BAD_TID
 | 
						|
            respData  = ''
 | 
						|
            respParameters = ''
 | 
						|
            errorCode = STATUS_SMB_BAD_TID
 | 
						|
 | 
						|
 | 
						|
        respSMBCommand['Parameters']             = respParameters
 | 
						|
        respSMBCommand['Data']                   = respData
 | 
						|
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smbComEcho(connId, smbServer, SMBCommand, recvPacket):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_ECHO)
 | 
						|
        respParameters = smb.SMBEchoResponse_Parameters()
 | 
						|
        respData       = smb.SMBEchoResponse_Data()
 | 
						|
 | 
						|
        echoData       = smb.SMBEcho_Data(SMBCommand['Data'])
 | 
						|
 | 
						|
        respParameters['SequenceNumber'] = 1
 | 
						|
        respData['Data']                 = echoData['Data']
 | 
						|
 | 
						|
        respSMBCommand['Parameters']     = respParameters
 | 
						|
        respSMBCommand['Data']           = respData
 | 
						|
 | 
						|
        errorCode = STATUS_SUCCESS
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smbComTreeDisconnect(connId, smbServer, SMBCommand, recvPacket):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_TREE_DISCONNECT)
 | 
						|
 | 
						|
        # Check if the Tid matches the Tid trying to disconnect
 | 
						|
        respParameters = ''
 | 
						|
        respData = ''
 | 
						|
 | 
						|
        if connData['ConnectedShares'].has_key(recvPacket['Tid']):
 | 
						|
            smbServer.log("Disconnecting Share(%d:%s)" % (recvPacket['Tid'],connData['ConnectedShares'][recvPacket['Tid']]['shareName']))
 | 
						|
            del(connData['ConnectedShares'][recvPacket['Tid']])
 | 
						|
            errorCode = STATUS_SUCCESS
 | 
						|
        else:
 | 
						|
            # STATUS_SMB_BAD_TID
 | 
						|
            errorCode = STATUS_SMB_BAD_TID
 | 
						|
 | 
						|
        respSMBCommand['Parameters'] = respParameters
 | 
						|
        respSMBCommand['Data']       = respData
 | 
						|
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smbComLogOffAndX(connId, smbServer, SMBCommand, recvPacket):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_LOGOFF_ANDX)
 | 
						|
 | 
						|
        # Check if the Uid matches the user trying to logoff
 | 
						|
        respParameters = ''
 | 
						|
        respData = ''
 | 
						|
        if recvPacket['Uid'] != connData['Uid']:
 | 
						|
            # STATUS_SMB_BAD_UID
 | 
						|
            errorCode = STATUS_SMB_BAD_UID
 | 
						|
        else:
 | 
						|
            errorCode = STATUS_SUCCESS
 | 
						|
 | 
						|
        respSMBCommand['Parameters']   = respParameters
 | 
						|
        respSMBCommand['Data']         = respData
 | 
						|
        connData['Uid'] = 0
 | 
						|
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smbComQueryInformation2(connId, smbServer, SMBCommand, recvPacket):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_QUERY_INFORMATION2)
 | 
						|
        respParameters        = smb.SMBQueryInformation2Response_Parameters()
 | 
						|
        respData              = ''
 | 
						|
 | 
						|
        queryInformation2 = smb.SMBQueryInformation2_Parameters(SMBCommand['Parameters'])
 | 
						|
        errorCode = 0xFF
 | 
						|
        if connData['OpenedFiles'].has_key(queryInformation2['Fid']):
 | 
						|
             errorCode = STATUS_SUCCESS
 | 
						|
             pathName = connData['OpenedFiles'][queryInformation2['Fid']]['FileName']
 | 
						|
             try:
 | 
						|
                 (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(pathName)
 | 
						|
                 respParameters['CreateDate']         = getSMBDate(ctime)
 | 
						|
                 respParameters['CreationTime']       = getSMBTime(ctime)
 | 
						|
                 respParameters['LastAccessDate']     = getSMBDate(atime)
 | 
						|
                 respParameters['LastAccessTime']     = getSMBTime(atime)
 | 
						|
                 respParameters['LastWriteDate']      = getSMBDate(mtime)
 | 
						|
                 respParameters['LastWriteTime']      = getSMBTime(mtime)
 | 
						|
                 respParameters['FileDataSize']       = size
 | 
						|
                 respParameters['FileAllocationSize'] = size
 | 
						|
                 attribs = 0
 | 
						|
                 if os.path.isdir(pathName):
 | 
						|
                     attribs = smb.SMB_FILE_ATTRIBUTE_DIRECTORY
 | 
						|
                 if os.path.isfile(pathName):
 | 
						|
                     attribs = smb.SMB_FILE_ATTRIBUTE_NORMAL
 | 
						|
                 respParameters['FileAttributes'] = attribs
 | 
						|
             except Exception, e:
 | 
						|
                 smbServer.log('smbComQueryInformation2 %s' % e,logging.ERROR)
 | 
						|
                 errorCode = STATUS_ACCESS_DENIED
 | 
						|
 | 
						|
        if errorCode > 0:
 | 
						|
            respParameters = ''
 | 
						|
            respData       = ''
 | 
						|
 | 
						|
        respSMBCommand['Parameters']             = respParameters
 | 
						|
        respSMBCommand['Data']                   = respData
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smbComNtCreateAndX(connId, smbServer, SMBCommand, recvPacket):
 | 
						|
        # TODO: Fully implement this
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_NT_CREATE_ANDX)
 | 
						|
        respParameters        = smb.SMBNtCreateAndXResponse_Parameters()
 | 
						|
        respData              = ''
 | 
						|
 | 
						|
        ntCreateAndXParameters = smb.SMBNtCreateAndX_Parameters(SMBCommand['Parameters'])
 | 
						|
        ntCreateAndXData       = smb.SMBNtCreateAndX_Data( flags = recvPacket['Flags2'], data = SMBCommand['Data'])
 | 
						|
 | 
						|
        #if ntCreateAndXParameters['CreateFlags'] & 0x10:  # NT_CREATE_REQUEST_EXTENDED_RESPONSE
 | 
						|
        #    respParameters        = smb.SMBNtCreateAndXExtendedResponse_Parameters()
 | 
						|
        #    respParameters['VolumeGUID'] = '\x00'
 | 
						|
 | 
						|
        # Get the Tid associated
 | 
						|
        if connData['ConnectedShares'].has_key(recvPacket['Tid']):
 | 
						|
             # If we have a rootFid, the path is relative to that fid
 | 
						|
             errorCode = STATUS_SUCCESS
 | 
						|
             if ntCreateAndXParameters['RootFid'] > 0:
 | 
						|
                 path = connData['OpenedFiles'][ntCreateAndXParameters['RootFid']]['FileName']
 | 
						|
                 LOG.debug("RootFid present %s!" % path)
 | 
						|
             else:
 | 
						|
                 if connData['ConnectedShares'][recvPacket['Tid']].has_key('path'):
 | 
						|
                     path = connData['ConnectedShares'][recvPacket['Tid']]['path']
 | 
						|
                 else:
 | 
						|
                     path = 'NONE'
 | 
						|
                     errorCode = STATUS_ACCESS_DENIED
 | 
						|
 | 
						|
             deleteOnClose = False
 | 
						|
 | 
						|
             fileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],ntCreateAndXData['FileName']).replace('\\','/'))
 | 
						|
             if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
 | 
						|
                # strip leading '/'
 | 
						|
                fileName = fileName[1:]
 | 
						|
             pathName = os.path.join(path,fileName)
 | 
						|
             createDisposition = ntCreateAndXParameters['Disposition']
 | 
						|
             mode = 0
 | 
						|
 | 
						|
             if createDisposition == smb.FILE_SUPERSEDE:
 | 
						|
                 mode |= os.O_TRUNC | os.O_CREAT
 | 
						|
             elif createDisposition & smb.FILE_OVERWRITE_IF == smb.FILE_OVERWRITE_IF:
 | 
						|
                 mode |= os.O_TRUNC | os.O_CREAT
 | 
						|
             elif createDisposition & smb.FILE_OVERWRITE == smb.FILE_OVERWRITE:
 | 
						|
                 if os.path.exists(pathName) is True:
 | 
						|
                     mode |= os.O_TRUNC
 | 
						|
                 else:
 | 
						|
                     errorCode = STATUS_NO_SUCH_FILE
 | 
						|
             elif createDisposition & smb.FILE_OPEN_IF == smb.FILE_OPEN_IF:
 | 
						|
                 if os.path.exists(pathName) is True:
 | 
						|
                     mode |= os.O_TRUNC
 | 
						|
                 else:
 | 
						|
                     mode |= os.O_TRUNC | os.O_CREAT
 | 
						|
             elif createDisposition & smb.FILE_CREATE == smb.FILE_CREATE:
 | 
						|
                 if os.path.exists(pathName) is True:
 | 
						|
                     errorCode = STATUS_OBJECT_NAME_COLLISION
 | 
						|
                 else:
 | 
						|
                     mode |= os.O_CREAT
 | 
						|
             elif createDisposition & smb.FILE_OPEN == smb.FILE_OPEN:
 | 
						|
                 if os.path.exists(pathName) is not True and smbServer.getRegisteredNamedPipes().has_key(unicode(pathName)) is not True:
 | 
						|
                     errorCode = STATUS_NO_SUCH_FILE
 | 
						|
 | 
						|
             if errorCode == STATUS_SUCCESS:
 | 
						|
                 desiredAccess = ntCreateAndXParameters['AccessMask']
 | 
						|
                 if (desiredAccess & smb.FILE_READ_DATA) or (desiredAccess & smb.GENERIC_READ):
 | 
						|
                     mode |= os.O_RDONLY
 | 
						|
                 if (desiredAccess & smb.FILE_WRITE_DATA) or (desiredAccess & smb.GENERIC_WRITE):
 | 
						|
                     if (desiredAccess & smb.FILE_READ_DATA) or (desiredAccess & smb.GENERIC_READ):
 | 
						|
                         mode |= os.O_RDWR #| os.O_APPEND
 | 
						|
                     else:
 | 
						|
                         mode |= os.O_WRONLY #| os.O_APPEND
 | 
						|
                 if desiredAccess & smb.GENERIC_ALL:
 | 
						|
                     mode |= os.O_RDWR #| os.O_APPEND
 | 
						|
 | 
						|
                 createOptions =  ntCreateAndXParameters['CreateOptions']
 | 
						|
                 if mode & os.O_CREAT == os.O_CREAT:
 | 
						|
                     if createOptions & smb.FILE_DIRECTORY_FILE == smb.FILE_DIRECTORY_FILE:
 | 
						|
                         try:
 | 
						|
                             # Let's create the directory
 | 
						|
                             os.mkdir(pathName)
 | 
						|
                             mode = os.O_RDONLY
 | 
						|
                         except Exception, e:
 | 
						|
                             smbServer.log("NTCreateAndX: %s,%s,%s" % (pathName,mode,e),logging.ERROR)
 | 
						|
                             errorCode = STATUS_ACCESS_DENIED
 | 
						|
                 if createOptions & smb.FILE_NON_DIRECTORY_FILE == smb.FILE_NON_DIRECTORY_FILE:
 | 
						|
                     # If the file being opened is a directory, the server MUST fail the request with
 | 
						|
                     # STATUS_FILE_IS_A_DIRECTORY in the Status field of the SMB Header in the server
 | 
						|
                     # response.
 | 
						|
                     if os.path.isdir(pathName) is True:
 | 
						|
                        errorCode = STATUS_FILE_IS_A_DIRECTORY
 | 
						|
 | 
						|
                 if createOptions & smb.FILE_DELETE_ON_CLOSE == smb.FILE_DELETE_ON_CLOSE:
 | 
						|
                     deleteOnClose = True
 | 
						|
 | 
						|
                 if errorCode == STATUS_SUCCESS:
 | 
						|
                     try:
 | 
						|
                         if os.path.isdir(pathName) and sys.platform == 'win32':
 | 
						|
                            fid = VOID_FILE_DESCRIPTOR
 | 
						|
                         else:
 | 
						|
                            if sys.platform == 'win32':
 | 
						|
                               mode |= os.O_BINARY
 | 
						|
                            if smbServer.getRegisteredNamedPipes().has_key(unicode(pathName)):
 | 
						|
                                fid = PIPE_FILE_DESCRIPTOR
 | 
						|
                                sock = socket.socket()
 | 
						|
                                sock.connect(smbServer.getRegisteredNamedPipes()[unicode(pathName)])
 | 
						|
                            else:
 | 
						|
                                fid = os.open(pathName, mode)
 | 
						|
                     except Exception, e:
 | 
						|
                         smbServer.log("NTCreateAndX: %s,%s,%s" % (pathName,mode,e),logging.ERROR)
 | 
						|
                         #print e
 | 
						|
                         fid = 0
 | 
						|
                         errorCode = STATUS_ACCESS_DENIED
 | 
						|
        else:
 | 
						|
            errorCode = STATUS_SMB_BAD_TID
 | 
						|
 | 
						|
        if errorCode == STATUS_SUCCESS:
 | 
						|
            # Simple way to generate a fid
 | 
						|
            if len(connData['OpenedFiles']) == 0:
 | 
						|
               fakefid = 1
 | 
						|
            else:
 | 
						|
               fakefid = connData['OpenedFiles'].keys()[-1] + 1
 | 
						|
            respParameters['Fid'] = fakefid
 | 
						|
            respParameters['CreateAction'] = createDisposition
 | 
						|
            if fid == PIPE_FILE_DESCRIPTOR:
 | 
						|
                respParameters['FileAttributes'] = 0x80
 | 
						|
                respParameters['IsDirectory'] = 0
 | 
						|
                respParameters['CreateTime']     = 0
 | 
						|
                respParameters['LastAccessTime'] = 0
 | 
						|
                respParameters['LastWriteTime']  = 0
 | 
						|
                respParameters['LastChangeTime'] = 0
 | 
						|
                respParameters['AllocationSize'] = 4096
 | 
						|
                respParameters['EndOfFile']      = 0
 | 
						|
                respParameters['FileType']       = 2
 | 
						|
                respParameters['IPCState']       = 0x5ff
 | 
						|
            else:
 | 
						|
                if os.path.isdir(pathName):
 | 
						|
                    respParameters['FileAttributes'] = smb.SMB_FILE_ATTRIBUTE_DIRECTORY
 | 
						|
                    respParameters['IsDirectory'] = 1
 | 
						|
                else:
 | 
						|
                    respParameters['IsDirectory'] = 0
 | 
						|
                    respParameters['FileAttributes'] = ntCreateAndXParameters['FileAttributes']
 | 
						|
                # Let's get this file's information
 | 
						|
                respInfo, errorCode = queryPathInformation('',pathName,level= smb.SMB_QUERY_FILE_ALL_INFO)
 | 
						|
                if errorCode == STATUS_SUCCESS:
 | 
						|
                    respParameters['CreateTime']     = respInfo['CreationTime']
 | 
						|
                    respParameters['LastAccessTime'] = respInfo['LastAccessTime']
 | 
						|
                    respParameters['LastWriteTime']  = respInfo['LastWriteTime']
 | 
						|
                    respParameters['LastChangeTime'] = respInfo['LastChangeTime']
 | 
						|
                    respParameters['FileAttributes'] = respInfo['ExtFileAttributes']
 | 
						|
                    respParameters['AllocationSize'] = respInfo['AllocationSize']
 | 
						|
                    respParameters['EndOfFile']      = respInfo['EndOfFile']
 | 
						|
                else:
 | 
						|
                    respParameters = ''
 | 
						|
                    respData       = ''
 | 
						|
 | 
						|
            if errorCode == STATUS_SUCCESS:
 | 
						|
                # Let's store the fid for the connection
 | 
						|
                # smbServer.log('Create file %s, mode:0x%x' % (pathName, mode))
 | 
						|
                connData['OpenedFiles'][fakefid] = {}
 | 
						|
                connData['OpenedFiles'][fakefid]['FileHandle'] = fid
 | 
						|
                connData['OpenedFiles'][fakefid]['FileName'] = pathName
 | 
						|
                connData['OpenedFiles'][fakefid]['DeleteOnClose']  = deleteOnClose
 | 
						|
                if fid == PIPE_FILE_DESCRIPTOR:
 | 
						|
                    connData['OpenedFiles'][fakefid]['Socket'] = sock
 | 
						|
        else:
 | 
						|
            respParameters = ''
 | 
						|
            respData       = ''
 | 
						|
 | 
						|
        respSMBCommand['Parameters']             = respParameters
 | 
						|
        respSMBCommand['Data']                   = respData
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smbComOpenAndX(connId, smbServer, SMBCommand, recvPacket):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_OPEN_ANDX)
 | 
						|
        respParameters        = smb.SMBOpenAndXResponse_Parameters()
 | 
						|
        respData              = ''
 | 
						|
 | 
						|
        openAndXParameters = smb.SMBOpenAndX_Parameters(SMBCommand['Parameters'])
 | 
						|
        openAndXData       = smb.SMBOpenAndX_Data( flags = recvPacket['Flags2'], data = SMBCommand['Data'])
 | 
						|
 | 
						|
        # Get the Tid associated
 | 
						|
        if connData['ConnectedShares'].has_key(recvPacket['Tid']):
 | 
						|
             path = connData['ConnectedShares'][recvPacket['Tid']]['path']
 | 
						|
             openedFile, mode, pathName, errorCode = openFile(path,
 | 
						|
                     decodeSMBString(recvPacket['Flags2'],openAndXData['FileName']),
 | 
						|
                     openAndXParameters['DesiredAccess'],
 | 
						|
                     openAndXParameters['FileAttributes'],
 | 
						|
                     openAndXParameters['OpenMode'])
 | 
						|
        else:
 | 
						|
           errorCode = STATUS_SMB_BAD_TID
 | 
						|
 | 
						|
        if errorCode == STATUS_SUCCESS:
 | 
						|
            # Simple way to generate a fid
 | 
						|
            fid = len(connData['OpenedFiles']) + 1
 | 
						|
            if len(connData['OpenedFiles']) == 0:
 | 
						|
               fid = 1
 | 
						|
            else:
 | 
						|
               fid = connData['OpenedFiles'].keys()[-1] + 1
 | 
						|
            respParameters['Fid'] = fid
 | 
						|
            if mode & os.O_CREAT:
 | 
						|
                # File did not exist and was created
 | 
						|
                respParameters['Action'] = 0x2
 | 
						|
            elif mode & os.O_RDONLY:
 | 
						|
                # File existed and was opened
 | 
						|
                respParameters['Action'] = 0x1
 | 
						|
            elif mode & os.O_APPEND:
 | 
						|
                # File existed and was opened
 | 
						|
                respParameters['Action'] = 0x1
 | 
						|
            else:
 | 
						|
                # File existed and was truncated
 | 
						|
                respParameters['Action'] = 0x3
 | 
						|
 | 
						|
            # Let's store the fid for the connection
 | 
						|
            #smbServer.log('Opening file %s' % pathName)
 | 
						|
            connData['OpenedFiles'][fid] = {}
 | 
						|
            connData['OpenedFiles'][fid]['FileHandle'] = openedFile
 | 
						|
            connData['OpenedFiles'][fid]['FileName'] = pathName
 | 
						|
            connData['OpenedFiles'][fid]['DeleteOnClose']  = False
 | 
						|
        else:
 | 
						|
            respParameters = ''
 | 
						|
            respData       = ''
 | 
						|
 | 
						|
        respSMBCommand['Parameters']             = respParameters
 | 
						|
        respSMBCommand['Data']                   = respData
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smbComTreeConnectAndX(connId, smbServer, SMBCommand, recvPacket):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        resp = smb.NewSMBPacket()
 | 
						|
        resp['Flags1'] = smb.SMB.FLAGS1_REPLY
 | 
						|
        resp['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES | recvPacket['Flags2'] & smb.SMB.FLAGS2_UNICODE
 | 
						|
 | 
						|
        resp['Tid'] = recvPacket['Tid']
 | 
						|
        resp['Mid'] = recvPacket['Mid']
 | 
						|
        resp['Pid'] = connData['Pid']
 | 
						|
 | 
						|
        respSMBCommand        = smb.SMBCommand(smb.SMB.SMB_COM_TREE_CONNECT_ANDX)
 | 
						|
        respParameters        = smb.SMBTreeConnectAndXResponse_Parameters()
 | 
						|
        respData              = smb.SMBTreeConnectAndXResponse_Data()
 | 
						|
 | 
						|
        treeConnectAndXParameters = smb.SMBTreeConnectAndX_Parameters(SMBCommand['Parameters'])
 | 
						|
 | 
						|
        if treeConnectAndXParameters['Flags'] & 0x8:
 | 
						|
            respParameters        = smb.SMBTreeConnectAndXExtendedResponse_Parameters()
 | 
						|
 | 
						|
        treeConnectAndXData                    = smb.SMBTreeConnectAndX_Data( flags = recvPacket['Flags2'] )
 | 
						|
        treeConnectAndXData['_PasswordLength'] = treeConnectAndXParameters['PasswordLength']
 | 
						|
        treeConnectAndXData.fromString(SMBCommand['Data'])
 | 
						|
 | 
						|
        errorCode = STATUS_SUCCESS
 | 
						|
 | 
						|
        ## Process here the request, does the share exist?
 | 
						|
        UNCOrShare = decodeSMBString(recvPacket['Flags2'], treeConnectAndXData['Path'])
 | 
						|
 | 
						|
        # Is this a UNC?
 | 
						|
        if ntpath.ismount(UNCOrShare):
 | 
						|
            path = UNCOrShare.split('\\')[3]
 | 
						|
        else:
 | 
						|
            path = ntpath.basename(UNCOrShare)
 | 
						|
 | 
						|
        share = searchShare(connId, path, smbServer)
 | 
						|
        if share is not None:
 | 
						|
            # Simple way to generate a Tid
 | 
						|
            if len(connData['ConnectedShares']) == 0:
 | 
						|
               tid = 1
 | 
						|
            else:
 | 
						|
               tid = connData['ConnectedShares'].keys()[-1] + 1
 | 
						|
            connData['ConnectedShares'][tid] = share
 | 
						|
            connData['ConnectedShares'][tid]['shareName'] = path
 | 
						|
            resp['Tid'] = tid
 | 
						|
            #smbServer.log("Connecting Share(%d:%s)" % (tid,path))
 | 
						|
        else:
 | 
						|
            smbServer.log("TreeConnectAndX not found %s" % path, logging.ERROR)
 | 
						|
            errorCode = STATUS_OBJECT_PATH_NOT_FOUND
 | 
						|
            resp['ErrorCode']   = errorCode >> 16
 | 
						|
            resp['ErrorClass']  = errorCode & 0xff
 | 
						|
        ##
 | 
						|
        respParameters['OptionalSupport'] = smb.SMB.SMB_SUPPORT_SEARCH_BITS
 | 
						|
 | 
						|
        if path == 'IPC$':
 | 
						|
            respData['Service']               = 'IPC'
 | 
						|
        else:
 | 
						|
            respData['Service']               = path
 | 
						|
        respData['PadLen']                = 0
 | 
						|
        respData['NativeFileSystem']      = encodeSMBString(recvPacket['Flags2'], 'NTFS' )
 | 
						|
 | 
						|
        respSMBCommand['Parameters']             = respParameters
 | 
						|
        respSMBCommand['Data']                   = respData
 | 
						|
 | 
						|
        resp['Uid'] = connData['Uid']
 | 
						|
        resp.addCommand(respSMBCommand)
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        return None, [resp], errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smbComSessionSetupAndX(connId, smbServer, SMBCommand, recvPacket):
 | 
						|
        connData = smbServer.getConnectionData(connId, checkStatus = False)
 | 
						|
 | 
						|
        respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_SESSION_SETUP_ANDX)
 | 
						|
 | 
						|
        # From [MS-SMB]
 | 
						|
        # When extended security is being used (see section 3.2.4.2.4), the
 | 
						|
        # request MUST take the following form
 | 
						|
        # [..]
 | 
						|
        # WordCount (1 byte): The value of this field MUST be 0x0C.
 | 
						|
        if SMBCommand['WordCount'] == 12:
 | 
						|
            # Extended security. Here we deal with all SPNEGO stuff
 | 
						|
            respParameters = smb.SMBSessionSetupAndX_Extended_Response_Parameters()
 | 
						|
            respData       = smb.SMBSessionSetupAndX_Extended_Response_Data(flags = recvPacket['Flags2'])
 | 
						|
            sessionSetupParameters = smb.SMBSessionSetupAndX_Extended_Parameters(SMBCommand['Parameters'])
 | 
						|
            sessionSetupData = smb.SMBSessionSetupAndX_Extended_Data()
 | 
						|
            sessionSetupData['SecurityBlobLength'] = sessionSetupParameters['SecurityBlobLength']
 | 
						|
            sessionSetupData.fromString(SMBCommand['Data'])
 | 
						|
            connData['Capabilities'] = sessionSetupParameters['Capabilities']
 | 
						|
 | 
						|
            rawNTLM = False
 | 
						|
            if struct.unpack('B',sessionSetupData['SecurityBlob'][0])[0] == ASN1_AID:
 | 
						|
               # NEGOTIATE packet
 | 
						|
               blob =  SPNEGO_NegTokenInit(sessionSetupData['SecurityBlob'])
 | 
						|
               token = blob['MechToken']
 | 
						|
               if len(blob['MechTypes'][0]) > 0:
 | 
						|
                   # Is this GSSAPI NTLM or something else we don't support?
 | 
						|
                   mechType = blob['MechTypes'][0]
 | 
						|
                   if mechType != TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']:
 | 
						|
                       # Nope, do we know it?
 | 
						|
                       if MechTypes.has_key(mechType):
 | 
						|
                           mechStr = MechTypes[mechType]
 | 
						|
                       else:
 | 
						|
                           mechStr = hexlify(mechType)
 | 
						|
                       smbServer.log("Unsupported MechType '%s'" % mechStr, logging.CRITICAL)
 | 
						|
                       # We don't know the token, we answer back again saying
 | 
						|
                       # we just support NTLM.
 | 
						|
                       # ToDo: Build this into a SPNEGO_NegTokenResp()
 | 
						|
                       respToken = '\xa1\x15\x30\x13\xa0\x03\x0a\x01\x03\xa1\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a'
 | 
						|
                       respParameters['SecurityBlobLength'] = len(respToken)
 | 
						|
                       respData['SecurityBlobLength'] = respParameters['SecurityBlobLength']
 | 
						|
                       respData['SecurityBlob']       = respToken
 | 
						|
                       respData['NativeOS']     = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS())
 | 
						|
                       respData['NativeLanMan'] = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS())
 | 
						|
                       respSMBCommand['Parameters'] = respParameters
 | 
						|
                       respSMBCommand['Data']       = respData
 | 
						|
                       return [respSMBCommand], None, STATUS_MORE_PROCESSING_REQUIRED
 | 
						|
 | 
						|
            elif struct.unpack('B',sessionSetupData['SecurityBlob'][0])[0] == ASN1_SUPPORTED_MECH:
 | 
						|
               # AUTH packet
 | 
						|
               blob = SPNEGO_NegTokenResp(sessionSetupData['SecurityBlob'])
 | 
						|
               token = blob['ResponseToken']
 | 
						|
            else:
 | 
						|
               # No GSSAPI stuff, raw NTLMSSP
 | 
						|
               rawNTLM = True
 | 
						|
               token = sessionSetupData['SecurityBlob']
 | 
						|
 | 
						|
            # Here we only handle NTLMSSP, depending on what stage of the
 | 
						|
            # authentication we are, we act on it
 | 
						|
            messageType = struct.unpack('<L',token[len('NTLMSSP\x00'):len('NTLMSSP\x00')+4])[0]
 | 
						|
 | 
						|
            if messageType == 0x01:
 | 
						|
                # NEGOTIATE_MESSAGE
 | 
						|
                negotiateMessage = ntlm.NTLMAuthNegotiate()
 | 
						|
                negotiateMessage.fromString(token)
 | 
						|
                # Let's store it in the connection data
 | 
						|
                connData['NEGOTIATE_MESSAGE'] = negotiateMessage
 | 
						|
                # Let's build the answer flags
 | 
						|
                # TODO: Parse all the flags. With this we're leaving some clients out
 | 
						|
 | 
						|
                ansFlags = 0
 | 
						|
 | 
						|
                if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_56:
 | 
						|
                   ansFlags |= ntlm.NTLMSSP_NEGOTIATE_56
 | 
						|
                if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_128:
 | 
						|
                   ansFlags |= ntlm.NTLMSSP_NEGOTIATE_128
 | 
						|
                if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH:
 | 
						|
                   ansFlags |= ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH
 | 
						|
                if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
 | 
						|
                   ansFlags |= ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
 | 
						|
                if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_UNICODE:
 | 
						|
                   ansFlags |= ntlm.NTLMSSP_NEGOTIATE_UNICODE
 | 
						|
                if negotiateMessage['flags'] & ntlm.NTLM_NEGOTIATE_OEM:
 | 
						|
                   ansFlags |= ntlm.NTLM_NEGOTIATE_OEM
 | 
						|
 | 
						|
                ansFlags |= ntlm.NTLMSSP_NEGOTIATE_VERSION | ntlm.NTLMSSP_NEGOTIATE_TARGET_INFO | ntlm.NTLMSSP_TARGET_TYPE_SERVER | ntlm.NTLMSSP_NEGOTIATE_NTLM | ntlm.NTLMSSP_REQUEST_TARGET
 | 
						|
 | 
						|
                # Generate the AV_PAIRS
 | 
						|
                av_pairs = ntlm.AV_PAIRS()
 | 
						|
                # TODO: Put the proper data from SMBSERVER config
 | 
						|
                av_pairs[ntlm.NTLMSSP_AV_HOSTNAME] = av_pairs[ntlm.NTLMSSP_AV_DNS_HOSTNAME] = smbServer.getServerName().encode('utf-16le')
 | 
						|
                av_pairs[ntlm.NTLMSSP_AV_DOMAINNAME] = av_pairs[ntlm.NTLMSSP_AV_DNS_DOMAINNAME] = smbServer.getServerDomain().encode('utf-16le')
 | 
						|
                av_pairs[ntlm.NTLMSSP_AV_TIME] = struct.pack('<q', (116444736000000000 + calendar.timegm(time.gmtime()) * 10000000) )
 | 
						|
 | 
						|
                challengeMessage = ntlm.NTLMAuthChallenge()
 | 
						|
                challengeMessage['flags']            = ansFlags
 | 
						|
                challengeMessage['domain_len']       = len(smbServer.getServerDomain().encode('utf-16le'))
 | 
						|
                challengeMessage['domain_max_len']   = challengeMessage['domain_len']
 | 
						|
                challengeMessage['domain_offset']    = 40 + 16
 | 
						|
                challengeMessage['challenge']        = smbServer.getSMBChallenge()
 | 
						|
                challengeMessage['domain_name']      = smbServer.getServerDomain().encode('utf-16le')
 | 
						|
                challengeMessage['TargetInfoFields_len']     = len(av_pairs)
 | 
						|
                challengeMessage['TargetInfoFields_max_len'] = len(av_pairs)
 | 
						|
                challengeMessage['TargetInfoFields'] = av_pairs
 | 
						|
                challengeMessage['TargetInfoFields_offset']  = 40 + 16 + len(challengeMessage['domain_name'])
 | 
						|
                challengeMessage['Version']          = '\xff'*8
 | 
						|
                challengeMessage['VersionLen']       = 8
 | 
						|
 | 
						|
                if rawNTLM is False:
 | 
						|
                    respToken = SPNEGO_NegTokenResp()
 | 
						|
                    # accept-incomplete. We want more data
 | 
						|
                    respToken['NegResult'] = '\x01'
 | 
						|
                    respToken['SupportedMech'] = TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']
 | 
						|
 | 
						|
                    respToken['ResponseToken'] = challengeMessage.getData()
 | 
						|
                else:
 | 
						|
                    respToken = challengeMessage
 | 
						|
 | 
						|
                # Setting the packet to STATUS_MORE_PROCESSING
 | 
						|
                errorCode = STATUS_MORE_PROCESSING_REQUIRED
 | 
						|
                # Let's set up an UID for this connection and store it
 | 
						|
                # in the connection's data
 | 
						|
                # Picking a fixed value
 | 
						|
                # TODO: Manage more UIDs for the same session
 | 
						|
                connData['Uid'] = 10
 | 
						|
                # Let's store it in the connection data
 | 
						|
                connData['CHALLENGE_MESSAGE'] = challengeMessage
 | 
						|
 | 
						|
            elif messageType == 0x02:
 | 
						|
                # CHALLENGE_MESSAGE
 | 
						|
                raise Exception('Challenge Message raise, not implemented!')
 | 
						|
            elif messageType == 0x03:
 | 
						|
                # AUTHENTICATE_MESSAGE, here we deal with authentication
 | 
						|
                authenticateMessage = ntlm.NTLMAuthChallengeResponse()
 | 
						|
                authenticateMessage.fromString(token)
 | 
						|
                smbServer.log("AUTHENTICATE_MESSAGE (%s\\%s,%s)" % (authenticateMessage['domain_name'], authenticateMessage['user_name'], authenticateMessage['host_name']))
 | 
						|
                # TODO: Check the credentials! Now granting permissions
 | 
						|
 | 
						|
                respToken = SPNEGO_NegTokenResp()
 | 
						|
                # accept-completed
 | 
						|
                respToken['NegResult'] = '\x00'
 | 
						|
 | 
						|
                # Status SUCCESS
 | 
						|
                errorCode = STATUS_SUCCESS
 | 
						|
                smbServer.log('User %s\\%s authenticated successfully' % (authenticateMessage['user_name'], authenticateMessage['host_name']))
 | 
						|
                # Let's store it in the connection data
 | 
						|
                connData['AUTHENTICATE_MESSAGE'] = authenticateMessage
 | 
						|
                try:
 | 
						|
                    jtr_dump_path = smbServer.getJTRdumpPath()
 | 
						|
                    ntlm_hash_data = outputToJohnFormat( connData['CHALLENGE_MESSAGE']['challenge'], authenticateMessage['user_name'], authenticateMessage['domain_name'], authenticateMessage['lanman'], authenticateMessage['ntlm'] )
 | 
						|
                    smbServer.log(ntlm_hash_data['hash_string'])
 | 
						|
                    if jtr_dump_path is not '':
 | 
						|
                        writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], jtr_dump_path)
 | 
						|
                except:
 | 
						|
                    smbServer.log("Could not write NTLM Hashes to the specified JTR_Dump_Path %s" % jtr_dump_path)
 | 
						|
            else:
 | 
						|
                raise Exception("Unknown NTLMSSP MessageType %d" % messageType)
 | 
						|
 | 
						|
            respParameters['SecurityBlobLength'] = len(respToken)
 | 
						|
            respData['SecurityBlobLength'] = respParameters['SecurityBlobLength']
 | 
						|
            respData['SecurityBlob']       = respToken.getData()
 | 
						|
 | 
						|
        else:
 | 
						|
            # Process Standard Security
 | 
						|
            respParameters = smb.SMBSessionSetupAndXResponse_Parameters()
 | 
						|
            respData       = smb.SMBSessionSetupAndXResponse_Data()
 | 
						|
            sessionSetupParameters = smb.SMBSessionSetupAndX_Parameters(SMBCommand['Parameters'])
 | 
						|
            sessionSetupData = smb.SMBSessionSetupAndX_Data()
 | 
						|
            sessionSetupData['AnsiPwdLength'] = sessionSetupParameters['AnsiPwdLength']
 | 
						|
            sessionSetupData['UnicodePwdLength'] = sessionSetupParameters['UnicodePwdLength']
 | 
						|
            sessionSetupData.fromString(SMBCommand['Data'])
 | 
						|
            connData['Capabilities'] = sessionSetupParameters['Capabilities']
 | 
						|
            # Do the verification here, for just now we grant access
 | 
						|
            # TODO: Manage more UIDs for the same session
 | 
						|
            errorCode = STATUS_SUCCESS
 | 
						|
            connData['Uid'] = 10
 | 
						|
            respParameters['Action'] = 0
 | 
						|
            smbServer.log('User %s\\%s authenticated successfully (basic)' % (sessionSetupData['PrimaryDomain'], sessionSetupData['Account']))
 | 
						|
            try:
 | 
						|
                jtr_dump_path = smbServer.getJTRdumpPath()
 | 
						|
                ntlm_hash_data = outputToJohnFormat( '', sessionSetupData['Account'], sessionSetupData['PrimaryDomain'], sessionSetupData['AnsiPwd'], sessionSetupData['UnicodePwd'] )
 | 
						|
                smbServer.log(ntlm_hash_data['hash_string'])
 | 
						|
                if jtr_dump_path is not '':
 | 
						|
                    writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], jtr_dump_path)
 | 
						|
            except:
 | 
						|
                smbServer.log("Could not write NTLM Hashes to the specified JTR_Dump_Path %s" % jtr_dump_path)
 | 
						|
 | 
						|
        respData['NativeOS']     = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS())
 | 
						|
        respData['NativeLanMan'] = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS())
 | 
						|
        respSMBCommand['Parameters'] = respParameters
 | 
						|
        respSMBCommand['Data']       = respData
 | 
						|
 | 
						|
        # From now on, the client can ask for other commands
 | 
						|
        connData['Authenticated'] = True
 | 
						|
        # For now, just switching to nobody
 | 
						|
        #os.setregid(65534,65534)
 | 
						|
        #os.setreuid(65534,65534)
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smbComNegotiate(connId, smbServer, SMBCommand, recvPacket ):
 | 
						|
        connData = smbServer.getConnectionData(connId, checkStatus = False)
 | 
						|
        connData['Pid'] = recvPacket['Pid']
 | 
						|
 | 
						|
        SMBCommand = smb.SMBCommand(recvPacket['Data'][0])
 | 
						|
        respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_NEGOTIATE)
 | 
						|
 | 
						|
        resp = smb.NewSMBPacket()
 | 
						|
        resp['Flags1'] = smb.SMB.FLAGS1_REPLY
 | 
						|
        resp['Pid'] = connData['Pid']
 | 
						|
        resp['Tid'] = recvPacket['Tid']
 | 
						|
        resp['Mid'] = recvPacket['Mid']
 | 
						|
 | 
						|
        # TODO: We support more dialects, and parse them accordingly
 | 
						|
        dialects = SMBCommand['Data'].split('\x02')
 | 
						|
        try:
 | 
						|
           index = dialects.index('NT LM 0.12\x00') - 1
 | 
						|
           # Let's fill the data for NTLM
 | 
						|
           if recvPacket['Flags2'] & smb.SMB.FLAGS2_EXTENDED_SECURITY:
 | 
						|
                    resp['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_UNICODE
 | 
						|
                    #resp['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS
 | 
						|
                    _dialects_data = smb.SMBExtended_Security_Data()
 | 
						|
                    _dialects_data['ServerGUID'] = 'A'*16
 | 
						|
                    blob = SPNEGO_NegTokenInit()
 | 
						|
                    blob['MechTypes'] = [TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']]
 | 
						|
                    _dialects_data['SecurityBlob'] = blob.getData()
 | 
						|
 | 
						|
                    _dialects_parameters = smb.SMBExtended_Security_Parameters()
 | 
						|
                    _dialects_parameters['Capabilities']    = smb.SMB.CAP_EXTENDED_SECURITY | smb.SMB.CAP_USE_NT_ERRORS | smb.SMB.CAP_NT_SMBS | smb.SMB.CAP_UNICODE
 | 
						|
                    _dialects_parameters['ChallengeLength'] = 0
 | 
						|
 | 
						|
           else:
 | 
						|
                    resp['Flags2'] = smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_UNICODE
 | 
						|
                    _dialects_parameters = smb.SMBNTLMDialect_Parameters()
 | 
						|
                    _dialects_data= smb.SMBNTLMDialect_Data()
 | 
						|
                    _dialects_data['Payload'] = ''
 | 
						|
                    if connData.has_key('EncryptionKey'):
 | 
						|
                        _dialects_data['Challenge'] = connData['EncryptionKey']
 | 
						|
                        _dialects_parameters['ChallengeLength'] = len(str(_dialects_data))
 | 
						|
                    else:
 | 
						|
                        # TODO: Handle random challenges, now one that can be used with rainbow tables
 | 
						|
                        _dialects_data['Challenge'] = '\x11\x22\x33\x44\x55\x66\x77\x88'
 | 
						|
                        _dialects_parameters['ChallengeLength'] = 8
 | 
						|
                    _dialects_parameters['Capabilities']    = smb.SMB.CAP_USE_NT_ERRORS | smb.SMB.CAP_NT_SMBS
 | 
						|
 | 
						|
           # Let's see if we need to support RPC_REMOTE_APIS
 | 
						|
           config = smbServer.getServerConfig()
 | 
						|
           if config.has_option('global','rpc_apis'):
 | 
						|
               if config.getboolean('global', 'rpc_apis') is True:
 | 
						|
                  _dialects_parameters['Capabilities'] |= smb.SMB.CAP_RPC_REMOTE_APIS
 | 
						|
 | 
						|
           _dialects_parameters['DialectIndex']    = index
 | 
						|
           _dialects_parameters['SecurityMode']    = smb.SMB.SECURITY_AUTH_ENCRYPTED | smb.SMB.SECURITY_SHARE_USER
 | 
						|
           _dialects_parameters['MaxMpxCount']     = 1
 | 
						|
           _dialects_parameters['MaxNumberVcs']    = 1
 | 
						|
           _dialects_parameters['MaxBufferSize']   = 64000
 | 
						|
           _dialects_parameters['MaxRawSize']      = 65536
 | 
						|
           _dialects_parameters['SessionKey']      = 0
 | 
						|
           _dialects_parameters['LowDateTime']     = 0
 | 
						|
           _dialects_parameters['HighDateTime']    = 0
 | 
						|
           _dialects_parameters['ServerTimeZone']  = 0
 | 
						|
 | 
						|
 | 
						|
           respSMBCommand['Data']           = _dialects_data
 | 
						|
           respSMBCommand['Parameters']     = _dialects_parameters
 | 
						|
           connData['_dialects_data']       = _dialects_data
 | 
						|
           connData['_dialects_parameters'] = _dialects_parameters
 | 
						|
 | 
						|
        except Exception, e:
 | 
						|
           # No NTLM throw an error
 | 
						|
           smbServer.log('smbComNegotiate: %s' % e, logging.ERROR)
 | 
						|
           respSMBCommand['Data'] = struct.pack('<H',0xffff)
 | 
						|
 | 
						|
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        resp.addCommand(respSMBCommand)
 | 
						|
 | 
						|
        return None, [resp], STATUS_SUCCESS
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def default(connId, smbServer, SMBCommand, recvPacket):
 | 
						|
        # By default we return an SMB Packet with error not implemented
 | 
						|
        smbServer.log("Not implemented command: 0x%x" % recvPacket['Command'],logging.DEBUG)
 | 
						|
        packet = smb.NewSMBPacket()
 | 
						|
        packet['Flags1']  = smb.SMB.FLAGS1_REPLY
 | 
						|
        packet['Flags2']  = smb.SMB.FLAGS2_NT_STATUS
 | 
						|
        packet['Command'] = recvPacket['Command']
 | 
						|
        packet['Pid']     = recvPacket['Pid']
 | 
						|
        packet['Tid']     = recvPacket['Tid']
 | 
						|
        packet['Mid']     = recvPacket['Mid']
 | 
						|
        packet['Uid']     = recvPacket['Uid']
 | 
						|
        packet['Data']    = '\x00\x00\x00'
 | 
						|
        errorCode = STATUS_NOT_IMPLEMENTED
 | 
						|
        packet['ErrorCode']   = errorCode >> 16
 | 
						|
        packet['ErrorClass']  = errorCode & 0xff
 | 
						|
 | 
						|
        return None, [packet], errorCode
 | 
						|
 | 
						|
class SMB2Commands:
 | 
						|
    @staticmethod
 | 
						|
    def smb2Negotiate(connId, smbServer, recvPacket, isSMB1 = False):
 | 
						|
        connData = smbServer.getConnectionData(connId, checkStatus = False)
 | 
						|
 | 
						|
        respPacket = smb2.SMB2Packet()
 | 
						|
        respPacket['Flags']     = smb2.SMB2_FLAGS_SERVER_TO_REDIR
 | 
						|
        respPacket['Status']    = STATUS_SUCCESS
 | 
						|
        respPacket['CreditRequestResponse'] = 1
 | 
						|
        respPacket['Command']   = smb2.SMB2_NEGOTIATE
 | 
						|
        respPacket['SessionID'] = 0
 | 
						|
        if isSMB1 is False:
 | 
						|
            respPacket['MessageID'] = recvPacket['MessageID']
 | 
						|
        else:
 | 
						|
            respPacket['MessageID'] = 0
 | 
						|
        respPacket['TreeID']    = 0
 | 
						|
 | 
						|
 | 
						|
        respSMBCommand = smb2.SMB2Negotiate_Response()
 | 
						|
 | 
						|
        respSMBCommand['SecurityMode'] = 1
 | 
						|
        if isSMB1 is True:
 | 
						|
            # Let's first parse the packet to see if the client supports SMB2
 | 
						|
            SMBCommand = smb.SMBCommand(recvPacket['Data'][0])
 | 
						|
 | 
						|
            dialects = SMBCommand['Data'].split('\x02')
 | 
						|
            if 'SMB 2.002\x00' in dialects or 'SMB 2.???\x00' in dialects:
 | 
						|
                respSMBCommand['DialectRevision'] = smb2.SMB2_DIALECT_002
 | 
						|
            else:
 | 
						|
                # Client does not support SMB2 fallbacking
 | 
						|
                raise Exception('SMB2 not supported, fallbacking')
 | 
						|
        else:
 | 
						|
            respSMBCommand['DialectRevision'] = smb2.SMB2_DIALECT_002
 | 
						|
        respSMBCommand['ServerGuid'] = 'A'*16
 | 
						|
        respSMBCommand['Capabilities'] = 0
 | 
						|
        respSMBCommand['MaxTransactSize'] = 65536
 | 
						|
        respSMBCommand['MaxReadSize'] = 65536
 | 
						|
        respSMBCommand['MaxWriteSize'] = 65536
 | 
						|
        respSMBCommand['SystemTime'] = getFileTime(calendar.timegm(time.gmtime()))
 | 
						|
        respSMBCommand['ServerStartTime'] = getFileTime(calendar.timegm(time.gmtime()))
 | 
						|
        respSMBCommand['SecurityBufferOffset'] = 0x80
 | 
						|
 | 
						|
        blob = SPNEGO_NegTokenInit()
 | 
						|
        blob['MechTypes'] = [TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']]
 | 
						|
 | 
						|
        respSMBCommand['Buffer'] = blob.getData()
 | 
						|
        respSMBCommand['SecurityBufferLength'] = len(respSMBCommand['Buffer'])
 | 
						|
 | 
						|
        respPacket['Data']      = respSMBCommand
 | 
						|
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        return None, [respPacket], STATUS_SUCCESS
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smb2SessionSetup(connId, smbServer, recvPacket):
 | 
						|
        connData = smbServer.getConnectionData(connId, checkStatus = False)
 | 
						|
 | 
						|
        respSMBCommand = smb2.SMB2SessionSetup_Response()
 | 
						|
 | 
						|
        sessionSetupData = smb2.SMB2SessionSetup(recvPacket['Data'])
 | 
						|
 | 
						|
        connData['Capabilities'] = sessionSetupData['Capabilities']
 | 
						|
 | 
						|
        securityBlob = sessionSetupData['Buffer']
 | 
						|
 | 
						|
        rawNTLM = False
 | 
						|
        if struct.unpack('B',securityBlob[0])[0] == ASN1_AID:
 | 
						|
           # NEGOTIATE packet
 | 
						|
           blob =  SPNEGO_NegTokenInit(securityBlob)
 | 
						|
           token = blob['MechToken']
 | 
						|
           if len(blob['MechTypes'][0]) > 0:
 | 
						|
               # Is this GSSAPI NTLM or something else we don't support?
 | 
						|
               mechType = blob['MechTypes'][0]
 | 
						|
               if mechType != TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']:
 | 
						|
                   # Nope, do we know it?
 | 
						|
                   if MechTypes.has_key(mechType):
 | 
						|
                       mechStr = MechTypes[mechType]
 | 
						|
                   else:
 | 
						|
                       mechStr = hexlify(mechType)
 | 
						|
                   smbServer.log("Unsupported MechType '%s'" % mechStr, logging.CRITICAL)
 | 
						|
                   # We don't know the token, we answer back again saying
 | 
						|
                   # we just support NTLM.
 | 
						|
                   # ToDo: Build this into a SPNEGO_NegTokenResp()
 | 
						|
                   respToken = '\xa1\x15\x30\x13\xa0\x03\x0a\x01\x03\xa1\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a'
 | 
						|
                   respSMBCommand['SecurityBufferOffset'] = 0x48
 | 
						|
                   respSMBCommand['SecurityBufferLength'] = len(respToken)
 | 
						|
                   respSMBCommand['Buffer'] = respToken
 | 
						|
 | 
						|
                   return [respSMBCommand], None, STATUS_MORE_PROCESSING_REQUIRED
 | 
						|
        elif struct.unpack('B',securityBlob[0])[0] == ASN1_SUPPORTED_MECH:
 | 
						|
           # AUTH packet
 | 
						|
           blob = SPNEGO_NegTokenResp(securityBlob)
 | 
						|
           token = blob['ResponseToken']
 | 
						|
        else:
 | 
						|
           # No GSSAPI stuff, raw NTLMSSP
 | 
						|
           rawNTLM = True
 | 
						|
           token = securityBlob
 | 
						|
 | 
						|
        # Here we only handle NTLMSSP, depending on what stage of the
 | 
						|
        # authentication we are, we act on it
 | 
						|
        messageType = struct.unpack('<L',token[len('NTLMSSP\x00'):len('NTLMSSP\x00')+4])[0]
 | 
						|
 | 
						|
        if messageType == 0x01:
 | 
						|
            # NEGOTIATE_MESSAGE
 | 
						|
            negotiateMessage = ntlm.NTLMAuthNegotiate()
 | 
						|
            negotiateMessage.fromString(token)
 | 
						|
            # Let's store it in the connection data
 | 
						|
            connData['NEGOTIATE_MESSAGE'] = negotiateMessage
 | 
						|
            # Let's build the answer flags
 | 
						|
            # TODO: Parse all the flags. With this we're leaving some clients out
 | 
						|
 | 
						|
            ansFlags = 0
 | 
						|
 | 
						|
            if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_56:
 | 
						|
               ansFlags |= ntlm.NTLMSSP_NEGOTIATE_56
 | 
						|
            if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_128:
 | 
						|
               ansFlags |= ntlm.NTLMSSP_NEGOTIATE_128
 | 
						|
            if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH:
 | 
						|
               ansFlags |= ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH
 | 
						|
            if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
 | 
						|
               ansFlags |= ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
 | 
						|
            if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_UNICODE:
 | 
						|
               ansFlags |= ntlm.NTLMSSP_NEGOTIATE_UNICODE
 | 
						|
            if negotiateMessage['flags'] & ntlm.NTLM_NEGOTIATE_OEM:
 | 
						|
               ansFlags |= ntlm.NTLM_NEGOTIATE_OEM
 | 
						|
 | 
						|
            ansFlags |= ntlm.NTLMSSP_NEGOTIATE_VERSION | ntlm.NTLMSSP_NEGOTIATE_TARGET_INFO | ntlm.NTLMSSP_TARGET_TYPE_SERVER | ntlm.NTLMSSP_NEGOTIATE_NTLM | ntlm.NTLMSSP_REQUEST_TARGET
 | 
						|
 | 
						|
            # Generate the AV_PAIRS
 | 
						|
            av_pairs = ntlm.AV_PAIRS()
 | 
						|
            # TODO: Put the proper data from SMBSERVER config
 | 
						|
            av_pairs[ntlm.NTLMSSP_AV_HOSTNAME] = av_pairs[ntlm.NTLMSSP_AV_DNS_HOSTNAME] = smbServer.getServerName().encode('utf-16le')
 | 
						|
            av_pairs[ntlm.NTLMSSP_AV_DOMAINNAME] = av_pairs[ntlm.NTLMSSP_AV_DNS_DOMAINNAME] = smbServer.getServerDomain().encode('utf-16le')
 | 
						|
            av_pairs[ntlm.NTLMSSP_AV_TIME] = struct.pack('<q', (116444736000000000 + calendar.timegm(time.gmtime()) * 10000000) )
 | 
						|
 | 
						|
            challengeMessage = ntlm.NTLMAuthChallenge()
 | 
						|
            challengeMessage['flags']            = ansFlags
 | 
						|
            challengeMessage['domain_len']       = len(smbServer.getServerDomain().encode('utf-16le'))
 | 
						|
            challengeMessage['domain_max_len']   = challengeMessage['domain_len']
 | 
						|
            challengeMessage['domain_offset']    = 40 + 16
 | 
						|
            challengeMessage['challenge']        = smbServer.getSMBChallenge()
 | 
						|
            challengeMessage['domain_name']      = smbServer.getServerDomain().encode('utf-16le')
 | 
						|
            challengeMessage['TargetInfoFields_len']     = len(av_pairs)
 | 
						|
            challengeMessage['TargetInfoFields_max_len'] = len(av_pairs)
 | 
						|
            challengeMessage['TargetInfoFields'] = av_pairs
 | 
						|
            challengeMessage['TargetInfoFields_offset']  = 40 + 16 + len(challengeMessage['domain_name'])
 | 
						|
            challengeMessage['Version']          = '\xff'*8
 | 
						|
            challengeMessage['VersionLen']       = 8
 | 
						|
 | 
						|
            if rawNTLM is False:
 | 
						|
                respToken = SPNEGO_NegTokenResp()
 | 
						|
                # accept-incomplete. We want more data
 | 
						|
                respToken['NegResult'] = '\x01'
 | 
						|
                respToken['SupportedMech'] = TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']
 | 
						|
 | 
						|
                respToken['ResponseToken'] = challengeMessage.getData()
 | 
						|
            else:
 | 
						|
                respToken = challengeMessage
 | 
						|
 | 
						|
            # Setting the packet to STATUS_MORE_PROCESSING
 | 
						|
            errorCode = STATUS_MORE_PROCESSING_REQUIRED
 | 
						|
            # Let's set up an UID for this connection and store it
 | 
						|
            # in the connection's data
 | 
						|
            # Picking a fixed value
 | 
						|
            # TODO: Manage more UIDs for the same session
 | 
						|
            connData['Uid'] = random.randint(1,0xffffffff)
 | 
						|
            # Let's store it in the connection data
 | 
						|
            connData['CHALLENGE_MESSAGE'] = challengeMessage
 | 
						|
 | 
						|
        elif messageType == 0x02:
 | 
						|
            # CHALLENGE_MESSAGE
 | 
						|
            raise Exception('Challenge Message raise, not implemented!')
 | 
						|
        elif messageType == 0x03:
 | 
						|
            # AUTHENTICATE_MESSAGE, here we deal with authentication
 | 
						|
            authenticateMessage = ntlm.NTLMAuthChallengeResponse()
 | 
						|
            authenticateMessage.fromString(token)
 | 
						|
            smbServer.log("AUTHENTICATE_MESSAGE (%s\\%s,%s)" % (authenticateMessage['domain_name'], authenticateMessage['user_name'], authenticateMessage['host_name']))
 | 
						|
            # TODO: Check the credentials! Now granting permissions
 | 
						|
 | 
						|
            respToken = SPNEGO_NegTokenResp()
 | 
						|
            # accept-completed
 | 
						|
            respToken['NegResult'] = '\x00'
 | 
						|
 | 
						|
            # Status SUCCESS
 | 
						|
            errorCode = STATUS_SUCCESS
 | 
						|
            smbServer.log('User %s\\%s authenticated successfully' % (authenticateMessage['user_name'], authenticateMessage['host_name']))
 | 
						|
            # Let's store it in the connection data
 | 
						|
            connData['AUTHENTICATE_MESSAGE'] = authenticateMessage
 | 
						|
            try:
 | 
						|
                jtr_dump_path = smbServer.getJTRdumpPath()
 | 
						|
                ntlm_hash_data = outputToJohnFormat( connData['CHALLENGE_MESSAGE']['challenge'], authenticateMessage['user_name'], authenticateMessage['domain_name'], authenticateMessage['lanman'], authenticateMessage['ntlm'] )
 | 
						|
                smbServer.log(ntlm_hash_data['hash_string'])
 | 
						|
                if jtr_dump_path is not '':
 | 
						|
                    writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], jtr_dump_path)
 | 
						|
            except:
 | 
						|
                smbServer.log("Could not write NTLM Hashes to the specified JTR_Dump_Path %s" % jtr_dump_path)
 | 
						|
            respSMBCommand['SessionFlags'] = 1
 | 
						|
        else:
 | 
						|
            raise Exception("Unknown NTLMSSP MessageType %d" % messageType)
 | 
						|
 | 
						|
        respSMBCommand['SecurityBufferOffset'] = 0x48
 | 
						|
        respSMBCommand['SecurityBufferLength'] = len(respToken)
 | 
						|
        respSMBCommand['Buffer'] = respToken.getData()
 | 
						|
 | 
						|
        # From now on, the client can ask for other commands
 | 
						|
        connData['Authenticated'] = True
 | 
						|
        # For now, just switching to nobody
 | 
						|
        #os.setregid(65534,65534)
 | 
						|
        #os.setreuid(65534,65534)
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smb2TreeConnect(connId, smbServer, recvPacket):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respPacket = smb2.SMB2Packet()
 | 
						|
        respPacket['Flags']     = smb2.SMB2_FLAGS_SERVER_TO_REDIR
 | 
						|
        respPacket['Status']    = STATUS_SUCCESS
 | 
						|
        respPacket['CreditRequestResponse'] = 1
 | 
						|
        respPacket['Command']   = recvPacket['Command']
 | 
						|
        respPacket['SessionID'] = connData['Uid']
 | 
						|
        respPacket['Reserved']  = recvPacket['Reserved']
 | 
						|
        respPacket['MessageID'] = recvPacket['MessageID']
 | 
						|
        respPacket['TreeID']    = recvPacket['TreeID']
 | 
						|
 | 
						|
        respSMBCommand        = smb2.SMB2TreeConnect_Response()
 | 
						|
 | 
						|
        treeConnectRequest = smb2.SMB2TreeConnect(recvPacket['Data'])
 | 
						|
 | 
						|
        errorCode = STATUS_SUCCESS
 | 
						|
 | 
						|
        ## Process here the request, does the share exist?
 | 
						|
        path = str(recvPacket)[treeConnectRequest['PathOffset']:][:treeConnectRequest['PathLength']]
 | 
						|
        UNCOrShare = path.decode('utf-16le')
 | 
						|
 | 
						|
        # Is this a UNC?
 | 
						|
        if ntpath.ismount(UNCOrShare):
 | 
						|
            path = UNCOrShare.split('\\')[3]
 | 
						|
        else:
 | 
						|
            path = ntpath.basename(UNCOrShare)
 | 
						|
 | 
						|
        share = searchShare(connId, path.upper(), smbServer)
 | 
						|
        if share is not None:
 | 
						|
            # Simple way to generate a Tid
 | 
						|
            if len(connData['ConnectedShares']) == 0:
 | 
						|
               tid = 1
 | 
						|
            else:
 | 
						|
               tid = connData['ConnectedShares'].keys()[-1] + 1
 | 
						|
            connData['ConnectedShares'][tid] = share
 | 
						|
            connData['ConnectedShares'][tid]['shareName'] = path
 | 
						|
            respPacket['TreeID']    = tid
 | 
						|
            smbServer.log("Connecting Share(%d:%s)" % (tid,path))
 | 
						|
        else:
 | 
						|
            smbServer.log("SMB2_TREE_CONNECT not found %s" % path, logging.ERROR)
 | 
						|
            errorCode = STATUS_OBJECT_PATH_NOT_FOUND
 | 
						|
            respPacket['Status'] = errorCode
 | 
						|
        ##
 | 
						|
 | 
						|
        if path == 'IPC$':
 | 
						|
            respSMBCommand['ShareType'] = smb2.SMB2_SHARE_TYPE_PIPE
 | 
						|
            respSMBCommand['ShareFlags'] = 0x30
 | 
						|
        else:
 | 
						|
            respSMBCommand['ShareType'] = smb2.SMB2_SHARE_TYPE_DISK
 | 
						|
            respSMBCommand['ShareFlags'] = 0x0
 | 
						|
 | 
						|
        respSMBCommand['Capabilities'] = 0
 | 
						|
        respSMBCommand['MaximalAccess'] = 0x000f01ff
 | 
						|
 | 
						|
        respPacket['Data'] = respSMBCommand
 | 
						|
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        return None, [respPacket], errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smb2Create(connId, smbServer, recvPacket):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand        = smb2.SMB2Create_Response()
 | 
						|
 | 
						|
        ntCreateRequest       = smb2.SMB2Create(recvPacket['Data'])
 | 
						|
 | 
						|
        respSMBCommand['Buffer'] = '\x00'
 | 
						|
        # Get the Tid associated
 | 
						|
        if connData['ConnectedShares'].has_key(recvPacket['TreeID']):
 | 
						|
             # If we have a rootFid, the path is relative to that fid
 | 
						|
             errorCode = STATUS_SUCCESS
 | 
						|
             if connData['ConnectedShares'][recvPacket['TreeID']].has_key('path'):
 | 
						|
                 path = connData['ConnectedShares'][recvPacket['TreeID']]['path']
 | 
						|
             else:
 | 
						|
                 path = 'NONE'
 | 
						|
                 errorCode = STATUS_ACCESS_DENIED
 | 
						|
 | 
						|
             deleteOnClose = False
 | 
						|
 | 
						|
             fileName = os.path.normpath(ntCreateRequest['Buffer'][:ntCreateRequest['NameLength']].decode('utf-16le').replace('\\','/'))
 | 
						|
             if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
 | 
						|
                # strip leading '/'
 | 
						|
                fileName = fileName[1:]
 | 
						|
             pathName = os.path.join(path,fileName)
 | 
						|
             createDisposition = ntCreateRequest['CreateDisposition']
 | 
						|
             mode = 0
 | 
						|
 | 
						|
             if createDisposition == smb2.FILE_SUPERSEDE:
 | 
						|
                 mode |= os.O_TRUNC | os.O_CREAT
 | 
						|
             elif createDisposition & smb2.FILE_OVERWRITE_IF == smb2.FILE_OVERWRITE_IF:
 | 
						|
                 mode |= os.O_TRUNC | os.O_CREAT
 | 
						|
             elif createDisposition & smb2.FILE_OVERWRITE == smb2.FILE_OVERWRITE:
 | 
						|
                 if os.path.exists(pathName) is True:
 | 
						|
                     mode |= os.O_TRUNC
 | 
						|
                 else:
 | 
						|
                     errorCode = STATUS_NO_SUCH_FILE
 | 
						|
             elif createDisposition & smb2.FILE_OPEN_IF == smb2.FILE_OPEN_IF:
 | 
						|
                 if os.path.exists(pathName) is True:
 | 
						|
                     mode |= os.O_TRUNC
 | 
						|
                 else:
 | 
						|
                     mode |= os.O_TRUNC | os.O_CREAT
 | 
						|
             elif createDisposition & smb2.FILE_CREATE == smb2.FILE_CREATE:
 | 
						|
                 if os.path.exists(pathName) is True:
 | 
						|
                     errorCode = STATUS_OBJECT_NAME_COLLISION
 | 
						|
                 else:
 | 
						|
                     mode |= os.O_CREAT
 | 
						|
             elif createDisposition & smb2.FILE_OPEN == smb2.FILE_OPEN:
 | 
						|
                 if os.path.exists(pathName) is not True and smbServer.getRegisteredNamedPipes().has_key(unicode(pathName)) is not True:
 | 
						|
                     errorCode = STATUS_NO_SUCH_FILE
 | 
						|
 | 
						|
             if errorCode == STATUS_SUCCESS:
 | 
						|
                 desiredAccess = ntCreateRequest['DesiredAccess']
 | 
						|
                 if (desiredAccess & smb2.FILE_READ_DATA) or (desiredAccess & smb2.GENERIC_READ):
 | 
						|
                     mode |= os.O_RDONLY
 | 
						|
                 if (desiredAccess & smb2.FILE_WRITE_DATA) or (desiredAccess & smb2.GENERIC_WRITE):
 | 
						|
                     if (desiredAccess & smb2.FILE_READ_DATA) or (desiredAccess & smb2.GENERIC_READ):
 | 
						|
                         mode |= os.O_RDWR #| os.O_APPEND
 | 
						|
                     else:
 | 
						|
                         mode |= os.O_WRONLY #| os.O_APPEND
 | 
						|
                 if desiredAccess & smb2.GENERIC_ALL:
 | 
						|
                     mode |= os.O_RDWR #| os.O_APPEND
 | 
						|
 | 
						|
                 createOptions =  ntCreateRequest['CreateOptions']
 | 
						|
                 if mode & os.O_CREAT == os.O_CREAT:
 | 
						|
                     if createOptions & smb2.FILE_DIRECTORY_FILE == smb2.FILE_DIRECTORY_FILE:
 | 
						|
                         try:
 | 
						|
                             # Let's create the directory
 | 
						|
                             os.mkdir(pathName)
 | 
						|
                             mode = os.O_RDONLY
 | 
						|
                         except Exception, e:
 | 
						|
                             smbServer.log("SMB2_CREATE: %s,%s,%s" % (pathName,mode,e),logging.ERROR)
 | 
						|
                             errorCode = STATUS_ACCESS_DENIED
 | 
						|
                 if createOptions & smb2.FILE_NON_DIRECTORY_FILE == smb2.FILE_NON_DIRECTORY_FILE:
 | 
						|
                     # If the file being opened is a directory, the server MUST fail the request with
 | 
						|
                     # STATUS_FILE_IS_A_DIRECTORY in the Status field of the SMB Header in the server
 | 
						|
                     # response.
 | 
						|
                     if os.path.isdir(pathName) is True:
 | 
						|
                        errorCode = STATUS_FILE_IS_A_DIRECTORY
 | 
						|
 | 
						|
                 if createOptions & smb2.FILE_DELETE_ON_CLOSE == smb2.FILE_DELETE_ON_CLOSE:
 | 
						|
                     deleteOnClose = True
 | 
						|
 | 
						|
                 if errorCode == STATUS_SUCCESS:
 | 
						|
                     try:
 | 
						|
                         if os.path.isdir(pathName) and sys.platform == 'win32':
 | 
						|
                            fid = VOID_FILE_DESCRIPTOR
 | 
						|
                         else:
 | 
						|
                            if sys.platform == 'win32':
 | 
						|
                               mode |= os.O_BINARY
 | 
						|
                            if smbServer.getRegisteredNamedPipes().has_key(unicode(pathName)):
 | 
						|
                                fid = PIPE_FILE_DESCRIPTOR
 | 
						|
                                sock = socket.socket()
 | 
						|
                                sock.connect(smbServer.getRegisteredNamedPipes()[unicode(pathName)])
 | 
						|
                            else:
 | 
						|
                                fid = os.open(pathName, mode)
 | 
						|
                     except Exception, e:
 | 
						|
                         smbServer.log("SMB2_CREATE: %s,%s,%s" % (pathName,mode,e),logging.ERROR)
 | 
						|
                         #print e
 | 
						|
                         fid = 0
 | 
						|
                         errorCode = STATUS_ACCESS_DENIED
 | 
						|
        else:
 | 
						|
            errorCode = STATUS_SMB_BAD_TID
 | 
						|
 | 
						|
        if errorCode == STATUS_SUCCESS:
 | 
						|
            # Simple way to generate a fid
 | 
						|
            fakefid = uuid.generate()
 | 
						|
 | 
						|
            respSMBCommand['FileID'] = fakefid
 | 
						|
            respSMBCommand['CreateAction'] = createDisposition
 | 
						|
 | 
						|
            if fid == PIPE_FILE_DESCRIPTOR:
 | 
						|
                respSMBCommand['CreationTime']   = 0
 | 
						|
                respSMBCommand['LastAccessTime'] = 0
 | 
						|
                respSMBCommand['LastWriteTime']  = 0
 | 
						|
                respSMBCommand['ChangeTime']     = 0
 | 
						|
                respSMBCommand['AllocationSize'] = 4096
 | 
						|
                respSMBCommand['EndOfFile']      = 0
 | 
						|
                respSMBCommand['FileAttributes'] = 0x80
 | 
						|
 | 
						|
            else:
 | 
						|
                if os.path.isdir(pathName):
 | 
						|
                    respSMBCommand['FileAttributes'] = smb.SMB_FILE_ATTRIBUTE_DIRECTORY
 | 
						|
                else:
 | 
						|
                    respSMBCommand['FileAttributes'] = ntCreateRequest['FileAttributes']
 | 
						|
                # Let's get this file's information
 | 
						|
                respInfo, errorCode = queryPathInformation('',pathName,level= smb.SMB_QUERY_FILE_ALL_INFO)
 | 
						|
                if errorCode == STATUS_SUCCESS:
 | 
						|
                    respSMBCommand['CreationTime']   = respInfo['CreationTime']
 | 
						|
                    respSMBCommand['LastAccessTime'] = respInfo['LastAccessTime']
 | 
						|
                    respSMBCommand['LastWriteTime']  = respInfo['LastWriteTime']
 | 
						|
                    respSMBCommand['LastChangeTime'] = respInfo['LastChangeTime']
 | 
						|
                    respSMBCommand['FileAttributes'] = respInfo['ExtFileAttributes']
 | 
						|
                    respSMBCommand['AllocationSize'] = respInfo['AllocationSize']
 | 
						|
                    respSMBCommand['EndOfFile']      = respInfo['EndOfFile']
 | 
						|
 | 
						|
            if errorCode == STATUS_SUCCESS:
 | 
						|
                # Let's store the fid for the connection
 | 
						|
                # smbServer.log('Create file %s, mode:0x%x' % (pathName, mode))
 | 
						|
                connData['OpenedFiles'][fakefid] = {}
 | 
						|
                connData['OpenedFiles'][fakefid]['FileHandle'] = fid
 | 
						|
                connData['OpenedFiles'][fakefid]['FileName'] = pathName
 | 
						|
                connData['OpenedFiles'][fakefid]['DeleteOnClose']  = deleteOnClose
 | 
						|
                connData['OpenedFiles'][fakefid]['Open']  = {}
 | 
						|
                connData['OpenedFiles'][fakefid]['Open']['EnumerationLocation'] = 0
 | 
						|
                connData['OpenedFiles'][fakefid]['Open']['EnumerationSearchPattern'] = ''
 | 
						|
                if fid == PIPE_FILE_DESCRIPTOR:
 | 
						|
                    connData['OpenedFiles'][fakefid]['Socket'] = sock
 | 
						|
        else:
 | 
						|
            respSMBCommand = smb2.SMB2Error()
 | 
						|
 | 
						|
        if errorCode == STATUS_SUCCESS:
 | 
						|
            connData['LastRequest']['SMB2_CREATE'] = respSMBCommand
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smb2Close(connId, smbServer, recvPacket):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand        = smb2.SMB2Close_Response()
 | 
						|
 | 
						|
        closeRequest = smb2.SMB2Close(recvPacket['Data'])
 | 
						|
 | 
						|
        if str(closeRequest['FileID']) == '\xff'*16:
 | 
						|
            # Let's take the data from the lastRequest
 | 
						|
            if  connData['LastRequest'].has_key('SMB2_CREATE'):
 | 
						|
                fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
 | 
						|
            else:
 | 
						|
                fileID = str(closeRequest['FileID'])
 | 
						|
        else:
 | 
						|
            fileID = str(closeRequest['FileID'])
 | 
						|
 | 
						|
        if connData['OpenedFiles'].has_key(fileID):
 | 
						|
             errorCode = STATUS_SUCCESS
 | 
						|
             fileHandle = connData['OpenedFiles'][fileID]['FileHandle']
 | 
						|
             pathName = connData['OpenedFiles'][fileID]['FileName']
 | 
						|
             infoRecord = None
 | 
						|
             try:
 | 
						|
                 if fileHandle == PIPE_FILE_DESCRIPTOR:
 | 
						|
                     connData['OpenedFiles'][fileID]['Socket'].close()
 | 
						|
                 elif fileHandle != VOID_FILE_DESCRIPTOR:
 | 
						|
                     os.close(fileHandle)
 | 
						|
                     infoRecord, errorCode = queryFileInformation(os.path.dirname(pathName), os.path.basename(pathName), smb2.SMB2_FILE_NETWORK_OPEN_INFO)
 | 
						|
             except Exception, e:
 | 
						|
                 smbServer.log("SMB2_CLOSE %s" % e, logging.ERROR)
 | 
						|
                 errorCode = STATUS_INVALID_HANDLE
 | 
						|
             else:
 | 
						|
                 # Check if the file was marked for removal
 | 
						|
                 if connData['OpenedFiles'][fileID]['DeleteOnClose'] is True:
 | 
						|
                     try:
 | 
						|
                         if os.path.isdir(pathName):
 | 
						|
                             shutil.rmtree(connData['OpenedFiles'][fileID]['FileName'])
 | 
						|
                         else:
 | 
						|
                             os.remove(connData['OpenedFiles'][fileID]['FileName'])
 | 
						|
                     except Exception, e:
 | 
						|
                         smbServer.log("SMB2_CLOSE %s" % e, logging.ERROR)
 | 
						|
                         errorCode = STATUS_ACCESS_DENIED
 | 
						|
 | 
						|
                 # Now fill out the response
 | 
						|
                 if infoRecord is not None:
 | 
						|
                     respSMBCommand['CreationTime']   = infoRecord['CreationTime']
 | 
						|
                     respSMBCommand['LastAccessTime'] = infoRecord['LastAccessTime']
 | 
						|
                     respSMBCommand['LastWriteTime']  = infoRecord['LastWriteTime']
 | 
						|
                     respSMBCommand['ChangeTime']     = infoRecord['ChangeTime']
 | 
						|
                     respSMBCommand['AllocationSize'] = infoRecord['AllocationSize']
 | 
						|
                     respSMBCommand['EndofFile']      = infoRecord['EndOfFile']
 | 
						|
                     respSMBCommand['FileAttributes'] = infoRecord['FileAttributes']
 | 
						|
                 if errorCode == STATUS_SUCCESS:
 | 
						|
                     del(connData['OpenedFiles'][fileID])
 | 
						|
        else:
 | 
						|
            errorCode = STATUS_INVALID_HANDLE
 | 
						|
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smb2QueryInfo(connId, smbServer, recvPacket):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand        = smb2.SMB2QueryInfo_Response()
 | 
						|
 | 
						|
        queryInfo = smb2.SMB2QueryInfo(recvPacket['Data'])
 | 
						|
 | 
						|
        errorCode = STATUS_SUCCESS
 | 
						|
 | 
						|
        respSMBCommand['OutputBufferOffset'] = 0x48
 | 
						|
        respSMBCommand['Buffer'] = '\x00'
 | 
						|
 | 
						|
        if str(queryInfo['FileID']) == '\xff'*16:
 | 
						|
            # Let's take the data from the lastRequest
 | 
						|
            if  connData['LastRequest'].has_key('SMB2_CREATE'):
 | 
						|
                fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
 | 
						|
            else:
 | 
						|
                fileID = str(queryInfo['FileID'])
 | 
						|
        else:
 | 
						|
            fileID = str(queryInfo['FileID'])
 | 
						|
 | 
						|
        if connData['ConnectedShares'].has_key(recvPacket['TreeID']):
 | 
						|
            if connData['OpenedFiles'].has_key(fileID):
 | 
						|
                fileName = connData['OpenedFiles'][fileID]['FileName']
 | 
						|
 | 
						|
                if queryInfo['InfoType'] == smb2.SMB2_0_INFO_FILE:
 | 
						|
                    if queryInfo['FileInfoClass'] == smb2.SMB2_FILE_INTERNAL_INFO:
 | 
						|
                        # No need to call queryFileInformation, we have the data here
 | 
						|
                        infoRecord = smb2.FileInternalInformation()
 | 
						|
                        infoRecord['IndexNumber'] = fileID
 | 
						|
                    else:
 | 
						|
                        infoRecord, errorCode = queryFileInformation(os.path.dirname(fileName), os.path.basename(fileName), queryInfo['FileInfoClass'])
 | 
						|
                elif queryInfo['InfoType'] == smb2.SMB2_0_INFO_FILESYSTEM:
 | 
						|
                    infoRecord = queryFsInformation(os.path.dirname(fileName), os.path.basename(fileName), queryInfo['FileInfoClass'])
 | 
						|
                elif queryInfo['InfoType'] == smb2.SMB2_0_INFO_SECURITY:
 | 
						|
                    # Failing for now, until we support it
 | 
						|
                    infoRecord = None
 | 
						|
                    errorCode = STATUS_ACCESS_DENIED
 | 
						|
                else:
 | 
						|
                    smbServer.log("queryInfo not supported (%x)" %  queryInfo['InfoType'], logging.ERROR)
 | 
						|
 | 
						|
                if infoRecord is not None:
 | 
						|
                    respSMBCommand['OutputBufferLength'] = len(infoRecord)
 | 
						|
                    respSMBCommand['Buffer'] = infoRecord
 | 
						|
            else:
 | 
						|
                errorCode = STATUS_INVALID_HANDLE
 | 
						|
        else:
 | 
						|
            errorCode = STATUS_SMB_BAD_TID
 | 
						|
 | 
						|
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smb2SetInfo(connId, smbServer, recvPacket):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand        = smb2.SMB2SetInfo_Response()
 | 
						|
 | 
						|
        setInfo = smb2.SMB2SetInfo(recvPacket['Data'])
 | 
						|
 | 
						|
        errorCode = STATUS_SUCCESS
 | 
						|
 | 
						|
        if str(setInfo['FileID']) == '\xff'*16:
 | 
						|
            # Let's take the data from the lastRequest
 | 
						|
            if  connData['LastRequest'].has_key('SMB2_CREATE'):
 | 
						|
                fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
 | 
						|
            else:
 | 
						|
                fileID = str(setInfo['FileID'])
 | 
						|
        else:
 | 
						|
            fileID = str(setInfo['FileID'])
 | 
						|
 | 
						|
        if connData['ConnectedShares'].has_key(recvPacket['TreeID']):
 | 
						|
            path     = connData['ConnectedShares'][recvPacket['TreeID']]['path']
 | 
						|
            if connData['OpenedFiles'].has_key(fileID):
 | 
						|
                pathName = connData['OpenedFiles'][fileID]['FileName']
 | 
						|
 | 
						|
                if setInfo['InfoType'] == smb2.SMB2_0_INFO_FILE:
 | 
						|
                    # The file information is being set
 | 
						|
                    informationLevel = setInfo['FileInfoClass']
 | 
						|
                    if informationLevel == smb2.SMB2_FILE_DISPOSITION_INFO:
 | 
						|
                        infoRecord = smb.SMBSetFileDispositionInfo(setInfo['Buffer'])
 | 
						|
                        if infoRecord['DeletePending'] > 0:
 | 
						|
                           # Mark this file for removal after closed
 | 
						|
                           connData['OpenedFiles'][fileID]['DeleteOnClose'] = True
 | 
						|
                    elif informationLevel == smb2.SMB2_FILE_BASIC_INFO:
 | 
						|
                        infoRecord = smb.SMBSetFileBasicInfo(setInfo['Buffer'])
 | 
						|
                        # Creation time won't be set,  the other ones we play with.
 | 
						|
                        atime = infoRecord['LastWriteTime']
 | 
						|
                        if atime == 0:
 | 
						|
                            atime = -1
 | 
						|
                        else:
 | 
						|
                            atime = getUnixTime(atime)
 | 
						|
                        mtime = infoRecord['ChangeTime']
 | 
						|
                        if mtime == 0:
 | 
						|
                            mtime = -1
 | 
						|
                        else:
 | 
						|
                            mtime = getUnixTime(mtime)
 | 
						|
                        if atime > 0 and mtime > 0:
 | 
						|
                            os.utime(pathName,(atime,mtime))
 | 
						|
                    elif informationLevel == smb2.SMB2_FILE_END_OF_FILE_INFO:
 | 
						|
                        fileHandle = connData['OpenedFiles'][fileID]['FileHandle']
 | 
						|
                        infoRecord = smb.SMBSetFileEndOfFileInfo(setInfo['Buffer'])
 | 
						|
                        if infoRecord['EndOfFile'] > 0:
 | 
						|
                            os.lseek(fileHandle, infoRecord['EndOfFile']-1, 0)
 | 
						|
                            os.write(fileHandle, '\x00')
 | 
						|
                    elif informationLevel == smb2.SMB2_FILE_RENAME_INFO:
 | 
						|
                        renameInfo = smb2.FILE_RENAME_INFORMATION_TYPE_2(setInfo['Buffer'])
 | 
						|
                        newPathName = os.path.join(path,renameInfo['FileName'].decode('utf-16le').replace('\\', '/'))
 | 
						|
                        if renameInfo['ReplaceIfExists'] == 0 and os.path.exists(newPathName):
 | 
						|
                            return [smb2.SMB2Error()], None, STATUS_OBJECT_NAME_COLLISION
 | 
						|
                        try:
 | 
						|
                             os.rename(pathName,newPathName)
 | 
						|
                             connData['OpenedFiles'][fileID]['FileName'] = newPathName
 | 
						|
                        except Exception, e:
 | 
						|
                             smbServer.log("smb2SetInfo: %s" % e, logging.ERROR)
 | 
						|
                             errorCode = STATUS_ACCESS_DENIED
 | 
						|
                    else:
 | 
						|
                        smbServer.log('Unknown level for set file info! 0x%x' % informationLevel, logging.ERROR)
 | 
						|
                        # UNSUPPORTED
 | 
						|
                        errorCode =  STATUS_NOT_SUPPORTED
 | 
						|
                #elif setInfo['InfoType'] == smb2.SMB2_0_INFO_FILESYSTEM:
 | 
						|
                #    # The underlying object store information is being set.
 | 
						|
                #    setInfo = queryFsInformation('/', fileName, queryInfo['FileInfoClass'])
 | 
						|
                #elif setInfo['InfoType'] == smb2.SMB2_0_INFO_SECURITY:
 | 
						|
                #    # The security information is being set.
 | 
						|
                #    # Failing for now, until we support it
 | 
						|
                #    infoRecord = None
 | 
						|
                #    errorCode = STATUS_ACCESS_DENIED
 | 
						|
                #elif setInfo['InfoType'] == smb2.SMB2_0_INFO_QUOTA:
 | 
						|
                #    # The underlying object store quota information is being set.
 | 
						|
                #    setInfo = queryFsInformation('/', fileName, queryInfo['FileInfoClass'])
 | 
						|
                else:
 | 
						|
                    smbServer.log("setInfo not supported (%x)" %  setInfo['InfoType'], logging.ERROR)
 | 
						|
 | 
						|
            else:
 | 
						|
                errorCode = STATUS_INVALID_HANDLE
 | 
						|
        else:
 | 
						|
            errorCode = STATUS_SMB_BAD_TID
 | 
						|
 | 
						|
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smb2Write(connId, smbServer, recvPacket):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand = smb2.SMB2Write_Response()
 | 
						|
        writeRequest   = smb2.SMB2Write(recvPacket['Data'])
 | 
						|
 | 
						|
        respSMBCommand['Buffer'] = '\x00'
 | 
						|
 | 
						|
        if str(writeRequest['FileID']) == '\xff'*16:
 | 
						|
            # Let's take the data from the lastRequest
 | 
						|
            if  connData['LastRequest'].has_key('SMB2_CREATE'):
 | 
						|
                fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
 | 
						|
            else:
 | 
						|
                fileID = str(writeRequest['FileID'])
 | 
						|
        else:
 | 
						|
            fileID = str(writeRequest['FileID'])
 | 
						|
 | 
						|
        if connData['OpenedFiles'].has_key(fileID):
 | 
						|
             fileHandle = connData['OpenedFiles'][fileID]['FileHandle']
 | 
						|
             errorCode = STATUS_SUCCESS
 | 
						|
             try:
 | 
						|
                 if fileHandle != PIPE_FILE_DESCRIPTOR:
 | 
						|
                     offset = writeRequest['Offset']
 | 
						|
                     # If we're trying to write past the file end we just skip the write call (Vista does this)
 | 
						|
                     if os.lseek(fileHandle, 0, 2) >= offset:
 | 
						|
                         os.lseek(fileHandle,offset,0)
 | 
						|
                         os.write(fileHandle,writeRequest['Buffer'])
 | 
						|
                 else:
 | 
						|
                     sock = connData['OpenedFiles'][fileID]['Socket']
 | 
						|
                     sock.send(writeRequest['Buffer'])
 | 
						|
 | 
						|
                 respSMBCommand['Count']    = writeRequest['Length']
 | 
						|
                 respSMBCommand['Remaining']= 0xff
 | 
						|
             except Exception, e:
 | 
						|
                 smbServer.log('SMB2_WRITE: %s' % e, logging.ERROR)
 | 
						|
                 errorCode = STATUS_ACCESS_DENIED
 | 
						|
        else:
 | 
						|
            errorCode = STATUS_INVALID_HANDLE
 | 
						|
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smb2Read(connId, smbServer, recvPacket):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand = smb2.SMB2Read_Response()
 | 
						|
        readRequest   = smb2.SMB2Read(recvPacket['Data'])
 | 
						|
 | 
						|
        respSMBCommand['Buffer'] = '\x00'
 | 
						|
 | 
						|
        if str(readRequest['FileID']) == '\xff'*16:
 | 
						|
            # Let's take the data from the lastRequest
 | 
						|
            if  connData['LastRequest'].has_key('SMB2_CREATE'):
 | 
						|
                fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
 | 
						|
            else:
 | 
						|
                fileID = str(readRequest['FileID'])
 | 
						|
        else:
 | 
						|
            fileID = str(readRequest['FileID'])
 | 
						|
 | 
						|
        if connData['OpenedFiles'].has_key(fileID):
 | 
						|
             fileHandle = connData['OpenedFiles'][fileID]['FileHandle']
 | 
						|
             errorCode = 0
 | 
						|
             try:
 | 
						|
                 if fileHandle != PIPE_FILE_DESCRIPTOR:
 | 
						|
                     offset = readRequest['Offset']
 | 
						|
                     os.lseek(fileHandle,offset,0)
 | 
						|
                     content = os.read(fileHandle,readRequest['Length'])
 | 
						|
                 else:
 | 
						|
                     sock = connData['OpenedFiles'][fileID]['Socket']
 | 
						|
                     content = sock.recv(readRequest['Length'])
 | 
						|
 | 
						|
                 respSMBCommand['DataOffset']   = 0x50
 | 
						|
                 respSMBCommand['DataLength']   = len(content)
 | 
						|
                 respSMBCommand['DataRemaining']= 0
 | 
						|
                 respSMBCommand['Buffer']       = content
 | 
						|
             except Exception, e:
 | 
						|
                 smbServer.log('SMB2_READ: %s ' % e, logging.ERROR)
 | 
						|
                 errorCode = STATUS_ACCESS_DENIED
 | 
						|
        else:
 | 
						|
            errorCode = STATUS_INVALID_HANDLE
 | 
						|
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smb2Flush(connId, smbServer, recvPacket):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand = smb2.SMB2Flush_Response()
 | 
						|
        flushRequest   = smb2.SMB2Flush(recvPacket['Data'])
 | 
						|
 | 
						|
        if connData['OpenedFiles'].has_key(str(flushRequest['FileID'])):
 | 
						|
             fileHandle = connData['OpenedFiles'][str(flushRequest['FileID'])]['FileHandle']
 | 
						|
             errorCode = STATUS_SUCCESS
 | 
						|
             try:
 | 
						|
                 os.fsync(fileHandle)
 | 
						|
             except Exception, e:
 | 
						|
                 smbServer.log("SMB2_FLUSH %s" % e, logging.ERROR)
 | 
						|
                 errorCode = STATUS_ACCESS_DENIED
 | 
						|
        else:
 | 
						|
            errorCode = STATUS_INVALID_HANDLE
 | 
						|
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smb2QueryDirectory(connId, smbServer, recvPacket):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
        respSMBCommand = smb2.SMB2QueryDirectory_Response()
 | 
						|
        queryDirectoryRequest   = smb2.SMB2QueryDirectory(recvPacket['Data'])
 | 
						|
 | 
						|
        respSMBCommand['Buffer'] = '\x00'
 | 
						|
 | 
						|
        # The server MUST locate the tree connection, as specified in section 3.3.5.2.11.
 | 
						|
        if connData['ConnectedShares'].has_key(recvPacket['TreeID']) is False:
 | 
						|
            return [smb2.SMB2Error()], None, STATUS_NETWORK_NAME_DELETED
 | 
						|
 | 
						|
        # Next, the server MUST locate the open for the directory to be queried
 | 
						|
        # If no open is found, the server MUST fail the request with STATUS_FILE_CLOSED
 | 
						|
        if str(queryDirectoryRequest['FileID']) == '\xff'*16:
 | 
						|
            # Let's take the data from the lastRequest
 | 
						|
            if  connData['LastRequest'].has_key('SMB2_CREATE'):
 | 
						|
                fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
 | 
						|
            else:
 | 
						|
                fileID = str(queryDirectoryRequest['FileID'])
 | 
						|
        else:
 | 
						|
            fileID = str(queryDirectoryRequest['FileID'])
 | 
						|
 | 
						|
        if connData['OpenedFiles'].has_key(fileID) is False:
 | 
						|
            return [smb2.SMB2Error()], None, STATUS_FILE_CLOSED
 | 
						|
 | 
						|
        # If the open is not an open to a directory, the request MUST be failed
 | 
						|
        # with STATUS_INVALID_PARAMETER.
 | 
						|
        if os.path.isdir(connData['OpenedFiles'][fileID]['FileName']) is False:
 | 
						|
            return [smb2.SMB2Error()], None, STATUS_INVALID_PARAMETER
 | 
						|
 | 
						|
        # If any other information class is specified in the FileInformationClass
 | 
						|
        # field of the SMB2 QUERY_DIRECTORY Request, the server MUST fail the
 | 
						|
        # operation with STATUS_INVALID_INFO_CLASS.
 | 
						|
        if queryDirectoryRequest['FileInformationClass'] not in (
 | 
						|
        smb2.FILE_DIRECTORY_INFORMATION, smb2.FILE_FULL_DIRECTORY_INFORMATION, smb2.FILEID_FULL_DIRECTORY_INFORMATION,
 | 
						|
        smb2.FILE_BOTH_DIRECTORY_INFORMATION, smb2.FILEID_BOTH_DIRECTORY_INFORMATION, smb2.FILENAMES_INFORMATION):
 | 
						|
            return [smb2.SMB2Error()], None, STATUS_INVALID_INFO_CLASS
 | 
						|
 | 
						|
        # If SMB2_REOPEN is set in the Flags field of the SMB2 QUERY_DIRECTORY
 | 
						|
        # Request, the server SHOULD<326> set Open.EnumerationLocation to 0
 | 
						|
        # and Open.EnumerationSearchPattern to an empty string.
 | 
						|
        if queryDirectoryRequest['Flags'] & smb2.SMB2_REOPEN:
 | 
						|
            connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] = 0
 | 
						|
            connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] = ''
 | 
						|
 | 
						|
        # If SMB2_RESTART_SCANS is set in the Flags field of the SMB2
 | 
						|
        # QUERY_DIRECTORY Request, the server MUST set
 | 
						|
        # Open.EnumerationLocation to 0.
 | 
						|
        if queryDirectoryRequest['Flags'] & smb2.SMB2_RESTART_SCANS:
 | 
						|
            connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] = 0
 | 
						|
 | 
						|
        # If Open.EnumerationLocation is 0 and Open.EnumerationSearchPattern
 | 
						|
        # is an empty string, then Open.EnumerationSearchPattern MUST be set
 | 
						|
        # to the search pattern specified in the SMB2 QUERY_DIRECTORY by
 | 
						|
        # FileNameOffset and FileNameLength. If FileNameLength is 0, the server
 | 
						|
        # SHOULD<327> set Open.EnumerationSearchPattern as "*" to search all entries.
 | 
						|
 | 
						|
        pattern = queryDirectoryRequest['Buffer'].decode('utf-16le')
 | 
						|
        if  connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] == 0 and \
 | 
						|
            connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] == '':
 | 
						|
            if pattern == '':
 | 
						|
                pattern = '*'
 | 
						|
            connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] = pattern
 | 
						|
 | 
						|
        # If SMB2_INDEX_SPECIFIED is set and FileNameLength is not zero,
 | 
						|
        # the server MUST set Open.EnumerationSearchPattern to the search pattern
 | 
						|
        # specified in the request by FileNameOffset and FileNameLength.
 | 
						|
        if queryDirectoryRequest['Flags'] & smb2.SMB2_INDEX_SPECIFIED and \
 | 
						|
           queryDirectoryRequest['FileNameLength'] > 0:
 | 
						|
            connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] = pattern
 | 
						|
 | 
						|
        pathName = os.path.join(os.path.normpath(connData['OpenedFiles'][fileID]['FileName']),pattern)
 | 
						|
        searchResult, searchCount, errorCode = findFirst2(os.path.dirname(pathName),
 | 
						|
                  os.path.basename(pathName),
 | 
						|
                  queryDirectoryRequest['FileInformationClass'],
 | 
						|
                  smb.ATTR_DIRECTORY, isSMB2 = True )
 | 
						|
 | 
						|
        if errorCode != STATUS_SUCCESS:
 | 
						|
            return [smb2.SMB2Error()], None, errorCode
 | 
						|
 | 
						|
        if searchCount > 2 and pattern == '*':
 | 
						|
            # strip . and ..
 | 
						|
            searchCount -= 2
 | 
						|
            searchResult = searchResult[2:]
 | 
						|
 | 
						|
        if searchCount == 0 and connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] == 0:
 | 
						|
            return [smb2.SMB2Error()], None, STATUS_NO_SUCH_FILE
 | 
						|
 | 
						|
        if  connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] < 0:
 | 
						|
            return [smb2.SMB2Error()], None, STATUS_NO_MORE_FILES
 | 
						|
 | 
						|
        totalData = 0
 | 
						|
        respData = ''
 | 
						|
        for nItem in range(connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'], searchCount):
 | 
						|
            connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] += 1
 | 
						|
            if queryDirectoryRequest['Flags'] & smb2.SL_RETURN_SINGLE_ENTRY:
 | 
						|
                # If single entry is requested we must clear the NextEntryOffset
 | 
						|
                searchResult[nItem]['NextEntryOffset'] = 0
 | 
						|
            data = searchResult[nItem].getData()
 | 
						|
            lenData = len(data)
 | 
						|
            padLen = (8-(lenData % 8)) %8
 | 
						|
 | 
						|
            if (totalData+lenData) >= queryDirectoryRequest['OutputBufferLength']:
 | 
						|
                connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] -= 1
 | 
						|
                break
 | 
						|
            else:
 | 
						|
                respData += data + '\x00'*padLen
 | 
						|
                totalData += lenData + padLen
 | 
						|
 | 
						|
            if queryDirectoryRequest['Flags'] & smb2.SL_RETURN_SINGLE_ENTRY:
 | 
						|
                break
 | 
						|
 | 
						|
        if connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] >= searchCount:
 | 
						|
             connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] = -1
 | 
						|
 | 
						|
        respSMBCommand['OutputBufferOffset'] = 0x48
 | 
						|
        respSMBCommand['OutputBufferLength'] = totalData
 | 
						|
        respSMBCommand['Buffer'] = respData
 | 
						|
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smb2ChangeNotify(connId, smbServer, recvPacket):
 | 
						|
 | 
						|
        return [smb2.SMB2Error()], None, STATUS_NOT_SUPPORTED
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smb2Echo(connId, smbServer, recvPacket):
 | 
						|
 | 
						|
        respSMBCommand = smb2.SMB2Echo_Response()
 | 
						|
 | 
						|
        return [respSMBCommand], None, STATUS_SUCCESS
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smb2TreeDisconnect(connId, smbServer, recvPacket):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand = smb2.SMB2TreeDisconnect_Response()
 | 
						|
 | 
						|
        if connData['ConnectedShares'].has_key(recvPacket['TreeID']):
 | 
						|
            smbServer.log("Disconnecting Share(%d:%s)" % (recvPacket['TreeID'],connData['ConnectedShares'][recvPacket['TreeID']]['shareName']))
 | 
						|
            del(connData['ConnectedShares'][recvPacket['TreeID']])
 | 
						|
            errorCode = STATUS_SUCCESS
 | 
						|
        else:
 | 
						|
            # STATUS_SMB_BAD_TID
 | 
						|
            errorCode = STATUS_SMB_BAD_TID
 | 
						|
 | 
						|
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smb2Logoff(connId, smbServer, recvPacket):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand = smb2.SMB2Logoff_Response()
 | 
						|
 | 
						|
        if recvPacket['SessionID'] != connData['Uid']:
 | 
						|
            # STATUS_SMB_BAD_UID
 | 
						|
            errorCode = STATUS_SMB_BAD_UID
 | 
						|
        else:
 | 
						|
            errorCode = STATUS_SUCCESS
 | 
						|
 | 
						|
        connData['Uid'] = 0
 | 
						|
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smb2Ioctl(connId, smbServer, recvPacket):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand = smb2.SMB2Ioctl_Response()
 | 
						|
        ioctlRequest   = smb2.SMB2Ioctl(recvPacket['Data'])
 | 
						|
 | 
						|
        ioctls = smbServer.getIoctls()
 | 
						|
        if ioctls.has_key(ioctlRequest['CtlCode']):
 | 
						|
            outputData, errorCode = ioctls[ioctlRequest['CtlCode']](connId, smbServer, ioctlRequest)
 | 
						|
            if errorCode == STATUS_SUCCESS:
 | 
						|
                respSMBCommand['CtlCode']      = ioctlRequest['CtlCode']
 | 
						|
                respSMBCommand['FileID']       = ioctlRequest['FileID']
 | 
						|
                respSMBCommand['InputOffset']  = 0
 | 
						|
                respSMBCommand['InputCount']   = 0
 | 
						|
                respSMBCommand['OutputOffset'] = 0x70
 | 
						|
                respSMBCommand['OutputCount']  = len(outputData)
 | 
						|
                respSMBCommand['Flags']        = 0
 | 
						|
                respSMBCommand['Buffer']       = outputData
 | 
						|
            else:
 | 
						|
                respSMBCommand = outputData
 | 
						|
        else:
 | 
						|
            smbServer.log("Ioctl not implemented command: 0x%x" % ioctlRequest['CtlCode'],logging.DEBUG)
 | 
						|
            errorCode = STATUS_INVALID_DEVICE_REQUEST
 | 
						|
            respSMBCommand = smb2.SMB2Error()
 | 
						|
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smb2Lock(connId, smbServer, recvPacket):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        respSMBCommand = smb2.SMB2Lock_Response()
 | 
						|
 | 
						|
        # I'm actually doing nothing.. just make MacOS happy ;)
 | 
						|
        errorCode = STATUS_SUCCESS
 | 
						|
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
        return [respSMBCommand], None, errorCode
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def smb2Cancel(connId, smbServer, recvPacket):
 | 
						|
        # I'm actually doing nothing
 | 
						|
        return [smb2.SMB2Error()], None, STATUS_CANCELLED
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def default(connId, smbServer, recvPacket):
 | 
						|
        # By default we return an SMB Packet with error not implemented
 | 
						|
        smbServer.log("Not implemented command: 0x%x" % recvPacket['Command'],logging.DEBUG)
 | 
						|
        return [smb2.SMB2Error()], None, STATUS_NOT_SUPPORTED
 | 
						|
 | 
						|
class Ioctls:
 | 
						|
   @staticmethod
 | 
						|
   def fsctlDfsGetReferrals(connId, smbServer, ioctlRequest):
 | 
						|
        return smb2.SMB2Error(), STATUS_FS_DRIVER_REQUIRED
 | 
						|
 | 
						|
   @staticmethod
 | 
						|
   def fsctlPipeTransceive(connId, smbServer, ioctlRequest):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        ioctlResponse = ''
 | 
						|
 | 
						|
        if connData['OpenedFiles'].has_key(str(ioctlRequest['FileID'])):
 | 
						|
             fileHandle = connData['OpenedFiles'][str(ioctlRequest['FileID'])]['FileHandle']
 | 
						|
             errorCode = STATUS_SUCCESS
 | 
						|
             try:
 | 
						|
                 if fileHandle != PIPE_FILE_DESCRIPTOR:
 | 
						|
                     errorCode = STATUS_INVALID_DEVICE_REQUEST
 | 
						|
                 else:
 | 
						|
                     sock = connData['OpenedFiles'][str(ioctlRequest['FileID'])]['Socket']
 | 
						|
                     sock.sendall(ioctlRequest['Buffer'])
 | 
						|
                     ioctlResponse = sock.recv(ioctlRequest['MaxOutputResponse'])
 | 
						|
             except Exception, e:
 | 
						|
                 smbServer.log('fsctlPipeTransceive: %s ' % e, logging.ERROR)
 | 
						|
                 errorCode = STATUS_ACCESS_DENIED
 | 
						|
        else:
 | 
						|
            errorCode = STATUS_INVALID_DEVICE_REQUEST
 | 
						|
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
        return ioctlResponse, errorCode
 | 
						|
 | 
						|
   @staticmethod
 | 
						|
   def fsctlValidateNegotiateInfo(connId, smbServer, ioctlRequest):
 | 
						|
        connData = smbServer.getConnectionData(connId)
 | 
						|
 | 
						|
        errorCode = STATUS_SUCCESS
 | 
						|
 | 
						|
        validateNegotiateInfo = smb2.VALIDATE_NEGOTIATE_INFO(ioctlRequest['Buffer'])
 | 
						|
        validateNegotiateInfo['Capabilities'] = 0
 | 
						|
        validateNegotiateInfo['Guid'] = 'A'*16
 | 
						|
        validateNegotiateInfo['SecurityMode'] = 1
 | 
						|
        validateNegotiateInfo['Dialects'] = (smb2.SMB2_DIALECT_002,)
 | 
						|
 | 
						|
        smbServer.setConnectionData(connId, connData)
 | 
						|
        return validateNegotiateInfo.getData(), errorCode
 | 
						|
 | 
						|
 | 
						|
class SMBSERVERHandler(SocketServer.BaseRequestHandler):
 | 
						|
    def __init__(self, request, client_address, server, select_poll = False):
 | 
						|
        self.__SMB = server
 | 
						|
        self.__ip, self.__port = client_address
 | 
						|
        self.__request = request
 | 
						|
        self.__connId = threading.currentThread().getName()
 | 
						|
        self.__timeOut = 60*5
 | 
						|
        self.__select_poll = select_poll
 | 
						|
        #self.__connId = os.getpid()
 | 
						|
        SocketServer.BaseRequestHandler.__init__(self, request, client_address, server)
 | 
						|
 | 
						|
    def handle(self):
 | 
						|
        self.__SMB.log("Incoming connection (%s,%d)" % (self.__ip, self.__port))
 | 
						|
        self.__SMB.addConnection(self.__connId, self.__ip, self.__port)
 | 
						|
        while True:
 | 
						|
            try:
 | 
						|
                # Firt of all let's get the NETBIOS packet
 | 
						|
                session = nmb.NetBIOSTCPSession(self.__SMB.getServerName(),'HOST', self.__ip, sess_port = self.__port, sock = self.__request, select_poll = self.__select_poll)
 | 
						|
                try:
 | 
						|
                    p = session.recv_packet(self.__timeOut)
 | 
						|
                except nmb.NetBIOSTimeout:
 | 
						|
                    raise
 | 
						|
                except nmb.NetBIOSError:
 | 
						|
                    break
 | 
						|
 | 
						|
                if p.get_type() == nmb.NETBIOS_SESSION_REQUEST:
 | 
						|
                   # Someone is requesting a session, we're gonna accept them all :)
 | 
						|
                   _, rn, my = p.get_trailer().split(' ')
 | 
						|
                   remote_name = nmb.decode_name('\x20'+rn)
 | 
						|
                   myname = nmb.decode_name('\x20'+my)
 | 
						|
                   self.__SMB.log("NetBIOS Session request (%s,%s,%s)" % (self.__ip, remote_name[1].strip(), myname[1]))
 | 
						|
                   r = nmb.NetBIOSSessionPacket()
 | 
						|
                   r.set_type(nmb.NETBIOS_SESSION_POSITIVE_RESPONSE)
 | 
						|
                   r.set_trailer(p.get_trailer())
 | 
						|
                   self.__request.send(r.rawData())
 | 
						|
                else:
 | 
						|
                   resp = self.__SMB.processRequest(self.__connId, p.get_trailer())
 | 
						|
                   # Send all the packets recevied. Except for big transactions this should be
 | 
						|
                   # a single packet
 | 
						|
                   for i in resp:
 | 
						|
                       session.send_packet(str(i))
 | 
						|
            except Exception, e:
 | 
						|
                self.__SMB.log("Handle: %s" % e)
 | 
						|
                #import traceback
 | 
						|
                #traceback.print_exc()
 | 
						|
                break
 | 
						|
 | 
						|
    def finish(self):
 | 
						|
        # Thread/process is dying, we should tell the main SMB thread to remove all this thread data
 | 
						|
        self.__SMB.log("Closing down connection (%s,%d)" % (self.__ip, self.__port))
 | 
						|
        self.__SMB.removeConnection(self.__connId)
 | 
						|
        return SocketServer.BaseRequestHandler.finish(self)
 | 
						|
 | 
						|
class SMBSERVER(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
 | 
						|
#class SMBSERVER(SocketServer.ForkingMixIn, SocketServer.TCPServer):
 | 
						|
    def __init__(self, server_address, handler_class=SMBSERVERHandler, config_parser = None):
 | 
						|
        SocketServer.TCPServer.allow_reuse_address = True
 | 
						|
        SocketServer.TCPServer.__init__(self, server_address, handler_class)
 | 
						|
 | 
						|
        # Server name and OS to be presented whenever is necessary
 | 
						|
        self.__serverName   = ''
 | 
						|
        self.__serverOS     = ''
 | 
						|
        self.__serverDomain = ''
 | 
						|
        self.__challenge    = ''
 | 
						|
        self.__log          = None
 | 
						|
 | 
						|
        # Our ConfigParser data
 | 
						|
        self.__serverConfig = config_parser
 | 
						|
 | 
						|
        # Our credentials to be used during the server's lifetime
 | 
						|
        self.__credentials = {}
 | 
						|
 | 
						|
        # Our log file
 | 
						|
        self.__logFile = ''
 | 
						|
 | 
						|
        # Registered Named Pipes, format is PipeName,Socket
 | 
						|
        self.__registeredNamedPipes = {}
 | 
						|
 | 
						|
        # JTR dump path
 | 
						|
        self.__jtr_dump_path = ''
 | 
						|
 | 
						|
        # SMB2 Support flag = default not active
 | 
						|
        self.__SMB2Support = False
 | 
						|
 | 
						|
        # Our list of commands we will answer, by default the NOT IMPLEMENTED one
 | 
						|
        self.__smbCommandsHandler = SMBCommands()
 | 
						|
        self.__smbTrans2Handler   = TRANS2Commands()
 | 
						|
        self.__smbTransHandler    = TRANSCommands()
 | 
						|
        self.__smbNTTransHandler  = NTTRANSCommands()
 | 
						|
        self.__smb2CommandsHandler = SMB2Commands()
 | 
						|
        self.__IoctlHandler       = Ioctls()
 | 
						|
 | 
						|
        self.__smbNTTransCommands = {
 | 
						|
        # NT IOCTL, can't find doc for this
 | 
						|
        0xff                               :self.__smbNTTransHandler.default
 | 
						|
        }
 | 
						|
 | 
						|
        self.__smbTransCommands  = {
 | 
						|
'\\PIPE\\LANMAN'                       :self.__smbTransHandler.lanMan,
 | 
						|
smb.SMB.TRANS_TRANSACT_NMPIPE          :self.__smbTransHandler.transactNamedPipe,
 | 
						|
        }
 | 
						|
        self.__smbTrans2Commands = {
 | 
						|
 smb.SMB.TRANS2_FIND_FIRST2            :self.__smbTrans2Handler.findFirst2,
 | 
						|
 smb.SMB.TRANS2_FIND_NEXT2             :self.__smbTrans2Handler.findNext2,
 | 
						|
 smb.SMB.TRANS2_QUERY_FS_INFORMATION   :self.__smbTrans2Handler.queryFsInformation,
 | 
						|
 smb.SMB.TRANS2_QUERY_PATH_INFORMATION :self.__smbTrans2Handler.queryPathInformation,
 | 
						|
 smb.SMB.TRANS2_QUERY_FILE_INFORMATION :self.__smbTrans2Handler.queryFileInformation,
 | 
						|
 smb.SMB.TRANS2_SET_FILE_INFORMATION   :self.__smbTrans2Handler.setFileInformation,
 | 
						|
 smb.SMB.TRANS2_SET_PATH_INFORMATION   :self.__smbTrans2Handler.setPathInformation
 | 
						|
        }
 | 
						|
 | 
						|
        self.__smbCommands = {
 | 
						|
 #smb.SMB.SMB_COM_FLUSH:              self.__smbCommandsHandler.smbComFlush,
 | 
						|
 smb.SMB.SMB_COM_CREATE_DIRECTORY:   self.__smbCommandsHandler.smbComCreateDirectory,
 | 
						|
 smb.SMB.SMB_COM_DELETE_DIRECTORY:   self.__smbCommandsHandler.smbComDeleteDirectory,
 | 
						|
 smb.SMB.SMB_COM_RENAME:             self.__smbCommandsHandler.smbComRename,
 | 
						|
 smb.SMB.SMB_COM_DELETE:             self.__smbCommandsHandler.smbComDelete,
 | 
						|
 smb.SMB.SMB_COM_NEGOTIATE:          self.__smbCommandsHandler.smbComNegotiate,
 | 
						|
 smb.SMB.SMB_COM_SESSION_SETUP_ANDX: self.__smbCommandsHandler.smbComSessionSetupAndX,
 | 
						|
 smb.SMB.SMB_COM_LOGOFF_ANDX:        self.__smbCommandsHandler.smbComLogOffAndX,
 | 
						|
 smb.SMB.SMB_COM_TREE_CONNECT_ANDX:  self.__smbCommandsHandler.smbComTreeConnectAndX,
 | 
						|
 smb.SMB.SMB_COM_TREE_DISCONNECT:    self.__smbCommandsHandler.smbComTreeDisconnect,
 | 
						|
 smb.SMB.SMB_COM_ECHO:               self.__smbCommandsHandler.smbComEcho,
 | 
						|
 smb.SMB.SMB_COM_QUERY_INFORMATION:  self.__smbCommandsHandler.smbQueryInformation,
 | 
						|
 smb.SMB.SMB_COM_TRANSACTION2:       self.__smbCommandsHandler.smbTransaction2,
 | 
						|
 smb.SMB.SMB_COM_TRANSACTION:        self.__smbCommandsHandler.smbTransaction,
 | 
						|
 # Not needed for now
 | 
						|
 smb.SMB.SMB_COM_NT_TRANSACT:        self.__smbCommandsHandler.smbNTTransact,
 | 
						|
 smb.SMB.SMB_COM_QUERY_INFORMATION_DISK: self.__smbCommandsHandler.smbQueryInformationDisk,
 | 
						|
 smb.SMB.SMB_COM_OPEN_ANDX:          self.__smbCommandsHandler.smbComOpenAndX,
 | 
						|
 smb.SMB.SMB_COM_QUERY_INFORMATION2: self.__smbCommandsHandler.smbComQueryInformation2,
 | 
						|
 smb.SMB.SMB_COM_READ_ANDX:          self.__smbCommandsHandler.smbComReadAndX,
 | 
						|
 smb.SMB.SMB_COM_READ:               self.__smbCommandsHandler.smbComRead,
 | 
						|
 smb.SMB.SMB_COM_WRITE_ANDX:         self.__smbCommandsHandler.smbComWriteAndX,
 | 
						|
 smb.SMB.SMB_COM_WRITE:              self.__smbCommandsHandler.smbComWrite,
 | 
						|
 smb.SMB.SMB_COM_CLOSE:              self.__smbCommandsHandler.smbComClose,
 | 
						|
 smb.SMB.SMB_COM_LOCKING_ANDX:       self.__smbCommandsHandler.smbComLockingAndX,
 | 
						|
 smb.SMB.SMB_COM_NT_CREATE_ANDX:     self.__smbCommandsHandler.smbComNtCreateAndX,
 | 
						|
 0xFF:                               self.__smbCommandsHandler.default
 | 
						|
}
 | 
						|
 | 
						|
        self.__smb2Ioctls = {
 | 
						|
 smb2.FSCTL_DFS_GET_REFERRALS:            self.__IoctlHandler.fsctlDfsGetReferrals,
 | 
						|
# smb2.FSCTL_PIPE_PEEK:                    self.__IoctlHandler.fsctlPipePeek,
 | 
						|
# smb2.FSCTL_PIPE_WAIT:                    self.__IoctlHandler.fsctlPipeWait,
 | 
						|
 smb2.FSCTL_PIPE_TRANSCEIVE:              self.__IoctlHandler.fsctlPipeTransceive,
 | 
						|
# smb2.FSCTL_SRV_COPYCHUNK:                self.__IoctlHandler.fsctlSrvCopyChunk,
 | 
						|
# smb2.FSCTL_SRV_ENUMERATE_SNAPSHOTS:      self.__IoctlHandler.fsctlSrvEnumerateSnapshots,
 | 
						|
# smb2.FSCTL_SRV_REQUEST_RESUME_KEY:       self.__IoctlHandler.fsctlSrvRequestResumeKey,
 | 
						|
# smb2.FSCTL_SRV_READ_HASH:                self.__IoctlHandler.fsctlSrvReadHash,
 | 
						|
# smb2.FSCTL_SRV_COPYCHUNK_WRITE:          self.__IoctlHandler.fsctlSrvCopyChunkWrite,
 | 
						|
# smb2.FSCTL_LMR_REQUEST_RESILIENCY:       self.__IoctlHandler.fsctlLmrRequestResiliency,
 | 
						|
# smb2.FSCTL_QUERY_NETWORK_INTERFACE_INFO: self.__IoctlHandler.fsctlQueryNetworkInterfaceInfo,
 | 
						|
# smb2.FSCTL_SET_REPARSE_POINT:            self.__IoctlHandler.fsctlSetReparsePoint,
 | 
						|
# smb2.FSCTL_DFS_GET_REFERRALS_EX:         self.__IoctlHandler.fsctlDfsGetReferralsEx,
 | 
						|
# smb2.FSCTL_FILE_LEVEL_TRIM:              self.__IoctlHandler.fsctlFileLevelTrim,
 | 
						|
 smb2.FSCTL_VALIDATE_NEGOTIATE_INFO:      self.__IoctlHandler.fsctlValidateNegotiateInfo,
 | 
						|
}
 | 
						|
 | 
						|
        self.__smb2Commands = {
 | 
						|
 smb2.SMB2_NEGOTIATE:       self.__smb2CommandsHandler.smb2Negotiate,
 | 
						|
 smb2.SMB2_SESSION_SETUP:   self.__smb2CommandsHandler.smb2SessionSetup,
 | 
						|
 smb2.SMB2_LOGOFF:          self.__smb2CommandsHandler.smb2Logoff,
 | 
						|
 smb2.SMB2_TREE_CONNECT:    self.__smb2CommandsHandler.smb2TreeConnect,
 | 
						|
 smb2.SMB2_TREE_DISCONNECT: self.__smb2CommandsHandler.smb2TreeDisconnect,
 | 
						|
 smb2.SMB2_CREATE:          self.__smb2CommandsHandler.smb2Create,
 | 
						|
 smb2.SMB2_CLOSE:           self.__smb2CommandsHandler.smb2Close,
 | 
						|
 smb2.SMB2_FLUSH:           self.__smb2CommandsHandler.smb2Flush,
 | 
						|
 smb2.SMB2_READ:            self.__smb2CommandsHandler.smb2Read,
 | 
						|
 smb2.SMB2_WRITE:           self.__smb2CommandsHandler.smb2Write,
 | 
						|
 smb2.SMB2_LOCK:            self.__smb2CommandsHandler.smb2Lock,
 | 
						|
 smb2.SMB2_IOCTL:           self.__smb2CommandsHandler.smb2Ioctl,
 | 
						|
 smb2.SMB2_CANCEL:          self.__smb2CommandsHandler.smb2Cancel,
 | 
						|
 smb2.SMB2_ECHO:            self.__smb2CommandsHandler.smb2Echo,
 | 
						|
 smb2.SMB2_QUERY_DIRECTORY: self.__smb2CommandsHandler.smb2QueryDirectory,
 | 
						|
 smb2.SMB2_CHANGE_NOTIFY:   self.__smb2CommandsHandler.smb2ChangeNotify,
 | 
						|
 smb2.SMB2_QUERY_INFO:      self.__smb2CommandsHandler.smb2QueryInfo,
 | 
						|
 smb2.SMB2_SET_INFO:        self.__smb2CommandsHandler.smb2SetInfo,
 | 
						|
# smb2.SMB2_OPLOCK_BREAK:    self.__smb2CommandsHandler.smb2SessionSetup,
 | 
						|
 0xFF:                      self.__smb2CommandsHandler.default
 | 
						|
}
 | 
						|
 | 
						|
        # List of active connections
 | 
						|
        self.__activeConnections = {}
 | 
						|
 | 
						|
    def getIoctls(self):
 | 
						|
        return self.__smb2Ioctls
 | 
						|
 | 
						|
    def getCredentials(self):
 | 
						|
        return self.__credentials
 | 
						|
 | 
						|
    def removeConnection(self, name):
 | 
						|
        try:
 | 
						|
           del(self.__activeConnections[name])
 | 
						|
        except:
 | 
						|
           pass
 | 
						|
        self.log("Remaining connections %s" % self.__activeConnections.keys())
 | 
						|
 | 
						|
    def addConnection(self, name, ip, port):
 | 
						|
        self.__activeConnections[name] = {}
 | 
						|
        # Let's init with some know stuff we will need to have
 | 
						|
        # TODO: Document what's in there
 | 
						|
        #print "Current Connections", self.__activeConnections.keys()
 | 
						|
        self.__activeConnections[name]['PacketNum']       = 0
 | 
						|
        self.__activeConnections[name]['ClientIP']        = ip
 | 
						|
        self.__activeConnections[name]['ClientPort']      = port
 | 
						|
        self.__activeConnections[name]['Uid']             = 0
 | 
						|
        self.__activeConnections[name]['ConnectedShares'] = {}
 | 
						|
        self.__activeConnections[name]['OpenedFiles']     = {}
 | 
						|
        # SID results for findfirst2
 | 
						|
        self.__activeConnections[name]['SIDs']            = {}
 | 
						|
        self.__activeConnections[name]['LastRequest']     = {}
 | 
						|
 | 
						|
    def getActiveConnections(self):
 | 
						|
        return self.__activeConnections
 | 
						|
 | 
						|
    def setConnectionData(self, connId, data):
 | 
						|
        self.__activeConnections[connId] = data
 | 
						|
        #print "setConnectionData"
 | 
						|
        #print self.__activeConnections
 | 
						|
 | 
						|
    def getConnectionData(self, connId, checkStatus = True):
 | 
						|
        conn = self.__activeConnections[connId]
 | 
						|
        if checkStatus is True:
 | 
						|
            if conn.has_key('Authenticated') is not True:
 | 
						|
                # Can't keep going further
 | 
						|
                raise Exception("User not Authenticated!")
 | 
						|
        return conn
 | 
						|
 | 
						|
    def getRegisteredNamedPipes(self):
 | 
						|
        return self.__registeredNamedPipes
 | 
						|
 | 
						|
    def registerNamedPipe(self, pipeName, address):
 | 
						|
        self.__registeredNamedPipes[unicode(pipeName)] = address
 | 
						|
        return True
 | 
						|
 | 
						|
    def unregisterNamedPipe(self, pipeName):
 | 
						|
        if self.__registeredNamedPipes.has_key(pipeName):
 | 
						|
            del(self.__registeredNamedPipes[unicode(pipeName)])
 | 
						|
            return True
 | 
						|
        return False
 | 
						|
 | 
						|
    def unregisterTransaction(self, transCommand):
 | 
						|
        if self.__smbTransCommands.has_key(transCommand):
 | 
						|
           del(self.__smbTransCommands[transCommand])
 | 
						|
 | 
						|
    def hookTransaction(self, transCommand, callback):
 | 
						|
        # If you call this function, callback will replace
 | 
						|
        # the current Transaction sub command.
 | 
						|
        # (don't get confused with the Transaction smbCommand)
 | 
						|
        # If the transaction sub command doesn't not exist, it is added
 | 
						|
        # If the transaction sub command exists, it returns the original function         # replaced
 | 
						|
        #
 | 
						|
        # callback MUST be declared as:
 | 
						|
        # callback(connId, smbServer, recvPacket, parameters, data, maxDataCount=0)
 | 
						|
        #
 | 
						|
        # WHERE:
 | 
						|
        #
 | 
						|
        # connId      : the connection Id, used to grab/update information about
 | 
						|
        #               the current connection
 | 
						|
        # smbServer   : the SMBServer instance available for you to ask
 | 
						|
        #               configuration data
 | 
						|
        # recvPacket  : the full SMBPacket that triggered this command
 | 
						|
        # parameters  : the transaction parameters
 | 
						|
        # data        : the transaction data
 | 
						|
        # maxDataCount: the max amount of data that can be transfered agreed
 | 
						|
        #               with the client
 | 
						|
        #
 | 
						|
        # and MUST return:
 | 
						|
        # respSetup, respParameters, respData, errorCode
 | 
						|
        #
 | 
						|
        # WHERE:
 | 
						|
        #
 | 
						|
        # respSetup: the setup response of the transaction
 | 
						|
        # respParameters: the parameters response of the transaction
 | 
						|
        # respData: the data reponse of the transaction
 | 
						|
        # errorCode: the NT error code
 | 
						|
 | 
						|
        if self.__smbTransCommands.has_key(transCommand):
 | 
						|
           originalCommand = self.__smbTransCommands[transCommand]
 | 
						|
        else:
 | 
						|
           originalCommand = None
 | 
						|
 | 
						|
        self.__smbTransCommands[transCommand] = callback
 | 
						|
        return originalCommand
 | 
						|
 | 
						|
    def unregisterTransaction2(self, transCommand):
 | 
						|
        if self.__smbTrans2Commands.has_key(transCommand):
 | 
						|
           del(self.__smbTrans2Commands[transCommand])
 | 
						|
 | 
						|
    def hookTransaction2(self, transCommand, callback):
 | 
						|
        # Here we should add to __smbTrans2Commands
 | 
						|
        # Same description as Transaction
 | 
						|
        if self.__smbTrans2Commands.has_key(transCommand):
 | 
						|
           originalCommand = self.__smbTrans2Commands[transCommand]
 | 
						|
        else:
 | 
						|
           originalCommand = None
 | 
						|
 | 
						|
        self.__smbTrans2Commands[transCommand] = callback
 | 
						|
        return originalCommand
 | 
						|
 | 
						|
    def unregisterNTTransaction(self, transCommand):
 | 
						|
        if self.__smbNTTransCommands.has_key(transCommand):
 | 
						|
           del(self.__smbNTTransCommands[transCommand])
 | 
						|
 | 
						|
    def hookNTTransaction(self, transCommand, callback):
 | 
						|
        # Here we should add to __smbNTTransCommands
 | 
						|
        # Same description as Transaction
 | 
						|
        if self.__smbNTTransCommands.has_key(transCommand):
 | 
						|
           originalCommand = self.__smbNTTransCommands[transCommand]
 | 
						|
        else:
 | 
						|
           originalCommand = None
 | 
						|
 | 
						|
        self.__smbNTTransCommands[transCommand] = callback
 | 
						|
        return originalCommand
 | 
						|
 | 
						|
    def unregisterSmbCommand(self, smbCommand):
 | 
						|
        if self.__smbCommands.has_key(smbCommand):
 | 
						|
           del(self.__smbCommands[smbCommand])
 | 
						|
 | 
						|
    def hookSmbCommand(self, smbCommand, callback):
 | 
						|
        # Here we should add to self.__smbCommands
 | 
						|
        # If you call this function, callback will replace
 | 
						|
        # the current smbCommand.
 | 
						|
        # If smbCommand doesn't not exist, it is added
 | 
						|
        # If SMB command exists, it returns the original function replaced
 | 
						|
        #
 | 
						|
        # callback MUST be declared as:
 | 
						|
        # callback(connId, smbServer, SMBCommand, recvPacket)
 | 
						|
        #
 | 
						|
        # WHERE:
 | 
						|
        #
 | 
						|
        # connId    : the connection Id, used to grab/update information about
 | 
						|
        #             the current connection
 | 
						|
        # smbServer : the SMBServer instance available for you to ask
 | 
						|
        #             configuration data
 | 
						|
        # SMBCommand: the SMBCommand itself, with its data and parameters.
 | 
						|
        #             Check smb.py:SMBCommand() for a reference
 | 
						|
        # recvPacket: the full SMBPacket that triggered this command
 | 
						|
        #
 | 
						|
        # and MUST return:
 | 
						|
        # <list of respSMBCommands>, <list of packets>, errorCode
 | 
						|
        # <list of packets> has higher preference over commands, in case you
 | 
						|
        # want to change the whole packet
 | 
						|
        # errorCode: the NT error code
 | 
						|
        #
 | 
						|
        # For SMB_COM_TRANSACTION2, SMB_COM_TRANSACTION and SMB_COM_NT_TRANSACT
 | 
						|
        # the callback function is slightly different:
 | 
						|
        #
 | 
						|
        # callback(connId, smbServer, SMBCommand, recvPacket, transCommands)
 | 
						|
        #
 | 
						|
        # WHERE:
 | 
						|
        #
 | 
						|
        # transCommands: a list of transaction subcommands already registered
 | 
						|
        #
 | 
						|
 | 
						|
        if self.__smbCommands.has_key(smbCommand):
 | 
						|
           originalCommand = self.__smbCommands[smbCommand]
 | 
						|
        else:
 | 
						|
           originalCommand = None
 | 
						|
 | 
						|
        self.__smbCommands[smbCommand] = callback
 | 
						|
        return originalCommand
 | 
						|
 | 
						|
    def unregisterSmb2Command(self, smb2Command):
 | 
						|
        if self.__smb2Commands.has_key(smb2Command):
 | 
						|
           del(self.__smb2Commands[smb2Command])
 | 
						|
 | 
						|
    def hookSmb2Command(self, smb2Command, callback):
 | 
						|
        if self.__smb2Commands.has_key(smb2Command):
 | 
						|
           originalCommand = self.__smb2Commands[smb2Command]
 | 
						|
        else:
 | 
						|
           originalCommand = None
 | 
						|
 | 
						|
        self.__smb2Commands[smb2Command] = callback
 | 
						|
        return originalCommand
 | 
						|
 | 
						|
    def log(self, msg, level=logging.INFO):
 | 
						|
        self.__log.log(level,msg)
 | 
						|
 | 
						|
    def getServerName(self):
 | 
						|
        return self.__serverName
 | 
						|
 | 
						|
    def getServerOS(self):
 | 
						|
        return self.__serverOS
 | 
						|
 | 
						|
    def getServerDomain(self):
 | 
						|
        return self.__serverDomain
 | 
						|
 | 
						|
    def getSMBChallenge(self):
 | 
						|
        return self.__challenge
 | 
						|
 | 
						|
    def getServerConfig(self):
 | 
						|
        return self.__serverConfig
 | 
						|
 | 
						|
    def setServerConfig(self, config):
 | 
						|
        self.__serverConfig = config
 | 
						|
 | 
						|
    def getJTRdumpPath(self):
 | 
						|
        return self.__jtr_dump_path
 | 
						|
 | 
						|
    def verify_request(self, request, client_address):
 | 
						|
        # TODO: Control here the max amount of processes we want to launch
 | 
						|
        # returning False, closes the connection
 | 
						|
        return True
 | 
						|
 | 
						|
    def processRequest(self, connId, data):
 | 
						|
 | 
						|
        # TODO: Process batched commands.
 | 
						|
        isSMB2      = False
 | 
						|
        SMBCommand  = None
 | 
						|
        try:
 | 
						|
            packet = smb.NewSMBPacket(data = data)
 | 
						|
            SMBCommand  = smb.SMBCommand(packet['Data'][0])
 | 
						|
        except:
 | 
						|
            # Maybe a SMB2 packet?
 | 
						|
            packet = smb2.SMB2Packet(data = data)
 | 
						|
            isSMB2 = True
 | 
						|
 | 
						|
        # We might have compound requests
 | 
						|
        compoundedPacketsResponse = []
 | 
						|
        compoundedPackets         = []
 | 
						|
        try:
 | 
						|
            # Search out list of implemented commands
 | 
						|
            # We provide them with:
 | 
						|
            # connId      : representing the data for this specific connection
 | 
						|
            # self        : the SMBSERVER if they want to ask data to it
 | 
						|
            # SMBCommand  : the SMBCommand they are expecting to process
 | 
						|
            # packet      : the received packet itself, in case they need more data than the actual command
 | 
						|
            # Only for Transactions
 | 
						|
            # transCommand: a list of transaction subcommands
 | 
						|
            # We expect to get:
 | 
						|
            # respCommands: a list of answers for the commands processed
 | 
						|
            # respPacket  : if the commands chose to directly craft packet/s, we use this and not the previous
 | 
						|
            #               this MUST be a list
 | 
						|
            # errorCode   : self explanatory
 | 
						|
            if isSMB2 is False:
 | 
						|
                if packet['Command'] == smb.SMB.SMB_COM_TRANSACTION2:
 | 
						|
                    respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
 | 
						|
                                  connId,
 | 
						|
                                  self,
 | 
						|
                                  SMBCommand,
 | 
						|
                                  packet,
 | 
						|
                                  self.__smbTrans2Commands)
 | 
						|
                elif packet['Command'] == smb.SMB.SMB_COM_NT_TRANSACT:
 | 
						|
                    respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
 | 
						|
                                  connId,
 | 
						|
                                  self,
 | 
						|
                                  SMBCommand,
 | 
						|
                                  packet,
 | 
						|
                                  self.__smbNTTransCommands)
 | 
						|
                elif packet['Command'] == smb.SMB.SMB_COM_TRANSACTION:
 | 
						|
                    respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
 | 
						|
                                  connId,
 | 
						|
                                  self,
 | 
						|
                                  SMBCommand,
 | 
						|
                                  packet,
 | 
						|
                                  self.__smbTransCommands)
 | 
						|
                else:
 | 
						|
                    if self.__smbCommands.has_key(packet['Command']):
 | 
						|
                       if self.__SMB2Support is True:
 | 
						|
                           if packet['Command'] == smb.SMB.SMB_COM_NEGOTIATE:
 | 
						|
                               try:
 | 
						|
                                   respCommands, respPackets, errorCode = self.__smb2Commands[smb2.SMB2_NEGOTIATE](connId, self, packet, True)
 | 
						|
                                   isSMB2 = True
 | 
						|
                               except Exception, e:
 | 
						|
                                   self.log('SMB2_NEGOTIATE: %s' % e, logging.ERROR)
 | 
						|
                                   # If something went wrong, let's fallback to SMB1
 | 
						|
                                   respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
 | 
						|
                                       connId,
 | 
						|
                                       self,
 | 
						|
                                       SMBCommand,
 | 
						|
                                       packet)
 | 
						|
                                   #self.__SMB2Support = False
 | 
						|
                                   pass
 | 
						|
                           else:
 | 
						|
                               respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
 | 
						|
                                       connId,
 | 
						|
                                       self,
 | 
						|
                                       SMBCommand,
 | 
						|
                                       packet)
 | 
						|
                       else:
 | 
						|
                           respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
 | 
						|
                                       connId,
 | 
						|
                                       self,
 | 
						|
                                       SMBCommand,
 | 
						|
                                       packet)
 | 
						|
                    else:
 | 
						|
                       respCommands, respPackets, errorCode = self.__smbCommands[255](connId, self, SMBCommand, packet)
 | 
						|
 | 
						|
                compoundedPacketsResponse.append((respCommands, respPackets, errorCode))
 | 
						|
                compoundedPackets.append(packet)
 | 
						|
 | 
						|
            else:
 | 
						|
                done = False
 | 
						|
                while not done:
 | 
						|
                    if self.__smb2Commands.has_key(packet['Command']):
 | 
						|
                       if self.__SMB2Support is True:
 | 
						|
                           respCommands, respPackets, errorCode = self.__smb2Commands[packet['Command']](
 | 
						|
                                   connId,
 | 
						|
                                   self,
 | 
						|
                                   packet)
 | 
						|
                       else:
 | 
						|
                           respCommands, respPackets, errorCode = self.__smb2Commands[255](connId, self, packet)
 | 
						|
                    else:
 | 
						|
                       respCommands, respPackets, errorCode = self.__smb2Commands[255](connId, self, packet)
 | 
						|
                    # Let's store the result for this compounded packet
 | 
						|
                    compoundedPacketsResponse.append((respCommands, respPackets, errorCode))
 | 
						|
                    compoundedPackets.append(packet)
 | 
						|
                    if packet['NextCommand'] != 0:
 | 
						|
                        data = data[packet['NextCommand']:]
 | 
						|
                        packet = smb2.SMB2Packet(data = data)
 | 
						|
                    else:
 | 
						|
                        done = True
 | 
						|
 | 
						|
        except Exception, e:
 | 
						|
            #import traceback
 | 
						|
            #traceback.print_exc()
 | 
						|
            # Something wen't wrong, defaulting to Bad user ID
 | 
						|
            self.log('processRequest (0x%x,%s)' % (packet['Command'],e), logging.ERROR)
 | 
						|
            raise
 | 
						|
 | 
						|
        # We prepare the response packet to commands don't need to bother about that.
 | 
						|
        connData    = self.getConnectionData(connId, False)
 | 
						|
 | 
						|
        # Force reconnection loop.. This is just a test.. client will send me back credentials :)
 | 
						|
        #connData['PacketNum'] += 1
 | 
						|
        #if connData['PacketNum'] == 15:
 | 
						|
        #    connData['PacketNum'] = 0
 | 
						|
        #    # Something wen't wrong, defaulting to Bad user ID
 | 
						|
        #    self.log('Sending BAD USER ID!', logging.ERROR)
 | 
						|
        #    #raise
 | 
						|
        #    packet['Flags1'] |= smb.SMB.FLAGS1_REPLY
 | 
						|
        #    packet['Flags2'] = 0
 | 
						|
        #    errorCode = STATUS_SMB_BAD_UID
 | 
						|
        #    packet['ErrorCode']   = errorCode >> 16
 | 
						|
        #    packet['ErrorClass']  = errorCode & 0xff
 | 
						|
        #    return [packet]
 | 
						|
 | 
						|
        self.setConnectionData(connId, connData)
 | 
						|
 | 
						|
        packetsToSend = []
 | 
						|
        for packetNum in range(len(compoundedPacketsResponse)):
 | 
						|
            respCommands, respPackets, errorCode = compoundedPacketsResponse[packetNum]
 | 
						|
            packet = compoundedPackets[packetNum]
 | 
						|
            if respPackets is None:
 | 
						|
                for respCommand in respCommands:
 | 
						|
                    if isSMB2 is False:
 | 
						|
                        respPacket           = smb.NewSMBPacket()
 | 
						|
                        respPacket['Flags1'] = smb.SMB.FLAGS1_REPLY
 | 
						|
 | 
						|
                        # TODO this should come from a per session configuration
 | 
						|
                        respPacket['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES | packet['Flags2'] & smb.SMB.FLAGS2_UNICODE
 | 
						|
                        #respPacket['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES
 | 
						|
                        #respPacket['Flags1'] = 0x98
 | 
						|
                        #respPacket['Flags2'] = 0xc807
 | 
						|
 | 
						|
 | 
						|
                        respPacket['Tid']    = packet['Tid']
 | 
						|
                        respPacket['Mid']    = packet['Mid']
 | 
						|
                        respPacket['Pid']    = packet['Pid']
 | 
						|
                        respPacket['Uid']    = connData['Uid']
 | 
						|
 | 
						|
                        respPacket['ErrorCode']   = errorCode >> 16
 | 
						|
                        respPacket['_reserved']   = errorCode >> 8 & 0xff
 | 
						|
                        respPacket['ErrorClass']  = errorCode & 0xff
 | 
						|
                        respPacket.addCommand(respCommand)
 | 
						|
 | 
						|
                        packetsToSend.append(respPacket)
 | 
						|
                    else:
 | 
						|
                        respPacket = smb2.SMB2Packet()
 | 
						|
                        respPacket['Flags']     = smb2.SMB2_FLAGS_SERVER_TO_REDIR
 | 
						|
                        if packetNum > 0:
 | 
						|
                            respPacket['Flags'] |= smb2.SMB2_FLAGS_RELATED_OPERATIONS
 | 
						|
                        respPacket['Status']    = errorCode
 | 
						|
                        respPacket['CreditRequestResponse'] = packet['CreditRequestResponse']
 | 
						|
                        respPacket['Command']   = packet['Command']
 | 
						|
                        respPacket['CreditCharge'] = packet['CreditCharge']
 | 
						|
                        #respPacket['CreditCharge'] = 0
 | 
						|
                        respPacket['Reserved']  = packet['Reserved']
 | 
						|
                        respPacket['SessionID'] = connData['Uid']
 | 
						|
                        respPacket['MessageID'] = packet['MessageID']
 | 
						|
                        respPacket['TreeID']    = packet['TreeID']
 | 
						|
                        respPacket['Data']      = str(respCommand)
 | 
						|
                        packetsToSend.append(respPacket)
 | 
						|
            else:
 | 
						|
                # The SMBCommand took care of building the packet
 | 
						|
                packetsToSend = respPackets
 | 
						|
 | 
						|
        if isSMB2 is True:
 | 
						|
            # Let's build a compound answer
 | 
						|
            finalData = ''
 | 
						|
            i = 0
 | 
						|
            for i in range(len(packetsToSend)-1):
 | 
						|
                packet = packetsToSend[i]
 | 
						|
                # Align to 8-bytes
 | 
						|
                padLen = (8 - (len(packet) % 8) ) % 8
 | 
						|
                packet['NextCommand'] = len(packet) + padLen
 | 
						|
                finalData += str(packet) + padLen*'\x00'
 | 
						|
 | 
						|
            # Last one
 | 
						|
            finalData += str(packetsToSend[len(packetsToSend)-1])
 | 
						|
            packetsToSend = [finalData]
 | 
						|
 | 
						|
        # We clear the compound requests
 | 
						|
        connData['LastRequest'] = {}
 | 
						|
 | 
						|
        return packetsToSend
 | 
						|
 | 
						|
    def processConfigFile(self, configFile = None):
 | 
						|
        # TODO: Do a real config parser
 | 
						|
        if self.__serverConfig is None:
 | 
						|
            if configFile is None:
 | 
						|
                configFile = 'smb.conf'
 | 
						|
            self.__serverConfig = ConfigParser.ConfigParser()
 | 
						|
            self.__serverConfig.read(configFile)
 | 
						|
 | 
						|
        self.__serverName   = self.__serverConfig.get('global','server_name')
 | 
						|
        self.__serverOS     = self.__serverConfig.get('global','server_os')
 | 
						|
        self.__serverDomain = self.__serverConfig.get('global','server_domain')
 | 
						|
        self.__logFile      = self.__serverConfig.get('global','log_file')
 | 
						|
        if self.__serverConfig.has_option('global', 'challenge'):
 | 
						|
            self.__challenge    = self.__serverConfig.get('global', 'challenge')
 | 
						|
        else:
 | 
						|
            self.__challenge    = 'A'*8
 | 
						|
 | 
						|
        if self.__serverConfig.has_option("global", "jtr_dump_path"):
 | 
						|
            self.__jtr_dump_path = self.__serverConfig.get("global", "jtr_dump_path")
 | 
						|
 | 
						|
        if self.__serverConfig.has_option("global", "SMB2Support"):
 | 
						|
            self.__SMB2Support = self.__serverConfig.getboolean("global","SMB2Support")
 | 
						|
        else:
 | 
						|
            self.__SMB2Support = False
 | 
						|
 | 
						|
        if self.__logFile != 'None':
 | 
						|
            logging.basicConfig(filename = self.__logFile,
 | 
						|
                             level = logging.DEBUG,
 | 
						|
                             format="%(asctime)s: %(levelname)s: %(message)s",
 | 
						|
                             datefmt = '%m/%d/%Y %I:%M:%S %p')
 | 
						|
        self.__log        = LOG
 | 
						|
 | 
						|
        # Process the credentials
 | 
						|
        credentials_fname = self.__serverConfig.get('global','credentials_file')
 | 
						|
        if credentials_fname is not "":
 | 
						|
            cred = open(credentials_fname)
 | 
						|
            line = cred.readline()
 | 
						|
            while line:
 | 
						|
                name, domain, lmhash, nthash = line.split(':')
 | 
						|
                self.__credentials[name] = (domain, lmhash, nthash.strip('\r\n'))
 | 
						|
                line = cred.readline()
 | 
						|
            cred.close()
 | 
						|
        self.log('Config file parsed')
 | 
						|
 | 
						|
# For windows platforms, opening a directory is not an option, so we set a void FD
 | 
						|
VOID_FILE_DESCRIPTOR = -1
 | 
						|
PIPE_FILE_DESCRIPTOR = -2
 |