async def tree_disconnect(self, tree_id): """ Disconnects from tree, removes all file entries associated to the tree """ if self.session_closed == True: return command = TREE_DISCONNECT_REQ() header = SMB2Header_SYNC() header.Command = SMB2Command.TREE_DISCONNECT header.TreeId = tree_id msg = SMB2Message(header, command) message_id = await self.sendSMB(msg) rply = await self.recvSMB(message_id) if rply.header.Status == NTStatus.SUCCESS: del_file_ids = [] share_name = self.TreeConnectTable_id[tree_id].share_name for fe in self.FileHandleTable: if self.FileHandleTable[fe].tree_id == tree_id: del_file_ids.append(self.FileHandleTable[fe].file_id) for file_id in del_file_ids: del self.FileHandleTable[file_id] del self.TreeConnectTable_id[tree_id] del self.TreeConnectTable_share[share_name]
async def echo(self): """ Issues an ECHO request to the server. Server will reply with and ECHO response, if it's still alive """ command = ECHO_REQ() header = SMB2Header_SYNC() header.Command = SMB2Command.ECHO msg = SMB2Message(header, command) message_id = await self.sendSMB(msg) rply = await self.recvSMB(message_id)
async def cancel(self, message_id): """ Issues a CANCEL command for the given message_id """ command = CANCEL_REQ() header = SMB2Header_SYNC() header.Command = SMB2Command.CANCEL msg.header.MessageId = message_id msg = SMB2Message(header, command) message_id = await self.sendSMB(msg) rply = await self.recvSMB(message_id)
async def query_directory( self, tree_id, file_id, search_pattern='*', resume_index=0, information_class=FileInfoClass.FileFullDirectoryInformation, maxBufferSize=None, flags=0): """ IMPORTANT: in case you are requesting big amounts of data, the result will arrive in chunks. You will need to invoke this function until None is returned to get the full data!!! """ if self.session_closed == True: return if tree_id not in self.TreeConnectTable_id: raise Exception('Unknown Tree ID!') if file_id not in self.FileHandleTable: raise Exception('Unknown File ID!') command = QUERY_DIRECTORY_REQ() command.FileInformationClass = information_class command.Flags = 0 if resume_index != 0: command.Flags |= QueryDirectoryFlag.SMB2_INDEX_SPECIFIED command.FileIndex = resume_index command.FileId = file_id command.FileName = search_pattern header = SMB2Header_SYNC() header.Command = SMB2Command.QUERY_DIRECTORY header.TreeId = tree_id msg = SMB2Message(header, command) message_id = await self.sendSMB(msg) rply = await self.recvSMB(message_id) if rply.header.Status == NTStatus.SUCCESS: if information_class == FileInfoClass.FileFullDirectoryInformation: return FileFullDirectoryInformationList.from_bytes( rply.command.Data) else: return rply.command.Data elif rply.header.Status == NTStatus.NO_MORE_FILES: return None else: raise Exception('query_directory reply: %s' % rply.header.Status)
async def logoff(self): """ Logs off from the server, effectively terminates the session. The underlying connection will still be active, so please either clean it up manually or dont touch this function For proper closing of the connection use the terminate function """ command = LOGOFF_REQ() header = SMB2Header_SYNC() header.Command = SMB2Command.LOGOFF msg = SMB2Message(header, command) message_id = await self.sendSMB(msg) rply = await self.recvSMB(message_id)
async def flush(tree_id, file_id): """ Flushes all cached data that may be on the server for the given file. """ command = FLUSH_REQ() command.FileId = file_id header = SMB2Header_SYNC() header.Command = SMB2Command.FLUSH header.TreeId = tree_id msg = SMB2Message(header, command) message_id = await self.sendSMB(msg) rply = await self.recvSMB(message_id)
async def close(self, tree_id, file_id, flags=CloseFlag.NONE): """ Closes the file/directory/pipe/whatever based on file_id. It will automatically remove all traces of the file handle. """ command = CLOSE_REQ() command.Flags = flags command.FileId = file_id header = SMB2Header_SYNC() header.Command = SMB2Command.CLOSE header.TreeId = tree_id msg = SMB2Message(header, command) message_id = await self.sendSMB(msg) rply = await self.recvSMB(message_id) if rply.header.Status == NTStatus.SUCCESS: del self.FileHandleTable[file_id]
async def negotiate(self): """ Initiates protocol negotiation. First we send an SMB_COM_NEGOTIATE_REQ with our supported dialects """ #let's construct an SMBv1 SMB_COM_NEGOTIATE_REQ packet header = SMBHeader() header.Command = SMBCommand.SMB_COM_NEGOTIATE header.Status = NTStatus.SUCCESS header.Flags = 0 header.Flags2 = SMBHeaderFlags2Enum.SMB_FLAGS2_UNICODE command = SMB_COM_NEGOTIATE_REQ() command.Dialects = ['SMB 2.???'] msg = SMBMessage(header, command) message_id = await self.sendSMB(msg) #recieveing reply, should be version2, because currently we dont support v1 :( rply = await self.recvSMB(message_id) #negotiate MessageId should be 1 if rply.header.Status == NTStatus.SUCCESS: if isinstance(rply, SMB2Message): if rply.command.DialectRevision == NegotiateDialects.WILDCARD: command = NEGOTIATE_REQ() command.SecurityMode = NegotiateSecurityMode.SMB2_NEGOTIATE_SIGNING_ENABLED | NegotiateSecurityMode.SMB2_NEGOTIATE_SIGNING_REQUIRED command.Capabilities = 0 command.ClientGuid = self.ClientGUID command.Dialects = self.dialects header = SMB2Header_SYNC() header.Command = SMB2Command.NEGOTIATE header.CreditReq = 0 msg = SMB2Message(header, command) message_id = await self.sendSMB(msg) rply = await self.recvSMB( message_id) #negotiate MessageId should be 1 if rply.header.Status != NTStatus.SUCCESS: print('session got reply!') print(rply) raise Exception( 'session_setup_1 (authentication probably failed) reply: %s' % rply.header.Status) if rply.command.DialectRevision not in self.supported_dialects: raise SMBUnsupportedDialectSelected() self.selected_dialect = rply.command.DialectRevision self.signing_required = NegotiateSecurityMode.SMB2_NEGOTIATE_SIGNING_ENABLED in rply.command.SecurityMode logger.log( 1, 'Server selected dialect: %s' % self.selected_dialect) self.MaxTransactSize = min(0x100000, rply.command.MaxTransactSize) self.MaxReadSize = min(0x100000, rply.command.MaxReadSize) self.MaxWriteSize = min(0x100000, rply.command.MaxWriteSize) self.ServerGuid = rply.command.ServerGuid self.SupportsMultiChannel = NegotiateCapabilities.MULTI_CHANNEL in rply.command.Capabilities else: logger.error( 'Server choose SMB v1 which is not supported currently') raise SMBUnsupportedSMBVersion() else: print('session got reply!') print(rply) raise Exception( 'session_setup_1 (authentication probably failed) reply: %s' % rply.header.Status) self.status = SMBConnectionStatus.SESSIONSETUP