diff --git a/nselib/drda.lua b/nselib/drda.lua index e1a5de09c..add96201c 100644 --- a/nselib/drda.lua +++ b/nselib/drda.lua @@ -60,6 +60,7 @@ local bin = require "bin" local bit = require "bit" +local match = require "match" local nmap = require "nmap" local stdnse = require "stdnse" local string = require "string" @@ -120,11 +121,12 @@ SecMec = DRDAPacket = { new = function(self, drda_array) - local o = {} - setmetatable(o, self) - self.__index = self - o.drda_array = drda_array - o.count = #drda_array + local o = { + drda_array = drda_array, + count = #drda_array + } + setmetatable(o, self) + self.__index = self return o end, @@ -161,11 +163,12 @@ DRDAPacket = { DRDA = { new = function(self, ddm) - local o = {} - setmetatable(o, self) - self.__index = self - o.Parameters = {} - o.DDM = ddm + local o = { + Parameters = {}, + DDM = ddm + } + setmetatable(o, self) + self.__index = self return o end, @@ -256,7 +259,7 @@ DRDA = { local pos = 1 -- first read atleast enough so that we can populate the DDM - status, data = db2socket:recv( DDM_SIZE ) + status, data = db2socket:receive_buf( match.numbytes(DDM_SIZE), true ) if ( not(status) ) then stdnse.print_debug("drda.DRDA.receive: %s", data) return false, ("Failed to read at least %d bytes from socket"):format(DDM_SIZE) @@ -266,7 +269,7 @@ DRDA = { ddm:fromString( data ) self:setDDM( ddm ) - status, data = db2socket:recv( ddm.Length - 10 ) + status, data = db2socket:receive_buf( match.numbytes(ddm.Length - 10), true ) if ( not(status) ) then return false, ("Failed to read the remaining %d bytes of the DRDA message") end @@ -292,16 +295,13 @@ DRDAParameter = { -- @param data string containing the data portion of the DRDA parameter -- @return o DRDAParameter object new = function(self, codepoint, data) - local o = {} - setmetatable(o, self) - self.__index = self - o.CodePoint = codepoint - if ( data ) then - o.Data = data - o.Length = #o.Data + 4 - else - o.Length = 4 - end + local o = { + CodePoint = codepoint, + Data = data, + Length = ( data and #data + 4 or 4 ) + } + setmetatable(o, self) + self.__index = self return o end, @@ -378,16 +378,13 @@ DDM = { -- @param corelid -- @return DDM object new = function(self, codepoint, format, corelid) - local o = {} - setmetatable(o, self) - self.__index = self - o.CodePoint = codepoint - if ( format ) then - o.Format = format - end - if ( corelid ) then - o.CorelId = corelid - end + local o = { + CodePoint = codepoint, + Format = format, + CorelId = corelid + } + setmetatable(o, self) + self.__index = self return o end, @@ -529,8 +526,8 @@ Helper = { new = function(self) local o = {} - setmetatable(o, self) - self.__index = self + setmetatable(o, self) + self.__index = self return o end, @@ -541,9 +538,8 @@ Helper = { -- @return Status (true or false). -- @return Error code (if status is false). connect = function( self, host, port ) - self.db2socket = DB2Socket:new() - self.comm = Comm:new( self.db2socket ) - return self.db2socket:connect(host, port) + self.comm = Comm:new( host, port ) + return self.comm:connect() end, --- Closes an open connection. @@ -551,7 +547,7 @@ Helper = { -- @return Status (true or false). -- @return Error code (if status is false). close = function( self ) - self.db2socket:close() + self.comm:close() end, --- Returns Server Information (name, platform, version) @@ -676,14 +672,41 @@ Helper = { -- The communication class Comm = { - new = function(self, socket) - local o = {} - setmetatable(o, self) - self.__index = self - o.socket = socket + new = function(self, host, port) + local o = { + host = host, + port = port, + socket = nmap.new_socket() + } + setmetatable(o, self) + self.__index = self return o end, + connect = function(self) + return self.socket:connect(self.host, self.port) + end, + + close = function(self) + return self.socket:close() + end, + + recvDRDA = function( self ) + local status, err + local drda_tbl = {} + + repeat + local drda = DRDA:new() + status, err = drda:receive( self.socket ) + if ( not(status) ) then + return false, err + end + table.insert(drda_tbl, drda) + until ( not(drda.DDM:isChained()) ) + + return true, drda_tbl + end, + --- Sends a packet to the server and receives the response -- -- @param DRDAPacket @@ -691,14 +714,14 @@ Comm = { -- @return packet an instance of DRDAPacket exchDRDAPacket = function( self, packet ) local drda, err - local status, err = self.socket:sendDRDA( packet ) + local status, err = self.socket:send( tostring(packet) ) if ( not(status) ) then stdnse.print_debug("drda.Helper.login: ERROR: DB2Socket error: %s", err ) return false, ("ERROR: DB2Socket error: %s"):format( err ) end - status, drda = self.socket:recvDRDA() + status, drda = self:recvDRDA() if( not(status) ) then stdnse.print_debug("drda.Helper.login: ERROR: DB2Socket error: %s", drda ) return false, ("ERROR: DB2Socket error: %s"):format( drda ) @@ -710,117 +733,6 @@ Comm = { } --- The DB2Socket class --- --- Allows for reading an exact count of bytes opposed to the nmap socket --- implementation that does at least count of bytes. --- --- The DB2Socket makes use of nmaps underlying socket implementation and --- buffers the bytes exceeding the number asked for. The next call to the --- recv function will fetch bytes from the buffer and call --- the recieve_bytes function of the underlying when there --- are no more buffered bytes. --- --- The connect, close and send --- functions are wrappers around the same functions of the nmap socket code. --- Consult the nsedoc for additional information on these. -DB2Socket = { - - retries = 3, - - new = function(self) - local o = {} - setmetatable(o, self) - self.__index = self - o.Socket = nmap.new_socket() - o.Buffer = nil - return o - end, - - - --- Establishes a connection. - -- - -- @param hostid Host table, hostname, or IP address. - -- @param port Port table or number. - -- @param protocol "tcp", "udp", or - -- @return Status (true or false). - -- @return Error code (if status is false). - connect = function( self, hostid, port, protocol ) - return self.Socket:connect( hostid, port, protocol ) - end, - - --- Closes an open connection. - -- - -- @return Status (true or false). - -- @return Error code (if status is false). - close = function( self ) - return self.Socket:close() - end, - - --- Opposed to the socket:receive_bytes function, that returns - -- at least x bytes, this function returns the amount of bytes requested. - -- - -- @param count of bytes to read - -- @return true on success, false on failure - -- @return data containing bytes read from the socket - -- err containing error message if status is false - recv = function( self, count ) - local status, data - - self.Buffer = self.Buffer or "" - - if ( #self.Buffer < count ) then - status, data = self.Socket:receive_bytes( count - #self.Buffer ) - if ( not(status) or #data < count - #self.Buffer ) then - return false, data - end - self.Buffer = self.Buffer .. data - end - - data = self.Buffer:sub( 1, count ) - self.Buffer = self.Buffer:sub( count + 1) - - return true, data - end, - - --- Sends data over the socket - -- - -- @return Status (true or false). - -- @return Error code (if status is false). - send = function( self, data ) - return self.Socket:send( data ) - end, - - --- Sends a single or multiple DRDA's over the socket - -- - -- @param drda a single or a table containing multiple DRDA's - -- @return Status (true or false). - -- @return Error code (if status is false). - sendDRDA = function( self, drda ) - return self:send(tostring(drda)) - end, - - --- Reads a single or multiple DRDA's of the socket - -- - -- @return status (true or false) - -- @return drda table containing retrieved DRDA's - recvDRDA = function( self ) - local status, err - local drda_tbl = {} - - repeat - local drda = DRDA:new() - status, err = drda:receive( self ) - if ( not(status) ) then - return false, err - end - table.insert(drda_tbl, drda) - until ( not(drda.DDM:isChained()) ) - - return true, drda_tbl - end, -} - -- EBCDIC/ASCII Conversion tables a2e_hex = "00010203372D2E2F1605250B0C0D0E0F101112133C3D322618193F271C1D1E1F" a2e_hex = a2e_hex .. "405A7F7B5B6C507D4D5D5C4E6B604B61F0F1F2F3F4F5F6F7F8F97A5E4C7E6E6F"