# -*- coding: binary -*- module Rex module Proto module SMB class SimpleClient class OpenFile attr_accessor :name, :tree_id, :file_id, :mode, :client, :chunk_size def initialize(client, name, tree_id, file_id) self.client = client self.name = name self.tree_id = tree_id self.file_id = file_id self.chunk_size = 48000 end def delete begin self.close rescue end self.client.delete(self.name, self.tree_id) end # Close this open file def close self.client.close(self.file_id, self.tree_id) end # Read data from the file def read(length = nil, offset = 0) if (length == nil) data = '' fptr = offset ok = self.client.read(self.file_id, fptr, self.chunk_size) while (ok and ok['Payload'].v['DataLenLow'] > 0) buff = ok.to_s.slice( ok['Payload'].v['DataOffset'] + 4, ok['Payload'].v['DataLenLow'] ) data << buff if ok['Payload'].v['Remaining'] == 0 break end fptr += ok['Payload'].v['DataLenLow'] begin ok = self.client.read(self.file_id, fptr, self.chunk_size) rescue XCEPT::ErrorCode => e case e.error_code when 0x00050001 # Novell fires off an access denied error on EOF ok = nil else raise e end end end return data else ok = self.client.read(self.file_id, offset, length) data = ok.to_s.slice( ok['Payload'].v['DataOffset'] + 4, ok['Payload'].v['DataLenLow'] ) return data end end def << (data) self.write(data) end # Write data to the file def write(data, offset = 0) # Track our offset into the remote file fptr = offset # Duplicate the data so we can use slice! data = data.dup # Take our first chunk of bytes chunk = data.slice!(0, self.chunk_size) # Keep writing data until we run out while (chunk.length > 0) ok = self.client.write(self.file_id, fptr, chunk) cl = ok['Payload'].v['CountLow'] # Partial write, push the failed data back into the queue if (cl != chunk.length) data = chunk.slice(cl - 1, chunk.length - cl) + data end # Increment our painter and grab the next chunk fptr += cl chunk = data.slice!(0, self.chunk_size) end end end end end end end