1 # Copyright (c) 2003-2016 CORE Security Technologies
3 # This software is provided under under a slightly modified version
4 # of the Apache Software License. See the accompanying LICENSE file
5 # for more information.
7 # Author: Alberto Solino (@agsolino)
10 # [-] Functions should return NT error codes
11 # [-] Handling errors in all situations, right now it's just raising exceptions.
12 # [*] Standard authentication support
13 # [ ] Organize the connectionData stuff
14 # [*] Add capability to send a bad user ID if the user is not authenticated,
15 # right now you can ask for any command without actually being authenticated
16 # [ ] PATH TRAVERSALS EVERYWHERE.. BE WARNED!
17 # [ ] Check the credentials.. now we're just letting everybody to log in.
18 # [ ] Check error situation (now many places assume the right data is coming)
19 # [ ] Implement IPC to the main process so the connectionData is on a single place
20 # [ ] Hence.. implement locking
23 from __future__ import with_statement
41 from binascii import hexlify
44 from impacket import smb, nmb, ntlm, uuid, LOG
45 from impacket import smb3structs as smb2
46 from impacket.spnego import SPNEGO_NegTokenInit, TypesMech, MechTypes, SPNEGO_NegTokenResp, ASN1_AID, ASN1_SUPPORTED_MECH
47 from impacket.nt_errors import STATUS_NO_MORE_FILES, STATUS_NETWORK_NAME_DELETED, STATUS_INVALID_PARAMETER, \
48 STATUS_FILE_CLOSED, STATUS_MORE_PROCESSING_REQUIRED, STATUS_OBJECT_PATH_NOT_FOUND, STATUS_DIRECTORY_NOT_EMPTY, \
49 STATUS_FILE_IS_A_DIRECTORY, STATUS_NOT_IMPLEMENTED, STATUS_INVALID_HANDLE, STATUS_OBJECT_NAME_COLLISION, \
50 STATUS_NO_SUCH_FILE, STATUS_CANCELLED, STATUS_OBJECT_NAME_NOT_FOUND, STATUS_SUCCESS, STATUS_ACCESS_DENIED, \
51 STATUS_NOT_SUPPORTED, STATUS_INVALID_DEVICE_REQUEST, STATUS_FS_DRIVER_REQUIRED, STATUS_INVALID_INFO_CLASS
53 # These ones not defined in nt_errors
54 STATUS_SMB_BAD_UID = 0x005B0002
55 STATUS_SMB_BAD_TID = 0x00050002
58 # and general functions.
59 # There are some common functions that can be accessed from more than one SMB
60 # command (or either TRANSACTION). That's why I'm putting them here
61 # TODO: Return NT ERROR Codes
63 def outputToJohnFormat(challenge, username, domain, lmresponse, ntresponse):
64 # We don't want to add a possible failure here, since this is an
65 # extra bonus. We try, if it fails, returns nothing
68 if len(ntresponse) > 24:
69 # Extended Security - NTLMv2
70 ret_value = {'hash_string':'%s::%s:%s:%s:%s' % (username.decode('utf-16le'), domain.decode('utf-16le'), hexlify(challenge), hexlify(ntresponse)[:32], hexlify(ntresponse)[32:]), 'hash_version':'ntlmv2'}
73 ret_value = {'hash_string':'%s::%s:%s:%s:%s' % (username.decode('utf-16le'), domain.decode('utf-16le'), hexlify(lmresponse), hexlify(ntresponse), hexlify(challenge)), 'hash_version':'ntlm'}
75 # Let's try w/o decoding Unicode
77 if len(ntresponse) > 24:
78 # Extended Security - NTLMv2
79 ret_value = {'hash_string':'%s::%s:%s:%s:%s' % (username, domain, hexlify(challenge), hexlify(ntresponse)[:32], hexlify(ntresponse)[32:]), 'hash_version':'ntlmv2'}
82 ret_value = {'hash_string':'%s::%s:%s:%s:%s' % (username, domain, hexlify(lmresponse), hexlify(ntresponse), hexlify(challenge)), 'hash_version':'ntlm'}
84 LOG.error("outputToJohnFormat: %s" % e)
89 def writeJohnOutputToFile(hash_string, hash_version, file_name):
90 fn_data = os.path.splitext(file_name)
91 if hash_version == "ntlmv2":
92 output_filename = fn_data[0] + "_ntlmv2" + fn_data[1]
94 output_filename = fn_data[0] + "_ntlm" + fn_data[1]
96 with open(output_filename,"a") as f:
101 def decodeSMBString( flags, text ):
102 if flags & smb.SMB.FLAGS2_UNICODE:
103 return text.decode('utf-16le')
107 def encodeSMBString( flags, text ):
108 if flags & smb.SMB.FLAGS2_UNICODE:
109 return (text).encode('utf-16le')
115 t += 116444736000000000
119 t -= 116444736000000000
125 d = datetime.date.fromtimestamp(t)
127 ret = (year << 8) + (d.month << 4) + d.day
132 d = datetime.datetime.fromtimestamp(t)
133 return (d.hour << 8) + (d.minute << 4) + d.second
135 def getShares(connId, smbServer):
136 config = smbServer.getServerConfig()
137 sections = config.sections()
138 # Remove the global one
139 del(sections[sections.index('global')])
142 shares[i] = dict(config.items(i))
145 def searchShare(connId, share, smbServer):
146 config = smbServer.getServerConfig()
147 if config.has_section(share):
148 return dict(config.items(share))
152 def openFile(path,fileName, accessMode, fileAttributes, openMode):
153 fileName = os.path.normpath(fileName.replace('\\','/'))
155 if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
157 fileName = fileName[1:]
158 pathName = os.path.join(path,fileName)
160 # Check the Open Mode
162 # If the file does not exist, create it.
165 # If file does not exist, return an error
166 if os.path.exists(pathName) is not True:
167 errorCode = STATUS_NO_SUCH_FILE
168 return 0,mode, pathName, errorCode
170 if os.path.isdir(pathName) and (fileAttributes & smb.ATTR_DIRECTORY) == 0:
171 # Request to open a normal file and this is actually a directory
172 errorCode = STATUS_FILE_IS_A_DIRECTORY
173 return 0, mode, pathName, errorCode
174 # Check the Access Mode
175 if accessMode & 0x7 == 1:
177 elif accessMode & 0x7 == 2:
183 if sys.platform == 'win32':
185 fid = os.open(pathName, mode)
187 LOG.error("openFile: %s,%s" % (pathName, mode) ,e)
189 errorCode = STATUS_ACCESS_DENIED
191 return fid, mode, pathName, errorCode
193 def queryFsInformation(path, filename, level=0):
195 if isinstance(filename,unicode):
196 encoding = 'utf-16le'
197 flags = smb.SMB.FLAGS2_UNICODE
202 fileName = os.path.normpath(filename.replace('\\','/'))
203 if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
205 fileName = fileName[1:]
206 pathName = os.path.join(path,fileName)
207 fileSize = os.path.getsize(pathName)
208 (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(pathName)
209 if level == smb.SMB_QUERY_FS_ATTRIBUTE_INFO or level == smb2.SMB2_FILESYSTEM_ATTRIBUTE_INFO:
210 data = smb.SMBQueryFsAttributeInfo()
211 data['FileSystemAttributes'] = smb.FILE_CASE_SENSITIVE_SEARCH | smb.FILE_CASE_PRESERVED_NAMES
212 data['MaxFilenNameLengthInBytes'] = 255
213 data['LengthOfFileSystemName'] = len('XTFS')*2
214 data['FileSystemName'] = 'XTFS'.encode('utf-16le')
215 return data.getData()
216 elif level == smb.SMB_INFO_VOLUME:
217 data = smb.SMBQueryFsInfoVolume( flags = flags )
218 data['VolumeLabel'] = 'SHARE'.encode(encoding)
219 return data.getData()
220 elif level == smb.SMB_QUERY_FS_VOLUME_INFO or level == smb2.SMB2_FILESYSTEM_VOLUME_INFO:
221 data = smb.SMBQueryFsVolumeInfo()
222 data['VolumeLabel'] = ''
223 data['VolumeCreationTime'] = getFileTime(ctime)
224 return data.getData()
225 elif level == smb.SMB_QUERY_FS_SIZE_INFO:
226 data = smb.SMBQueryFsSizeInfo()
227 return data.getData()
228 elif level == smb.FILE_FS_FULL_SIZE_INFORMATION:
229 data = smb.SMBFileFsFullSizeInformation()
230 return data.getData()
231 elif level == smb.FILE_FS_SIZE_INFORMATION:
232 data = smb.FileFsSizeInformation()
233 return data.getData()
235 lastWriteTime = mtime
237 if os.path.isdir(pathName):
238 attribs |= smb.SMB_FILE_ATTRIBUTE_DIRECTORY
239 if os.path.isfile(pathName):
240 attribs |= smb.SMB_FILE_ATTRIBUTE_NORMAL
241 fileAttributes = attribs
242 return fileSize, lastWriteTime, fileAttributes
244 def findFirst2(path, fileName, level, searchAttributes, isSMB2 = False):
245 # TODO: Depending on the level, this could be done much simpler
247 #print "FindFirs2 path:%s, filename:%s" % (path, fileName)
248 fileName = os.path.normpath(fileName.replace('\\','/'))
249 # Let's choose the right encoding depending on the request
250 if isinstance(fileName,unicode):
251 encoding = 'utf-16le'
252 flags = smb.SMB.FLAGS2_UNICODE
257 if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
259 fileName = fileName[1:]
261 pathName = os.path.join(path,fileName)
264 if pathName.find('*') == -1 and pathName.find('?') == -1:
268 pattern = os.path.basename(pathName)
269 dirName = os.path.dirname(pathName)
271 # Always add . and .. Not that important for Windows, but Samba whines if
272 # not present (for * search only)
274 files.append(os.path.join(dirName,'.'))
275 files.append(os.path.join(dirName,'..'))
278 for file in os.listdir(dirName):
279 if fnmatch.fnmatch(file.lower(),pattern.lower()):
280 entry = os.path.join(dirName, file)
281 if os.path.isdir(entry):
282 if searchAttributes & smb.ATTR_DIRECTORY:
287 if os.path.exists(pathName):
288 files.append(pathName)
291 searchCount = len(files)
292 errorCode = STATUS_SUCCESS
295 if level == smb.SMB_FIND_FILE_BOTH_DIRECTORY_INFO or level == smb2.SMB2_FILE_BOTH_DIRECTORY_INFO:
296 item = smb.SMBFindFileBothDirectoryInfo( flags = flags )
297 elif level == smb.SMB_FIND_FILE_DIRECTORY_INFO or level == smb2.SMB2_FILE_DIRECTORY_INFO:
298 item = smb.SMBFindFileDirectoryInfo( flags = flags )
299 elif level == smb.SMB_FIND_FILE_FULL_DIRECTORY_INFO or level == smb2.SMB2_FULL_DIRECTORY_INFO:
300 item = smb.SMBFindFileFullDirectoryInfo( flags = flags )
301 elif level == smb.SMB_FIND_INFO_STANDARD:
302 item = smb.SMBFindInfoStandard( flags = flags )
303 elif level == smb.SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO or level == smb2.SMB2_FILE_ID_FULL_DIRECTORY_INFO:
304 item = smb.SMBFindFileIdFullDirectoryInfo( flags = flags )
305 elif level == smb.SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO or level == smb2.SMB2_FILE_ID_BOTH_DIRECTORY_INFO:
306 item = smb.SMBFindFileIdBothDirectoryInfo( flags = flags )
307 elif level == smb.SMB_FIND_FILE_NAMES_INFO or level == smb2.SMB2_FILE_NAMES_INFO:
308 item = smb.SMBFindFileNamesInfo( flags = flags )
310 LOG.error("Wrong level %d!" % level)
311 return searchResult, searchCount, STATUS_NOT_SUPPORTED
313 (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(i)
315 item['ExtFileAttributes'] = smb.ATTR_DIRECTORY
317 item['ExtFileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE
319 item['FileName'] = os.path.basename(i).encode(encoding)
321 if level == smb.SMB_FIND_FILE_BOTH_DIRECTORY_INFO or level == smb.SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO or level == smb2.SMB2_FILE_ID_BOTH_DIRECTORY_INFO or level == smb2.SMB2_FILE_BOTH_DIRECTORY_INFO:
323 item['EndOfFile'] = size
324 item['AllocationSize'] = size
325 item['CreationTime'] = getFileTime(ctime)
326 item['LastAccessTime'] = getFileTime(atime)
327 item['LastWriteTime'] = getFileTime(mtime)
328 item['LastChangeTime'] = getFileTime(mtime)
329 item['ShortName'] = '\x00'*24
330 item['FileName'] = os.path.basename(i).encode(encoding)
331 padLen = (8-(len(item) % 8)) % 8
332 item['NextEntryOffset'] = len(item) + padLen
333 elif level == smb.SMB_FIND_FILE_DIRECTORY_INFO:
334 item['EndOfFile'] = size
335 item['AllocationSize'] = size
336 item['CreationTime'] = getFileTime(ctime)
337 item['LastAccessTime'] = getFileTime(atime)
338 item['LastWriteTime'] = getFileTime(mtime)
339 item['LastChangeTime'] = getFileTime(mtime)
340 item['FileName'] = os.path.basename(i).encode(encoding)
341 padLen = (8-(len(item) % 8)) % 8
342 item['NextEntryOffset'] = len(item) + padLen
343 elif level == smb.SMB_FIND_FILE_FULL_DIRECTORY_INFO or level == smb.SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO or level == smb2.SMB2_FULL_DIRECTORY_INFO:
345 item['EndOfFile'] = size
346 item['AllocationSize'] = size
347 item['CreationTime'] = getFileTime(ctime)
348 item['LastAccessTime'] = getFileTime(atime)
349 item['LastWriteTime'] = getFileTime(mtime)
350 item['LastChangeTime'] = getFileTime(mtime)
351 padLen = (8-(len(item) % 8)) % 8
352 item['NextEntryOffset'] = len(item) + padLen
353 elif level == smb.SMB_FIND_INFO_STANDARD:
354 item['EaSize'] = size
355 item['CreationDate'] = getSMBDate(ctime)
356 item['CreationTime'] = getSMBTime(ctime)
357 item['LastAccessDate'] = getSMBDate(atime)
358 item['LastAccessTime'] = getSMBTime(atime)
359 item['LastWriteDate'] = getSMBDate(mtime)
360 item['LastWriteTime'] = getSMBTime(mtime)
361 searchResult.append(item)
364 if (level >= smb.SMB_FIND_FILE_DIRECTORY_INFO or isSMB2 == True) and searchCount > 0:
365 searchResult[-1]['NextEntryOffset'] = 0
367 return searchResult, searchCount, errorCode
369 def queryFileInformation(path, filename, level):
370 #print "queryFileInfo path: %s, filename: %s, level:0x%x" % (path,filename,level)
371 return queryPathInformation(path,filename, level)
373 def queryPathInformation(path, filename, level):
374 # TODO: Depending on the level, this could be done much simpler
375 #print "queryPathInfo path: %s, filename: %s, level:0x%x" % (path,filename,level)
378 fileName = os.path.normpath(filename.replace('\\','/'))
379 if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\') and path != '':
381 fileName = fileName[1:]
382 pathName = os.path.join(path,fileName)
383 if os.path.exists(pathName):
384 (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(pathName)
385 if level == smb.SMB_QUERY_FILE_BASIC_INFO:
386 infoRecord = smb.SMBQueryFileBasicInfo()
387 infoRecord['CreationTime'] = getFileTime(ctime)
388 infoRecord['LastAccessTime'] = getFileTime(atime)
389 infoRecord['LastWriteTime'] = getFileTime(mtime)
390 infoRecord['LastChangeTime'] = getFileTime(mtime)
391 if os.path.isdir(pathName):
392 infoRecord['ExtFileAttributes'] = smb.ATTR_DIRECTORY
394 infoRecord['ExtFileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE
395 elif level == smb.SMB_QUERY_FILE_STANDARD_INFO:
396 infoRecord = smb.SMBQueryFileStandardInfo()
397 infoRecord['AllocationSize'] = size
398 infoRecord['EndOfFile'] = size
399 if os.path.isdir(pathName):
400 infoRecord['Directory'] = 1
402 infoRecord['Directory'] = 0
403 elif level == smb.SMB_QUERY_FILE_ALL_INFO or level == smb2.SMB2_FILE_ALL_INFO:
404 infoRecord = smb.SMBQueryFileAllInfo()
405 infoRecord['CreationTime'] = getFileTime(ctime)
406 infoRecord['LastAccessTime'] = getFileTime(atime)
407 infoRecord['LastWriteTime'] = getFileTime(mtime)
408 infoRecord['LastChangeTime'] = getFileTime(mtime)
409 if os.path.isdir(pathName):
410 infoRecord['ExtFileAttributes'] = smb.ATTR_DIRECTORY
412 infoRecord['ExtFileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE
413 infoRecord['AllocationSize'] = size
414 infoRecord['EndOfFile'] = size
415 if os.path.isdir(pathName):
416 infoRecord['Directory'] = 1
418 infoRecord['Directory'] = 0
419 infoRecord['FileName'] = filename.encode('utf-16le')
420 elif level == smb2.SMB2_FILE_NETWORK_OPEN_INFO:
421 infoRecord = smb.SMBFileNetworkOpenInfo()
422 infoRecord['CreationTime'] = getFileTime(ctime)
423 infoRecord['LastAccessTime'] = getFileTime(atime)
424 infoRecord['LastWriteTime'] = getFileTime(mtime)
425 infoRecord['ChangeTime'] = getFileTime(mtime)
426 infoRecord['AllocationSize'] = size
427 infoRecord['EndOfFile'] = size
428 if os.path.isdir(pathName):
429 infoRecord['FileAttributes'] = smb.ATTR_DIRECTORY
431 infoRecord['FileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE
432 elif level == smb.SMB_QUERY_FILE_EA_INFO or level == smb2.SMB2_FILE_EA_INFO:
433 infoRecord = smb.SMBQueryFileEaInfo()
434 elif level == smb2.SMB2_FILE_STREAM_INFO:
435 infoRecord = smb.SMBFileStreamInformation()
437 LOG.error('Unknown level for query path info! 0x%x' % level)
439 return None, STATUS_NOT_SUPPORTED
441 return infoRecord, errorCode
444 return None, STATUS_OBJECT_NAME_NOT_FOUND
446 LOG.error('queryPathInfo: %s' % e)
449 def queryDiskInformation(path):
450 # TODO: Do something useful here :)
451 # For now we just return fake values
454 return totalUnits, freeUnits
456 # Here we implement the NT transaction handlers
457 class NTTRANSCommands:
458 def default(self, connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
461 # Here we implement the NT transaction handlers
464 def lanMan(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
465 # Minimal [MS-RAP] implementation, just to return the shares
466 connData = smbServer.getConnectionData(connId)
471 errorCode = STATUS_SUCCESS
472 if struct.unpack('<H',parameters[:2])[0] == 0:
473 # NetShareEnum Request
474 netShareEnum = smb.SMBNetShareEnum(parameters)
475 if netShareEnum['InfoLevel'] == 1:
476 shares = getShares(connId, smbServer)
477 respParameters = smb.SMBNetShareEnumResponse()
478 respParameters['EntriesReturned'] = len(shares)
479 respParameters['EntriesAvailable'] = len(shares)
482 # NetShareInfo1 len == 20
483 entry = smb.NetShareInfo1()
484 entry['NetworkName'] = i + '\x00'*(13-len(i))
485 entry['Type'] = int(shares[i]['share type'])
486 # (beto) If offset == 0 it crashes explorer.exe on windows 7
487 entry['RemarkOffsetLow'] = 20 * len(shares) + len(tailData)
488 respData += entry.getData()
489 if shares[i].has_key('comment'):
490 tailData += shares[i]['comment'] + '\x00'
495 # We don't support other info levels
496 errorCode = STATUS_NOT_SUPPORTED
497 elif struct.unpack('<H',parameters[:2])[0] == 13:
498 # NetrServerGetInfo Request
499 respParameters = smb.SMBNetServerGetInfoResponse()
500 netServerInfo = smb.SMBNetServerInfo1()
501 netServerInfo['ServerName'] = smbServer.getServerName()
502 respData = str(netServerInfo)
503 respParameters['TotalBytesAvailable'] = len(respData)
504 elif struct.unpack('<H',parameters[:2])[0] == 1:
505 # NetrShareGetInfo Request
506 request = smb.SMBNetShareGetInfo(parameters)
507 respParameters = smb.SMBNetShareGetInfoResponse()
508 shares = getShares(connId, smbServer)
509 share = shares[request['ShareName'].upper()]
510 shareInfo = smb.NetShareInfo1()
511 shareInfo['NetworkName'] = request['ShareName'].upper() + '\x00'
512 shareInfo['Type'] = int(share['share type'])
513 respData = shareInfo.getData()
514 if share.has_key('comment'):
515 shareInfo['RemarkOffsetLow'] = len(respData)
516 respData += share['comment'] + '\x00'
517 respParameters['TotalBytesAvailable'] = len(respData)
520 # We don't know how to handle anything else
521 errorCode = STATUS_NOT_SUPPORTED
523 smbServer.setConnectionData(connId, connData)
525 return respSetup, respParameters, respData, errorCode
528 def transactNamedPipe(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
529 connData = smbServer.getConnectionData(connId)
534 errorCode = STATUS_SUCCESS
535 SMBCommand = smb.SMBCommand(recvPacket['Data'][0])
536 transParameters= smb.SMBTransaction_Parameters(SMBCommand['Parameters'])
539 fid = struct.unpack('<H', transParameters['Setup'][2:])[0]
541 if connData['OpenedFiles'].has_key(fid):
542 fileHandle = connData['OpenedFiles'][fid]['FileHandle']
543 if fileHandle != PIPE_FILE_DESCRIPTOR:
544 os.write(fileHandle,data)
545 respData = os.read(fileHandle,data)
547 sock = connData['OpenedFiles'][fid]['Socket']
549 respData = sock.recv(maxDataCount)
551 errorCode = STATUS_INVALID_HANDLE
553 smbServer.setConnectionData(connId, connData)
555 return respSetup, respParameters, respData, errorCode
557 # Here we implement the transaction2 handlers
558 class TRANS2Commands:
559 # All these commands return setup, parameters, data, errorCode
561 def setPathInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
562 connData = smbServer.getConnectionData(connId)
567 errorCode = STATUS_SUCCESS
568 setPathInfoParameters = smb.SMBSetPathInformation_Parameters(flags = recvPacket['Flags2'], data = parameters)
569 if connData['ConnectedShares'].has_key(recvPacket['Tid']):
570 path = connData['ConnectedShares'][recvPacket['Tid']]['path']
571 fileName = decodeSMBString(recvPacket['Flags2'], setPathInfoParameters['FileName'])
572 fileName = os.path.normpath(fileName.replace('\\','/'))
573 if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\') and path != '':
575 fileName = fileName[1:]
576 pathName = os.path.join(path,fileName)
577 if os.path.exists(pathName):
578 informationLevel = setPathInfoParameters['InformationLevel']
579 if informationLevel == smb.SMB_SET_FILE_BASIC_INFO:
580 infoRecord = smb.SMBSetFileBasicInfo(data)
581 # Creation time won't be set, the other ones we play with.
582 atime = infoRecord['LastAccessTime']
586 atime = getUnixTime(atime)
587 mtime = infoRecord['LastWriteTime']
591 mtime = getUnixTime(mtime)
592 if mtime != -1 or atime != -1:
593 os.utime(pathName,(atime,mtime))
595 smbServer.log('Unknown level for set path info! 0x%x' % setPathInfoParameters['InformationLevel'], logging.ERROR)
597 errorCode = STATUS_NOT_SUPPORTED
599 errorCode = STATUS_OBJECT_NAME_NOT_FOUND
601 if errorCode == STATUS_SUCCESS:
602 respParameters = smb.SMBSetPathInformationResponse_Parameters()
605 errorCode = STATUS_SMB_BAD_TID
607 smbServer.setConnectionData(connId, connData)
609 return respSetup, respParameters, respData, errorCode
613 def setFileInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
614 connData = smbServer.getConnectionData(connId)
619 errorCode = STATUS_SUCCESS
620 setFileInfoParameters = smb.SMBSetFileInformation_Parameters(parameters)
622 if connData['ConnectedShares'].has_key(recvPacket['Tid']):
623 if connData['OpenedFiles'].has_key(setFileInfoParameters['FID']):
624 fileName = connData['OpenedFiles'][setFileInfoParameters['FID']]['FileName']
625 informationLevel = setFileInfoParameters['InformationLevel']
626 if informationLevel == smb.SMB_SET_FILE_DISPOSITION_INFO:
627 infoRecord = smb.SMBSetFileDispositionInfo(parameters)
628 if infoRecord['DeletePending'] > 0:
629 # Mark this file for removal after closed
630 connData['OpenedFiles'][setFileInfoParameters['FID']]['DeleteOnClose'] = True
631 respParameters = smb.SMBSetFileInformationResponse_Parameters()
632 elif informationLevel == smb.SMB_SET_FILE_BASIC_INFO:
633 infoRecord = smb.SMBSetFileBasicInfo(data)
634 # Creation time won't be set, the other ones we play with.
635 atime = infoRecord['LastAccessTime']
639 atime = getUnixTime(atime)
640 mtime = infoRecord['LastWriteTime']
644 mtime = getUnixTime(mtime)
645 os.utime(fileName,(atime,mtime))
646 elif informationLevel == smb.SMB_SET_FILE_END_OF_FILE_INFO:
647 fileHandle = connData['OpenedFiles'][setFileInfoParameters['FID']]['FileHandle']
648 infoRecord = smb.SMBSetFileEndOfFileInfo(data)
649 if infoRecord['EndOfFile'] > 0:
650 os.lseek(fileHandle, infoRecord['EndOfFile']-1, 0)
651 os.write(fileHandle, '\x00')
653 smbServer.log('Unknown level for set file info! 0x%x' % setFileInfoParameters['InformationLevel'], logging.ERROR)
655 errorCode = STATUS_NOT_SUPPORTED
657 errorCode = STATUS_NO_SUCH_FILE
659 if errorCode == STATUS_SUCCESS:
660 respParameters = smb.SMBSetFileInformationResponse_Parameters()
662 errorCode = STATUS_SMB_BAD_TID
664 smbServer.setConnectionData(connId, connData)
666 return respSetup, respParameters, respData, errorCode
669 def queryFileInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
670 connData = smbServer.getConnectionData(connId)
676 queryFileInfoParameters = smb.SMBQueryFileInformation_Parameters(parameters)
678 if connData['ConnectedShares'].has_key(recvPacket['Tid']):
679 if connData['OpenedFiles'].has_key(queryFileInfoParameters['FID']):
680 fileName = connData['OpenedFiles'][queryFileInfoParameters['FID']]['FileName']
682 infoRecord, errorCode = queryFileInformation('', fileName, queryFileInfoParameters['InformationLevel'])
684 if infoRecord is not None:
685 respParameters = smb.SMBQueryFileInformationResponse_Parameters()
686 respData = infoRecord
688 errorCode = STATUS_INVALID_HANDLE
690 errorCode = STATUS_SMB_BAD_TID
692 smbServer.setConnectionData(connId, connData)
694 return respSetup, respParameters, respData, errorCode
697 def queryPathInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
698 connData = smbServer.getConnectionData(connId)
705 queryPathInfoParameters = smb.SMBQueryPathInformation_Parameters(flags = recvPacket['Flags2'], data = parameters)
707 if connData['ConnectedShares'].has_key(recvPacket['Tid']):
708 path = connData['ConnectedShares'][recvPacket['Tid']]['path']
710 infoRecord, errorCode = queryPathInformation(path, decodeSMBString(recvPacket['Flags2'], queryPathInfoParameters['FileName']), queryPathInfoParameters['InformationLevel'])
712 smbServer.log("queryPathInformation: %s" % e,logging.ERROR)
714 if infoRecord is not None:
715 respParameters = smb.SMBQueryPathInformationResponse_Parameters()
716 respData = infoRecord
718 errorCode = STATUS_SMB_BAD_TID
720 smbServer.setConnectionData(connId, connData)
722 return respSetup, respParameters, respData, errorCode
725 def queryFsInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
726 connData = smbServer.getConnectionData(connId)
728 # Get the Tid associated
729 if connData['ConnectedShares'].has_key(recvPacket['Tid']):
730 data = queryFsInformation(connData['ConnectedShares'][recvPacket['Tid']]['path'], '', struct.unpack('<H',parameters)[0])
732 smbServer.setConnectionData(connId, connData)
734 return '','', data, errorCode
737 def findNext2(connId, smbServer, recvPacket, parameters, data, maxDataCount):
738 connData = smbServer.getConnectionData(connId)
743 errorCode = STATUS_SUCCESS
744 findNext2Parameters = smb.SMBFindNext2_Parameters(flags = recvPacket['Flags2'], data = parameters)
746 sid = findNext2Parameters['SID']
747 if connData['ConnectedShares'].has_key(recvPacket['Tid']):
748 if connData['SIDs'].has_key(sid):
749 searchResult = connData['SIDs'][sid]
750 respParameters = smb.SMBFindNext2Response_Parameters()
754 for i in enumerate(searchResult):
755 data = i[1].getData()
757 if (totalData+lenData) >= maxDataCount or (i[0]+1) >= findNext2Parameters['SearchCount']:
758 # We gotta stop here and continue on a find_next2
760 connData['SIDs'][sid] = searchResult[i[0]:]
761 respParameters['LastNameOffset'] = totalData
768 # Have we reached the end of the search or still stuff to send?
770 # Let's remove the SID from our ConnData
771 del(connData['SIDs'][sid])
773 respParameters['EndOfSearch'] = endOfSearch
774 respParameters['SearchCount'] = searchCount
776 errorCode = STATUS_INVALID_HANDLE
778 errorCode = STATUS_SMB_BAD_TID
780 smbServer.setConnectionData(connId, connData)
782 return respSetup, respParameters, respData, errorCode
785 def findFirst2(connId, smbServer, recvPacket, parameters, data, maxDataCount):
786 connData = smbServer.getConnectionData(connId)
791 findFirst2Parameters = smb.SMBFindFirst2_Parameters( recvPacket['Flags2'], data = parameters)
793 if connData['ConnectedShares'].has_key(recvPacket['Tid']):
794 path = connData['ConnectedShares'][recvPacket['Tid']]['path']
796 searchResult, searchCount, errorCode = findFirst2(path,
797 decodeSMBString( recvPacket['Flags2'], findFirst2Parameters['FileName'] ),
798 findFirst2Parameters['InformationLevel'],
799 findFirst2Parameters['SearchAttributes'] )
801 respParameters = smb.SMBFindFirst2Response_Parameters()
803 sid = 0x80 # default SID
806 for i in enumerate(searchResult):
808 data = i[1].getData()
810 if (totalData+lenData) >= maxDataCount or (i[0]+1) > findFirst2Parameters['SearchCount']:
811 # We gotta stop here and continue on a find_next2
813 # Simple way to generate a fid
814 if len(connData['SIDs']) == 0:
817 sid = connData['SIDs'].keys()[-1] + 1
818 # Store the remaining search results in the ConnData SID
819 connData['SIDs'][sid] = searchResult[i[0]:]
820 respParameters['LastNameOffset'] = totalData
826 padLen = (8-(lenData % 8)) %8
827 respData += '\xaa'*padLen
828 totalData += lenData + padLen
830 respParameters['SID'] = sid
831 respParameters['EndOfSearch'] = endOfSearch
832 respParameters['SearchCount'] = searchCount
834 errorCode = STATUS_SMB_BAD_TID
836 smbServer.setConnectionData(connId, connData)
838 return respSetup, respParameters, respData, errorCode
840 # Here we implement the commands handlers
844 def smbTransaction(connId, smbServer, SMBCommand, recvPacket, transCommands):
845 connData = smbServer.getConnectionData(connId)
847 respSMBCommand = smb.SMBCommand(recvPacket['Command'])
849 transParameters= smb.SMBTransaction_Parameters(SMBCommand['Parameters'])
852 if transParameters['ParameterCount'] != transParameters['TotalParameterCount']:
853 # TODO: Handle partial parameters
854 raise Exception("Unsupported partial parameters in TRANSACT2!")
856 transData = smb.SMBTransaction_SData(flags = recvPacket['Flags2'])
857 # Standard says servers shouldn't trust Parameters and Data comes
858 # in order, so we have to parse the offsets, ugly
860 paramCount = transParameters['ParameterCount']
861 transData['Trans_ParametersLength'] = paramCount
862 dataCount = transParameters['DataCount']
863 transData['Trans_DataLength'] = dataCount
864 transData.fromString(SMBCommand['Data'])
865 if transParameters['ParameterOffset'] > 0:
866 paramOffset = transParameters['ParameterOffset'] - 63 - transParameters['SetupLength']
867 transData['Trans_Parameters'] = SMBCommand['Data'][paramOffset:paramOffset+paramCount]
869 transData['Trans_Parameters'] = ''
871 if transParameters['DataOffset'] > 0:
872 dataOffset = transParameters['DataOffset'] - 63 - transParameters['SetupLength']
873 transData['Trans_Data'] = SMBCommand['Data'][dataOffset:dataOffset + dataCount]
875 transData['Trans_Data'] = ''
877 # Call the handler for this TRANSACTION
878 if transParameters['SetupCount'] == 0:
879 # No subcommand, let's play with the Name
880 command = decodeSMBString(recvPacket['Flags2'],transData['Name'])
882 command = struct.unpack('<H', transParameters['Setup'][:2])[0]
884 if transCommands.has_key(command):
885 # Call the TRANS subcommand
890 setup, parameters, data, errorCode = transCommands[command](connId,
893 transData['Trans_Parameters'],
894 transData['Trans_Data'],
895 transParameters['MaxDataCount'])
897 #print 'Transaction: %s' % e,e
898 smbServer.log('Transaction: (%r,%s)' % (command, e), logging.ERROR)
899 errorCode = STATUS_ACCESS_DENIED
902 if setup == '' and parameters == '' and data == '':
903 # Something wen't wrong
909 remainingData = len(data)
910 parameters = str(parameters)
911 remainingParameters = len(parameters)
914 while remainingData > 0 or remainingParameters > 0:
915 respSMBCommand = smb.SMBCommand(recvPacket['Command'])
916 respParameters = smb.SMBTransactionResponse_Parameters()
917 respData = smb.SMBTransaction2Response_Data()
919 respParameters['TotalParameterCount'] = len(parameters)
920 respParameters['ParameterCount'] = len(parameters)
921 respData['Trans_ParametersLength'] = len(parameters)
922 respParameters['TotalDataCount'] = len(data)
923 respParameters['DataDisplacement'] = dataDisplacement
925 # TODO: Do the same for parameters
926 if len(data) > transParameters['MaxDataCount']:
927 # Answer doesn't fit in this packet
928 LOG.debug("Lowering answer from %d to %d" % (len(data),transParameters['MaxDataCount']) )
929 respParameters['DataCount'] = transParameters['MaxDataCount']
931 respParameters['DataCount'] = len(data)
933 respData['Trans_DataLength'] = respParameters['DataCount']
934 respParameters['SetupCount'] = len(setup)
935 respParameters['Setup'] = setup
936 # TODO: Make sure we're calculating the pad right
937 if len(parameters) > 0:
938 #padLen = 4 - (55 + len(setup)) % 4
939 padLen = (4 - (55 + len(setup)) % 4 ) % 4
940 padBytes = '\xFF' * padLen
941 respData['Pad1'] = padBytes
942 respParameters['ParameterOffset'] = 55 + len(setup) + padLen
945 respParameters['ParameterOffset'] = 0
946 respData['Pad1'] = ''
949 #pad2Len = 4 - (55 + len(setup) + padLen + len(parameters)) % 4
950 pad2Len = (4 - (55 + len(setup) + padLen + len(parameters)) % 4) % 4
951 respData['Pad2'] = '\xFF' * pad2Len
952 respParameters['DataOffset'] = 55 + len(setup) + padLen + len(parameters) + pad2Len
954 respParameters['DataOffset'] = 0
955 respData['Pad2'] = ''
957 respData['Trans_Parameters'] = parameters[:respParameters['ParameterCount']]
958 respData['Trans_Data'] = data[:respParameters['DataCount']]
959 respSMBCommand['Parameters'] = respParameters
960 respSMBCommand['Data'] = respData
962 data = data[respParameters['DataCount']:]
963 remainingData -= respParameters['DataCount']
964 dataDisplacement += respParameters['DataCount'] + 1
966 parameters = parameters[respParameters['ParameterCount']:]
967 remainingParameters -= respParameters['ParameterCount']
968 commands.append(respSMBCommand)
970 smbServer.setConnectionData(connId, connData)
971 return commands, None, errorCode
974 smbServer.log("Unsupported Transact command %r" % command, logging.ERROR)
977 errorCode = STATUS_NOT_IMPLEMENTED
979 respSMBCommand['Parameters'] = respParameters
980 respSMBCommand['Data'] = respData
981 smbServer.setConnectionData(connId, connData)
983 return [respSMBCommand], None, errorCode
987 def smbNTTransact(connId, smbServer, SMBCommand, recvPacket, transCommands):
988 connData = smbServer.getConnectionData(connId)
990 respSMBCommand = smb.SMBCommand(recvPacket['Command'])
992 NTTransParameters= smb.SMBNTTransaction_Parameters(SMBCommand['Parameters'])
994 if NTTransParameters['ParameterCount'] != NTTransParameters['TotalParameterCount']:
995 # TODO: Handle partial parameters
996 raise Exception("Unsupported partial parameters in NTTrans!")
998 NTTransData = smb.SMBNTTransaction_Data()
999 # Standard says servers shouldn't trust Parameters and Data comes
1000 # in order, so we have to parse the offsets, ugly
1002 paramCount = NTTransParameters['ParameterCount']
1003 NTTransData['NT_Trans_ParametersLength'] = paramCount
1004 dataCount = NTTransParameters['DataCount']
1005 NTTransData['NT_Trans_DataLength'] = dataCount
1007 if NTTransParameters['ParameterOffset'] > 0:
1008 paramOffset = NTTransParameters['ParameterOffset'] - 73 - NTTransParameters['SetupLength']
1009 NTTransData['NT_Trans_Parameters'] = SMBCommand['Data'][paramOffset:paramOffset+paramCount]
1011 NTTransData['NT_Trans_Parameters'] = ''
1013 if NTTransParameters['DataOffset'] > 0:
1014 dataOffset = NTTransParameters['DataOffset'] - 73 - NTTransParameters['SetupLength']
1015 NTTransData['NT_Trans_Data'] = SMBCommand['Data'][dataOffset:dataOffset + dataCount]
1017 NTTransData['NT_Trans_Data'] = ''
1019 # Call the handler for this TRANSACTION
1020 command = NTTransParameters['Function']
1021 if transCommands.has_key(command):
1022 # Call the NT TRANS subcommand
1027 setup, parameters, data, errorCode = transCommands[command](connId,
1030 NTTransData['NT_Trans_Parameters'],
1031 NTTransData['NT_Trans_Data'],
1032 NTTransParameters['MaxDataCount'])
1033 except Exception, e:
1034 smbServer.log('NTTransaction: (0x%x,%s)' % (command, e), logging.ERROR)
1035 errorCode = STATUS_ACCESS_DENIED
1038 if setup == '' and parameters == '' and data == '':
1039 # Something wen't wrong
1042 if errorCode == STATUS_SUCCESS:
1043 errorCode = STATUS_ACCESS_DENIED
1047 remainingData = len(data)
1048 parameters = str(parameters)
1049 remainingParameters = len(parameters)
1051 dataDisplacement = 0
1052 while remainingData > 0 or remainingParameters > 0:
1053 respSMBCommand = smb.SMBCommand(recvPacket['Command'])
1054 respParameters = smb.SMBNTTransactionResponse_Parameters()
1055 respData = smb.SMBNTTransactionResponse_Data()
1057 respParameters['TotalParameterCount'] = len(parameters)
1058 respParameters['ParameterCount'] = len(parameters)
1059 respData['Trans_ParametersLength'] = len(parameters)
1060 respParameters['TotalDataCount'] = len(data)
1061 respParameters['DataDisplacement'] = dataDisplacement
1062 # TODO: Do the same for parameters
1063 if len(data) > NTTransParameters['MaxDataCount']:
1064 # Answer doesn't fit in this packet
1065 LOG.debug("Lowering answer from %d to %d" % (len(data),NTTransParameters['MaxDataCount']) )
1066 respParameters['DataCount'] = NTTransParameters['MaxDataCount']
1068 respParameters['DataCount'] = len(data)
1070 respData['NT_Trans_DataLength'] = respParameters['DataCount']
1071 respParameters['SetupCount'] = len(setup)
1072 respParameters['Setup'] = setup
1073 # TODO: Make sure we're calculating the pad right
1074 if len(parameters) > 0:
1075 #padLen = 4 - (71 + len(setup)) % 4
1076 padLen = (4 - (73 + len(setup)) % 4 ) % 4
1077 padBytes = '\xFF' * padLen
1078 respData['Pad1'] = padBytes
1079 respParameters['ParameterOffset'] = 73 + len(setup) + padLen
1082 respParameters['ParameterOffset'] = 0
1083 respData['Pad1'] = ''
1086 #pad2Len = 4 - (71 + len(setup) + padLen + len(parameters)) % 4
1087 pad2Len = (4 - (73 + len(setup) + padLen + len(parameters)) % 4) % 4
1088 respData['Pad2'] = '\xFF' * pad2Len
1089 respParameters['DataOffset'] = 73 + len(setup) + padLen + len(parameters) + pad2Len
1091 respParameters['DataOffset'] = 0
1092 respData['Pad2'] = ''
1094 respData['NT_Trans_Parameters'] = parameters[:respParameters['ParameterCount']]
1095 respData['NT_Trans_Data'] = data[:respParameters['DataCount']]
1096 respSMBCommand['Parameters'] = respParameters
1097 respSMBCommand['Data'] = respData
1099 data = data[respParameters['DataCount']:]
1100 remainingData -= respParameters['DataCount']
1101 dataDisplacement += respParameters['DataCount'] + 1
1103 parameters = parameters[respParameters['ParameterCount']:]
1104 remainingParameters -= respParameters['ParameterCount']
1105 commands.append(respSMBCommand)
1107 smbServer.setConnectionData(connId, connData)
1108 return commands, None, errorCode
1111 #smbServer.log("Unsupported NTTransact command 0x%x" % command, logging.ERROR)
1114 errorCode = STATUS_NOT_IMPLEMENTED
1116 respSMBCommand['Parameters'] = respParameters
1117 respSMBCommand['Data'] = respData
1119 smbServer.setConnectionData(connId, connData)
1120 return [respSMBCommand], None, errorCode
1124 def smbTransaction2(connId, smbServer, SMBCommand, recvPacket, transCommands):
1125 connData = smbServer.getConnectionData(connId)
1127 respSMBCommand = smb.SMBCommand(recvPacket['Command'])
1129 trans2Parameters= smb.SMBTransaction2_Parameters(SMBCommand['Parameters'])
1132 if trans2Parameters['ParameterCount'] != trans2Parameters['TotalParameterCount']:
1133 # TODO: Handle partial parameters
1134 #print "Unsupported partial parameters in TRANSACT2!"
1135 raise Exception("Unsupported partial parameters in TRANSACT2!")
1137 trans2Data = smb.SMBTransaction2_Data()
1138 # Standard says servers shouldn't trust Parameters and Data comes
1139 # in order, so we have to parse the offsets, ugly
1141 paramCount = trans2Parameters['ParameterCount']
1142 trans2Data['Trans_ParametersLength'] = paramCount
1143 dataCount = trans2Parameters['DataCount']
1144 trans2Data['Trans_DataLength'] = dataCount
1146 if trans2Parameters['ParameterOffset'] > 0:
1147 paramOffset = trans2Parameters['ParameterOffset'] - 63 - trans2Parameters['SetupLength']
1148 trans2Data['Trans_Parameters'] = SMBCommand['Data'][paramOffset:paramOffset+paramCount]
1150 trans2Data['Trans_Parameters'] = ''
1152 if trans2Parameters['DataOffset'] > 0:
1153 dataOffset = trans2Parameters['DataOffset'] - 63 - trans2Parameters['SetupLength']
1154 trans2Data['Trans_Data'] = SMBCommand['Data'][dataOffset:dataOffset + dataCount]
1156 trans2Data['Trans_Data'] = ''
1158 # Call the handler for this TRANSACTION
1159 command = struct.unpack('<H', trans2Parameters['Setup'])[0]
1160 if transCommands.has_key(command):
1161 # Call the TRANS2 subcommand
1163 setup, parameters, data, errorCode = transCommands[command](connId,
1166 trans2Data['Trans_Parameters'],
1167 trans2Data['Trans_Data'],
1168 trans2Parameters['MaxDataCount'])
1169 except Exception, e:
1170 smbServer.log('Transaction2: (0x%x,%s)' % (command, e), logging.ERROR)
1172 #traceback.print_exc()
1175 if setup == '' and parameters == '' and data == '':
1176 # Something wen't wrong
1182 remainingData = len(data)
1183 parameters = str(parameters)
1184 remainingParameters = len(parameters)
1186 dataDisplacement = 0
1187 while remainingData > 0 or remainingParameters > 0:
1188 respSMBCommand = smb.SMBCommand(recvPacket['Command'])
1189 respParameters = smb.SMBTransaction2Response_Parameters()
1190 respData = smb.SMBTransaction2Response_Data()
1192 respParameters['TotalParameterCount'] = len(parameters)
1193 respParameters['ParameterCount'] = len(parameters)
1194 respData['Trans_ParametersLength'] = len(parameters)
1195 respParameters['TotalDataCount'] = len(data)
1196 respParameters['DataDisplacement'] = dataDisplacement
1197 # TODO: Do the same for parameters
1198 if len(data) > trans2Parameters['MaxDataCount']:
1199 # Answer doesn't fit in this packet
1200 LOG.debug("Lowering answer from %d to %d" % (len(data),trans2Parameters['MaxDataCount']) )
1201 respParameters['DataCount'] = trans2Parameters['MaxDataCount']
1203 respParameters['DataCount'] = len(data)
1205 respData['Trans_DataLength'] = respParameters['DataCount']
1206 respParameters['SetupCount'] = len(setup)
1207 respParameters['Setup'] = setup
1208 # TODO: Make sure we're calculating the pad right
1209 if len(parameters) > 0:
1210 #padLen = 4 - (55 + len(setup)) % 4
1211 padLen = (4 - (55 + len(setup)) % 4 ) % 4
1212 padBytes = '\xFF' * padLen
1213 respData['Pad1'] = padBytes
1214 respParameters['ParameterOffset'] = 55 + len(setup) + padLen
1217 respParameters['ParameterOffset'] = 0
1218 respData['Pad1'] = ''
1221 #pad2Len = 4 - (55 + len(setup) + padLen + len(parameters)) % 4
1222 pad2Len = (4 - (55 + len(setup) + padLen + len(parameters)) % 4) % 4
1223 respData['Pad2'] = '\xFF' * pad2Len
1224 respParameters['DataOffset'] = 55 + len(setup) + padLen + len(parameters) + pad2Len
1226 respParameters['DataOffset'] = 0
1227 respData['Pad2'] = ''
1229 respData['Trans_Parameters'] = parameters[:respParameters['ParameterCount']]
1230 respData['Trans_Data'] = data[:respParameters['DataCount']]
1231 respSMBCommand['Parameters'] = respParameters
1232 respSMBCommand['Data'] = respData
1234 data = data[respParameters['DataCount']:]
1235 remainingData -= respParameters['DataCount']
1236 dataDisplacement += respParameters['DataCount'] + 1
1238 parameters = parameters[respParameters['ParameterCount']:]
1239 remainingParameters -= respParameters['ParameterCount']
1240 commands.append(respSMBCommand)
1242 smbServer.setConnectionData(connId, connData)
1243 return commands, None, errorCode
1246 smbServer.log("Unsupported Transact/2 command 0x%x" % command, logging.ERROR)
1249 errorCode = STATUS_NOT_IMPLEMENTED
1251 respSMBCommand['Parameters'] = respParameters
1252 respSMBCommand['Data'] = respData
1254 smbServer.setConnectionData(connId, connData)
1255 return [respSMBCommand], None, errorCode
1258 def smbComLockingAndX(connId, smbServer, SMBCommand, recvPacket):
1259 connData = smbServer.getConnectionData(connId)
1261 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_LOCKING_ANDX)
1265 # I'm actually doing nothing.. just make MacOS happy ;)
1266 errorCode = STATUS_SUCCESS
1268 respSMBCommand['Parameters'] = respParameters
1269 respSMBCommand['Data'] = respData
1270 smbServer.setConnectionData(connId, connData)
1272 return [respSMBCommand], None, errorCode
1276 def smbComClose(connId, smbServer, SMBCommand, recvPacket):
1277 connData = smbServer.getConnectionData(connId)
1279 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_CLOSE)
1283 comClose = smb.SMBClose_Parameters(SMBCommand['Parameters'])
1285 if connData['OpenedFiles'].has_key(comClose['FID']):
1286 errorCode = STATUS_SUCCESS
1287 fileHandle = connData['OpenedFiles'][comClose['FID']]['FileHandle']
1289 if fileHandle == PIPE_FILE_DESCRIPTOR:
1290 connData['OpenedFiles'][comClose['FID']]['Socket'].close()
1291 elif fileHandle != VOID_FILE_DESCRIPTOR:
1292 os.close(fileHandle)
1293 except Exception, e:
1294 smbServer.log("comClose %s" % e, logging.ERROR)
1295 errorCode = STATUS_ACCESS_DENIED
1297 # Check if the file was marked for removal
1298 if connData['OpenedFiles'][comClose['FID']]['DeleteOnClose'] is True:
1300 os.remove(connData['OpenedFiles'][comClose['FID']]['FileName'])
1301 except Exception, e:
1302 smbServer.log("comClose %s" % e, logging.ERROR)
1303 errorCode = STATUS_ACCESS_DENIED
1304 del(connData['OpenedFiles'][comClose['FID']])
1306 errorCode = STATUS_INVALID_HANDLE
1312 respSMBCommand['Parameters'] = respParameters
1313 respSMBCommand['Data'] = respData
1314 smbServer.setConnectionData(connId, connData)
1316 return [respSMBCommand], None, errorCode
1319 def smbComWrite(connId, smbServer, SMBCommand, recvPacket):
1320 connData = smbServer.getConnectionData(connId)
1322 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_WRITE)
1323 respParameters = smb.SMBWriteResponse_Parameters()
1326 comWriteParameters = smb.SMBWrite_Parameters(SMBCommand['Parameters'])
1327 comWriteData = smb.SMBWrite_Data(SMBCommand['Data'])
1329 if connData['OpenedFiles'].has_key(comWriteParameters['Fid']):
1330 fileHandle = connData['OpenedFiles'][comWriteParameters['Fid']]['FileHandle']
1331 errorCode = STATUS_SUCCESS
1333 if fileHandle != PIPE_FILE_DESCRIPTOR:
1334 # TODO: Handle big size files
1335 # If we're trying to write past the file end we just skip the write call (Vista does this)
1336 if os.lseek(fileHandle, 0, 2) >= comWriteParameters['Offset']:
1337 os.lseek(fileHandle,comWriteParameters['Offset'],0)
1338 os.write(fileHandle,comWriteData['Data'])
1340 sock = connData['OpenedFiles'][comWriteParameters['Fid']]['Socket']
1341 sock.send(comWriteData['Data'])
1342 respParameters['Count'] = comWriteParameters['Count']
1343 except Exception, e:
1344 smbServer.log('smbComWrite: %s' % e, logging.ERROR)
1345 errorCode = STATUS_ACCESS_DENIED
1347 errorCode = STATUS_INVALID_HANDLE
1354 respSMBCommand['Parameters'] = respParameters
1355 respSMBCommand['Data'] = respData
1356 smbServer.setConnectionData(connId, connData)
1358 return [respSMBCommand], None, errorCode
1361 def smbComFlush(connId, smbServer, SMBCommand,recvPacket ):
1362 connData = smbServer.getConnectionData(connId)
1364 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_FLUSH)
1368 comFlush = smb.SMBFlush_Parameters(SMBCommand['Parameters'])
1370 if connData['OpenedFiles'].has_key(comFlush['FID']):
1371 errorCode = STATUS_SUCCESS
1372 fileHandle = connData['OpenedFiles'][comFlush['FID']]['FileHandle']
1374 os.fsync(fileHandle)
1375 except Exception, e:
1376 smbServer.log("comFlush %s" % e, logging.ERROR)
1377 errorCode = STATUS_ACCESS_DENIED
1379 errorCode = STATUS_INVALID_HANDLE
1385 respSMBCommand['Parameters'] = respParameters
1386 respSMBCommand['Data'] = respData
1387 smbServer.setConnectionData(connId, connData)
1389 return [respSMBCommand], None, errorCode
1393 def smbComCreateDirectory(connId, smbServer, SMBCommand,recvPacket ):
1394 connData = smbServer.getConnectionData(connId)
1396 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_CREATE_DIRECTORY)
1400 comCreateDirectoryData= smb.SMBCreateDirectory_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
1402 # Get the Tid associated
1403 if connData['ConnectedShares'].has_key(recvPacket['Tid']):
1404 errorCode = STATUS_SUCCESS
1405 path = connData['ConnectedShares'][recvPacket['Tid']]['path']
1406 fileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comCreateDirectoryData['DirectoryName']).replace('\\','/'))
1407 if len(fileName) > 0:
1408 if fileName[0] == '/' or fileName[0] == '\\':
1410 fileName = fileName[1:]
1411 pathName = os.path.join(path,fileName)
1412 if os.path.exists(pathName):
1413 errorCode = STATUS_OBJECT_NAME_COLLISION
1415 # TODO: More checks here in the future.. Specially when we support
1420 except Exception, e:
1421 smbServer.log("smbComCreateDirectory: %s" % e, logging.ERROR)
1422 errorCode = STATUS_ACCESS_DENIED
1424 errorCode = STATUS_SMB_BAD_TID
1431 respSMBCommand['Parameters'] = respParameters
1432 respSMBCommand['Data'] = respData
1433 smbServer.setConnectionData(connId, connData)
1435 return [respSMBCommand], None, errorCode
1438 def smbComRename(connId, smbServer, SMBCommand, recvPacket ):
1439 connData = smbServer.getConnectionData(connId)
1441 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_RENAME)
1445 comRenameData = smb.SMBRename_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
1446 # Get the Tid associated
1447 if connData['ConnectedShares'].has_key(recvPacket['Tid']):
1448 errorCode = STATUS_SUCCESS
1449 path = connData['ConnectedShares'][recvPacket['Tid']]['path']
1450 oldFileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comRenameData['OldFileName']).replace('\\','/'))
1451 newFileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comRenameData['NewFileName']).replace('\\','/'))
1452 if len(oldFileName) > 0 and (oldFileName[0] == '/' or oldFileName[0] == '\\'):
1454 oldFileName = oldFileName[1:]
1455 oldPathName = os.path.join(path,oldFileName)
1456 if len(newFileName) > 0 and (newFileName[0] == '/' or newFileName[0] == '\\'):
1458 newFileName = newFileName[1:]
1459 newPathName = os.path.join(path,newFileName)
1461 if os.path.exists(oldPathName) is not True:
1462 errorCode = STATUS_NO_SUCH_FILE
1464 # TODO: More checks here in the future.. Specially when we support
1468 os.rename(oldPathName,newPathName)
1470 smbServer.log("smbComRename: %s" % e, logging.ERROR)
1471 errorCode = STATUS_ACCESS_DENIED
1473 errorCode = STATUS_SMB_BAD_TID
1480 respSMBCommand['Parameters'] = respParameters
1481 respSMBCommand['Data'] = respData
1482 smbServer.setConnectionData(connId, connData)
1484 return [respSMBCommand], None, errorCode
1487 def smbComDelete(connId, smbServer, SMBCommand, recvPacket ):
1488 connData = smbServer.getConnectionData(connId)
1490 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_DELETE)
1494 comDeleteData = smb.SMBDelete_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
1496 # Get the Tid associated
1497 if connData['ConnectedShares'].has_key(recvPacket['Tid']):
1498 errorCode = STATUS_SUCCESS
1499 path = connData['ConnectedShares'][recvPacket['Tid']]['path']
1500 fileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comDeleteData['FileName']).replace('\\','/'))
1501 if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
1503 fileName = fileName[1:]
1504 pathName = os.path.join(path,fileName)
1505 if os.path.exists(pathName) is not True:
1506 errorCode = STATUS_NO_SUCH_FILE
1508 # TODO: More checks here in the future.. Specially when we support
1514 smbServer.log("smbComDelete: %s" % e, logging.ERROR)
1515 errorCode = STATUS_ACCESS_DENIED
1517 errorCode = STATUS_SMB_BAD_TID
1523 respSMBCommand['Parameters'] = respParameters
1524 respSMBCommand['Data'] = respData
1525 smbServer.setConnectionData(connId, connData)
1527 return [respSMBCommand], None, errorCode
1531 def smbComDeleteDirectory(connId, smbServer, SMBCommand, recvPacket ):
1532 connData = smbServer.getConnectionData(connId)
1534 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_DELETE_DIRECTORY)
1538 comDeleteDirectoryData= smb.SMBDeleteDirectory_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
1540 # Get the Tid associated
1541 if connData['ConnectedShares'].has_key(recvPacket['Tid']):
1542 errorCode = STATUS_SUCCESS
1543 path = connData['ConnectedShares'][recvPacket['Tid']]['path']
1544 fileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comDeleteDirectoryData['DirectoryName']).replace('\\','/'))
1545 if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
1547 fileName = fileName[1:]
1548 pathName = os.path.join(path,fileName)
1549 if os.path.exists(pathName) is not True:
1550 errorCode = STATUS_NO_SUCH_FILE
1552 # TODO: More checks here in the future.. Specially when we support
1558 smbServer.log("smbComDeleteDirectory: %s" % e,logging.ERROR)
1559 if e.errno == errno.ENOTEMPTY:
1560 errorCode = STATUS_DIRECTORY_NOT_EMPTY
1562 errorCode = STATUS_ACCESS_DENIED
1564 errorCode = STATUS_SMB_BAD_TID
1570 respSMBCommand['Parameters'] = respParameters
1571 respSMBCommand['Data'] = respData
1572 smbServer.setConnectionData(connId, connData)
1574 return [respSMBCommand], None, errorCode
1578 def smbComWriteAndX(connId, smbServer, SMBCommand, recvPacket):
1579 connData = smbServer.getConnectionData(connId)
1581 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_WRITE_ANDX)
1582 respParameters = smb.SMBWriteAndXResponse_Parameters()
1585 if SMBCommand['WordCount'] == 0x0C:
1586 writeAndX = smb.SMBWriteAndX_Parameters_Short(SMBCommand['Parameters'])
1587 writeAndXData = smb.SMBWriteAndX_Data_Short()
1589 writeAndX = smb.SMBWriteAndX_Parameters(SMBCommand['Parameters'])
1590 writeAndXData = smb.SMBWriteAndX_Data()
1591 writeAndXData['DataLength'] = writeAndX['DataLength']
1592 writeAndXData['DataOffset'] = writeAndX['DataOffset']
1593 writeAndXData.fromString(SMBCommand['Data'])
1596 if connData['OpenedFiles'].has_key(writeAndX['Fid']):
1597 fileHandle = connData['OpenedFiles'][writeAndX['Fid']]['FileHandle']
1598 errorCode = STATUS_SUCCESS
1600 if fileHandle != PIPE_FILE_DESCRIPTOR:
1601 offset = writeAndX['Offset']
1602 if writeAndX.fields.has_key('HighOffset'):
1603 offset += (writeAndX['HighOffset'] << 32)
1604 # If we're trying to write past the file end we just skip the write call (Vista does this)
1605 if os.lseek(fileHandle, 0, 2) >= offset:
1606 os.lseek(fileHandle,offset,0)
1607 os.write(fileHandle,writeAndXData['Data'])
1609 sock = connData['OpenedFiles'][writeAndX['Fid']]['Socket']
1610 sock.send(writeAndXData['Data'])
1612 respParameters['Count'] = writeAndX['DataLength']
1613 respParameters['Available']= 0xff
1614 except Exception, e:
1615 smbServer.log('smbComWriteAndx: %s' % e, logging.ERROR)
1616 errorCode = STATUS_ACCESS_DENIED
1618 errorCode = STATUS_INVALID_HANDLE
1624 respSMBCommand['Parameters'] = respParameters
1625 respSMBCommand['Data'] = respData
1626 smbServer.setConnectionData(connId, connData)
1628 return [respSMBCommand], None, errorCode
1631 def smbComRead(connId, smbServer, SMBCommand, recvPacket):
1632 connData = smbServer.getConnectionData(connId)
1634 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_READ)
1635 respParameters = smb.SMBReadResponse_Parameters()
1636 respData = smb.SMBReadResponse_Data()
1638 comReadParameters = smb.SMBRead_Parameters(SMBCommand['Parameters'])
1640 if connData['OpenedFiles'].has_key(comReadParameters['Fid']):
1641 fileHandle = connData['OpenedFiles'][comReadParameters['Fid']]['FileHandle']
1642 errorCode = STATUS_SUCCESS
1644 if fileHandle != PIPE_FILE_DESCRIPTOR:
1645 # TODO: Handle big size files
1646 os.lseek(fileHandle,comReadParameters['Offset'],0)
1647 content = os.read(fileHandle,comReadParameters['Count'])
1649 sock = connData['OpenedFiles'][comReadParameters['Fid']]['Socket']
1650 content = sock.recv(comReadParameters['Count'])
1651 respParameters['Count'] = len(content)
1652 respData['DataLength'] = len(content)
1653 respData['Data'] = content
1654 except Exception, e:
1655 smbServer.log('smbComRead: %s ' % e, logging.ERROR)
1656 errorCode = STATUS_ACCESS_DENIED
1658 errorCode = STATUS_INVALID_HANDLE
1664 respSMBCommand['Parameters'] = respParameters
1665 respSMBCommand['Data'] = respData
1666 smbServer.setConnectionData(connId, connData)
1668 return [respSMBCommand], None, errorCode
1671 def smbComReadAndX(connId, smbServer, SMBCommand, recvPacket):
1672 connData = smbServer.getConnectionData(connId)
1674 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_READ_ANDX)
1675 respParameters = smb.SMBReadAndXResponse_Parameters()
1678 if SMBCommand['WordCount'] == 0x0A:
1679 readAndX = smb.SMBReadAndX_Parameters2(SMBCommand['Parameters'])
1681 readAndX = smb.SMBReadAndX_Parameters(SMBCommand['Parameters'])
1683 if connData['OpenedFiles'].has_key(readAndX['Fid']):
1684 fileHandle = connData['OpenedFiles'][readAndX['Fid']]['FileHandle']
1687 if fileHandle != PIPE_FILE_DESCRIPTOR:
1688 offset = readAndX['Offset']
1689 if readAndX.fields.has_key('HighOffset'):
1690 offset += (readAndX['HighOffset'] << 32)
1691 os.lseek(fileHandle,offset,0)
1692 content = os.read(fileHandle,readAndX['MaxCount'])
1694 sock = connData['OpenedFiles'][readAndX['Fid']]['Socket']
1695 content = sock.recv(readAndX['MaxCount'])
1696 respParameters['Remaining'] = 0xffff
1697 respParameters['DataCount'] = len(content)
1698 respParameters['DataOffset'] = 59
1699 respParameters['DataCount_Hi'] = 0
1701 except Exception, e:
1702 smbServer.log('smbComReadAndX: %s ' % e, logging.ERROR)
1703 errorCode = STATUS_ACCESS_DENIED
1705 errorCode = STATUS_INVALID_HANDLE
1711 respSMBCommand['Parameters'] = respParameters
1712 respSMBCommand['Data'] = respData
1713 smbServer.setConnectionData(connId, connData)
1715 return [respSMBCommand], None, errorCode
1718 def smbQueryInformation(connId, smbServer, SMBCommand, recvPacket):
1719 connData = smbServer.getConnectionData(connId)
1721 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_QUERY_INFORMATION)
1722 respParameters = smb.SMBQueryInformationResponse_Parameters()
1725 queryInformation= smb.SMBQueryInformation_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
1727 # Get the Tid associated
1728 if connData['ConnectedShares'].has_key(recvPacket['Tid']):
1729 fileSize, lastWriteTime, fileAttributes = queryFsInformation(
1730 connData['ConnectedShares'][recvPacket['Tid']]['path'],
1731 decodeSMBString(recvPacket['Flags2'],queryInformation['FileName']))
1733 respParameters['FileSize'] = fileSize
1734 respParameters['LastWriteTime'] = lastWriteTime
1735 respParameters['FileAttributes'] = fileAttributes
1736 errorCode = STATUS_SUCCESS
1738 # STATUS_SMB_BAD_TID
1739 errorCode = STATUS_SMB_BAD_TID
1743 respSMBCommand['Parameters'] = respParameters
1744 respSMBCommand['Data'] = respData
1746 smbServer.setConnectionData(connId, connData)
1747 return [respSMBCommand], None, errorCode
1750 def smbQueryInformationDisk(connId, smbServer, SMBCommand, recvPacket):
1751 connData = smbServer.getConnectionData(connId)
1753 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_QUERY_INFORMATION_DISK)
1754 respParameters = smb.SMBQueryInformationDiskResponse_Parameters()
1757 # Get the Tid associated
1758 if connData['ConnectedShares'].has_key(recvPacket['Tid']):
1759 totalUnits, freeUnits = queryDiskInformation(
1760 connData['ConnectedShares'][recvPacket['Tid']]['path'])
1762 respParameters['TotalUnits'] = totalUnits
1763 respParameters['BlocksPerUnit'] = 1
1764 respParameters['BlockSize'] = 1
1765 respParameters['FreeUnits'] = freeUnits
1766 errorCode = STATUS_SUCCESS
1768 # STATUS_SMB_BAD_TID
1771 errorCode = STATUS_SMB_BAD_TID
1774 respSMBCommand['Parameters'] = respParameters
1775 respSMBCommand['Data'] = respData
1777 smbServer.setConnectionData(connId, connData)
1778 return [respSMBCommand], None, errorCode
1781 def smbComEcho(connId, smbServer, SMBCommand, recvPacket):
1782 connData = smbServer.getConnectionData(connId)
1784 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_ECHO)
1785 respParameters = smb.SMBEchoResponse_Parameters()
1786 respData = smb.SMBEchoResponse_Data()
1788 echoData = smb.SMBEcho_Data(SMBCommand['Data'])
1790 respParameters['SequenceNumber'] = 1
1791 respData['Data'] = echoData['Data']
1793 respSMBCommand['Parameters'] = respParameters
1794 respSMBCommand['Data'] = respData
1796 errorCode = STATUS_SUCCESS
1797 smbServer.setConnectionData(connId, connData)
1798 return [respSMBCommand], None, errorCode
1801 def smbComTreeDisconnect(connId, smbServer, SMBCommand, recvPacket):
1802 connData = smbServer.getConnectionData(connId)
1804 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_TREE_DISCONNECT)
1806 # Check if the Tid matches the Tid trying to disconnect
1810 if connData['ConnectedShares'].has_key(recvPacket['Tid']):
1811 smbServer.log("Disconnecting Share(%d:%s)" % (recvPacket['Tid'],connData['ConnectedShares'][recvPacket['Tid']]['shareName']))
1812 del(connData['ConnectedShares'][recvPacket['Tid']])
1813 errorCode = STATUS_SUCCESS
1815 # STATUS_SMB_BAD_TID
1816 errorCode = STATUS_SMB_BAD_TID
1818 respSMBCommand['Parameters'] = respParameters
1819 respSMBCommand['Data'] = respData
1821 smbServer.setConnectionData(connId, connData)
1822 return [respSMBCommand], None, errorCode
1825 def smbComLogOffAndX(connId, smbServer, SMBCommand, recvPacket):
1826 connData = smbServer.getConnectionData(connId)
1828 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_LOGOFF_ANDX)
1830 # Check if the Uid matches the user trying to logoff
1833 if recvPacket['Uid'] != connData['Uid']:
1834 # STATUS_SMB_BAD_UID
1835 errorCode = STATUS_SMB_BAD_UID
1837 errorCode = STATUS_SUCCESS
1839 respSMBCommand['Parameters'] = respParameters
1840 respSMBCommand['Data'] = respData
1843 smbServer.setConnectionData(connId, connData)
1845 return [respSMBCommand], None, errorCode
1848 def smbComQueryInformation2(connId, smbServer, SMBCommand, recvPacket):
1849 connData = smbServer.getConnectionData(connId)
1851 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_QUERY_INFORMATION2)
1852 respParameters = smb.SMBQueryInformation2Response_Parameters()
1855 queryInformation2 = smb.SMBQueryInformation2_Parameters(SMBCommand['Parameters'])
1857 if connData['OpenedFiles'].has_key(queryInformation2['Fid']):
1858 errorCode = STATUS_SUCCESS
1859 pathName = connData['OpenedFiles'][queryInformation2['Fid']]['FileName']
1861 (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(pathName)
1862 respParameters['CreateDate'] = getSMBDate(ctime)
1863 respParameters['CreationTime'] = getSMBTime(ctime)
1864 respParameters['LastAccessDate'] = getSMBDate(atime)
1865 respParameters['LastAccessTime'] = getSMBTime(atime)
1866 respParameters['LastWriteDate'] = getSMBDate(mtime)
1867 respParameters['LastWriteTime'] = getSMBTime(mtime)
1868 respParameters['FileDataSize'] = size
1869 respParameters['FileAllocationSize'] = size
1871 if os.path.isdir(pathName):
1872 attribs = smb.SMB_FILE_ATTRIBUTE_DIRECTORY
1873 if os.path.isfile(pathName):
1874 attribs = smb.SMB_FILE_ATTRIBUTE_NORMAL
1875 respParameters['FileAttributes'] = attribs
1876 except Exception, e:
1877 smbServer.log('smbComQueryInformation2 %s' % e,logging.ERROR)
1878 errorCode = STATUS_ACCESS_DENIED
1884 respSMBCommand['Parameters'] = respParameters
1885 respSMBCommand['Data'] = respData
1886 smbServer.setConnectionData(connId, connData)
1888 return [respSMBCommand], None, errorCode
1891 def smbComNtCreateAndX(connId, smbServer, SMBCommand, recvPacket):
1892 # TODO: Fully implement this
1893 connData = smbServer.getConnectionData(connId)
1895 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_NT_CREATE_ANDX)
1896 respParameters = smb.SMBNtCreateAndXResponse_Parameters()
1899 ntCreateAndXParameters = smb.SMBNtCreateAndX_Parameters(SMBCommand['Parameters'])
1900 ntCreateAndXData = smb.SMBNtCreateAndX_Data( flags = recvPacket['Flags2'], data = SMBCommand['Data'])
1902 #if ntCreateAndXParameters['CreateFlags'] & 0x10: # NT_CREATE_REQUEST_EXTENDED_RESPONSE
1903 # respParameters = smb.SMBNtCreateAndXExtendedResponse_Parameters()
1904 # respParameters['VolumeGUID'] = '\x00'
1906 # Get the Tid associated
1907 if connData['ConnectedShares'].has_key(recvPacket['Tid']):
1908 # If we have a rootFid, the path is relative to that fid
1909 errorCode = STATUS_SUCCESS
1910 if ntCreateAndXParameters['RootFid'] > 0:
1911 path = connData['OpenedFiles'][ntCreateAndXParameters['RootFid']]['FileName']
1912 LOG.debug("RootFid present %s!" % path)
1914 if connData['ConnectedShares'][recvPacket['Tid']].has_key('path'):
1915 path = connData['ConnectedShares'][recvPacket['Tid']]['path']
1918 errorCode = STATUS_ACCESS_DENIED
1920 deleteOnClose = False
1922 fileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],ntCreateAndXData['FileName']).replace('\\','/'))
1923 if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
1925 fileName = fileName[1:]
1926 pathName = os.path.join(path,fileName)
1927 createDisposition = ntCreateAndXParameters['Disposition']
1930 if createDisposition == smb.FILE_SUPERSEDE:
1931 mode |= os.O_TRUNC | os.O_CREAT
1932 elif createDisposition & smb.FILE_OVERWRITE_IF == smb.FILE_OVERWRITE_IF:
1933 mode |= os.O_TRUNC | os.O_CREAT
1934 elif createDisposition & smb.FILE_OVERWRITE == smb.FILE_OVERWRITE:
1935 if os.path.exists(pathName) is True:
1938 errorCode = STATUS_NO_SUCH_FILE
1939 elif createDisposition & smb.FILE_OPEN_IF == smb.FILE_OPEN_IF:
1940 if os.path.exists(pathName) is True:
1943 mode |= os.O_TRUNC | os.O_CREAT
1944 elif createDisposition & smb.FILE_CREATE == smb.FILE_CREATE:
1945 if os.path.exists(pathName) is True:
1946 errorCode = STATUS_OBJECT_NAME_COLLISION
1949 elif createDisposition & smb.FILE_OPEN == smb.FILE_OPEN:
1950 if os.path.exists(pathName) is not True and smbServer.getRegisteredNamedPipes().has_key(unicode(pathName)) is not True:
1951 errorCode = STATUS_NO_SUCH_FILE
1953 if errorCode == STATUS_SUCCESS:
1954 desiredAccess = ntCreateAndXParameters['AccessMask']
1955 if (desiredAccess & smb.FILE_READ_DATA) or (desiredAccess & smb.GENERIC_READ):
1957 if (desiredAccess & smb.FILE_WRITE_DATA) or (desiredAccess & smb.GENERIC_WRITE):
1958 if (desiredAccess & smb.FILE_READ_DATA) or (desiredAccess & smb.GENERIC_READ):
1959 mode |= os.O_RDWR #| os.O_APPEND
1961 mode |= os.O_WRONLY #| os.O_APPEND
1962 if desiredAccess & smb.GENERIC_ALL:
1963 mode |= os.O_RDWR #| os.O_APPEND
1965 createOptions = ntCreateAndXParameters['CreateOptions']
1966 if mode & os.O_CREAT == os.O_CREAT:
1967 if createOptions & smb.FILE_DIRECTORY_FILE == smb.FILE_DIRECTORY_FILE:
1969 # Let's create the directory
1972 except Exception, e:
1973 smbServer.log("NTCreateAndX: %s,%s,%s" % (pathName,mode,e),logging.ERROR)
1974 errorCode = STATUS_ACCESS_DENIED
1975 if createOptions & smb.FILE_NON_DIRECTORY_FILE == smb.FILE_NON_DIRECTORY_FILE:
1976 # If the file being opened is a directory, the server MUST fail the request with
1977 # STATUS_FILE_IS_A_DIRECTORY in the Status field of the SMB Header in the server
1979 if os.path.isdir(pathName) is True:
1980 errorCode = STATUS_FILE_IS_A_DIRECTORY
1982 if createOptions & smb.FILE_DELETE_ON_CLOSE == smb.FILE_DELETE_ON_CLOSE:
1983 deleteOnClose = True
1985 if errorCode == STATUS_SUCCESS:
1987 if os.path.isdir(pathName) and sys.platform == 'win32':
1988 fid = VOID_FILE_DESCRIPTOR
1990 if sys.platform == 'win32':
1992 if smbServer.getRegisteredNamedPipes().has_key(unicode(pathName)):
1993 fid = PIPE_FILE_DESCRIPTOR
1994 sock = socket.socket()
1995 sock.connect(smbServer.getRegisteredNamedPipes()[unicode(pathName)])
1997 fid = os.open(pathName, mode)
1998 except Exception, e:
1999 smbServer.log("NTCreateAndX: %s,%s,%s" % (pathName,mode,e),logging.ERROR)
2002 errorCode = STATUS_ACCESS_DENIED
2004 errorCode = STATUS_SMB_BAD_TID
2006 if errorCode == STATUS_SUCCESS:
2007 # Simple way to generate a fid
2008 if len(connData['OpenedFiles']) == 0:
2011 fakefid = connData['OpenedFiles'].keys()[-1] + 1
2012 respParameters['Fid'] = fakefid
2013 respParameters['CreateAction'] = createDisposition
2014 if fid == PIPE_FILE_DESCRIPTOR:
2015 respParameters['FileAttributes'] = 0x80
2016 respParameters['IsDirectory'] = 0
2017 respParameters['CreateTime'] = 0
2018 respParameters['LastAccessTime'] = 0
2019 respParameters['LastWriteTime'] = 0
2020 respParameters['LastChangeTime'] = 0
2021 respParameters['AllocationSize'] = 4096
2022 respParameters['EndOfFile'] = 0
2023 respParameters['FileType'] = 2
2024 respParameters['IPCState'] = 0x5ff
2026 if os.path.isdir(pathName):
2027 respParameters['FileAttributes'] = smb.SMB_FILE_ATTRIBUTE_DIRECTORY
2028 respParameters['IsDirectory'] = 1
2030 respParameters['IsDirectory'] = 0
2031 respParameters['FileAttributes'] = ntCreateAndXParameters['FileAttributes']
2032 # Let's get this file's information
2033 respInfo, errorCode = queryPathInformation('',pathName,level= smb.SMB_QUERY_FILE_ALL_INFO)
2034 if errorCode == STATUS_SUCCESS:
2035 respParameters['CreateTime'] = respInfo['CreationTime']
2036 respParameters['LastAccessTime'] = respInfo['LastAccessTime']
2037 respParameters['LastWriteTime'] = respInfo['LastWriteTime']
2038 respParameters['LastChangeTime'] = respInfo['LastChangeTime']
2039 respParameters['FileAttributes'] = respInfo['ExtFileAttributes']
2040 respParameters['AllocationSize'] = respInfo['AllocationSize']
2041 respParameters['EndOfFile'] = respInfo['EndOfFile']
2046 if errorCode == STATUS_SUCCESS:
2047 # Let's store the fid for the connection
2048 # smbServer.log('Create file %s, mode:0x%x' % (pathName, mode))
2049 connData['OpenedFiles'][fakefid] = {}
2050 connData['OpenedFiles'][fakefid]['FileHandle'] = fid
2051 connData['OpenedFiles'][fakefid]['FileName'] = pathName
2052 connData['OpenedFiles'][fakefid]['DeleteOnClose'] = deleteOnClose
2053 if fid == PIPE_FILE_DESCRIPTOR:
2054 connData['OpenedFiles'][fakefid]['Socket'] = sock
2059 respSMBCommand['Parameters'] = respParameters
2060 respSMBCommand['Data'] = respData
2061 smbServer.setConnectionData(connId, connData)
2063 return [respSMBCommand], None, errorCode
2066 def smbComOpenAndX(connId, smbServer, SMBCommand, recvPacket):
2067 connData = smbServer.getConnectionData(connId)
2069 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_OPEN_ANDX)
2070 respParameters = smb.SMBOpenAndXResponse_Parameters()
2073 openAndXParameters = smb.SMBOpenAndX_Parameters(SMBCommand['Parameters'])
2074 openAndXData = smb.SMBOpenAndX_Data( flags = recvPacket['Flags2'], data = SMBCommand['Data'])
2076 # Get the Tid associated
2077 if connData['ConnectedShares'].has_key(recvPacket['Tid']):
2078 path = connData['ConnectedShares'][recvPacket['Tid']]['path']
2079 openedFile, mode, pathName, errorCode = openFile(path,
2080 decodeSMBString(recvPacket['Flags2'],openAndXData['FileName']),
2081 openAndXParameters['DesiredAccess'],
2082 openAndXParameters['FileAttributes'],
2083 openAndXParameters['OpenMode'])
2085 errorCode = STATUS_SMB_BAD_TID
2087 if errorCode == STATUS_SUCCESS:
2088 # Simple way to generate a fid
2089 fid = len(connData['OpenedFiles']) + 1
2090 if len(connData['OpenedFiles']) == 0:
2093 fid = connData['OpenedFiles'].keys()[-1] + 1
2094 respParameters['Fid'] = fid
2095 if mode & os.O_CREAT:
2096 # File did not exist and was created
2097 respParameters['Action'] = 0x2
2098 elif mode & os.O_RDONLY:
2099 # File existed and was opened
2100 respParameters['Action'] = 0x1
2101 elif mode & os.O_APPEND:
2102 # File existed and was opened
2103 respParameters['Action'] = 0x1
2105 # File existed and was truncated
2106 respParameters['Action'] = 0x3
2108 # Let's store the fid for the connection
2109 #smbServer.log('Opening file %s' % pathName)
2110 connData['OpenedFiles'][fid] = {}
2111 connData['OpenedFiles'][fid]['FileHandle'] = openedFile
2112 connData['OpenedFiles'][fid]['FileName'] = pathName
2113 connData['OpenedFiles'][fid]['DeleteOnClose'] = False
2118 respSMBCommand['Parameters'] = respParameters
2119 respSMBCommand['Data'] = respData
2120 smbServer.setConnectionData(connId, connData)
2122 return [respSMBCommand], None, errorCode
2125 def smbComTreeConnectAndX(connId, smbServer, SMBCommand, recvPacket):
2126 connData = smbServer.getConnectionData(connId)
2128 resp = smb.NewSMBPacket()
2129 resp['Flags1'] = smb.SMB.FLAGS1_REPLY
2130 resp['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES | recvPacket['Flags2'] & smb.SMB.FLAGS2_UNICODE
2132 resp['Tid'] = recvPacket['Tid']
2133 resp['Mid'] = recvPacket['Mid']
2134 resp['Pid'] = connData['Pid']
2136 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_TREE_CONNECT_ANDX)
2137 respParameters = smb.SMBTreeConnectAndXResponse_Parameters()
2138 respData = smb.SMBTreeConnectAndXResponse_Data()
2140 treeConnectAndXParameters = smb.SMBTreeConnectAndX_Parameters(SMBCommand['Parameters'])
2142 if treeConnectAndXParameters['Flags'] & 0x8:
2143 respParameters = smb.SMBTreeConnectAndXExtendedResponse_Parameters()
2145 treeConnectAndXData = smb.SMBTreeConnectAndX_Data( flags = recvPacket['Flags2'] )
2146 treeConnectAndXData['_PasswordLength'] = treeConnectAndXParameters['PasswordLength']
2147 treeConnectAndXData.fromString(SMBCommand['Data'])
2149 errorCode = STATUS_SUCCESS
2151 ## Process here the request, does the share exist?
2152 UNCOrShare = decodeSMBString(recvPacket['Flags2'], treeConnectAndXData['Path'])
2155 if ntpath.ismount(UNCOrShare):
2156 path = UNCOrShare.split('\\')[3]
2158 path = ntpath.basename(UNCOrShare)
2160 share = searchShare(connId, path, smbServer)
2161 if share is not None:
2162 # Simple way to generate a Tid
2163 if len(connData['ConnectedShares']) == 0:
2166 tid = connData['ConnectedShares'].keys()[-1] + 1
2167 connData['ConnectedShares'][tid] = share
2168 connData['ConnectedShares'][tid]['shareName'] = path
2170 #smbServer.log("Connecting Share(%d:%s)" % (tid,path))
2172 smbServer.log("TreeConnectAndX not found %s" % path, logging.ERROR)
2173 errorCode = STATUS_OBJECT_PATH_NOT_FOUND
2174 resp['ErrorCode'] = errorCode >> 16
2175 resp['ErrorClass'] = errorCode & 0xff
2177 respParameters['OptionalSupport'] = smb.SMB.SMB_SUPPORT_SEARCH_BITS
2180 respData['Service'] = 'IPC'
2182 respData['Service'] = path
2183 respData['PadLen'] = 0
2184 respData['NativeFileSystem'] = encodeSMBString(recvPacket['Flags2'], 'NTFS' )
2186 respSMBCommand['Parameters'] = respParameters
2187 respSMBCommand['Data'] = respData
2189 resp['Uid'] = connData['Uid']
2190 resp.addCommand(respSMBCommand)
2191 smbServer.setConnectionData(connId, connData)
2193 return None, [resp], errorCode
2196 def smbComSessionSetupAndX(connId, smbServer, SMBCommand, recvPacket):
2197 connData = smbServer.getConnectionData(connId, checkStatus = False)
2199 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_SESSION_SETUP_ANDX)
2202 # When extended security is being used (see section 3.2.4.2.4), the
2203 # request MUST take the following form
2205 # WordCount (1 byte): The value of this field MUST be 0x0C.
2206 if SMBCommand['WordCount'] == 12:
2207 # Extended security. Here we deal with all SPNEGO stuff
2208 respParameters = smb.SMBSessionSetupAndX_Extended_Response_Parameters()
2209 respData = smb.SMBSessionSetupAndX_Extended_Response_Data(flags = recvPacket['Flags2'])
2210 sessionSetupParameters = smb.SMBSessionSetupAndX_Extended_Parameters(SMBCommand['Parameters'])
2211 sessionSetupData = smb.SMBSessionSetupAndX_Extended_Data()
2212 sessionSetupData['SecurityBlobLength'] = sessionSetupParameters['SecurityBlobLength']
2213 sessionSetupData.fromString(SMBCommand['Data'])
2214 connData['Capabilities'] = sessionSetupParameters['Capabilities']
2217 if struct.unpack('B',sessionSetupData['SecurityBlob'][0])[0] == ASN1_AID:
2219 blob = SPNEGO_NegTokenInit(sessionSetupData['SecurityBlob'])
2220 token = blob['MechToken']
2221 if len(blob['MechTypes'][0]) > 0:
2222 # Is this GSSAPI NTLM or something else we don't support?
2223 mechType = blob['MechTypes'][0]
2224 if mechType != TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']:
2225 # Nope, do we know it?
2226 if MechTypes.has_key(mechType):
2227 mechStr = MechTypes[mechType]
2229 mechStr = hexlify(mechType)
2230 smbServer.log("Unsupported MechType '%s'" % mechStr, logging.CRITICAL)
2231 # We don't know the token, we answer back again saying
2232 # we just support NTLM.
2233 # ToDo: Build this into a SPNEGO_NegTokenResp()
2234 respToken = '\xa1\x15\x30\x13\xa0\x03\x0a\x01\x03\xa1\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a'
2235 respParameters['SecurityBlobLength'] = len(respToken)
2236 respData['SecurityBlobLength'] = respParameters['SecurityBlobLength']
2237 respData['SecurityBlob'] = respToken
2238 respData['NativeOS'] = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS())
2239 respData['NativeLanMan'] = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS())
2240 respSMBCommand['Parameters'] = respParameters
2241 respSMBCommand['Data'] = respData
2242 return [respSMBCommand], None, STATUS_MORE_PROCESSING_REQUIRED
2244 elif struct.unpack('B',sessionSetupData['SecurityBlob'][0])[0] == ASN1_SUPPORTED_MECH:
2246 blob = SPNEGO_NegTokenResp(sessionSetupData['SecurityBlob'])
2247 token = blob['ResponseToken']
2249 # No GSSAPI stuff, raw NTLMSSP
2251 token = sessionSetupData['SecurityBlob']
2253 # Here we only handle NTLMSSP, depending on what stage of the
2254 # authentication we are, we act on it
2255 messageType = struct.unpack('<L',token[len('NTLMSSP\x00'):len('NTLMSSP\x00')+4])[0]
2257 if messageType == 0x01:
2259 negotiateMessage = ntlm.NTLMAuthNegotiate()
2260 negotiateMessage.fromString(token)
2261 # Let's store it in the connection data
2262 connData['NEGOTIATE_MESSAGE'] = negotiateMessage
2263 # Let's build the answer flags
2264 # TODO: Parse all the flags. With this we're leaving some clients out
2268 if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_56:
2269 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_56
2270 if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_128:
2271 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_128
2272 if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH:
2273 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH
2274 if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
2275 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
2276 if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_UNICODE:
2277 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_UNICODE
2278 if negotiateMessage['flags'] & ntlm.NTLM_NEGOTIATE_OEM:
2279 ansFlags |= ntlm.NTLM_NEGOTIATE_OEM
2281 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_VERSION | ntlm.NTLMSSP_NEGOTIATE_TARGET_INFO | ntlm.NTLMSSP_TARGET_TYPE_SERVER | ntlm.NTLMSSP_NEGOTIATE_NTLM | ntlm.NTLMSSP_REQUEST_TARGET
2283 # Generate the AV_PAIRS
2284 av_pairs = ntlm.AV_PAIRS()
2285 # TODO: Put the proper data from SMBSERVER config
2286 av_pairs[ntlm.NTLMSSP_AV_HOSTNAME] = av_pairs[ntlm.NTLMSSP_AV_DNS_HOSTNAME] = smbServer.getServerName().encode('utf-16le')
2287 av_pairs[ntlm.NTLMSSP_AV_DOMAINNAME] = av_pairs[ntlm.NTLMSSP_AV_DNS_DOMAINNAME] = smbServer.getServerDomain().encode('utf-16le')
2288 av_pairs[ntlm.NTLMSSP_AV_TIME] = struct.pack('<q', (116444736000000000 + calendar.timegm(time.gmtime()) * 10000000) )
2290 challengeMessage = ntlm.NTLMAuthChallenge()
2291 challengeMessage['flags'] = ansFlags
2292 challengeMessage['domain_len'] = len(smbServer.getServerDomain().encode('utf-16le'))
2293 challengeMessage['domain_max_len'] = challengeMessage['domain_len']
2294 challengeMessage['domain_offset'] = 40 + 16
2295 challengeMessage['challenge'] = smbServer.getSMBChallenge()
2296 challengeMessage['domain_name'] = smbServer.getServerDomain().encode('utf-16le')
2297 challengeMessage['TargetInfoFields_len'] = len(av_pairs)
2298 challengeMessage['TargetInfoFields_max_len'] = len(av_pairs)
2299 challengeMessage['TargetInfoFields'] = av_pairs
2300 challengeMessage['TargetInfoFields_offset'] = 40 + 16 + len(challengeMessage['domain_name'])
2301 challengeMessage['Version'] = '\xff'*8
2302 challengeMessage['VersionLen'] = 8
2304 if rawNTLM is False:
2305 respToken = SPNEGO_NegTokenResp()
2306 # accept-incomplete. We want more data
2307 respToken['NegResult'] = '\x01'
2308 respToken['SupportedMech'] = TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']
2310 respToken['ResponseToken'] = challengeMessage.getData()
2312 respToken = challengeMessage
2314 # Setting the packet to STATUS_MORE_PROCESSING
2315 errorCode = STATUS_MORE_PROCESSING_REQUIRED
2316 # Let's set up an UID for this connection and store it
2317 # in the connection's data
2318 # Picking a fixed value
2319 # TODO: Manage more UIDs for the same session
2320 connData['Uid'] = 10
2321 # Let's store it in the connection data
2322 connData['CHALLENGE_MESSAGE'] = challengeMessage
2324 elif messageType == 0x02:
2326 raise Exception('Challenge Message raise, not implemented!')
2327 elif messageType == 0x03:
2328 # AUTHENTICATE_MESSAGE, here we deal with authentication
2329 authenticateMessage = ntlm.NTLMAuthChallengeResponse()
2330 authenticateMessage.fromString(token)
2331 smbServer.log("AUTHENTICATE_MESSAGE (%s\\%s,%s)" % (authenticateMessage['domain_name'], authenticateMessage['user_name'], authenticateMessage['host_name']))
2332 # TODO: Check the credentials! Now granting permissions
2334 respToken = SPNEGO_NegTokenResp()
2336 respToken['NegResult'] = '\x00'
2339 errorCode = STATUS_SUCCESS
2340 smbServer.log('User %s\\%s authenticated successfully' % (authenticateMessage['user_name'], authenticateMessage['host_name']))
2341 # Let's store it in the connection data
2342 connData['AUTHENTICATE_MESSAGE'] = authenticateMessage
2344 jtr_dump_path = smbServer.getJTRdumpPath()
2345 ntlm_hash_data = outputToJohnFormat( connData['CHALLENGE_MESSAGE']['challenge'], authenticateMessage['user_name'], authenticateMessage['domain_name'], authenticateMessage['lanman'], authenticateMessage['ntlm'] )
2346 smbServer.log(ntlm_hash_data['hash_string'])
2347 if jtr_dump_path is not '':
2348 writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], jtr_dump_path)
2350 smbServer.log("Could not write NTLM Hashes to the specified JTR_Dump_Path %s" % jtr_dump_path)
2352 raise Exception("Unknown NTLMSSP MessageType %d" % messageType)
2354 respParameters['SecurityBlobLength'] = len(respToken)
2355 respData['SecurityBlobLength'] = respParameters['SecurityBlobLength']
2356 respData['SecurityBlob'] = respToken.getData()
2359 # Process Standard Security
2360 respParameters = smb.SMBSessionSetupAndXResponse_Parameters()
2361 respData = smb.SMBSessionSetupAndXResponse_Data()
2362 sessionSetupParameters = smb.SMBSessionSetupAndX_Parameters(SMBCommand['Parameters'])
2363 sessionSetupData = smb.SMBSessionSetupAndX_Data()
2364 sessionSetupData['AnsiPwdLength'] = sessionSetupParameters['AnsiPwdLength']
2365 sessionSetupData['UnicodePwdLength'] = sessionSetupParameters['UnicodePwdLength']
2366 sessionSetupData.fromString(SMBCommand['Data'])
2367 connData['Capabilities'] = sessionSetupParameters['Capabilities']
2368 # Do the verification here, for just now we grant access
2369 # TODO: Manage more UIDs for the same session
2370 errorCode = STATUS_SUCCESS
2371 connData['Uid'] = 10
2372 respParameters['Action'] = 0
2373 smbServer.log('User %s\\%s authenticated successfully (basic)' % (sessionSetupData['PrimaryDomain'], sessionSetupData['Account']))
2375 jtr_dump_path = smbServer.getJTRdumpPath()
2376 ntlm_hash_data = outputToJohnFormat( '', sessionSetupData['Account'], sessionSetupData['PrimaryDomain'], sessionSetupData['AnsiPwd'], sessionSetupData['UnicodePwd'] )
2377 smbServer.log(ntlm_hash_data['hash_string'])
2378 if jtr_dump_path is not '':
2379 writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], jtr_dump_path)
2381 smbServer.log("Could not write NTLM Hashes to the specified JTR_Dump_Path %s" % jtr_dump_path)
2383 respData['NativeOS'] = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS())
2384 respData['NativeLanMan'] = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS())
2385 respSMBCommand['Parameters'] = respParameters
2386 respSMBCommand['Data'] = respData
2388 # From now on, the client can ask for other commands
2389 connData['Authenticated'] = True
2390 # For now, just switching to nobody
2391 #os.setregid(65534,65534)
2392 #os.setreuid(65534,65534)
2393 smbServer.setConnectionData(connId, connData)
2395 return [respSMBCommand], None, errorCode
2398 def smbComNegotiate(connId, smbServer, SMBCommand, recvPacket ):
2399 connData = smbServer.getConnectionData(connId, checkStatus = False)
2400 connData['Pid'] = recvPacket['Pid']
2402 SMBCommand = smb.SMBCommand(recvPacket['Data'][0])
2403 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_NEGOTIATE)
2405 resp = smb.NewSMBPacket()
2406 resp['Flags1'] = smb.SMB.FLAGS1_REPLY
2407 resp['Pid'] = connData['Pid']
2408 resp['Tid'] = recvPacket['Tid']
2409 resp['Mid'] = recvPacket['Mid']
2411 # TODO: We support more dialects, and parse them accordingly
2412 dialects = SMBCommand['Data'].split('\x02')
2414 index = dialects.index('NT LM 0.12\x00') - 1
2415 # Let's fill the data for NTLM
2416 if recvPacket['Flags2'] & smb.SMB.FLAGS2_EXTENDED_SECURITY:
2417 resp['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_UNICODE
2418 #resp['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS
2419 _dialects_data = smb.SMBExtended_Security_Data()
2420 _dialects_data['ServerGUID'] = 'A'*16
2421 blob = SPNEGO_NegTokenInit()
2422 blob['MechTypes'] = [TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']]
2423 _dialects_data['SecurityBlob'] = blob.getData()
2425 _dialects_parameters = smb.SMBExtended_Security_Parameters()
2426 _dialects_parameters['Capabilities'] = smb.SMB.CAP_EXTENDED_SECURITY | smb.SMB.CAP_USE_NT_ERRORS | smb.SMB.CAP_NT_SMBS | smb.SMB.CAP_UNICODE
2427 _dialects_parameters['ChallengeLength'] = 0
2430 resp['Flags2'] = smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_UNICODE
2431 _dialects_parameters = smb.SMBNTLMDialect_Parameters()
2432 _dialects_data= smb.SMBNTLMDialect_Data()
2433 _dialects_data['Payload'] = ''
2434 if connData.has_key('EncryptionKey'):
2435 _dialects_data['Challenge'] = connData['EncryptionKey']
2436 _dialects_parameters['ChallengeLength'] = len(str(_dialects_data))
2438 # TODO: Handle random challenges, now one that can be used with rainbow tables
2439 _dialects_data['Challenge'] = '\x11\x22\x33\x44\x55\x66\x77\x88'
2440 _dialects_parameters['ChallengeLength'] = 8
2441 _dialects_parameters['Capabilities'] = smb.SMB.CAP_USE_NT_ERRORS | smb.SMB.CAP_NT_SMBS
2443 # Let's see if we need to support RPC_REMOTE_APIS
2444 config = smbServer.getServerConfig()
2445 if config.has_option('global','rpc_apis'):
2446 if config.getboolean('global', 'rpc_apis') is True:
2447 _dialects_parameters['Capabilities'] |= smb.SMB.CAP_RPC_REMOTE_APIS
2449 _dialects_parameters['DialectIndex'] = index
2450 _dialects_parameters['SecurityMode'] = smb.SMB.SECURITY_AUTH_ENCRYPTED | smb.SMB.SECURITY_SHARE_USER
2451 _dialects_parameters['MaxMpxCount'] = 1
2452 _dialects_parameters['MaxNumberVcs'] = 1
2453 _dialects_parameters['MaxBufferSize'] = 64000
2454 _dialects_parameters['MaxRawSize'] = 65536
2455 _dialects_parameters['SessionKey'] = 0
2456 _dialects_parameters['LowDateTime'] = 0
2457 _dialects_parameters['HighDateTime'] = 0
2458 _dialects_parameters['ServerTimeZone'] = 0
2461 respSMBCommand['Data'] = _dialects_data
2462 respSMBCommand['Parameters'] = _dialects_parameters
2463 connData['_dialects_data'] = _dialects_data
2464 connData['_dialects_parameters'] = _dialects_parameters
2466 except Exception, e:
2467 # No NTLM throw an error
2468 smbServer.log('smbComNegotiate: %s' % e, logging.ERROR)
2469 respSMBCommand['Data'] = struct.pack('<H',0xffff)
2472 smbServer.setConnectionData(connId, connData)
2474 resp.addCommand(respSMBCommand)
2476 return None, [resp], STATUS_SUCCESS
2479 def default(connId, smbServer, SMBCommand, recvPacket):
2480 # By default we return an SMB Packet with error not implemented
2481 smbServer.log("Not implemented command: 0x%x" % recvPacket['Command'],logging.DEBUG)
2482 packet = smb.NewSMBPacket()
2483 packet['Flags1'] = smb.SMB.FLAGS1_REPLY
2484 packet['Flags2'] = smb.SMB.FLAGS2_NT_STATUS
2485 packet['Command'] = recvPacket['Command']
2486 packet['Pid'] = recvPacket['Pid']
2487 packet['Tid'] = recvPacket['Tid']
2488 packet['Mid'] = recvPacket['Mid']
2489 packet['Uid'] = recvPacket['Uid']
2490 packet['Data'] = '\x00\x00\x00'
2491 errorCode = STATUS_NOT_IMPLEMENTED
2492 packet['ErrorCode'] = errorCode >> 16
2493 packet['ErrorClass'] = errorCode & 0xff
2495 return None, [packet], errorCode
2499 def smb2Negotiate(connId, smbServer, recvPacket, isSMB1 = False):
2500 connData = smbServer.getConnectionData(connId, checkStatus = False)
2502 respPacket = smb2.SMB2Packet()
2503 respPacket['Flags'] = smb2.SMB2_FLAGS_SERVER_TO_REDIR
2504 respPacket['Status'] = STATUS_SUCCESS
2505 respPacket['CreditRequestResponse'] = 1
2506 respPacket['Command'] = smb2.SMB2_NEGOTIATE
2507 respPacket['SessionID'] = 0
2509 respPacket['MessageID'] = recvPacket['MessageID']
2511 respPacket['MessageID'] = 0
2512 respPacket['TreeID'] = 0
2515 respSMBCommand = smb2.SMB2Negotiate_Response()
2517 respSMBCommand['SecurityMode'] = 1
2519 # Let's first parse the packet to see if the client supports SMB2
2520 SMBCommand = smb.SMBCommand(recvPacket['Data'][0])
2522 dialects = SMBCommand['Data'].split('\x02')
2523 if 'SMB 2.002\x00' in dialects or 'SMB 2.???\x00' in dialects:
2524 respSMBCommand['DialectRevision'] = smb2.SMB2_DIALECT_002
2526 # Client does not support SMB2 fallbacking
2527 raise Exception('SMB2 not supported, fallbacking')
2529 respSMBCommand['DialectRevision'] = smb2.SMB2_DIALECT_002
2530 respSMBCommand['ServerGuid'] = 'A'*16
2531 respSMBCommand['Capabilities'] = 0
2532 respSMBCommand['MaxTransactSize'] = 65536
2533 respSMBCommand['MaxReadSize'] = 65536
2534 respSMBCommand['MaxWriteSize'] = 65536
2535 respSMBCommand['SystemTime'] = getFileTime(calendar.timegm(time.gmtime()))
2536 respSMBCommand['ServerStartTime'] = getFileTime(calendar.timegm(time.gmtime()))
2537 respSMBCommand['SecurityBufferOffset'] = 0x80
2539 blob = SPNEGO_NegTokenInit()
2540 blob['MechTypes'] = [TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']]
2542 respSMBCommand['Buffer'] = blob.getData()
2543 respSMBCommand['SecurityBufferLength'] = len(respSMBCommand['Buffer'])
2545 respPacket['Data'] = respSMBCommand
2547 smbServer.setConnectionData(connId, connData)
2549 return None, [respPacket], STATUS_SUCCESS
2552 def smb2SessionSetup(connId, smbServer, recvPacket):
2553 connData = smbServer.getConnectionData(connId, checkStatus = False)
2555 respSMBCommand = smb2.SMB2SessionSetup_Response()
2557 sessionSetupData = smb2.SMB2SessionSetup(recvPacket['Data'])
2559 connData['Capabilities'] = sessionSetupData['Capabilities']
2561 securityBlob = sessionSetupData['Buffer']
2564 if struct.unpack('B',securityBlob[0])[0] == ASN1_AID:
2566 blob = SPNEGO_NegTokenInit(securityBlob)
2567 token = blob['MechToken']
2568 if len(blob['MechTypes'][0]) > 0:
2569 # Is this GSSAPI NTLM or something else we don't support?
2570 mechType = blob['MechTypes'][0]
2571 if mechType != TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']:
2572 # Nope, do we know it?
2573 if MechTypes.has_key(mechType):
2574 mechStr = MechTypes[mechType]
2576 mechStr = hexlify(mechType)
2577 smbServer.log("Unsupported MechType '%s'" % mechStr, logging.CRITICAL)
2578 # We don't know the token, we answer back again saying
2579 # we just support NTLM.
2580 # ToDo: Build this into a SPNEGO_NegTokenResp()
2581 respToken = '\xa1\x15\x30\x13\xa0\x03\x0a\x01\x03\xa1\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a'
2582 respSMBCommand['SecurityBufferOffset'] = 0x48
2583 respSMBCommand['SecurityBufferLength'] = len(respToken)
2584 respSMBCommand['Buffer'] = respToken
2586 return [respSMBCommand], None, STATUS_MORE_PROCESSING_REQUIRED
2587 elif struct.unpack('B',securityBlob[0])[0] == ASN1_SUPPORTED_MECH:
2589 blob = SPNEGO_NegTokenResp(securityBlob)
2590 token = blob['ResponseToken']
2592 # No GSSAPI stuff, raw NTLMSSP
2594 token = securityBlob
2596 # Here we only handle NTLMSSP, depending on what stage of the
2597 # authentication we are, we act on it
2598 messageType = struct.unpack('<L',token[len('NTLMSSP\x00'):len('NTLMSSP\x00')+4])[0]
2600 if messageType == 0x01:
2602 negotiateMessage = ntlm.NTLMAuthNegotiate()
2603 negotiateMessage.fromString(token)
2604 # Let's store it in the connection data
2605 connData['NEGOTIATE_MESSAGE'] = negotiateMessage
2606 # Let's build the answer flags
2607 # TODO: Parse all the flags. With this we're leaving some clients out
2611 if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_56:
2612 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_56
2613 if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_128:
2614 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_128
2615 if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH:
2616 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH
2617 if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
2618 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
2619 if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_UNICODE:
2620 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_UNICODE
2621 if negotiateMessage['flags'] & ntlm.NTLM_NEGOTIATE_OEM:
2622 ansFlags |= ntlm.NTLM_NEGOTIATE_OEM
2624 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_VERSION | ntlm.NTLMSSP_NEGOTIATE_TARGET_INFO | ntlm.NTLMSSP_TARGET_TYPE_SERVER | ntlm.NTLMSSP_NEGOTIATE_NTLM | ntlm.NTLMSSP_REQUEST_TARGET
2626 # Generate the AV_PAIRS
2627 av_pairs = ntlm.AV_PAIRS()
2628 # TODO: Put the proper data from SMBSERVER config
2629 av_pairs[ntlm.NTLMSSP_AV_HOSTNAME] = av_pairs[ntlm.NTLMSSP_AV_DNS_HOSTNAME] = smbServer.getServerName().encode('utf-16le')
2630 av_pairs[ntlm.NTLMSSP_AV_DOMAINNAME] = av_pairs[ntlm.NTLMSSP_AV_DNS_DOMAINNAME] = smbServer.getServerDomain().encode('utf-16le')
2631 av_pairs[ntlm.NTLMSSP_AV_TIME] = struct.pack('<q', (116444736000000000 + calendar.timegm(time.gmtime()) * 10000000) )
2633 challengeMessage = ntlm.NTLMAuthChallenge()
2634 challengeMessage['flags'] = ansFlags
2635 challengeMessage['domain_len'] = len(smbServer.getServerDomain().encode('utf-16le'))
2636 challengeMessage['domain_max_len'] = challengeMessage['domain_len']
2637 challengeMessage['domain_offset'] = 40 + 16
2638 challengeMessage['challenge'] = smbServer.getSMBChallenge()
2639 challengeMessage['domain_name'] = smbServer.getServerDomain().encode('utf-16le')
2640 challengeMessage['TargetInfoFields_len'] = len(av_pairs)
2641 challengeMessage['TargetInfoFields_max_len'] = len(av_pairs)
2642 challengeMessage['TargetInfoFields'] = av_pairs
2643 challengeMessage['TargetInfoFields_offset'] = 40 + 16 + len(challengeMessage['domain_name'])
2644 challengeMessage['Version'] = '\xff'*8
2645 challengeMessage['VersionLen'] = 8
2647 if rawNTLM is False:
2648 respToken = SPNEGO_NegTokenResp()
2649 # accept-incomplete. We want more data
2650 respToken['NegResult'] = '\x01'
2651 respToken['SupportedMech'] = TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']
2653 respToken['ResponseToken'] = challengeMessage.getData()
2655 respToken = challengeMessage
2657 # Setting the packet to STATUS_MORE_PROCESSING
2658 errorCode = STATUS_MORE_PROCESSING_REQUIRED
2659 # Let's set up an UID for this connection and store it
2660 # in the connection's data
2661 # Picking a fixed value
2662 # TODO: Manage more UIDs for the same session
2663 connData['Uid'] = random.randint(1,0xffffffff)
2664 # Let's store it in the connection data
2665 connData['CHALLENGE_MESSAGE'] = challengeMessage
2667 elif messageType == 0x02:
2669 raise Exception('Challenge Message raise, not implemented!')
2670 elif messageType == 0x03:
2671 # AUTHENTICATE_MESSAGE, here we deal with authentication
2672 authenticateMessage = ntlm.NTLMAuthChallengeResponse()
2673 authenticateMessage.fromString(token)
2674 smbServer.log("AUTHENTICATE_MESSAGE (%s\\%s,%s)" % (authenticateMessage['domain_name'], authenticateMessage['user_name'], authenticateMessage['host_name']))
2675 # TODO: Check the credentials! Now granting permissions
2677 respToken = SPNEGO_NegTokenResp()
2679 respToken['NegResult'] = '\x00'
2682 errorCode = STATUS_SUCCESS
2683 smbServer.log('User %s\\%s authenticated successfully' % (authenticateMessage['user_name'], authenticateMessage['host_name']))
2684 # Let's store it in the connection data
2685 connData['AUTHENTICATE_MESSAGE'] = authenticateMessage
2687 jtr_dump_path = smbServer.getJTRdumpPath()
2688 ntlm_hash_data = outputToJohnFormat( connData['CHALLENGE_MESSAGE']['challenge'], authenticateMessage['user_name'], authenticateMessage['domain_name'], authenticateMessage['lanman'], authenticateMessage['ntlm'] )
2689 smbServer.log(ntlm_hash_data['hash_string'])
2690 if jtr_dump_path is not '':
2691 writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], jtr_dump_path)
2693 smbServer.log("Could not write NTLM Hashes to the specified JTR_Dump_Path %s" % jtr_dump_path)
2694 respSMBCommand['SessionFlags'] = 1
2696 raise Exception("Unknown NTLMSSP MessageType %d" % messageType)
2698 respSMBCommand['SecurityBufferOffset'] = 0x48
2699 respSMBCommand['SecurityBufferLength'] = len(respToken)
2700 respSMBCommand['Buffer'] = respToken.getData()
2702 # From now on, the client can ask for other commands
2703 connData['Authenticated'] = True
2704 # For now, just switching to nobody
2705 #os.setregid(65534,65534)
2706 #os.setreuid(65534,65534)
2707 smbServer.setConnectionData(connId, connData)
2709 return [respSMBCommand], None, errorCode
2712 def smb2TreeConnect(connId, smbServer, recvPacket):
2713 connData = smbServer.getConnectionData(connId)
2715 respPacket = smb2.SMB2Packet()
2716 respPacket['Flags'] = smb2.SMB2_FLAGS_SERVER_TO_REDIR
2717 respPacket['Status'] = STATUS_SUCCESS
2718 respPacket['CreditRequestResponse'] = 1
2719 respPacket['Command'] = recvPacket['Command']
2720 respPacket['SessionID'] = connData['Uid']
2721 respPacket['Reserved'] = recvPacket['Reserved']
2722 respPacket['MessageID'] = recvPacket['MessageID']
2723 respPacket['TreeID'] = recvPacket['TreeID']
2725 respSMBCommand = smb2.SMB2TreeConnect_Response()
2727 treeConnectRequest = smb2.SMB2TreeConnect(recvPacket['Data'])
2729 errorCode = STATUS_SUCCESS
2731 ## Process here the request, does the share exist?
2732 path = str(recvPacket)[treeConnectRequest['PathOffset']:][:treeConnectRequest['PathLength']]
2733 UNCOrShare = path.decode('utf-16le')
2736 if ntpath.ismount(UNCOrShare):
2737 path = UNCOrShare.split('\\')[3]
2739 path = ntpath.basename(UNCOrShare)
2741 share = searchShare(connId, path.upper(), smbServer)
2742 if share is not None:
2743 # Simple way to generate a Tid
2744 if len(connData['ConnectedShares']) == 0:
2747 tid = connData['ConnectedShares'].keys()[-1] + 1
2748 connData['ConnectedShares'][tid] = share
2749 connData['ConnectedShares'][tid]['shareName'] = path
2750 respPacket['TreeID'] = tid
2751 smbServer.log("Connecting Share(%d:%s)" % (tid,path))
2753 smbServer.log("SMB2_TREE_CONNECT not found %s" % path, logging.ERROR)
2754 errorCode = STATUS_OBJECT_PATH_NOT_FOUND
2755 respPacket['Status'] = errorCode
2759 respSMBCommand['ShareType'] = smb2.SMB2_SHARE_TYPE_PIPE
2760 respSMBCommand['ShareFlags'] = 0x30
2762 respSMBCommand['ShareType'] = smb2.SMB2_SHARE_TYPE_DISK
2763 respSMBCommand['ShareFlags'] = 0x0
2765 respSMBCommand['Capabilities'] = 0
2766 respSMBCommand['MaximalAccess'] = 0x000f01ff
2768 respPacket['Data'] = respSMBCommand
2770 smbServer.setConnectionData(connId, connData)
2772 return None, [respPacket], errorCode
2775 def smb2Create(connId, smbServer, recvPacket):
2776 connData = smbServer.getConnectionData(connId)
2778 respSMBCommand = smb2.SMB2Create_Response()
2780 ntCreateRequest = smb2.SMB2Create(recvPacket['Data'])
2782 respSMBCommand['Buffer'] = '\x00'
2783 # Get the Tid associated
2784 if connData['ConnectedShares'].has_key(recvPacket['TreeID']):
2785 # If we have a rootFid, the path is relative to that fid
2786 errorCode = STATUS_SUCCESS
2787 if connData['ConnectedShares'][recvPacket['TreeID']].has_key('path'):
2788 path = connData['ConnectedShares'][recvPacket['TreeID']]['path']
2791 errorCode = STATUS_ACCESS_DENIED
2793 deleteOnClose = False
2795 fileName = os.path.normpath(ntCreateRequest['Buffer'][:ntCreateRequest['NameLength']].decode('utf-16le').replace('\\','/'))
2796 if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
2798 fileName = fileName[1:]
2799 pathName = os.path.join(path,fileName)
2800 createDisposition = ntCreateRequest['CreateDisposition']
2803 if createDisposition == smb2.FILE_SUPERSEDE:
2804 mode |= os.O_TRUNC | os.O_CREAT
2805 elif createDisposition & smb2.FILE_OVERWRITE_IF == smb2.FILE_OVERWRITE_IF:
2806 mode |= os.O_TRUNC | os.O_CREAT
2807 elif createDisposition & smb2.FILE_OVERWRITE == smb2.FILE_OVERWRITE:
2808 if os.path.exists(pathName) is True:
2811 errorCode = STATUS_NO_SUCH_FILE
2812 elif createDisposition & smb2.FILE_OPEN_IF == smb2.FILE_OPEN_IF:
2813 if os.path.exists(pathName) is True:
2816 mode |= os.O_TRUNC | os.O_CREAT
2817 elif createDisposition & smb2.FILE_CREATE == smb2.FILE_CREATE:
2818 if os.path.exists(pathName) is True:
2819 errorCode = STATUS_OBJECT_NAME_COLLISION
2822 elif createDisposition & smb2.FILE_OPEN == smb2.FILE_OPEN:
2823 if os.path.exists(pathName) is not True and smbServer.getRegisteredNamedPipes().has_key(unicode(pathName)) is not True:
2824 errorCode = STATUS_NO_SUCH_FILE
2826 if errorCode == STATUS_SUCCESS:
2827 desiredAccess = ntCreateRequest['DesiredAccess']
2828 if (desiredAccess & smb2.FILE_READ_DATA) or (desiredAccess & smb2.GENERIC_READ):
2830 if (desiredAccess & smb2.FILE_WRITE_DATA) or (desiredAccess & smb2.GENERIC_WRITE):
2831 if (desiredAccess & smb2.FILE_READ_DATA) or (desiredAccess & smb2.GENERIC_READ):
2832 mode |= os.O_RDWR #| os.O_APPEND
2834 mode |= os.O_WRONLY #| os.O_APPEND
2835 if desiredAccess & smb2.GENERIC_ALL:
2836 mode |= os.O_RDWR #| os.O_APPEND
2838 createOptions = ntCreateRequest['CreateOptions']
2839 if mode & os.O_CREAT == os.O_CREAT:
2840 if createOptions & smb2.FILE_DIRECTORY_FILE == smb2.FILE_DIRECTORY_FILE:
2842 # Let's create the directory
2845 except Exception, e:
2846 smbServer.log("SMB2_CREATE: %s,%s,%s" % (pathName,mode,e),logging.ERROR)
2847 errorCode = STATUS_ACCESS_DENIED
2848 if createOptions & smb2.FILE_NON_DIRECTORY_FILE == smb2.FILE_NON_DIRECTORY_FILE:
2849 # If the file being opened is a directory, the server MUST fail the request with
2850 # STATUS_FILE_IS_A_DIRECTORY in the Status field of the SMB Header in the server
2852 if os.path.isdir(pathName) is True:
2853 errorCode = STATUS_FILE_IS_A_DIRECTORY
2855 if createOptions & smb2.FILE_DELETE_ON_CLOSE == smb2.FILE_DELETE_ON_CLOSE:
2856 deleteOnClose = True
2858 if errorCode == STATUS_SUCCESS:
2860 if os.path.isdir(pathName) and sys.platform == 'win32':
2861 fid = VOID_FILE_DESCRIPTOR
2863 if sys.platform == 'win32':
2865 if smbServer.getRegisteredNamedPipes().has_key(unicode(pathName)):
2866 fid = PIPE_FILE_DESCRIPTOR
2867 sock = socket.socket()
2868 sock.connect(smbServer.getRegisteredNamedPipes()[unicode(pathName)])
2870 fid = os.open(pathName, mode)
2871 except Exception, e:
2872 smbServer.log("SMB2_CREATE: %s,%s,%s" % (pathName,mode,e),logging.ERROR)
2875 errorCode = STATUS_ACCESS_DENIED
2877 errorCode = STATUS_SMB_BAD_TID
2879 if errorCode == STATUS_SUCCESS:
2880 # Simple way to generate a fid
2881 fakefid = uuid.generate()
2883 respSMBCommand['FileID'] = fakefid
2884 respSMBCommand['CreateAction'] = createDisposition
2886 if fid == PIPE_FILE_DESCRIPTOR:
2887 respSMBCommand['CreationTime'] = 0
2888 respSMBCommand['LastAccessTime'] = 0
2889 respSMBCommand['LastWriteTime'] = 0
2890 respSMBCommand['ChangeTime'] = 0
2891 respSMBCommand['AllocationSize'] = 4096
2892 respSMBCommand['EndOfFile'] = 0
2893 respSMBCommand['FileAttributes'] = 0x80
2896 if os.path.isdir(pathName):
2897 respSMBCommand['FileAttributes'] = smb.SMB_FILE_ATTRIBUTE_DIRECTORY
2899 respSMBCommand['FileAttributes'] = ntCreateRequest['FileAttributes']
2900 # Let's get this file's information
2901 respInfo, errorCode = queryPathInformation('',pathName,level= smb.SMB_QUERY_FILE_ALL_INFO)
2902 if errorCode == STATUS_SUCCESS:
2903 respSMBCommand['CreationTime'] = respInfo['CreationTime']
2904 respSMBCommand['LastAccessTime'] = respInfo['LastAccessTime']
2905 respSMBCommand['LastWriteTime'] = respInfo['LastWriteTime']
2906 respSMBCommand['LastChangeTime'] = respInfo['LastChangeTime']
2907 respSMBCommand['FileAttributes'] = respInfo['ExtFileAttributes']
2908 respSMBCommand['AllocationSize'] = respInfo['AllocationSize']
2909 respSMBCommand['EndOfFile'] = respInfo['EndOfFile']
2911 if errorCode == STATUS_SUCCESS:
2912 # Let's store the fid for the connection
2913 # smbServer.log('Create file %s, mode:0x%x' % (pathName, mode))
2914 connData['OpenedFiles'][fakefid] = {}
2915 connData['OpenedFiles'][fakefid]['FileHandle'] = fid
2916 connData['OpenedFiles'][fakefid]['FileName'] = pathName
2917 connData['OpenedFiles'][fakefid]['DeleteOnClose'] = deleteOnClose
2918 connData['OpenedFiles'][fakefid]['Open'] = {}
2919 connData['OpenedFiles'][fakefid]['Open']['EnumerationLocation'] = 0
2920 connData['OpenedFiles'][fakefid]['Open']['EnumerationSearchPattern'] = ''
2921 if fid == PIPE_FILE_DESCRIPTOR:
2922 connData['OpenedFiles'][fakefid]['Socket'] = sock
2924 respSMBCommand = smb2.SMB2Error()
2926 if errorCode == STATUS_SUCCESS:
2927 connData['LastRequest']['SMB2_CREATE'] = respSMBCommand
2928 smbServer.setConnectionData(connId, connData)
2930 return [respSMBCommand], None, errorCode
2933 def smb2Close(connId, smbServer, recvPacket):
2934 connData = smbServer.getConnectionData(connId)
2936 respSMBCommand = smb2.SMB2Close_Response()
2938 closeRequest = smb2.SMB2Close(recvPacket['Data'])
2940 if str(closeRequest['FileID']) == '\xff'*16:
2941 # Let's take the data from the lastRequest
2942 if connData['LastRequest'].has_key('SMB2_CREATE'):
2943 fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
2945 fileID = str(closeRequest['FileID'])
2947 fileID = str(closeRequest['FileID'])
2949 if connData['OpenedFiles'].has_key(fileID):
2950 errorCode = STATUS_SUCCESS
2951 fileHandle = connData['OpenedFiles'][fileID]['FileHandle']
2952 pathName = connData['OpenedFiles'][fileID]['FileName']
2955 if fileHandle == PIPE_FILE_DESCRIPTOR:
2956 connData['OpenedFiles'][fileID]['Socket'].close()
2957 elif fileHandle != VOID_FILE_DESCRIPTOR:
2958 os.close(fileHandle)
2959 infoRecord, errorCode = queryFileInformation(os.path.dirname(pathName), os.path.basename(pathName), smb2.SMB2_FILE_NETWORK_OPEN_INFO)
2960 except Exception, e:
2961 smbServer.log("SMB2_CLOSE %s" % e, logging.ERROR)
2962 errorCode = STATUS_INVALID_HANDLE
2964 # Check if the file was marked for removal
2965 if connData['OpenedFiles'][fileID]['DeleteOnClose'] is True:
2967 if os.path.isdir(pathName):
2968 shutil.rmtree(connData['OpenedFiles'][fileID]['FileName'])
2970 os.remove(connData['OpenedFiles'][fileID]['FileName'])
2971 except Exception, e:
2972 smbServer.log("SMB2_CLOSE %s" % e, logging.ERROR)
2973 errorCode = STATUS_ACCESS_DENIED
2975 # Now fill out the response
2976 if infoRecord is not None:
2977 respSMBCommand['CreationTime'] = infoRecord['CreationTime']
2978 respSMBCommand['LastAccessTime'] = infoRecord['LastAccessTime']
2979 respSMBCommand['LastWriteTime'] = infoRecord['LastWriteTime']
2980 respSMBCommand['ChangeTime'] = infoRecord['ChangeTime']
2981 respSMBCommand['AllocationSize'] = infoRecord['AllocationSize']
2982 respSMBCommand['EndofFile'] = infoRecord['EndOfFile']
2983 respSMBCommand['FileAttributes'] = infoRecord['FileAttributes']
2984 if errorCode == STATUS_SUCCESS:
2985 del(connData['OpenedFiles'][fileID])
2987 errorCode = STATUS_INVALID_HANDLE
2989 smbServer.setConnectionData(connId, connData)
2990 return [respSMBCommand], None, errorCode
2993 def smb2QueryInfo(connId, smbServer, recvPacket):
2994 connData = smbServer.getConnectionData(connId)
2996 respSMBCommand = smb2.SMB2QueryInfo_Response()
2998 queryInfo = smb2.SMB2QueryInfo(recvPacket['Data'])
3000 errorCode = STATUS_SUCCESS
3002 respSMBCommand['OutputBufferOffset'] = 0x48
3003 respSMBCommand['Buffer'] = '\x00'
3005 if str(queryInfo['FileID']) == '\xff'*16:
3006 # Let's take the data from the lastRequest
3007 if connData['LastRequest'].has_key('SMB2_CREATE'):
3008 fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
3010 fileID = str(queryInfo['FileID'])
3012 fileID = str(queryInfo['FileID'])
3014 if connData['ConnectedShares'].has_key(recvPacket['TreeID']):
3015 if connData['OpenedFiles'].has_key(fileID):
3016 fileName = connData['OpenedFiles'][fileID]['FileName']
3018 if queryInfo['InfoType'] == smb2.SMB2_0_INFO_FILE:
3019 if queryInfo['FileInfoClass'] == smb2.SMB2_FILE_INTERNAL_INFO:
3020 # No need to call queryFileInformation, we have the data here
3021 infoRecord = smb2.FileInternalInformation()
3022 infoRecord['IndexNumber'] = fileID
3024 infoRecord, errorCode = queryFileInformation(os.path.dirname(fileName), os.path.basename(fileName), queryInfo['FileInfoClass'])
3025 elif queryInfo['InfoType'] == smb2.SMB2_0_INFO_FILESYSTEM:
3026 infoRecord = queryFsInformation(os.path.dirname(fileName), os.path.basename(fileName), queryInfo['FileInfoClass'])
3027 elif queryInfo['InfoType'] == smb2.SMB2_0_INFO_SECURITY:
3028 # Failing for now, until we support it
3030 errorCode = STATUS_ACCESS_DENIED
3032 smbServer.log("queryInfo not supported (%x)" % queryInfo['InfoType'], logging.ERROR)
3034 if infoRecord is not None:
3035 respSMBCommand['OutputBufferLength'] = len(infoRecord)
3036 respSMBCommand['Buffer'] = infoRecord
3038 errorCode = STATUS_INVALID_HANDLE
3040 errorCode = STATUS_SMB_BAD_TID
3043 smbServer.setConnectionData(connId, connData)
3044 return [respSMBCommand], None, errorCode
3047 def smb2SetInfo(connId, smbServer, recvPacket):
3048 connData = smbServer.getConnectionData(connId)
3050 respSMBCommand = smb2.SMB2SetInfo_Response()
3052 setInfo = smb2.SMB2SetInfo(recvPacket['Data'])
3054 errorCode = STATUS_SUCCESS
3056 if str(setInfo['FileID']) == '\xff'*16:
3057 # Let's take the data from the lastRequest
3058 if connData['LastRequest'].has_key('SMB2_CREATE'):
3059 fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
3061 fileID = str(setInfo['FileID'])
3063 fileID = str(setInfo['FileID'])
3065 if connData['ConnectedShares'].has_key(recvPacket['TreeID']):
3066 path = connData['ConnectedShares'][recvPacket['TreeID']]['path']
3067 if connData['OpenedFiles'].has_key(fileID):
3068 pathName = connData['OpenedFiles'][fileID]['FileName']
3070 if setInfo['InfoType'] == smb2.SMB2_0_INFO_FILE:
3071 # The file information is being set
3072 informationLevel = setInfo['FileInfoClass']
3073 if informationLevel == smb2.SMB2_FILE_DISPOSITION_INFO:
3074 infoRecord = smb.SMBSetFileDispositionInfo(setInfo['Buffer'])
3075 if infoRecord['DeletePending'] > 0:
3076 # Mark this file for removal after closed
3077 connData['OpenedFiles'][fileID]['DeleteOnClose'] = True
3078 elif informationLevel == smb2.SMB2_FILE_BASIC_INFO:
3079 infoRecord = smb.SMBSetFileBasicInfo(setInfo['Buffer'])
3080 # Creation time won't be set, the other ones we play with.
3081 atime = infoRecord['LastWriteTime']
3085 atime = getUnixTime(atime)
3086 mtime = infoRecord['ChangeTime']
3090 mtime = getUnixTime(mtime)
3091 if atime > 0 and mtime > 0:
3092 os.utime(pathName,(atime,mtime))
3093 elif informationLevel == smb2.SMB2_FILE_END_OF_FILE_INFO:
3094 fileHandle = connData['OpenedFiles'][fileID]['FileHandle']
3095 infoRecord = smb.SMBSetFileEndOfFileInfo(setInfo['Buffer'])
3096 if infoRecord['EndOfFile'] > 0:
3097 os.lseek(fileHandle, infoRecord['EndOfFile']-1, 0)
3098 os.write(fileHandle, '\x00')
3099 elif informationLevel == smb2.SMB2_FILE_RENAME_INFO:
3100 renameInfo = smb2.FILE_RENAME_INFORMATION_TYPE_2(setInfo['Buffer'])
3101 newPathName = os.path.join(path,renameInfo['FileName'].decode('utf-16le').replace('\\', '/'))
3102 if renameInfo['ReplaceIfExists'] == 0 and os.path.exists(newPathName):
3103 return [smb2.SMB2Error()], None, STATUS_OBJECT_NAME_COLLISION
3105 os.rename(pathName,newPathName)
3106 connData['OpenedFiles'][fileID]['FileName'] = newPathName
3107 except Exception, e:
3108 smbServer.log("smb2SetInfo: %s" % e, logging.ERROR)
3109 errorCode = STATUS_ACCESS_DENIED
3111 smbServer.log('Unknown level for set file info! 0x%x' % informationLevel, logging.ERROR)
3113 errorCode = STATUS_NOT_SUPPORTED
3114 #elif setInfo['InfoType'] == smb2.SMB2_0_INFO_FILESYSTEM:
3115 # # The underlying object store information is being set.
3116 # setInfo = queryFsInformation('/', fileName, queryInfo['FileInfoClass'])
3117 #elif setInfo['InfoType'] == smb2.SMB2_0_INFO_SECURITY:
3118 # # The security information is being set.
3119 # # Failing for now, until we support it
3121 # errorCode = STATUS_ACCESS_DENIED
3122 #elif setInfo['InfoType'] == smb2.SMB2_0_INFO_QUOTA:
3123 # # The underlying object store quota information is being set.
3124 # setInfo = queryFsInformation('/', fileName, queryInfo['FileInfoClass'])
3126 smbServer.log("setInfo not supported (%x)" % setInfo['InfoType'], logging.ERROR)
3129 errorCode = STATUS_INVALID_HANDLE
3131 errorCode = STATUS_SMB_BAD_TID
3134 smbServer.setConnectionData(connId, connData)
3135 return [respSMBCommand], None, errorCode
3138 def smb2Write(connId, smbServer, recvPacket):
3139 connData = smbServer.getConnectionData(connId)
3141 respSMBCommand = smb2.SMB2Write_Response()
3142 writeRequest = smb2.SMB2Write(recvPacket['Data'])
3144 respSMBCommand['Buffer'] = '\x00'
3146 if str(writeRequest['FileID']) == '\xff'*16:
3147 # Let's take the data from the lastRequest
3148 if connData['LastRequest'].has_key('SMB2_CREATE'):
3149 fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
3151 fileID = str(writeRequest['FileID'])
3153 fileID = str(writeRequest['FileID'])
3155 if connData['OpenedFiles'].has_key(fileID):
3156 fileHandle = connData['OpenedFiles'][fileID]['FileHandle']
3157 errorCode = STATUS_SUCCESS
3159 if fileHandle != PIPE_FILE_DESCRIPTOR:
3160 offset = writeRequest['Offset']
3161 # If we're trying to write past the file end we just skip the write call (Vista does this)
3162 if os.lseek(fileHandle, 0, 2) >= offset:
3163 os.lseek(fileHandle,offset,0)
3164 os.write(fileHandle,writeRequest['Buffer'])
3166 sock = connData['OpenedFiles'][fileID]['Socket']
3167 sock.send(writeRequest['Buffer'])
3169 respSMBCommand['Count'] = writeRequest['Length']
3170 respSMBCommand['Remaining']= 0xff
3171 except Exception, e:
3172 smbServer.log('SMB2_WRITE: %s' % e, logging.ERROR)
3173 errorCode = STATUS_ACCESS_DENIED
3175 errorCode = STATUS_INVALID_HANDLE
3177 smbServer.setConnectionData(connId, connData)
3178 return [respSMBCommand], None, errorCode
3181 def smb2Read(connId, smbServer, recvPacket):
3182 connData = smbServer.getConnectionData(connId)
3184 respSMBCommand = smb2.SMB2Read_Response()
3185 readRequest = smb2.SMB2Read(recvPacket['Data'])
3187 respSMBCommand['Buffer'] = '\x00'
3189 if str(readRequest['FileID']) == '\xff'*16:
3190 # Let's take the data from the lastRequest
3191 if connData['LastRequest'].has_key('SMB2_CREATE'):
3192 fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
3194 fileID = str(readRequest['FileID'])
3196 fileID = str(readRequest['FileID'])
3198 if connData['OpenedFiles'].has_key(fileID):
3199 fileHandle = connData['OpenedFiles'][fileID]['FileHandle']
3202 if fileHandle != PIPE_FILE_DESCRIPTOR:
3203 offset = readRequest['Offset']
3204 os.lseek(fileHandle,offset,0)
3205 content = os.read(fileHandle,readRequest['Length'])
3207 sock = connData['OpenedFiles'][fileID]['Socket']
3208 content = sock.recv(readRequest['Length'])
3210 respSMBCommand['DataOffset'] = 0x50
3211 respSMBCommand['DataLength'] = len(content)
3212 respSMBCommand['DataRemaining']= 0
3213 respSMBCommand['Buffer'] = content
3214 except Exception, e:
3215 smbServer.log('SMB2_READ: %s ' % e, logging.ERROR)
3216 errorCode = STATUS_ACCESS_DENIED
3218 errorCode = STATUS_INVALID_HANDLE
3220 smbServer.setConnectionData(connId, connData)
3221 return [respSMBCommand], None, errorCode
3224 def smb2Flush(connId, smbServer, recvPacket):
3225 connData = smbServer.getConnectionData(connId)
3227 respSMBCommand = smb2.SMB2Flush_Response()
3228 flushRequest = smb2.SMB2Flush(recvPacket['Data'])
3230 if connData['OpenedFiles'].has_key(str(flushRequest['FileID'])):
3231 fileHandle = connData['OpenedFiles'][str(flushRequest['FileID'])]['FileHandle']
3232 errorCode = STATUS_SUCCESS
3234 os.fsync(fileHandle)
3235 except Exception, e:
3236 smbServer.log("SMB2_FLUSH %s" % e, logging.ERROR)
3237 errorCode = STATUS_ACCESS_DENIED
3239 errorCode = STATUS_INVALID_HANDLE
3241 smbServer.setConnectionData(connId, connData)
3242 return [respSMBCommand], None, errorCode
3246 def smb2QueryDirectory(connId, smbServer, recvPacket):
3247 connData = smbServer.getConnectionData(connId)
3248 respSMBCommand = smb2.SMB2QueryDirectory_Response()
3249 queryDirectoryRequest = smb2.SMB2QueryDirectory(recvPacket['Data'])
3251 respSMBCommand['Buffer'] = '\x00'
3253 # The server MUST locate the tree connection, as specified in section 3.3.5.2.11.
3254 if connData['ConnectedShares'].has_key(recvPacket['TreeID']) is False:
3255 return [smb2.SMB2Error()], None, STATUS_NETWORK_NAME_DELETED
3257 # Next, the server MUST locate the open for the directory to be queried
3258 # If no open is found, the server MUST fail the request with STATUS_FILE_CLOSED
3259 if str(queryDirectoryRequest['FileID']) == '\xff'*16:
3260 # Let's take the data from the lastRequest
3261 if connData['LastRequest'].has_key('SMB2_CREATE'):
3262 fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
3264 fileID = str(queryDirectoryRequest['FileID'])
3266 fileID = str(queryDirectoryRequest['FileID'])
3268 if connData['OpenedFiles'].has_key(fileID) is False:
3269 return [smb2.SMB2Error()], None, STATUS_FILE_CLOSED
3271 # If the open is not an open to a directory, the request MUST be failed
3272 # with STATUS_INVALID_PARAMETER.
3273 if os.path.isdir(connData['OpenedFiles'][fileID]['FileName']) is False:
3274 return [smb2.SMB2Error()], None, STATUS_INVALID_PARAMETER
3276 # If any other information class is specified in the FileInformationClass
3277 # field of the SMB2 QUERY_DIRECTORY Request, the server MUST fail the
3278 # operation with STATUS_INVALID_INFO_CLASS.
3279 if queryDirectoryRequest['FileInformationClass'] not in (
3280 smb2.FILE_DIRECTORY_INFORMATION, smb2.FILE_FULL_DIRECTORY_INFORMATION, smb2.FILEID_FULL_DIRECTORY_INFORMATION,
3281 smb2.FILE_BOTH_DIRECTORY_INFORMATION, smb2.FILEID_BOTH_DIRECTORY_INFORMATION, smb2.FILENAMES_INFORMATION):
3282 return [smb2.SMB2Error()], None, STATUS_INVALID_INFO_CLASS
3284 # If SMB2_REOPEN is set in the Flags field of the SMB2 QUERY_DIRECTORY
3285 # Request, the server SHOULD<326> set Open.EnumerationLocation to 0
3286 # and Open.EnumerationSearchPattern to an empty string.
3287 if queryDirectoryRequest['Flags'] & smb2.SMB2_REOPEN:
3288 connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] = 0
3289 connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] = ''
3291 # If SMB2_RESTART_SCANS is set in the Flags field of the SMB2
3292 # QUERY_DIRECTORY Request, the server MUST set
3293 # Open.EnumerationLocation to 0.
3294 if queryDirectoryRequest['Flags'] & smb2.SMB2_RESTART_SCANS:
3295 connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] = 0
3297 # If Open.EnumerationLocation is 0 and Open.EnumerationSearchPattern
3298 # is an empty string, then Open.EnumerationSearchPattern MUST be set
3299 # to the search pattern specified in the SMB2 QUERY_DIRECTORY by
3300 # FileNameOffset and FileNameLength. If FileNameLength is 0, the server
3301 # SHOULD<327> set Open.EnumerationSearchPattern as "*" to search all entries.
3303 pattern = queryDirectoryRequest['Buffer'].decode('utf-16le')
3304 if connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] == 0 and \
3305 connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] == '':
3308 connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] = pattern
3310 # If SMB2_INDEX_SPECIFIED is set and FileNameLength is not zero,
3311 # the server MUST set Open.EnumerationSearchPattern to the search pattern
3312 # specified in the request by FileNameOffset and FileNameLength.
3313 if queryDirectoryRequest['Flags'] & smb2.SMB2_INDEX_SPECIFIED and \
3314 queryDirectoryRequest['FileNameLength'] > 0:
3315 connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] = pattern
3317 pathName = os.path.join(os.path.normpath(connData['OpenedFiles'][fileID]['FileName']),pattern)
3318 searchResult, searchCount, errorCode = findFirst2(os.path.dirname(pathName),
3319 os.path.basename(pathName),
3320 queryDirectoryRequest['FileInformationClass'],
3321 smb.ATTR_DIRECTORY, isSMB2 = True )
3323 if errorCode != STATUS_SUCCESS:
3324 return [smb2.SMB2Error()], None, errorCode
3326 if searchCount > 2 and pattern == '*':
3329 searchResult = searchResult[2:]
3331 if searchCount == 0 and connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] == 0:
3332 return [smb2.SMB2Error()], None, STATUS_NO_SUCH_FILE
3334 if connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] < 0:
3335 return [smb2.SMB2Error()], None, STATUS_NO_MORE_FILES
3339 for nItem in range(connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'], searchCount):
3340 connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] += 1
3341 if queryDirectoryRequest['Flags'] & smb2.SL_RETURN_SINGLE_ENTRY:
3342 # If single entry is requested we must clear the NextEntryOffset
3343 searchResult[nItem]['NextEntryOffset'] = 0
3344 data = searchResult[nItem].getData()
3346 padLen = (8-(lenData % 8)) %8
3348 if (totalData+lenData) >= queryDirectoryRequest['OutputBufferLength']:
3349 connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] -= 1
3352 respData += data + '\x00'*padLen
3353 totalData += lenData + padLen
3355 if queryDirectoryRequest['Flags'] & smb2.SL_RETURN_SINGLE_ENTRY:
3358 if connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] >= searchCount:
3359 connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] = -1
3361 respSMBCommand['OutputBufferOffset'] = 0x48
3362 respSMBCommand['OutputBufferLength'] = totalData
3363 respSMBCommand['Buffer'] = respData
3365 smbServer.setConnectionData(connId, connData)
3366 return [respSMBCommand], None, errorCode
3369 def smb2ChangeNotify(connId, smbServer, recvPacket):
3371 return [smb2.SMB2Error()], None, STATUS_NOT_SUPPORTED
3374 def smb2Echo(connId, smbServer, recvPacket):
3376 respSMBCommand = smb2.SMB2Echo_Response()
3378 return [respSMBCommand], None, STATUS_SUCCESS
3381 def smb2TreeDisconnect(connId, smbServer, recvPacket):
3382 connData = smbServer.getConnectionData(connId)
3384 respSMBCommand = smb2.SMB2TreeDisconnect_Response()
3386 if connData['ConnectedShares'].has_key(recvPacket['TreeID']):
3387 smbServer.log("Disconnecting Share(%d:%s)" % (recvPacket['TreeID'],connData['ConnectedShares'][recvPacket['TreeID']]['shareName']))
3388 del(connData['ConnectedShares'][recvPacket['TreeID']])
3389 errorCode = STATUS_SUCCESS
3391 # STATUS_SMB_BAD_TID
3392 errorCode = STATUS_SMB_BAD_TID
3395 smbServer.setConnectionData(connId, connData)
3396 return [respSMBCommand], None, errorCode
3399 def smb2Logoff(connId, smbServer, recvPacket):
3400 connData = smbServer.getConnectionData(connId)
3402 respSMBCommand = smb2.SMB2Logoff_Response()
3404 if recvPacket['SessionID'] != connData['Uid']:
3405 # STATUS_SMB_BAD_UID
3406 errorCode = STATUS_SMB_BAD_UID
3408 errorCode = STATUS_SUCCESS
3412 smbServer.setConnectionData(connId, connData)
3413 return [respSMBCommand], None, errorCode
3416 def smb2Ioctl(connId, smbServer, recvPacket):
3417 connData = smbServer.getConnectionData(connId)
3419 respSMBCommand = smb2.SMB2Ioctl_Response()
3420 ioctlRequest = smb2.SMB2Ioctl(recvPacket['Data'])
3422 ioctls = smbServer.getIoctls()
3423 if ioctls.has_key(ioctlRequest['CtlCode']):
3424 outputData, errorCode = ioctls[ioctlRequest['CtlCode']](connId, smbServer, ioctlRequest)
3425 if errorCode == STATUS_SUCCESS:
3426 respSMBCommand['CtlCode'] = ioctlRequest['CtlCode']
3427 respSMBCommand['FileID'] = ioctlRequest['FileID']
3428 respSMBCommand['InputOffset'] = 0
3429 respSMBCommand['InputCount'] = 0
3430 respSMBCommand['OutputOffset'] = 0x70
3431 respSMBCommand['OutputCount'] = len(outputData)
3432 respSMBCommand['Flags'] = 0
3433 respSMBCommand['Buffer'] = outputData
3435 respSMBCommand = outputData
3437 smbServer.log("Ioctl not implemented command: 0x%x" % ioctlRequest['CtlCode'],logging.DEBUG)
3438 errorCode = STATUS_INVALID_DEVICE_REQUEST
3439 respSMBCommand = smb2.SMB2Error()
3441 smbServer.setConnectionData(connId, connData)
3442 return [respSMBCommand], None, errorCode
3445 def smb2Lock(connId, smbServer, recvPacket):
3446 connData = smbServer.getConnectionData(connId)
3448 respSMBCommand = smb2.SMB2Lock_Response()
3450 # I'm actually doing nothing.. just make MacOS happy ;)
3451 errorCode = STATUS_SUCCESS
3453 smbServer.setConnectionData(connId, connData)
3454 return [respSMBCommand], None, errorCode
3457 def smb2Cancel(connId, smbServer, recvPacket):
3458 # I'm actually doing nothing
3459 return [smb2.SMB2Error()], None, STATUS_CANCELLED
3462 def default(connId, smbServer, recvPacket):
3463 # By default we return an SMB Packet with error not implemented
3464 smbServer.log("Not implemented command: 0x%x" % recvPacket['Command'],logging.DEBUG)
3465 return [smb2.SMB2Error()], None, STATUS_NOT_SUPPORTED
3469 def fsctlDfsGetReferrals(connId, smbServer, ioctlRequest):
3470 return smb2.SMB2Error(), STATUS_FS_DRIVER_REQUIRED
3473 def fsctlPipeTransceive(connId, smbServer, ioctlRequest):
3474 connData = smbServer.getConnectionData(connId)
3478 if connData['OpenedFiles'].has_key(str(ioctlRequest['FileID'])):
3479 fileHandle = connData['OpenedFiles'][str(ioctlRequest['FileID'])]['FileHandle']
3480 errorCode = STATUS_SUCCESS
3482 if fileHandle != PIPE_FILE_DESCRIPTOR:
3483 errorCode = STATUS_INVALID_DEVICE_REQUEST
3485 sock = connData['OpenedFiles'][str(ioctlRequest['FileID'])]['Socket']
3486 sock.sendall(ioctlRequest['Buffer'])
3487 ioctlResponse = sock.recv(ioctlRequest['MaxOutputResponse'])
3488 except Exception, e:
3489 smbServer.log('fsctlPipeTransceive: %s ' % e, logging.ERROR)
3490 errorCode = STATUS_ACCESS_DENIED
3492 errorCode = STATUS_INVALID_DEVICE_REQUEST
3494 smbServer.setConnectionData(connId, connData)
3495 return ioctlResponse, errorCode
3498 def fsctlValidateNegotiateInfo(connId, smbServer, ioctlRequest):
3499 connData = smbServer.getConnectionData(connId)
3501 errorCode = STATUS_SUCCESS
3503 validateNegotiateInfo = smb2.VALIDATE_NEGOTIATE_INFO(ioctlRequest['Buffer'])
3504 validateNegotiateInfo['Capabilities'] = 0
3505 validateNegotiateInfo['Guid'] = 'A'*16
3506 validateNegotiateInfo['SecurityMode'] = 1
3507 validateNegotiateInfo['Dialects'] = (smb2.SMB2_DIALECT_002,)
3509 smbServer.setConnectionData(connId, connData)
3510 return validateNegotiateInfo.getData(), errorCode
3513 class SMBSERVERHandler(SocketServer.BaseRequestHandler):
3514 def __init__(self, request, client_address, server, select_poll = False):
3516 self.__ip, self.__port = client_address
3517 self.__request = request
3518 self.__connId = threading.currentThread().getName()
3519 self.__timeOut = 60*5
3520 self.__select_poll = select_poll
3521 #self.__connId = os.getpid()
3522 SocketServer.BaseRequestHandler.__init__(self, request, client_address, server)
3525 self.__SMB.log("Incoming connection (%s,%d)" % (self.__ip, self.__port))
3526 self.__SMB.addConnection(self.__connId, self.__ip, self.__port)
3529 # Firt of all let's get the NETBIOS packet
3530 session = nmb.NetBIOSTCPSession(self.__SMB.getServerName(),'HOST', self.__ip, sess_port = self.__port, sock = self.__request, select_poll = self.__select_poll)
3532 p = session.recv_packet(self.__timeOut)
3533 except nmb.NetBIOSTimeout:
3535 except nmb.NetBIOSError:
3538 if p.get_type() == nmb.NETBIOS_SESSION_REQUEST:
3539 # Someone is requesting a session, we're gonna accept them all :)
3540 _, rn, my = p.get_trailer().split(' ')
3541 remote_name = nmb.decode_name('\x20'+rn)
3542 myname = nmb.decode_name('\x20'+my)
3543 self.__SMB.log("NetBIOS Session request (%s,%s,%s)" % (self.__ip, remote_name[1].strip(), myname[1]))
3544 r = nmb.NetBIOSSessionPacket()
3545 r.set_type(nmb.NETBIOS_SESSION_POSITIVE_RESPONSE)
3546 r.set_trailer(p.get_trailer())
3547 self.__request.send(r.rawData())
3549 resp = self.__SMB.processRequest(self.__connId, p.get_trailer())
3550 # Send all the packets recevied. Except for big transactions this should be
3553 session.send_packet(str(i))
3554 except Exception, e:
3555 self.__SMB.log("Handle: %s" % e)
3557 #traceback.print_exc()
3561 # Thread/process is dying, we should tell the main SMB thread to remove all this thread data
3562 self.__SMB.log("Closing down connection (%s,%d)" % (self.__ip, self.__port))
3563 self.__SMB.removeConnection(self.__connId)
3564 return SocketServer.BaseRequestHandler.finish(self)
3566 class SMBSERVER(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
3567 #class SMBSERVER(SocketServer.ForkingMixIn, SocketServer.TCPServer):
3568 def __init__(self, server_address, handler_class=SMBSERVERHandler, config_parser = None):
3569 SocketServer.TCPServer.allow_reuse_address = True
3570 SocketServer.TCPServer.__init__(self, server_address, handler_class)
3572 # Server name and OS to be presented whenever is necessary
3573 self.__serverName = ''
3574 self.__serverOS = ''
3575 self.__serverDomain = ''
3576 self.__challenge = ''
3579 # Our ConfigParser data
3580 self.__serverConfig = config_parser
3582 # Our credentials to be used during the server's lifetime
3583 self.__credentials = {}
3588 # Registered Named Pipes, format is PipeName,Socket
3589 self.__registeredNamedPipes = {}
3592 self.__jtr_dump_path = ''
3594 # SMB2 Support flag = default not active
3595 self.__SMB2Support = False
3597 # Our list of commands we will answer, by default the NOT IMPLEMENTED one
3598 self.__smbCommandsHandler = SMBCommands()
3599 self.__smbTrans2Handler = TRANS2Commands()
3600 self.__smbTransHandler = TRANSCommands()
3601 self.__smbNTTransHandler = NTTRANSCommands()
3602 self.__smb2CommandsHandler = SMB2Commands()
3603 self.__IoctlHandler = Ioctls()
3605 self.__smbNTTransCommands = {
3606 # NT IOCTL, can't find doc for this
3607 0xff :self.__smbNTTransHandler.default
3610 self.__smbTransCommands = {
3611 '\\PIPE\\LANMAN' :self.__smbTransHandler.lanMan,
3612 smb.SMB.TRANS_TRANSACT_NMPIPE :self.__smbTransHandler.transactNamedPipe,
3614 self.__smbTrans2Commands = {
3615 smb.SMB.TRANS2_FIND_FIRST2 :self.__smbTrans2Handler.findFirst2,
3616 smb.SMB.TRANS2_FIND_NEXT2 :self.__smbTrans2Handler.findNext2,
3617 smb.SMB.TRANS2_QUERY_FS_INFORMATION :self.__smbTrans2Handler.queryFsInformation,
3618 smb.SMB.TRANS2_QUERY_PATH_INFORMATION :self.__smbTrans2Handler.queryPathInformation,
3619 smb.SMB.TRANS2_QUERY_FILE_INFORMATION :self.__smbTrans2Handler.queryFileInformation,
3620 smb.SMB.TRANS2_SET_FILE_INFORMATION :self.__smbTrans2Handler.setFileInformation,
3621 smb.SMB.TRANS2_SET_PATH_INFORMATION :self.__smbTrans2Handler.setPathInformation
3624 self.__smbCommands = {
3625 #smb.SMB.SMB_COM_FLUSH: self.__smbCommandsHandler.smbComFlush,
3626 smb.SMB.SMB_COM_CREATE_DIRECTORY: self.__smbCommandsHandler.smbComCreateDirectory,
3627 smb.SMB.SMB_COM_DELETE_DIRECTORY: self.__smbCommandsHandler.smbComDeleteDirectory,
3628 smb.SMB.SMB_COM_RENAME: self.__smbCommandsHandler.smbComRename,
3629 smb.SMB.SMB_COM_DELETE: self.__smbCommandsHandler.smbComDelete,
3630 smb.SMB.SMB_COM_NEGOTIATE: self.__smbCommandsHandler.smbComNegotiate,
3631 smb.SMB.SMB_COM_SESSION_SETUP_ANDX: self.__smbCommandsHandler.smbComSessionSetupAndX,
3632 smb.SMB.SMB_COM_LOGOFF_ANDX: self.__smbCommandsHandler.smbComLogOffAndX,
3633 smb.SMB.SMB_COM_TREE_CONNECT_ANDX: self.__smbCommandsHandler.smbComTreeConnectAndX,
3634 smb.SMB.SMB_COM_TREE_DISCONNECT: self.__smbCommandsHandler.smbComTreeDisconnect,
3635 smb.SMB.SMB_COM_ECHO: self.__smbCommandsHandler.smbComEcho,
3636 smb.SMB.SMB_COM_QUERY_INFORMATION: self.__smbCommandsHandler.smbQueryInformation,
3637 smb.SMB.SMB_COM_TRANSACTION2: self.__smbCommandsHandler.smbTransaction2,
3638 smb.SMB.SMB_COM_TRANSACTION: self.__smbCommandsHandler.smbTransaction,
3639 # Not needed for now
3640 smb.SMB.SMB_COM_NT_TRANSACT: self.__smbCommandsHandler.smbNTTransact,
3641 smb.SMB.SMB_COM_QUERY_INFORMATION_DISK: self.__smbCommandsHandler.smbQueryInformationDisk,
3642 smb.SMB.SMB_COM_OPEN_ANDX: self.__smbCommandsHandler.smbComOpenAndX,
3643 smb.SMB.SMB_COM_QUERY_INFORMATION2: self.__smbCommandsHandler.smbComQueryInformation2,
3644 smb.SMB.SMB_COM_READ_ANDX: self.__smbCommandsHandler.smbComReadAndX,
3645 smb.SMB.SMB_COM_READ: self.__smbCommandsHandler.smbComRead,
3646 smb.SMB.SMB_COM_WRITE_ANDX: self.__smbCommandsHandler.smbComWriteAndX,
3647 smb.SMB.SMB_COM_WRITE: self.__smbCommandsHandler.smbComWrite,
3648 smb.SMB.SMB_COM_CLOSE: self.__smbCommandsHandler.smbComClose,
3649 smb.SMB.SMB_COM_LOCKING_ANDX: self.__smbCommandsHandler.smbComLockingAndX,
3650 smb.SMB.SMB_COM_NT_CREATE_ANDX: self.__smbCommandsHandler.smbComNtCreateAndX,
3651 0xFF: self.__smbCommandsHandler.default
3654 self.__smb2Ioctls = {
3655 smb2.FSCTL_DFS_GET_REFERRALS: self.__IoctlHandler.fsctlDfsGetReferrals,
3656 # smb2.FSCTL_PIPE_PEEK: self.__IoctlHandler.fsctlPipePeek,
3657 # smb2.FSCTL_PIPE_WAIT: self.__IoctlHandler.fsctlPipeWait,
3658 smb2.FSCTL_PIPE_TRANSCEIVE: self.__IoctlHandler.fsctlPipeTransceive,
3659 # smb2.FSCTL_SRV_COPYCHUNK: self.__IoctlHandler.fsctlSrvCopyChunk,
3660 # smb2.FSCTL_SRV_ENUMERATE_SNAPSHOTS: self.__IoctlHandler.fsctlSrvEnumerateSnapshots,
3661 # smb2.FSCTL_SRV_REQUEST_RESUME_KEY: self.__IoctlHandler.fsctlSrvRequestResumeKey,
3662 # smb2.FSCTL_SRV_READ_HASH: self.__IoctlHandler.fsctlSrvReadHash,
3663 # smb2.FSCTL_SRV_COPYCHUNK_WRITE: self.__IoctlHandler.fsctlSrvCopyChunkWrite,
3664 # smb2.FSCTL_LMR_REQUEST_RESILIENCY: self.__IoctlHandler.fsctlLmrRequestResiliency,
3665 # smb2.FSCTL_QUERY_NETWORK_INTERFACE_INFO: self.__IoctlHandler.fsctlQueryNetworkInterfaceInfo,
3666 # smb2.FSCTL_SET_REPARSE_POINT: self.__IoctlHandler.fsctlSetReparsePoint,
3667 # smb2.FSCTL_DFS_GET_REFERRALS_EX: self.__IoctlHandler.fsctlDfsGetReferralsEx,
3668 # smb2.FSCTL_FILE_LEVEL_TRIM: self.__IoctlHandler.fsctlFileLevelTrim,
3669 smb2.FSCTL_VALIDATE_NEGOTIATE_INFO: self.__IoctlHandler.fsctlValidateNegotiateInfo,
3672 self.__smb2Commands = {
3673 smb2.SMB2_NEGOTIATE: self.__smb2CommandsHandler.smb2Negotiate,
3674 smb2.SMB2_SESSION_SETUP: self.__smb2CommandsHandler.smb2SessionSetup,
3675 smb2.SMB2_LOGOFF: self.__smb2CommandsHandler.smb2Logoff,
3676 smb2.SMB2_TREE_CONNECT: self.__smb2CommandsHandler.smb2TreeConnect,
3677 smb2.SMB2_TREE_DISCONNECT: self.__smb2CommandsHandler.smb2TreeDisconnect,
3678 smb2.SMB2_CREATE: self.__smb2CommandsHandler.smb2Create,
3679 smb2.SMB2_CLOSE: self.__smb2CommandsHandler.smb2Close,
3680 smb2.SMB2_FLUSH: self.__smb2CommandsHandler.smb2Flush,
3681 smb2.SMB2_READ: self.__smb2CommandsHandler.smb2Read,
3682 smb2.SMB2_WRITE: self.__smb2CommandsHandler.smb2Write,
3683 smb2.SMB2_LOCK: self.__smb2CommandsHandler.smb2Lock,
3684 smb2.SMB2_IOCTL: self.__smb2CommandsHandler.smb2Ioctl,
3685 smb2.SMB2_CANCEL: self.__smb2CommandsHandler.smb2Cancel,
3686 smb2.SMB2_ECHO: self.__smb2CommandsHandler.smb2Echo,
3687 smb2.SMB2_QUERY_DIRECTORY: self.__smb2CommandsHandler.smb2QueryDirectory,
3688 smb2.SMB2_CHANGE_NOTIFY: self.__smb2CommandsHandler.smb2ChangeNotify,
3689 smb2.SMB2_QUERY_INFO: self.__smb2CommandsHandler.smb2QueryInfo,
3690 smb2.SMB2_SET_INFO: self.__smb2CommandsHandler.smb2SetInfo,
3691 # smb2.SMB2_OPLOCK_BREAK: self.__smb2CommandsHandler.smb2SessionSetup,
3692 0xFF: self.__smb2CommandsHandler.default
3695 # List of active connections
3696 self.__activeConnections = {}
3698 def getIoctls(self):
3699 return self.__smb2Ioctls
3701 def getCredentials(self):
3702 return self.__credentials
3704 def removeConnection(self, name):
3706 del(self.__activeConnections[name])
3709 self.log("Remaining connections %s" % self.__activeConnections.keys())
3711 def addConnection(self, name, ip, port):
3712 self.__activeConnections[name] = {}
3713 # Let's init with some know stuff we will need to have
3714 # TODO: Document what's in there
3715 #print "Current Connections", self.__activeConnections.keys()
3716 self.__activeConnections[name]['PacketNum'] = 0
3717 self.__activeConnections[name]['ClientIP'] = ip
3718 self.__activeConnections[name]['ClientPort'] = port
3719 self.__activeConnections[name]['Uid'] = 0
3720 self.__activeConnections[name]['ConnectedShares'] = {}
3721 self.__activeConnections[name]['OpenedFiles'] = {}
3722 # SID results for findfirst2
3723 self.__activeConnections[name]['SIDs'] = {}
3724 self.__activeConnections[name]['LastRequest'] = {}
3726 def getActiveConnections(self):
3727 return self.__activeConnections
3729 def setConnectionData(self, connId, data):
3730 self.__activeConnections[connId] = data
3731 #print "setConnectionData"
3732 #print self.__activeConnections
3734 def getConnectionData(self, connId, checkStatus = True):
3735 conn = self.__activeConnections[connId]
3736 if checkStatus is True:
3737 if conn.has_key('Authenticated') is not True:
3738 # Can't keep going further
3739 raise Exception("User not Authenticated!")
3742 def getRegisteredNamedPipes(self):
3743 return self.__registeredNamedPipes
3745 def registerNamedPipe(self, pipeName, address):
3746 self.__registeredNamedPipes[unicode(pipeName)] = address
3749 def unregisterNamedPipe(self, pipeName):
3750 if self.__registeredNamedPipes.has_key(pipeName):
3751 del(self.__registeredNamedPipes[unicode(pipeName)])
3755 def unregisterTransaction(self, transCommand):
3756 if self.__smbTransCommands.has_key(transCommand):
3757 del(self.__smbTransCommands[transCommand])
3759 def hookTransaction(self, transCommand, callback):
3760 # If you call this function, callback will replace
3761 # the current Transaction sub command.
3762 # (don't get confused with the Transaction smbCommand)
3763 # If the transaction sub command doesn't not exist, it is added
3764 # If the transaction sub command exists, it returns the original function # replaced
3766 # callback MUST be declared as:
3767 # callback(connId, smbServer, recvPacket, parameters, data, maxDataCount=0)
3771 # connId : the connection Id, used to grab/update information about
3772 # the current connection
3773 # smbServer : the SMBServer instance available for you to ask
3774 # configuration data
3775 # recvPacket : the full SMBPacket that triggered this command
3776 # parameters : the transaction parameters
3777 # data : the transaction data
3778 # maxDataCount: the max amount of data that can be transfered agreed
3782 # respSetup, respParameters, respData, errorCode
3786 # respSetup: the setup response of the transaction
3787 # respParameters: the parameters response of the transaction
3788 # respData: the data reponse of the transaction
3789 # errorCode: the NT error code
3791 if self.__smbTransCommands.has_key(transCommand):
3792 originalCommand = self.__smbTransCommands[transCommand]
3794 originalCommand = None
3796 self.__smbTransCommands[transCommand] = callback
3797 return originalCommand
3799 def unregisterTransaction2(self, transCommand):
3800 if self.__smbTrans2Commands.has_key(transCommand):
3801 del(self.__smbTrans2Commands[transCommand])
3803 def hookTransaction2(self, transCommand, callback):
3804 # Here we should add to __smbTrans2Commands
3805 # Same description as Transaction
3806 if self.__smbTrans2Commands.has_key(transCommand):
3807 originalCommand = self.__smbTrans2Commands[transCommand]
3809 originalCommand = None
3811 self.__smbTrans2Commands[transCommand] = callback
3812 return originalCommand
3814 def unregisterNTTransaction(self, transCommand):
3815 if self.__smbNTTransCommands.has_key(transCommand):
3816 del(self.__smbNTTransCommands[transCommand])
3818 def hookNTTransaction(self, transCommand, callback):
3819 # Here we should add to __smbNTTransCommands
3820 # Same description as Transaction
3821 if self.__smbNTTransCommands.has_key(transCommand):
3822 originalCommand = self.__smbNTTransCommands[transCommand]
3824 originalCommand = None
3826 self.__smbNTTransCommands[transCommand] = callback
3827 return originalCommand
3829 def unregisterSmbCommand(self, smbCommand):
3830 if self.__smbCommands.has_key(smbCommand):
3831 del(self.__smbCommands[smbCommand])
3833 def hookSmbCommand(self, smbCommand, callback):
3834 # Here we should add to self.__smbCommands
3835 # If you call this function, callback will replace
3836 # the current smbCommand.
3837 # If smbCommand doesn't not exist, it is added
3838 # If SMB command exists, it returns the original function replaced
3840 # callback MUST be declared as:
3841 # callback(connId, smbServer, SMBCommand, recvPacket)
3845 # connId : the connection Id, used to grab/update information about
3846 # the current connection
3847 # smbServer : the SMBServer instance available for you to ask
3848 # configuration data
3849 # SMBCommand: the SMBCommand itself, with its data and parameters.
3850 # Check smb.py:SMBCommand() for a reference
3851 # recvPacket: the full SMBPacket that triggered this command
3854 # <list of respSMBCommands>, <list of packets>, errorCode
3855 # <list of packets> has higher preference over commands, in case you
3856 # want to change the whole packet
3857 # errorCode: the NT error code
3859 # For SMB_COM_TRANSACTION2, SMB_COM_TRANSACTION and SMB_COM_NT_TRANSACT
3860 # the callback function is slightly different:
3862 # callback(connId, smbServer, SMBCommand, recvPacket, transCommands)
3866 # transCommands: a list of transaction subcommands already registered
3869 if self.__smbCommands.has_key(smbCommand):
3870 originalCommand = self.__smbCommands[smbCommand]
3872 originalCommand = None
3874 self.__smbCommands[smbCommand] = callback
3875 return originalCommand
3877 def unregisterSmb2Command(self, smb2Command):
3878 if self.__smb2Commands.has_key(smb2Command):
3879 del(self.__smb2Commands[smb2Command])
3881 def hookSmb2Command(self, smb2Command, callback):
3882 if self.__smb2Commands.has_key(smb2Command):
3883 originalCommand = self.__smb2Commands[smb2Command]
3885 originalCommand = None
3887 self.__smb2Commands[smb2Command] = callback
3888 return originalCommand
3890 def log(self, msg, level=logging.INFO):
3891 self.__log.log(level,msg)
3893 def getServerName(self):
3894 return self.__serverName
3896 def getServerOS(self):
3897 return self.__serverOS
3899 def getServerDomain(self):
3900 return self.__serverDomain
3902 def getSMBChallenge(self):
3903 return self.__challenge
3905 def getServerConfig(self):
3906 return self.__serverConfig
3908 def setServerConfig(self, config):
3909 self.__serverConfig = config
3911 def getJTRdumpPath(self):
3912 return self.__jtr_dump_path
3914 def verify_request(self, request, client_address):
3915 # TODO: Control here the max amount of processes we want to launch
3916 # returning False, closes the connection
3919 def processRequest(self, connId, data):
3921 # TODO: Process batched commands.
3925 packet = smb.NewSMBPacket(data = data)
3926 SMBCommand = smb.SMBCommand(packet['Data'][0])
3928 # Maybe a SMB2 packet?
3929 packet = smb2.SMB2Packet(data = data)
3932 # We might have compound requests
3933 compoundedPacketsResponse = []
3934 compoundedPackets = []
3936 # Search out list of implemented commands
3937 # We provide them with:
3938 # connId : representing the data for this specific connection
3939 # self : the SMBSERVER if they want to ask data to it
3940 # SMBCommand : the SMBCommand they are expecting to process
3941 # packet : the received packet itself, in case they need more data than the actual command
3942 # Only for Transactions
3943 # transCommand: a list of transaction subcommands
3945 # respCommands: a list of answers for the commands processed
3946 # respPacket : if the commands chose to directly craft packet/s, we use this and not the previous
3947 # this MUST be a list
3948 # errorCode : self explanatory
3950 if packet['Command'] == smb.SMB.SMB_COM_TRANSACTION2:
3951 respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
3956 self.__smbTrans2Commands)
3957 elif packet['Command'] == smb.SMB.SMB_COM_NT_TRANSACT:
3958 respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
3963 self.__smbNTTransCommands)
3964 elif packet['Command'] == smb.SMB.SMB_COM_TRANSACTION:
3965 respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
3970 self.__smbTransCommands)
3972 if self.__smbCommands.has_key(packet['Command']):
3973 if self.__SMB2Support is True:
3974 if packet['Command'] == smb.SMB.SMB_COM_NEGOTIATE:
3976 respCommands, respPackets, errorCode = self.__smb2Commands[smb2.SMB2_NEGOTIATE](connId, self, packet, True)
3978 except Exception, e:
3979 self.log('SMB2_NEGOTIATE: %s' % e, logging.ERROR)
3980 # If something went wrong, let's fallback to SMB1
3981 respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
3986 #self.__SMB2Support = False
3989 respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
3995 respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
4001 respCommands, respPackets, errorCode = self.__smbCommands[255](connId, self, SMBCommand, packet)
4003 compoundedPacketsResponse.append((respCommands, respPackets, errorCode))
4004 compoundedPackets.append(packet)
4009 if self.__smb2Commands.has_key(packet['Command']):
4010 if self.__SMB2Support is True:
4011 respCommands, respPackets, errorCode = self.__smb2Commands[packet['Command']](
4016 respCommands, respPackets, errorCode = self.__smb2Commands[255](connId, self, packet)
4018 respCommands, respPackets, errorCode = self.__smb2Commands[255](connId, self, packet)
4019 # Let's store the result for this compounded packet
4020 compoundedPacketsResponse.append((respCommands, respPackets, errorCode))
4021 compoundedPackets.append(packet)
4022 if packet['NextCommand'] != 0:
4023 data = data[packet['NextCommand']:]
4024 packet = smb2.SMB2Packet(data = data)
4028 except Exception, e:
4030 #traceback.print_exc()
4031 # Something wen't wrong, defaulting to Bad user ID
4032 self.log('processRequest (0x%x,%s)' % (packet['Command'],e), logging.ERROR)
4035 # We prepare the response packet to commands don't need to bother about that.
4036 connData = self.getConnectionData(connId, False)
4038 # Force reconnection loop.. This is just a test.. client will send me back credentials :)
4039 #connData['PacketNum'] += 1
4040 #if connData['PacketNum'] == 15:
4041 # connData['PacketNum'] = 0
4042 # # Something wen't wrong, defaulting to Bad user ID
4043 # self.log('Sending BAD USER ID!', logging.ERROR)
4045 # packet['Flags1'] |= smb.SMB.FLAGS1_REPLY
4046 # packet['Flags2'] = 0
4047 # errorCode = STATUS_SMB_BAD_UID
4048 # packet['ErrorCode'] = errorCode >> 16
4049 # packet['ErrorClass'] = errorCode & 0xff
4052 self.setConnectionData(connId, connData)
4055 for packetNum in range(len(compoundedPacketsResponse)):
4056 respCommands, respPackets, errorCode = compoundedPacketsResponse[packetNum]
4057 packet = compoundedPackets[packetNum]
4058 if respPackets is None:
4059 for respCommand in respCommands:
4061 respPacket = smb.NewSMBPacket()
4062 respPacket['Flags1'] = smb.SMB.FLAGS1_REPLY
4064 # TODO this should come from a per session configuration
4065 respPacket['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES | packet['Flags2'] & smb.SMB.FLAGS2_UNICODE
4066 #respPacket['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES
4067 #respPacket['Flags1'] = 0x98
4068 #respPacket['Flags2'] = 0xc807
4071 respPacket['Tid'] = packet['Tid']
4072 respPacket['Mid'] = packet['Mid']
4073 respPacket['Pid'] = packet['Pid']
4074 respPacket['Uid'] = connData['Uid']
4076 respPacket['ErrorCode'] = errorCode >> 16
4077 respPacket['_reserved'] = errorCode >> 8 & 0xff
4078 respPacket['ErrorClass'] = errorCode & 0xff
4079 respPacket.addCommand(respCommand)
4081 packetsToSend.append(respPacket)
4083 respPacket = smb2.SMB2Packet()
4084 respPacket['Flags'] = smb2.SMB2_FLAGS_SERVER_TO_REDIR
4086 respPacket['Flags'] |= smb2.SMB2_FLAGS_RELATED_OPERATIONS
4087 respPacket['Status'] = errorCode
4088 respPacket['CreditRequestResponse'] = packet['CreditRequestResponse']
4089 respPacket['Command'] = packet['Command']
4090 respPacket['CreditCharge'] = packet['CreditCharge']
4091 #respPacket['CreditCharge'] = 0
4092 respPacket['Reserved'] = packet['Reserved']
4093 respPacket['SessionID'] = connData['Uid']
4094 respPacket['MessageID'] = packet['MessageID']
4095 respPacket['TreeID'] = packet['TreeID']
4096 respPacket['Data'] = str(respCommand)
4097 packetsToSend.append(respPacket)
4099 # The SMBCommand took care of building the packet
4100 packetsToSend = respPackets
4103 # Let's build a compound answer
4106 for i in range(len(packetsToSend)-1):
4107 packet = packetsToSend[i]
4109 padLen = (8 - (len(packet) % 8) ) % 8
4110 packet['NextCommand'] = len(packet) + padLen
4111 finalData += str(packet) + padLen*'\x00'
4114 finalData += str(packetsToSend[len(packetsToSend)-1])
4115 packetsToSend = [finalData]
4117 # We clear the compound requests
4118 connData['LastRequest'] = {}
4120 return packetsToSend
4122 def processConfigFile(self, configFile = None):
4123 # TODO: Do a real config parser
4124 if self.__serverConfig is None:
4125 if configFile is None:
4126 configFile = 'smb.conf'
4127 self.__serverConfig = ConfigParser.ConfigParser()
4128 self.__serverConfig.read(configFile)
4130 self.__serverName = self.__serverConfig.get('global','server_name')
4131 self.__serverOS = self.__serverConfig.get('global','server_os')
4132 self.__serverDomain = self.__serverConfig.get('global','server_domain')
4133 self.__logFile = self.__serverConfig.get('global','log_file')
4134 if self.__serverConfig.has_option('global', 'challenge'):
4135 self.__challenge = self.__serverConfig.get('global', 'challenge')
4137 self.__challenge = 'A'*8
4139 if self.__serverConfig.has_option("global", "jtr_dump_path"):
4140 self.__jtr_dump_path = self.__serverConfig.get("global", "jtr_dump_path")
4142 if self.__serverConfig.has_option("global", "SMB2Support"):
4143 self.__SMB2Support = self.__serverConfig.getboolean("global","SMB2Support")
4145 self.__SMB2Support = False
4147 if self.__logFile != 'None':
4148 logging.basicConfig(filename = self.__logFile,
4149 level = logging.DEBUG,
4150 format="%(asctime)s: %(levelname)s: %(message)s",
4151 datefmt = '%m/%d/%Y %I:%M:%S %p')
4154 # Process the credentials
4155 credentials_fname = self.__serverConfig.get('global','credentials_file')
4156 if credentials_fname is not "":
4157 cred = open(credentials_fname)
4158 line = cred.readline()
4160 name, domain, lmhash, nthash = line.split(':')
4161 self.__credentials[name] = (domain, lmhash, nthash.strip('\r\n'))
4162 line = cred.readline()
4164 self.log('Config file parsed')
4166 # For windows platforms, opening a directory is not an option, so we set a void FD
4167 VOID_FILE_DESCRIPTOR = -1
4168 PIPE_FILE_DESCRIPTOR = -2