From 769db9823a1469d7b315ab3bf0c79f1cd24b2f5f Mon Sep 17 00:00:00 2001 From: djalal Date: Sun, 26 Sep 2010 12:55:05 +0000 Subject: [PATCH] o Added the debug level to some print_debug() functions that were missing this argument. o Create the mutex in the RpcInfo() function before the connect call, to prevent some rare race conditions that can cause one of the running rpc and nfs scripts to fail. This mutex is used to cache the portmapper program list in the registry, to reduce the number of connections and RPC DUMP procedure calls. o whitespace formatting. --- nselib/rpc.lua | 1468 ++++++++++++++++++++++++------------------------ 1 file changed, 742 insertions(+), 726 deletions(-) diff --git a/nselib/rpc.lua b/nselib/rpc.lua index e17b0f4c7..3ba91a9f4 100644 --- a/nselib/rpc.lua +++ b/nselib/rpc.lua @@ -47,9 +47,9 @@ -- -- iterate over every share -- for _, mount in ipairs( mounts ) do -- --- -- get the NFS attributes for the share --- status, attribs = rpc.Helper.GetAttributes( host, port, mount.name ) --- .... process NFS attributes here .... +-- -- get the NFS attributes for the share +-- status, attribs = rpc.Helper.GetAttributes( host, port, mount.name ) +-- .... process NFS attributes here .... -- end -- -- @@ -96,28 +96,28 @@ require("datafiles") -- RPC args using the nmap.registry.args RPC_args = { - ["rpcbind"] = { proto = 'rpc.protocol' }, - ["nfs"] = { ver = 'nfs.version' }, - ["mountd"] = { ver = 'mount.version' }, + ["rpcbind"] = { proto = 'rpc.protocol' }, + ["nfs"] = { ver = 'nfs.version' }, + ["mountd"] = { ver = 'mount.version' }, } -- Defines the order in which to try to connect to the RPC programs -- TCP appears to be more stable than UDP in most cases, so try it first local RPC_PROTOCOLS = (nmap.registry.args and nmap.registry.args[RPC_args['rpcbind'].proto] and - type(nmap.registry.args[RPC_args['rpcbind'].proto]) == 'table') and - nmap.registry.args[RPC_args['rpcbind'].proto] or { "tcp", "udp" } + type(nmap.registry.args[RPC_args['rpcbind'].proto]) == 'table') and + nmap.registry.args[RPC_args['rpcbind'].proto] or { "tcp", "udp" } -- used to cache the contents of the rpc datafile local RPC_PROGRAMS --- local mutex to synchronize I/O operations on nmap.registry[host.ip]['portmap'] +-- local mutex to synchronize I/O operations on nmap.registry[host.ip]['portmapper'] local mutex = nmap.mutex("rpc") -- Supported protocol versions RPC_version = { - ["rpcbind"] = { min=2, max=2 }, - ["nfs"] = { min=1, max=3 }, - ["mountd"] = { min=1, max=3 }, + ["rpcbind"] = { min=2, max=2 }, + ["nfs"] = { min=1, max=3 }, + ["mountd"] = { min=1, max=3 }, } math.randomseed( os.time() ) @@ -125,264 +125,270 @@ math.randomseed( os.time() ) -- Low-level communication class Comm = { - --- Creats a new rpc Comm object - -- - -- @param program name string - -- @param version number containing the program version to use - -- @return a new Comm object - new = function(self, program, version) - local o = {} - setmetatable(o, self) - self.__index = self - o.program = program - o.program_id = Util.ProgNameToNumber(program) - o:SetVersion(version) - return o - end, + --- Creats a new rpc Comm object + -- + -- @param program name string + -- @param version number containing the program version to use + -- @return a new Comm object + new = function(self, program, version) + local o = {} + setmetatable(o, self) + self.__index = self + o.program = program + o.program_id = Util.ProgNameToNumber(program) + o:SetVersion(version) + return o + end, - --- Connects to the remote program - -- - -- @param host table - -- @param port table - -- @return status boolean true on success, false on failure - -- @return string containing error message (if status is false) - Connect = function(self, host, port) - local status, err, socket - status, err = self:ChkProgram() - if (not(status)) then - return status, err - end - status, err = self:ChkVersion() - if (not(status)) then - return status, err - end - socket = nmap.new_socket() - status, err = socket:connect(host, port) - if (not(status)) then - return status, string.format("%s connect error: %s", self.program, err) - else - self.socket = socket - self.ip = host.ip - self.port = port.number - self.proto = port.protocol - return status, nil - end - end, + --- Connects to the remote program + -- + -- @param host table + -- @param port table + -- @return status boolean true on success, false on failure + -- @return string containing error message (if status is false) + Connect = function(self, host, port) + local status, err, socket + status, err = self:ChkProgram() + if (not(status)) then + return status, err + end + status, err = self:ChkVersion() + if (not(status)) then + return status, err + end + socket = nmap.new_socket() + status, err = socket:connect(host, port) + if (not(status)) then + return status, string.format("%s connect error: %s", + self.program, err) + else + self.socket = socket + self.ip = host.ip + self.port = port.number + self.proto = port.protocol + return status, nil + end + end, - --- Disconnects from the remote program - -- - -- @return status boolean true on success, false on failure - -- @return string containing error message (if status is false) - Disconnect = function(self) - local status, err = self.socket:close() - if (not(status)) then - return status, string.format("%s disconnect error: %s", self.program, err) - end - self.socket=nil - return status, nil - end, + --- Disconnects from the remote program + -- + -- @return status boolean true on success, false on failure + -- @return string containing error message (if status is false) + Disconnect = function(self) + local status, err = self.socket:close() + if (not(status)) then + return status, string.format("%s disconnect error: %s", + self.program, err) + end + self.socket=nil + return status, nil + end, - --- Checks if the rpc program is supported - -- - -- @return status boolean true on success, false on failure - -- @return string containing error message (if status is false) - ChkProgram = function(self) - if (not(RPC_version[self.program])) then - return false, string.format("RPC library does not support: %s protocol", self.program) - end - return true, nil - end, + --- Checks if the rpc program is supported + -- + -- @return status boolean true on success, false on failure + -- @return string containing error message (if status is false) + ChkProgram = function(self) + if (not(RPC_version[self.program])) then + return false, string.format("RPC library does not support: %s protocol", + self.program) + end + return true, nil + end, - --- Checks if the rpc program version is supported - -- - -- @return status boolean true on success, false on failure - -- @return string containing error message (if status is false) - ChkVersion = function(self) - if ( self.version > RPC_version[self.program].max or self.version < RPC_version[self.program].min ) then - return false, string.format("RPC library does not support: %s version %d",self.program,self.version) - end - return true, nil - end, + --- Checks if the rpc program version is supported + -- + -- @return status boolean true on success, false on failure + -- @return string containing error message (if status is false) + ChkVersion = function(self) + if ( self.version > RPC_version[self.program].max or + self.version < RPC_version[self.program].min ) then + return false, string.format("RPC library does not support: %s version %d", + self.program,self.version) + end + return true, nil + end, - --- Sets the rpc program version - -- - -- @return status boolean true - SetVersion = function(self, version) - if (RPC_version[self.program] and RPC_args[self.program] and - nmap.registry.args and nmap.registry.args[RPC_args[self.program].ver]) then - self.version = tonumber(nmap.registry.args[RPC_args[self.program].ver]) - elseif (not(self.version) and version) then - self.version = version - end - return true, nil - end, + --- Sets the rpc program version + -- + -- @return status boolean true + SetVersion = function(self, version) + if (RPC_version[self.program] and RPC_args[self.program] and + nmap.registry.args and nmap.registry.args[RPC_args[self.program].ver]) then + self.version = tonumber(nmap.registry.args[RPC_args[self.program].ver]) + elseif (not(self.version) and version) then + self.version = version + end + return true, nil + end, - --- Checks if data contains enough bytes to read the needed amount - -- If it doesn't it attempts to read the remaining amount of bytes from the socket - -- - -- @param data string containing the current buffer - -- @param pos number containing the current offset into the buffer - -- @param needed number containing the number of bytes needed to be available - -- @return status success or failure - -- @return data string containing the data passed to the function and the additional data appended to it or error message on failure - GetAdditionalBytes = function( self, data, pos, needed ) + --- Checks if data contains enough bytes to read the needed amount + -- If it doesn't it attempts to read the remaining amount of bytes from the socket + -- + -- @param data string containing the current buffer + -- @param pos number containing the current offset into the buffer + -- @param needed number containing the number of bytes needed to be available + -- @return status success or failure + -- @return data string containing the data passed to the function and the additional data appended to it or error message on failure + GetAdditionalBytes = function( self, data, pos, needed ) + local status, tmp - local status, tmp + if data:len() - pos + 1 < needed then + local toread = needed - ( data:len() - pos + 1 ) + status, tmp = self.socket:receive_bytes( toread ) + if status then + data = data .. tmp + else + return false, string.format("getAdditionalBytes() failed to read: %d bytes from the socket", + needed - ( data:len() - pos ) ) + end + end + return true, data + end, - if data:len() - pos + 1 < needed then - local toread = needed - ( data:len() - pos + 1 ) - status, tmp = self.socket:receive_bytes( toread ) - if status then - data = data .. tmp - else - return false, string.format("getAdditionalBytes() failed to read: %d bytes from the socket", needed - ( data:len() - pos ) ) - end - end - return true, data - end, + --- Creates a RPC header + -- + -- @param xid number + -- @param procedure number containing the procedure to call + -- @param auth table containing the authentication data to use + -- @return status boolean true on success, false on failure + -- @return string of bytes on success, error message on failure + CreateHeader = function( self, xid, procedure, auth ) + local RPC_VERSION = 2 + local packet - --- Creates a RPC header - -- - -- @param xid number - -- @param procedure number containing the procedure to call - -- @param auth table containing the authentication data to use - -- @return status boolean true on success, false on failure - -- @return string of bytes on success, error message on failure - CreateHeader = function( self, xid, procedure, auth ) - local RPC_VERSION = 2 - local packet + if not(xid) then + xid = math.random(1234567890) + end + if not auth then + return false, "Comm.CreateHeader: No authentication specified" + elseif auth.type ~= Portmap.AuthType.NULL then + return false, "Comm.CreateHeader: invalid authentication type specified" + end - if not(xid) then - xid = math.random(1234567890) - end - if not auth then - return false, "Comm.CreateHeader: No authentication specified" - elseif auth.type ~= Portmap.AuthType.NULL then - return false, "Comm.CreateHeader: invalid authentication type specified" - end + packet = bin.pack( ">IIIIII", xid, Portmap.MessageType.CALL, RPC_VERSION, self.program_id, self.version, procedure ) + if auth.type == Portmap.AuthType.NULL then + packet = packet .. bin.pack( "IIII", 0, 0, 0, 0 ) + end + return true, packet + end, - packet = bin.pack( ">IIIIII", xid, Portmap.MessageType.CALL, RPC_VERSION, self.program_id, self.version, procedure ) - if auth.type == Portmap.AuthType.NULL then - packet = packet .. bin.pack( "IIII", 0, 0, 0, 0 ) - end - return true, packet - end, + --- Decodes the RPC header (without the leading 4 bytes as received over TCP) + -- + -- @param data string containing the buffer of bytes read so far + -- @param pos number containing the current offset into data + -- @return pos number containing the offset after the decoding + -- @return header table containing xid, type, state, + -- verifier and ( accept_state or denied_state ) + DecodeHeader = function( self, data, pos ) + local header = {} + local status - --- Decodes the RPC header (without the leading 4 bytes as received over TCP) - -- - -- @param data string containing the buffer of bytes read so far - -- @param pos number containing the current offset into data - -- @return pos number containing the offset after the decoding - -- @return header table containing xid, type, state, - -- verifier and ( accept_state or denied_state ) - DecodeHeader = function( self, data, pos ) - local header = {} - local status + local HEADER_LEN = 20 - local HEADER_LEN = 20 + header.verifier = {} - header.verifier = {} + if ( data:len() - pos < HEADER_LEN ) then + local tmp + status, tmp = self:GetAdditionalBytes( data, pos, HEADER_LEN - ( data:len() - pos ) ) + if not status then + stdnse.print_debug(4, + string.format("Comm.ReceivePacket: failed to call GetAdditionalBytes")) + return -1, nil + end + data = data .. tmp + end - if ( data:len() - pos < HEADER_LEN ) then - local tmp - status, tmp = self:GetAdditionalBytes( data, pos, HEADER_LEN - ( data:len() - pos ) ) - if not status then - stdnse.print_debug(string.format("Comm.ReceivePacket: failed to call GetAdditionalBytes")) - return -1, nil - end - data = data .. tmp - end + pos, header.xid, header.type, header.state = bin.unpack(">III", data, pos) - pos, header.xid, header.type, header.state = bin.unpack(">III", data, pos) + if ( header.state == Portmap.State.MSG_DENIED ) then + pos, header.denied_state = bin.unpack(">I", data, pos ) + return pos, header + end - if ( header.state == Portmap.State.MSG_DENIED ) then - pos, header.denied_state = bin.unpack(">I", data, pos ) - return pos, header - end + pos, header.verifier.flavor = bin.unpack(">I", data, pos) + pos, header.verifier.length = bin.unpack(">I", data, pos) - pos, header.verifier.flavor = bin.unpack(">I", data, pos) - pos, header.verifier.length = bin.unpack(">I", data, pos) + if header.verifier.length - 8 > 0 then + status, data = self:GetAdditionalBytes( data, pos, header.verifier.length - 8 ) + if not status then + stdnse.print_debug(4, + string.format("Comm.ReceivePacket: failed to call GetAdditionalBytes")) + return -1, nil + end + pos, header.verifier.data = bin.unpack("A" .. header.verifier.length - 8, data, pos ) + end + pos, header.accept_state = bin.unpack(">I", data, pos ) - if header.verifier.length - 8 > 0 then - status, data = self:GetAdditionalBytes( data, pos, header.verifier.length - 8 ) - if not status then - stdnse.print_debug(string.format("Comm.ReceivePacket: failed to call GetAdditionalBytes")) - return -1, nil - end - pos, header.verifier.data = bin.unpack("A" .. header.verifier.length - 8, data, pos ) - end - pos, header.accept_state = bin.unpack(">I", data, pos ) + return pos, header + end, + --- Reads the response from the socket + -- + -- @return status true on success, false on failure + -- @return data string containing the raw response or error message on failure + ReceivePacket = function( self ) + local status - return pos, header - end, + if ( self.proto == "udp" ) then + -- There's not much we can do in here to check if we received all data + -- as the packet contains no length field. It's up to each decoding function + -- to do appropriate checks + return self.socket:receive_bytes(1) + else + local tmp, lastfragment, length + local data, pos = "", 1 - --- Reads the response from the socket - -- - -- @return status true on success, false on failure - -- @return data string containing the raw response or error message on failure - ReceivePacket = function( self ) - local status + repeat + lastfragment = false + status, data = self:GetAdditionalBytes( data, pos, 4 ) + if ( not(status) ) then + return false, "Comm.ReceivePacket: failed to call GetAdditionalBytes" + end - if ( self.proto == "udp" ) then - -- There's not much we can do in here to check if we received all data - -- as the packet contains no length field. It's up to each decoding function - -- to do appropriate checks - return self.socket:receive_bytes(1) - else - local tmp, lastfragment, length - local data, pos = "", 1 + pos, tmp = bin.unpack(">i", data, pos ) + length = bit.band( tmp, 0x7FFFFFFF ) - repeat - lastfragment = false - status, data = self:GetAdditionalBytes( data, pos, 4 ) - if ( not(status) ) then - return false, "Comm.ReceivePacket: failed to call GetAdditionalBytes" - end + if ( bit.band( tmp, 0x80000000 ) == 0x80000000 ) then + lastfragment = true + end - pos, tmp = bin.unpack(">i", data, pos ) - length = bit.band( tmp, 0x7FFFFFFF ) + status, data = self:GetAdditionalBytes( data, pos, length ) + if ( not(status) ) then + return false, "Comm.ReceivePacket: failed to call GetAdditionalBytes" + end - if ( bit.band( tmp, 0x80000000 ) == 0x80000000 ) then - lastfragment = true - end + -- + -- When multiple packets are received they look like this + -- H = Header data + -- D = Data + -- + -- We don't want the Header + -- + -- HHHHDDDDDDDDDDDDDDHHHHDDDDDDDDDDD + -- ^ ^ ^ ^ + -- 1 5 18 22 + -- + -- eg. we want + -- data:sub(5, 18) and data:sub(22) + -- - status, data = self:GetAdditionalBytes( data, pos, length ) - if ( not(status) ) then - return false, "Comm.ReceivePacket: failed to call GetAdditionalBytes" - end + local bufcopy = data:sub(pos) - -- - -- When multiple packets are received they look like this - -- H = Header data - -- D = Data - -- - -- We don't want the Header - -- - -- HHHHDDDDDDDDDDDDDDHHHHDDDDDDDDDDD - -- ^ ^ ^ ^ - -- 1 5 18 22 - -- - -- eg. we want - -- data:sub(5, 18) and data:sub(22) - -- + if 1 ~= pos - 4 then + bufcopy = data:sub(1, pos - 5) .. bufcopy + pos = pos - 4 + else + pos = 1 + end - local bufcopy = data:sub(pos) + pos = pos + length + data = bufcopy + until lastfragment == true + return true, data + end + end, - if 1 ~= pos - 4 then - bufcopy = data:sub(1, pos - 5) .. bufcopy - pos = pos - 4 - else - pos = 1 - end - - pos = pos + length - data = bufcopy - until lastfragment == true - return true, data - end - end, - --- Encodes a RPC packet -- -- @param xid number containing the transaction ID @@ -416,205 +422,200 @@ Comm = { --- Portmap (rpcbind) class Portmap = { - PROTOCOLS = { - ['tcp'] = 6, - ['udp'] = 17, - }, - - -- TODO: add more Authentication Protocols - AuthType = - { - NULL = 0 - }, + PROTOCOLS = { + ['tcp'] = 6, + ['udp'] = 17, + }, - -- TODO: complete Authentication stats and error messages - AuthState = - { - AUTH_OK = 0, - AUTH_BADCRED = 1, - AUTH_REJECTEDCRED = 2, - AUTH_BADVERF = 3, - AUTH_REJECTEDVERF = 4, - AUTH_TOOWEAK = 5, - AUTH_INVALIDRESP = 6, - AUTH_FAILED = 7, - }, + -- TODO: add more Authentication Protocols + AuthType = + { + NULL = 0 + }, - AuthMsg = - { - [0] = "Success.", - [1] = "bad credential (seal broken).", - [2] = "client must begin new session.", - [3] = "bad verifier (seal broken).", - [4] = "verifier expired or replayed.", - [5] = "rejected for security reasons.", - [6] = "bogus response verifier.", - [7] = "reason unknown.", - }, + -- TODO: complete Authentication stats and error messages + AuthState = + { + AUTH_OK = 0, + AUTH_BADCRED = 1, + AUTH_REJECTEDCRED = 2, + AUTH_BADVERF = 3, + AUTH_REJECTEDVERF = 4, + AUTH_TOOWEAK = 5, + AUTH_INVALIDRESP = 6, + AUTH_FAILED = 7, + }, - MessageType = - { - CALL = 0, - REPLY = 1 - }, + AuthMsg = + { + [0] = "Success.", + [1] = "bad credential (seal broken).", + [2] = "client must begin new session.", + [3] = "bad verifier (seal broken).", + [4] = "verifier expired or replayed.", + [5] = "rejected for security reasons.", + [6] = "bogus response verifier.", + [7] = "reason unknown.", + }, - Procedure = - { - [2] = - { - GETPORT = 3, - DUMP = 4, - }, - - }, - - State = - { - MSG_ACCEPTED = 0, - MSG_DENIED = 1, - }, - - AcceptState = - { - SUCCESS = 0, - PROG_UNAVAIL = 1, - PROG_MISMATCH = 2, - PROC_UNAVAIL = 3, - GARBAGE_ARGS = 4, - SYSTEM_ERR = 5, - }, + MessageType = + { + CALL = 0, + REPLY = 1 + }, - AcceptMsg = - { - [0] = "RPC executed successfully.", - [1] = "remote hasn't exported program.", - [2] = "remote can't support version.", - [3] = "program can't support procedure.", - [4] = "procedure can't decode params.", - [5] = "errors like memory allocation failure.", - }, + Procedure = + { + [2] = + { + GETPORT = 3, + DUMP = 4, + }, - RejectState = - { - RPC_MISMATCH = 0, - AUTH_ERROR = 1, - }, + }, + + State = + { + MSG_ACCEPTED = 0, + MSG_DENIED = 1, + }, + + AcceptState = + { + SUCCESS = 0, + PROG_UNAVAIL = 1, + PROG_MISMATCH = 2, + PROC_UNAVAIL = 3, + GARBAGE_ARGS = 4, + SYSTEM_ERR = 5, + }, - RejectMsg = - { - [0] = "RPC version number != 2.", - [1] = "remote can't authenticate caller.", - }, + AcceptMsg = + { + [0] = "RPC executed successfully.", + [1] = "remote hasn't exported program.", + [2] = "remote can't support version.", + [3] = "program can't support procedure.", + [4] = "procedure can't decode params.", + [5] = "errors like memory allocation failure.", + }, - new = function(self,o) - o = o or {} - setmetatable(o, self) - self.__index = self - return o - end, - - --- Dumps a list of RCP programs from the portmapper - -- - -- @param comm object handles rpc program information and - -- low-level packet manipulation - -- @return status boolean true on success, false on failure - -- @return result table containing RPC program information or error message - -- on failure. The table has the following format: - -- - -- - -- table[program_id][protocol]["port"] = - -- table[program_id][protocol]["version"] = - -- - -- - -- Where - -- o program_id is the number associated with the program - -- o protocol is either "tcp" or "udp" - -- - Dump = function(self, comm) - local status, data, packet, response, pos, header - local program_table = setmetatable({}, { __mode = 'v' }) + RejectState = + { + RPC_MISMATCH = 0, + AUTH_ERROR = 1, + }, - if nmap.registry[comm.ip] == nil then - nmap.registry[comm.ip] = {} - end - if nmap.registry[comm.ip]['portmap'] == nil then - nmap.registry[comm.ip]['portmap'] = {} - elseif next(nmap.registry[comm.ip]['portmap']) ~= nil then - return true, nmap.registry[comm.ip]['portmap'] - end + RejectMsg = + { + [0] = "RPC version number != 2.", + [1] = "remote can't authenticate caller.", + }, - packet = comm:EncodePacket( nil, Portmap.Procedure[comm.version].DUMP, { type=Portmap.AuthType.NULL }, data ) - if (not(comm:SendPacket(packet))) then - return false, "Portmap.Dump: Failed to send data" - end - status, data = comm:ReceivePacket() - if ( not(status) ) then - return false, "Portmap.Dump: Failed to read data from socket" - end + new = function(self,o) + o = o or {} + setmetatable(o, self) + self.__index = self + return o + end, - pos, header = comm:DecodeHeader( data, 1 ) - if ( not(header) ) then - return false, "Portmap.Dump: Failed to decode RPC header" - end + --- Dumps a list of RCP programs from the portmapper + -- + -- @param comm object handles rpc program information and + -- low-level packet manipulation + -- @return status boolean true on success, false on failure + -- @return result table containing RPC program information or error message + -- on failure. The table has the following format: + -- + -- + -- table[program_id][protocol]["port"] = + -- table[program_id][protocol]["version"] =
+ -- + -- + -- Where + -- o program_id is the number associated with the program + -- o protocol is either "tcp" or "udp" + -- + Dump = function(self, comm) + local status, data, packet, response, pos, header + local program_table = setmetatable({}, { __mode = 'v' }) - if header.type ~= Portmap.MessageType.REPLY then - return false, "Portmap.Dump: Packet was not a reply" - end + packet = comm:EncodePacket( nil, Portmap.Procedure[comm.version].DUMP, { type=Portmap.AuthType.NULL }, data ) + if (not(comm:SendPacket(packet))) then + return false, "Portmap.Dump: Failed to send data" + end + status, data = comm:ReceivePacket() + if ( not(status) ) then + return false, "Portmap.Dump: Failed to read data from socket" + end - if header.state ~= Portmap.State.MSG_ACCEPTED then - if (Portmap.RejectMsg[header.denied_state]) then - return false, string.format("Portmap.Dump: RPC call failed: %s", - Portmap.RejectMsg[header.denied_state]) - else - return false, string.format("Portmap.Dump: RPC call failed: code %d", - header.state) - end - end + pos, header = comm:DecodeHeader( data, 1 ) + if ( not(header) ) then + return false, "Portmap.Dump: Failed to decode RPC header" + end - if header.accept_state ~= Portmap.AcceptState.SUCCESS then - if (Portmap.AcceptMsg[header.accept_state]) then - return false, string.format("Portmap.Dump: RPC accepted state: %s", - Portmap.AcceptMsg[header.accept_state]) - else - return false, string.format("Portmap.Dump: RPC accepted state code %d", - header.accept_state) - end - end + if header.type ~= Portmap.MessageType.REPLY then + return false, "Portmap.Dump: Packet was not a reply" + end - while true do - local vfollows - local program, version, protocol, port + if header.state ~= Portmap.State.MSG_ACCEPTED then + if (Portmap.RejectMsg[header.denied_state]) then + return false, + string.format("Portmap.Dump: RPC call failed: %s", + Portmap.RejectMsg[header.denied_state]) + else + return false, + string.format("Portmap.Dump: RPC call failed: code %d", + header.state) + end + end - status, data = comm:GetAdditionalBytes( data, pos, 4 ) - if ( not(status) ) then - return false, "Portmap.Dump: Failed to call GetAdditionalBytes" - end - pos, vfollows = bin.unpack( ">I", data, pos ) - if ( vfollows == 0 ) then - break - end - - pos, program, version, protocol, port = bin.unpack(">IIII", data, pos) - if ( protocol == Portmap.PROTOCOLS.tcp ) then - protocol = "tcp" - elseif ( protocol == Portmap.PROTOCOLS.udp ) then - protocol = "udp" - end - - program_table[program] = program_table[program] or {} - program_table[program][protocol] = program_table[program][protocol] or {} - program_table[program][protocol]["port"] = port - program_table[program][protocol]["version"] = program_table[program][protocol]["version"] or {} - table.insert( program_table[program][protocol]["version"], version ) - -- parts of the code rely on versions being in order - -- this way the highest version can be chosen by choosing the last element - table.sort( program_table[program][protocol]["version"] ) - end + if header.accept_state ~= Portmap.AcceptState.SUCCESS then + if (Portmap.AcceptMsg[header.accept_state]) then + return false, + string.format("Portmap.Dump: RPC accepted state: %s", + Portmap.AcceptMsg[header.accept_state]) + else + return false, + string.format("Portmap.Dump: RPC accepted state code %d", + header.accept_state) + end + end + + while true do + local vfollows + local program, version, protocol, port + + status, data = comm:GetAdditionalBytes( data, pos, 4 ) + if ( not(status) ) then + return false, "Portmap.Dump: Failed to call GetAdditionalBytes" + end + pos, vfollows = bin.unpack( ">I", data, pos ) + if ( vfollows == 0 ) then + break + end + + pos, program, version, protocol, port = bin.unpack(">IIII", data, pos) + if ( protocol == Portmap.PROTOCOLS.tcp ) then + protocol = "tcp" + elseif ( protocol == Portmap.PROTOCOLS.udp ) then + protocol = "udp" + end + + program_table[program] = program_table[program] or {} + program_table[program][protocol] = program_table[program][protocol] or {} + program_table[program][protocol]["port"] = port + program_table[program][protocol]["version"] = program_table[program][protocol]["version"] or {} + table.insert( program_table[program][protocol]["version"], version ) + -- parts of the code rely on versions being in order + -- this way the highest version can be chosen by choosing the last element + table.sort( program_table[program][protocol]["version"] ) + end + + nmap.registry[comm.ip]['portmapper'] = program_table + return true, nmap.registry[comm.ip]['portmapper'] + end, - nmap.registry[comm.ip]['portmap'] = program_table - return true, nmap.registry[comm.ip]['portmap'] - end, - --- Queries the portmapper for the port of the selected program, -- protocol and version -- @@ -1032,206 +1033,207 @@ Mount = { -- NFS = { - -- NFS error msg v2 and v3 - StatMsg = { - [1] = "Not owner.", - [2] = "No such file or directory.", - [5] = "I/O error.", - [6] = "I/O error. No such device or address.", - [13] = "Permission denied.", - [17] = "File exists.", - [18] = "Attempt to do a cross-device hard link.", - [19] = "No such device.", - [20] = "Not a directory.", - [21] = "Is a directory.", - [22] = "Invalid argument or unsupported argument for an operation.", - [27] = "File too large.", - [28] = "No space left on device.", - [30] = "Read-only file system.", - [31] = "Too many hard links.", - [63] = "The filename in an operation was too long.", - [66] = "An attempt was made to remove a directory that was not empty.", - [69] = "Resource (quota) hard limit exceeded.", - [70] = "Invalid file handle.", - [71] = "Too many levels of remote in path.", - [99] = "The server's write cache used in the \"WRITECACHE\" call got flushed to disk.", - [10001] = "Illegal NFS file handle.", - [10002] = "Update synchronization mismatch was detected during a SETATTR operation.", - [10003] = "READDIR or READDIRPLUS cookie is stale.", - [10004] = "Operation is not supported.", - [10005] = "Buffer or request is too small.", - [10006] = "An error occurred on the server which does not map to any of the legal NFS version 3 protocol error values.", - [10007] = "An attempt was made to create an object of a type not supported by the server.", - [10008] = "The server initiated the request, but was not able to complete it in a timely fashion.", - }, + -- NFS error msg v2 and v3 + StatMsg = { + [1] = "Not owner.", + [2] = "No such file or directory.", + [5] = "I/O error.", + [6] = "I/O error. No such device or address.", + [13] = "Permission denied.", + [17] = "File exists.", + [18] = "Attempt to do a cross-device hard link.", + [19] = "No such device.", + [20] = "Not a directory.", + [21] = "Is a directory.", + [22] = "Invalid argument or unsupported argument for an operation.", + [27] = "File too large.", + [28] = "No space left on device.", + [30] = "Read-only file system.", + [31] = "Too many hard links.", + [63] = "The filename in an operation was too long.", + [66] = "An attempt was made to remove a directory that was not empty.", + [69] = "Resource (quota) hard limit exceeded.", + [70] = "Invalid file handle.", + [71] = "Too many levels of remote in path.", + [99] = "The server's write cache used in the \"WRITECACHE\" call got flushed to disk.", + [10001] = "Illegal NFS file handle.", + [10002] = "Update synchronization mismatch was detected during a SETATTR operation.", + [10003] = "READDIR or READDIRPLUS cookie is stale.", + [10004] = "Operation is not supported.", + [10005] = "Buffer or request is too small.", + [10006] = "An error occurred on the server which does not map to any of the legal NFS version 3 protocol error values.", + [10007] = "An attempt was made to create an object of a type not supported by the server.", + [10008] = "The server initiated the request, but was not able to complete it in a timely fashion.", + }, - StatCode = { - -- NFS Version 1 - [1] = { - NFS_OK = 0, - NFSERR_PERM = 1, - NFSERR_NOENT = 2, - NFSERR_IO = 5, - NFSERR_NXIO = 6, - NFSERR_ACCES = 13, - NFSERR_EXIST = 17, - NFSERR_NODEV = 19, - NFSERR_NOTDIR = 20, - NFSERR_ISDIR = 21, - NFSERR_FBIG = 27, - NFSERR_NOSPC = 28, - NFSERR_ROFS = 30, - NFSERR_NAMETOOLONG = 63, - NFSERR_NOTEMPTY = 66, - NFSERR_DQUOT = 69, - NFSERR_STALE = 70, - NFSERR_WFLUSH = 99, - }, + StatCode = { + -- NFS Version 1 + [1] = { + NFS_OK = 0, + NFSERR_PERM = 1, + NFSERR_NOENT = 2, + NFSERR_IO = 5, + NFSERR_NXIO = 6, + NFSERR_ACCES = 13, + NFSERR_EXIST = 17, + NFSERR_NODEV = 19, + NFSERR_NOTDIR = 20, + NFSERR_ISDIR = 21, + NFSERR_FBIG = 27, + NFSERR_NOSPC = 28, + NFSERR_ROFS = 30, + NFSERR_NAMETOOLONG = 63, + NFSERR_NOTEMPTY = 66, + NFSERR_DQUOT = 69, + NFSERR_STALE = 70, + NFSERR_WFLUSH = 99, + }, - -- NFS Version 2 - [2] = { - NFS_OK = 0, - NFSERR_PERM = 1, - NFSERR_NOENT = 2, - NFSERR_IO = 5, - NFSERR_NXIO = 6, - NFSERR_ACCES = 13, - NFSERR_EXIST = 17, - NFSERR_NODEV = 19, - NFSERR_NOTDIR = 20, - NFSERR_ISDIR = 21, - NFSERR_FBIG = 27, - NFSERR_NOSPC = 28, - NFSERR_ROFS = 30, - NFSERR_NAMETOOLONG = 63, - NFSERR_NOTEMPTY = 66, - NFSERR_DQUOT = 69, - NFSERR_STALE = 70, - NFSERR_WFLUSH = 99, - }, + -- NFS Version 2 + [2] = { + NFS_OK = 0, + NFSERR_PERM = 1, + NFSERR_NOENT = 2, + NFSERR_IO = 5, + NFSERR_NXIO = 6, + NFSERR_ACCES = 13, + NFSERR_EXIST = 17, + NFSERR_NODEV = 19, + NFSERR_NOTDIR = 20, + NFSERR_ISDIR = 21, + NFSERR_FBIG = 27, + NFSERR_NOSPC = 28, + NFSERR_ROFS = 30, + NFSERR_NAMETOOLONG = 63, + NFSERR_NOTEMPTY = 66, + NFSERR_DQUOT = 69, + NFSERR_STALE = 70, + NFSERR_WFLUSH = 99, + }, - -- NFS Version 3 - [3] = { - NFS_OK = 0, - NFSERR_PERM = 1, - NFSERR_NOENT = 2, - NFSERR_IO = 5, - NFSERR_NXIO = 6, - NFSERR_ACCES = 13, - NFSERR_EXIST = 17, - NFSERR_XDEV = 18, - NFSERR_NODEV = 19, - NFSERR_NOTDIR = 20, - NFSERR_ISDIR = 21, - NFSERR_INVAL = 22, - NFSERR_FBIG = 27, - NFSERR_NOSPC = 28, - NFSERR_ROFS = 30, - NFSERR_MLINK = 31, - NFSERR_NAMETOOLONG = 63, - NFSERR_NOTEMPTY = 66, - NFSERR_DQUOT = 69, - NFSERR_STALE = 70, - NFSERR_REMOTE = 71, - NFSERR_BADHANDLE = 10001, - NFSERR_NOT_SYNC = 10002, - NFSERR_BAD_COOKIE = 10003, - NFSERR_NOTSUPP = 10004, - NFSERR_TOOSMALL = 10005, - NFSERR_SERVERFAULT = 10006, - NFSERR_BADTYPE = 10007, - NFSERR_JUKEBOX = 10008, - }, - }, + -- NFS Version 3 + [3] = { + NFS_OK = 0, + NFSERR_PERM = 1, + NFSERR_NOENT = 2, + NFSERR_IO = 5, + NFSERR_NXIO = 6, + NFSERR_ACCES = 13, + NFSERR_EXIST = 17, + NFSERR_XDEV = 18, + NFSERR_NODEV = 19, + NFSERR_NOTDIR = 20, + NFSERR_ISDIR = 21, + NFSERR_INVAL = 22, + NFSERR_FBIG = 27, + NFSERR_NOSPC = 28, + NFSERR_ROFS = 30, + NFSERR_MLINK = 31, + NFSERR_NAMETOOLONG = 63, + NFSERR_NOTEMPTY = 66, + NFSERR_DQUOT = 69, + NFSERR_STALE = 70, + NFSERR_REMOTE = 71, + NFSERR_BADHANDLE = 10001, + NFSERR_NOT_SYNC = 10002, + NFSERR_BAD_COOKIE = 10003, + NFSERR_NOTSUPP = 10004, + NFSERR_TOOSMALL = 10005, + NFSERR_SERVERFAULT = 10006, + NFSERR_BADTYPE = 10007, + NFSERR_JUKEBOX = 10008, + }, + }, - -- Unfortunately the NFS procedure numbers differ in between versions - Procedure = - { - -- NFS Version 1 - [1] = - { - GETATTR = 1, - ROOT = 3, - LOOKUP = 4, - EXPORT = 5, - READDIR = 16, - STATFS = 17, - }, + -- Unfortunately the NFS procedure numbers differ in between versions + Procedure = + { + -- NFS Version 1 + [1] = + { + GETATTR = 1, + ROOT = 3, + LOOKUP = 4, + EXPORT = 5, + READDIR = 16, + STATFS = 17, + }, - -- NFS Version 2 - [2] = - { - GETATTR = 1, - ROOT = 3, - LOOKUP = 4, - EXPORT = 5, - READDIR = 16, - STATFS = 17, - }, + -- NFS Version 2 + [2] = + { + GETATTR = 1, + ROOT = 3, + LOOKUP = 4, + EXPORT = 5, + READDIR = 16, + STATFS = 17, + }, - -- NFS Version 3 - [3] = - { - GETATTR = 1, - SETATTR = 2, - LOOKUP = 3, - ACCESS = 4, - EXPORT = 5, - READDIR = 16, - READDIRPLUS = 17, - FSSTAT = 18, - FSINFO = 19, - PATHCONF = 20, - COMMIT = 21, - }, - }, + -- NFS Version 3 + [3] = + { + GETATTR = 1, + SETATTR = 2, + LOOKUP = 3, + ACCESS = 4, + EXPORT = 5, + READDIR = 16, + READDIRPLUS = 17, + FSSTAT = 18, + FSINFO = 19, + PATHCONF = 20, + COMMIT = 21, + }, + }, - -- ACCESS values used to check the bit mask. - AccessBits = - { - [3] = - { - ACCESS_READ = 0x0001, - ACCESS_LOOKUP = 0x0002, - ACCESS_MODIFY = 0x0004, - ACCESS_EXTEND = 0x0008, - ACCESS_DELETE = 0x0010, - ACCESS_EXECUTE = 0x0020, - }, - }, + -- ACCESS values used to check the bit mask. + AccessBits = + { + [3] = + { + ACCESS_READ = 0x0001, + ACCESS_LOOKUP = 0x0002, + ACCESS_MODIFY = 0x0004, + ACCESS_EXTEND = 0x0008, + ACCESS_DELETE = 0x0010, + ACCESS_EXECUTE = 0x0020, + }, + }, - FSinfoBits = - { - [3] = - { - FSF_LINK = 0x0001, - FSF_SYMLINK = 0x0002, - FSF_HOMOGENEOUS = 0x0008, - FSF_CANSETTIME = 0x0010, - }, - }, + FSinfoBits = + { + [3] = + { + FSF_LINK = 0x0001, + FSF_SYMLINK = 0x0002, + FSF_HOMOGENEOUS = 0x0008, + FSF_CANSETTIME = 0x0010, + }, + }, - new = function(self,o) - o = o or {} - setmetatable(o, self) - self.__index = self - return o - end, + new = function(self,o) + o = o or {} + setmetatable(o, self) + self.__index = self + return o + end, - CheckStat = function (self, procedurename, version, status) - if (status ~= NFS.StatCode[version].NFS_OK) then - if (NFS.StatMsg[status]) then - stdnse.print_debug(string.format("%s failed: %s", - procedurename, NFS.StatMsg[status])) - else - stdnse.print_debug(string.format("%s failed: code %d", - procedurename, status)) - end - return false - end + CheckStat = function (self, procedurename, version, status) + if (status ~= NFS.StatCode[version].NFS_OK) then + if (NFS.StatMsg[status]) then + stdnse.print_debug(4, + string.format("%s failed: %s", procedurename, NFS.StatMsg[status])) + else + stdnse.print_debug(4, + string.format("%s failed: code %d", procedurename, status)) + end - return true - end, + return false + end + + return true + end, AccessRead = function (self, mask, version) return bit.band(mask, NFS.AccessBits[version].ACCESS_READ) @@ -1273,7 +1275,7 @@ NFS = { return bit.band(mask, NFS.FSinfoBits[version].FSF_CANSETTIME) end, - --- Decodes the READDIR section of a NFS ReadDir response + --- Decodes the READDIR section of a NFS ReadDir response -- -- @param comm object handles rpc program information and -- low-level packet manipulation @@ -1293,7 +1295,7 @@ NFS = { status, data = comm:GetAdditionalBytes( data, pos, 4 ) if (not(status)) then - stdnse.print_debug("NFS.ReadDirDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.ReadDirDecode: Failed to call GetAdditionalBytes") return -1, nil end @@ -1307,7 +1309,7 @@ NFS = { response.attributes = {} status, data = comm:GetAdditionalBytes( data, pos, 4 ) if (not(status)) then - stdnse.print_debug("NFS.ReadDirDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.ReadDirDecode: Failed to call GetAdditionalBytes") return -1, nil end @@ -1317,7 +1319,7 @@ NFS = { end status, data = comm:GetAdditionalBytes( data, pos, 84 ) if (not(status)) then - stdnse.print_debug("NFS.ReadDirDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.ReadDirDecode: Failed to call GetAdditionalBytes") return -1, nil end pos, attrib = Util.unmarshall_nfsattr(data, pos, comm.version) @@ -1325,7 +1327,7 @@ NFS = { -- opaque data status, data = comm:GetAdditionalBytes( data, pos, 8 ) if (not(status)) then - stdnse.print_debug("NFS.ReadDirDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.ReadDirDecode: Failed to call GetAdditionalBytes") return -1, nil end pos, _ = bin.unpack(">L", data, pos) @@ -1336,7 +1338,7 @@ NFS = { entry = {} status, data = comm:GetAdditionalBytes( data, pos, 4 ) if (not(status)) then - stdnse.print_debug("NFS.ReadDirDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.ReadDirDecode: Failed to call GetAdditionalBytes") return -1, nil end @@ -1348,14 +1350,14 @@ NFS = { if ( 3 == comm.version ) then status, data = comm:GetAdditionalBytes( data, pos, 8 ) if (not(status)) then - stdnse.print_debug("NFS.ReadDirDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.ReadDirDecode: Failed to call GetAdditionalBytes") return -1, nil end pos, entry.fileid = Util.unmarshall_uint64(data, pos ) else status, data = comm:GetAdditionalBytes( data, pos, 4 ) if (not(status)) then - stdnse.print_debug("NFS.ReadDirDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.ReadDirDecode: Failed to call GetAdditionalBytes") return -1, nil end pos, entry.fileid = Util.unmarshall_uint32(data, pos) @@ -1363,14 +1365,14 @@ NFS = { status, data = comm:GetAdditionalBytes( data, pos, 4 ) if (not(status)) then - stdnse.print_debug("NFS.ReadDirDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.ReadDirDecode: Failed to call GetAdditionalBytes") return -1, nil end pos, entry.length = Util.unmarshall_uint32(data, pos) status, data = comm:GetAdditionalBytes( data, pos, entry.length ) if (not(status)) then - stdnse.print_debug("NFS.ReadDirDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.ReadDirDecode: Failed to call GetAdditionalBytes") return -1, nil end @@ -1378,14 +1380,14 @@ NFS = { if ( 3 == comm.version ) then status, data = comm:GetAdditionalBytes( data, pos, 8 ) if (not(status)) then - stdnse.print_debug("NFS.ReadDirDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.ReadDirDecode: Failed to call GetAdditionalBytes") return -1, nil end pos, entry.cookie = Util.unmarshall_uint64(data, pos) else status, data = comm:GetAdditionalBytes( data, pos, 4 ) if (not(status)) then - stdnse.print_debug("NFS.ReadDirDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.ReadDirDecode: Failed to call GetAdditionalBytes") return -1, nil end pos, entry.cookie = Util.unmarshall_uint32(data, pos) @@ -1445,7 +1447,7 @@ NFS = { status, data = comm:GetAdditionalBytes(data, pos, 4) if not status then - stdnse.print_debug("NFS.LookUpDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.LookUpDecode: Failed to call GetAdditionalBytes") return -1, nil end @@ -1457,20 +1459,20 @@ NFS = { if (comm.version == 3) then status, data = comm:GetAdditionalBytes( data, pos, 4) if (not(status)) then - stdnse.print_debug("NFS.LookUpDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.LookUpDecode: Failed to call GetAdditionalBytes") return -1, nil end _, len = Util.unmarshall_uint32(data, pos) status, data = comm:GetAdditionalBytes( data, pos, len + 4) if (not(status)) then - stdnse.print_debug("NFS.LookUpDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.LookUpDecode: Failed to call GetAdditionalBytes") return -1, nil end pos, lookup.fhandle = bin.unpack( "A" .. len + 4, data, pos) status, data = comm:GetAdditionalBytes( data, pos, 4) if (not(status)) then - stdnse.print_debug("NFS.LookUpDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.LookUpDecode: Failed to call GetAdditionalBytes") return -1, nil end @@ -1479,7 +1481,7 @@ NFS = { if (value_follows ~= 0) then status, data = comm:GetAdditionalBytes(data, pos, 84) if (not(status)) then - stdnse.print_debug("NFS.LookUpDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.LookUpDecode: Failed to call GetAdditionalBytes") return -1, nil end pos, lookup.attributes = Util.unmarshall_nfsattr(data, pos, comm.version) @@ -1489,7 +1491,7 @@ NFS = { status, data = comm:GetAdditionalBytes( data, pos, 4) if (not(status)) then - stdnse.print_debug("NFS.LookUpDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.LookUpDecode: Failed to call GetAdditionalBytes") return -1, nil end @@ -1498,7 +1500,7 @@ NFS = { if (value_follows ~= 0) then status, data = comm:GetAdditionalBytes(data, pos, 84) if (not(status)) then - stdnse.print_debug("NFS.LookUpDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.LookUpDecode: Failed to call GetAdditionalBytes") return -1, nil end pos, lookup.dir_attributes = Util.unmarshall_nfsattr(data, pos, comm.version) @@ -1509,13 +1511,13 @@ NFS = { elseif (comm.version < 3) then status, data = comm:GetAdditionalBytes( data, pos, 32) if (not(status)) then - stdnse.print_debug("NFS.LookUpDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.LookUpDecode: Failed to call GetAdditionalBytes") return -1, nil end pos, lookup.fhandle = bin.unpack("A32", data, pos) status, data = comm:GetAdditionalBytes( data, pos, 64 ) if (not(status)) then - stdnse.print_debug("NFS.LookUpDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.LookUpDecode: Failed to call GetAdditionalBytes") return -1, nil end pos, lookup.attributes = Util.unmarshall_nfsattr(data, pos, comm.version) @@ -1566,7 +1568,7 @@ NFS = { status, data = comm:GetAdditionalBytes(data, pos, 4) if not status then - stdnse.print_debug("NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes") return -1, nil end @@ -1577,19 +1579,19 @@ NFS = { status, data = comm:GetAdditionalBytes(data, pos, 4) if not status then - stdnse.print_debug("NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes") return -1, nil end pos, value_follows = bin.unpack(">I", data, pos) if value_follows == 0 then - stdnse.print_debug("NFS.ReadDirPlusDecode: Attributes follow failed") + stdnse.print_debug(4, "NFS.ReadDirPlusDecode: Attributes follow failed") return -1, nil end status, data = comm:GetAdditionalBytes( data, pos, 84 ) if not status then - stdnse.print_debug("NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes") return -1, nil end @@ -1599,7 +1601,7 @@ NFS = { status, data = comm:GetAdditionalBytes(data, pos, 8) if not status then - stdnse.print_debug("NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes") return -1, nil end pos, _ = bin.unpack(">L", data, pos) @@ -1610,7 +1612,7 @@ NFS = { local entry, len = {} status, data = comm:GetAdditionalBytes(data, pos, 4) if not status then - stdnse.print_debug("NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes") return -1, nil end @@ -1621,7 +1623,7 @@ NFS = { end status, data = comm:GetAdditionalBytes(data, pos, 8) if not status then - stdnse.print_debug("NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes") return -1, nil end pos, entry.fileid = bin.unpack(">L", data, pos) @@ -1629,27 +1631,27 @@ NFS = { status, data = comm:GetAdditionalBytes(data, pos, 4) if not status then - stdnse.print_debug("NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes") return -1, nil end pos, entry.length = bin.unpack(">I", data, pos) status, data = comm:GetAdditionalBytes( data, pos, entry.length ) if not status then - stdnse.print_debug("NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes") return -1, nil end pos, entry.name = Util.unmarshall_vopaque(entry.length, data, pos) status, data = comm:GetAdditionalBytes(data, pos, 8) if not status then - stdnse.print_debug("NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes") return -1, nil end pos, entry.cookie = bin.unpack(">L", data, pos) status, data = comm:GetAdditionalBytes(data, pos, 4) if not status then - stdnse.print_debug("NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes") return -1, nil end @@ -1658,7 +1660,7 @@ NFS = { if (value_follows ~= 0) then status, data = comm:GetAdditionalBytes(data, pos, 84) if not status then - stdnse.print_debug("NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes") return -1, nil end pos, entry.attributes = Util.unmarshall_nfsattr(data, pos, comm.version) @@ -1669,7 +1671,7 @@ NFS = { status, data = comm:GetAdditionalBytes(data, pos, 4) if not status then - stdnse.print_debug("NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes") return -1, nil end @@ -1678,14 +1680,14 @@ NFS = { if (value_follows ~= 0) then status, data = comm:GetAdditionalBytes(data, pos, 4) if not status then - stdnse.print_debug("NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes") return -1, nil end _, len = bin.unpack(">I", data, pos) status, data = comm:GetAdditionalBytes(data, pos, len + 4) if not status then - stdnse.print_debug("NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes") return -1, nil end pos, entry.fhandle = bin.unpack( "A" .. len + 4, data, pos ) @@ -1747,7 +1749,7 @@ NFS = { status, data = comm:GetAdditionalBytes(data, pos, 4) if not status then - stdnse.print_debug("NFS.FsStatDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.FsStatDecode: Failed to call GetAdditionalBytes") return -1, nil end @@ -1761,7 +1763,7 @@ NFS = { if (value_follows ~= 0) then status, data = comm:GetAdditionalBytes(data, pos, 84) if not status then - stdnse.print_debug("NFS.FsStatDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.FsStatDecode: Failed to call GetAdditionalBytes") return -1, nil end pos, fsstat.attributes = Util.unmarshall_nfsattr(data, pos, comm.version) @@ -1771,7 +1773,7 @@ NFS = { status, data = comm:GetAdditionalBytes( data, pos, 52) if not status then - stdnse.print_debug("NFS.FsStatDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.FsStatDecode: Failed to call GetAdditionalBytes") return -1, nil end @@ -1826,7 +1828,7 @@ NFS = { status, data = comm:GetAdditionalBytes(data, pos, 4) if not status then - stdnse.print_debug("NFS.FsInfoDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.FsInfoDecode: Failed to call GetAdditionalBytes") return -1, nil end @@ -1840,7 +1842,7 @@ NFS = { if (value_follows ~= 0) then status, data = comm:GetAdditionalBytes(data, pos, 84) if not status then - stdnse.print_debug("NFS.FsInfoDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.FsInfoDecode: Failed to call GetAdditionalBytes") return -1, nil end pos, fsinfo.attributes = Util.unmarshall_nfsattr(data, pos, comm.version) @@ -1850,7 +1852,7 @@ NFS = { status, data = comm:GetAdditionalBytes(data, pos, 48) if not status then - stdnse.print_debug("NFS.FsStatDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.FsStatDecode: Failed to call GetAdditionalBytes") return -1, nil end @@ -1908,7 +1910,7 @@ NFS = { status, data = comm:GetAdditionalBytes(data, pos, 4) if not status then - stdnse.print_debug("NFS.PathConfDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.PathConfDecode: Failed to call GetAdditionalBytes") return -1, nil end @@ -1922,7 +1924,7 @@ NFS = { if (value_follows ~= 0) then status, data = comm:GetAdditionalBytes(data, pos, 84) if not status then - stdnse.print_debug("NFS.PathConfDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.PathConfDecode: Failed to call GetAdditionalBytes") return -1, nil end pos, pconf.attributes = Util.unmarshall_nfsattr(data, pos, comm.version) @@ -1932,7 +1934,7 @@ NFS = { status, data = comm:GetAdditionalBytes(data, pos, 24) if not status then - stdnse.print_debug("NFS.PathConfDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.PathConfDecode: Failed to call GetAdditionalBytes") return -1, nil end @@ -1987,7 +1989,7 @@ NFS = { status, data = comm:GetAdditionalBytes(data, pos, 4) if not status then - stdnse.print_debug("NFS.AccessDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.AccessDecode: Failed to call GetAdditionalBytes") return -1, nil end @@ -2001,7 +2003,7 @@ NFS = { if (value_follows ~= 0) then status, data = comm:GetAdditionalBytes(data, pos, 84) if not status then - stdnse.print_debug("NFS.AccessDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.AccessDecode: Failed to call GetAdditionalBytes") return -1, nil end pos, access.attributes = Util.unmarshall_nfsattr(data, pos, comm.version) @@ -2011,7 +2013,7 @@ NFS = { status, data = comm:GetAdditionalBytes(data, pos, 4) if not status then - stdnse.print_debug("NFS.AccessDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "NFS.AccessDecode: Failed to call GetAdditionalBytes") return -1, nil end @@ -2125,7 +2127,7 @@ NFS = { status, data = comm:GetAdditionalBytes( data, pos, 4 ) if (not(status)) then - stdnse.print_debug("GetAttrDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "GetAttrDecode: Failed to call GetAdditionalBytes") return -1, nil end @@ -2139,11 +2141,11 @@ NFS = { elseif (comm.version == 3) then status, data = comm:GetAdditionalBytes( data, pos, 84 ) else - stdnse.print_debug("GetAttrDecode: Unsupported version") + stdnse.print_debug(4, "GetAttrDecode: Unsupported version") return -1, nil end if ( not(status) ) then - stdnse.print_debug("GetAttrDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "GetAttrDecode: Failed to call GetAdditionalBytes") return -1, nil end return Util.unmarshall_nfsattr(data, pos, comm.version) @@ -2202,7 +2204,7 @@ NFS = { status, data = comm:GetAdditionalBytes( data, pos, 4 ) if (not(status)) then - stdnse.print_debug("StatFsDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "StatFsDecode: Failed to call GetAdditionalBytes") return -1, nil end @@ -2213,7 +2215,7 @@ NFS = { status, data = comm:GetAdditionalBytes( data, pos, 20 ) if (not(status)) then - stdnse.print_debug("StatFsDecode: Failed to call GetAdditionalBytes") + stdnse.print_debug(4, "StatFsDecode: Failed to call GetAdditionalBytes") return -1, nil end pos, statfs.transfer_size, statfs.block_size, @@ -2241,20 +2243,20 @@ Helper = { status, mountd = Helper.GetProgramInfo( host, port, "mountd") if ( not(status) ) then - stdnse.print_debug("rpc.Helper.ShowMounts: GetProgramInfo failed") + stdnse.print_debug(4, "rpc.Helper.ShowMounts: GetProgramInfo failed") return status, "rpc.Helper.ShowMounts: GetProgramInfo failed" end mnt_comm = Comm:new('mountd', mountd.version) status, result = mnt_comm:Connect(host, mountd.port) if ( not(status) ) then - stdnse.print_debug("rpc.Helper.ShowMounts: %s", result) + stdnse.print_debug(4, "rpc.Helper.ShowMounts: %s", result) return false, result end status, mounts = mnt:Export(mnt_comm) mnt_comm:Disconnect() if ( not(status) ) then - stdnse.print_debug("rpc.Helper.ShowMounts: %s", mounts) + stdnse.print_debug(4, "rpc.Helper.ShowMounts: %s", mounts) end return status, mounts end, @@ -2279,7 +2281,7 @@ Helper = { status, mountd = Helper.GetProgramInfo( host, port, "mountd") if not status then - stdnse.print_debug("rpc.Helper.MountPath: %s", mountd) + stdnse.print_debug(1, "rpc.Helper.MountPath: %s", mountd) return nil, mountd end @@ -2287,14 +2289,14 @@ Helper = { status, err = mnt_comm:Connect(host, mountd.port) if not status then - stdnse.print_debug("rpc.Helper.MountPath: %s", err) + stdnse.print_debug(4, "rpc.Helper.MountPath: %s", err) return nil, err end status, fhandle = mnt:Mount(mnt_comm, path) if not status then mnt_comm:Disconnect() - stdnse.print_debug("rpc.Helper.MountPath: %s", fhandle) + stdnse.print_debug(4, "rpc.Helper.MountPath: %s", fhandle) return nil, fhandle end @@ -2317,7 +2319,7 @@ Helper = { local status, ret = mnt:Unmount(mnt_comm, path) mnt_comm:Disconnect() if not status then - stdnse.print_debug("rpc.Helper.UnmountPath: %s", ret) + stdnse.print_debug(4, "rpc.Helper.UnmountPath: %s", ret) return nil, ret end @@ -2340,14 +2342,14 @@ Helper = { status, nfsd = Helper.GetProgramInfo(host, port, "nfs") if not status then - stdnse.print_debug("rpc.Helper.NfsProc: %s", nfsd) + stdnse.print_debug(4, "rpc.Helper.NfsProc: %s", nfsd) return nil, nfsd end nfs_comm = Comm:new('nfs', nfsd.version) status, err = nfs_comm:Connect(host, nfsd.port) if not status then - stdnse.print_debug("rpc.Helper.NfsProc: %s", err) + stdnse.print_debug(4, "rpc.Helper.NfsProc: %s", err) return nil, err end @@ -2366,7 +2368,7 @@ Helper = { NfsClose = function(nfs_comm) local status, ret = nfs_comm:Disconnect() if not status then - stdnse.print_debug("rpc.Helper.NfsClose: %s", ret) + stdnse.print_debug(4, "rpc.Helper.NfsClose: %s", ret) return nil, ret end @@ -2390,13 +2392,13 @@ Helper = { status, mountd = Helper.GetProgramInfo( host, port, "mountd", 2) if ( not(status) ) then - stdnse.print_debug("rpc.Helper.ExportStats: %s", mountd) + stdnse.print_debug(4, "rpc.Helper.ExportStats: %s", mountd) return status, mountd end status, nfsd = Helper.GetProgramInfo( host, port, "nfs", 2) if ( not(status) ) then - stdnse.print_debug("rpc.Helper.ExportStats: %s", nfsd) + stdnse.print_debug(4, "rpc.Helper.ExportStats: %s", nfsd) return status, nfsd end mnt_comm = Comm:new('mountd', mountd.version) @@ -2404,20 +2406,20 @@ Helper = { -- TODO: recheck the version mismatch when adding NFSv4 if (nfs_comm.version <= 2 and mnt_comm.version > 2) then - stdnse.print_debug("rpc.Helper.ExportStats: versions mismatch, nfs v%d - mount v%d", + stdnse.print_debug(4, "rpc.Helper.ExportStats: versions mismatch, nfs v%d - mount v%d", nfs_comm.version, mnt_comm.version) return false, string.format("versions mismatch, nfs v%d - mount v%d", nfs_comm.version, mnt_comm.version) end status, result = mnt_comm:Connect(host, mountd.port) if ( not(status) ) then - stdnse.print_debug("rpc.Helper.ExportStats: %s", result) + stdnse.print_debug(4, "rpc.Helper.ExportStats: %s", result) return status, result end status, result = nfs_comm:Connect(host, nfsd.port) if ( not(status) ) then mnt_comm:Disconnect() - stdnse.print_debug("rpc.Helper.ExportStats: %s", result) + stdnse.print_debug(4, "rpc.Helper.ExportStats: %s", result) return status, result end @@ -2425,14 +2427,14 @@ Helper = { if ( not(status) ) then mnt_comm:Disconnect() nfs_comm:Disconnect() - stdnse.print_debug("rpc.Helper.ExportStats: %s", fhandle) + stdnse.print_debug(4, "rpc.Helper.ExportStats: %s", fhandle) return status, fhandle end status, stats = nfs:StatFs(nfs_comm, fhandle) if ( not(status) ) then mnt_comm:Disconnect() nfs_comm:Disconnect() - stdnse.print_debug("rpc.Helper.ExportStats: %s", stats) + stdnse.print_debug(4, "rpc.Helper.ExportStats: %s", stats) return status, stats end @@ -2440,7 +2442,7 @@ Helper = { mnt_comm:Disconnect() nfs_comm:Disconnect() if ( not(status) ) then - stdnse.print_debug("rpc.Helper.ExportStats: %s", fhandle) + stdnse.print_debug(4, "rpc.Helper.ExportStats: %s", fhandle) return status, fhandle end return true, stats @@ -2462,13 +2464,13 @@ Helper = { status, mountd = Helper.GetProgramInfo( host, port, "mountd") if ( not(status) ) then - stdnse.print_debug("rpc.Helper.Dir: %s", mountd) + stdnse.print_debug(4, "rpc.Helper.Dir: %s", mountd) return status, mountd end status, nfsd = Helper.GetProgramInfo( host, port, "nfs") if ( not(status) ) then - stdnse.print_debug("rpc.Helper.Dir: %s", nfsd) + stdnse.print_debug(4, "rpc.Helper.Dir: %s", nfsd) return status, nfsd end @@ -2477,21 +2479,21 @@ Helper = { -- TODO: recheck the version mismatch when adding NFSv4 if (nfs_comm.version <= 2 and mnt_comm.version > 2) then - stdnse.print_debug("rpc.Helper.Dir: versions mismatch, nfs v%d - mount v%d", + stdnse.print_debug(4, "rpc.Helper.Dir: versions mismatch, nfs v%d - mount v%d", nfs_comm.version, mnt_comm.version) return false, string.format("versions mismatch, nfs v%d - mount v%d", nfs_comm.version, mnt_comm.version) end status, result = mnt_comm:Connect(host, mountd.port) if ( not(status) ) then - stdnse.print_debug("rpc.Helper.Dir: %s", result) + stdnse.print_debug(4, "rpc.Helper.Dir: %s", result) return status, result end status, result = nfs_comm:Connect(host, nfsd.port) if ( not(status) ) then mnt_comm:Disconnect() - stdnse.print_debug("rpc.Helper.Dir: %s", result) + stdnse.print_debug(4, "rpc.Helper.Dir: %s", result) return status, result end @@ -2499,7 +2501,7 @@ Helper = { if ( not(status) ) then mnt_comm:Disconnect() nfs_comm:Disconnect() - stdnse.print_debug("rpc.Helper.Dir: %s", fhandle) + stdnse.print_debug(4, "rpc.Helper.Dir: %s", fhandle) return status, fhandle end @@ -2507,7 +2509,7 @@ Helper = { if ( not(status) ) then mnt_comm:Disconnect() nfs_comm:Disconnect() - stdnse.print_debug("rpc.Helper.Dir: %s", dirs) + stdnse.print_debug(4, "rpc.Helper.Dir: %s", dirs) return status, dirs end @@ -2515,7 +2517,7 @@ Helper = { mnt_comm:Disconnect() nfs_comm:Disconnect() if ( not(status) ) then - stdnse.print_debug("rpc.Helper.Dir: %s", fhandle) + stdnse.print_debug(4, "rpc.Helper.Dir: %s", fhandle) return status, fhandle end return true, dirs @@ -2538,13 +2540,13 @@ Helper = { status, mountd = Helper.GetProgramInfo( host, port, "mountd") if ( not(status) ) then - stdnse.print_debug("rpc.Helper.GetAttributes: %s", mountd) + stdnse.print_debug(4, "rpc.Helper.GetAttributes: %s", mountd) return status, mountd end status, nfsd = Helper.GetProgramInfo( host, port, "nfs") if ( not(status) ) then - stdnse.print_debug("rpc.Helper.GetAttributes: %s", nfsd) + stdnse.print_debug(4, "rpc.Helper.GetAttributes: %s", nfsd) return status, nfsd end @@ -2553,7 +2555,7 @@ Helper = { -- TODO: recheck the version mismatch when adding NFSv4 if (nfs_comm.version <= 2 and mnt_comm.version > 2) then - stdnse.print_debug("rpc.Helper.GetAttributes: versions mismatch, nfs v%d - mount v%d", + stdnse.print_debug(4, "rpc.Helper.GetAttributes: versions mismatch, nfs v%d - mount v%d", nfs_comm.version, mnt_comm.version) return false, string.format("versions mismatch, nfs v%d - mount v%d", nfs_comm.version, mnt_comm.version) @@ -2561,14 +2563,14 @@ Helper = { status, result = mnt_comm:Connect(host, mountd.port) if ( not(status) ) then - stdnse.print_debug("rpc.Helper.GetAttributes: %s", result) + stdnse.print_debug(4, "rpc.Helper.GetAttributes: %s", result) return status, result end status, result = nfs_comm:Connect(host, nfsd.port) if ( not(status) ) then mnt_comm:Disconnect() - stdnse.print_debug("rpc.Helper.GetAttributes: %s", result) + stdnse.print_debug(4, "rpc.Helper.GetAttributes: %s", result) return status, result end @@ -2576,7 +2578,7 @@ Helper = { if ( not(status) ) then mnt_comm:Disconnect() nfs_comm:Disconnect() - stdnse.print_debug("rpc.Helper.GetAttributes: %s", fhandle) + stdnse.print_debug(4, "rpc.Helper.GetAttributes: %s", fhandle) return status, fhandle end @@ -2584,7 +2586,7 @@ Helper = { if ( not(status) ) then mnt_comm:Disconnect() nfs_comm:Disconnect() - stdnse.print_debug("rpc.Helper.GetAttributes: %s", attribs) + stdnse.print_debug(4, "rpc.Helper.GetAttributes: %s", attribs) return status, attribs end @@ -2593,40 +2595,54 @@ Helper = { mnt_comm:Disconnect() nfs_comm:Disconnect() if ( not(status) ) then - stdnse.print_debug("rpc.Helper.GetAttributes: %s", fhandle) + stdnse.print_debug(4, "rpc.Helper.GetAttributes: %s", fhandle) return status, fhandle end return true, attribs end, - --- Queries the portmapper for a list of programs - -- - -- @param host table - -- @param port table - -- @return status true on success, false on failure - -- @return table containing the portmapper information as returned by - -- Portmap.Dump - RpcInfo = function( host, port ) - local status, result - local portmap = Portmap:new() - local comm = Comm:new('rpcbind', 2) + --- Queries the portmapper for a list of programs + -- + -- @param host table + -- @param port table + -- @return status true on success, false on failure + -- @return table containing the portmapper information as returned by + -- Portmap.Dump + RpcInfo = function( host, port ) + local status, result + local portmap = Portmap:new() + local comm = Comm:new('rpcbind', 2) - status, result = comm:Connect(host, port) - if (not(status)) then - stdnse.print_debug("rpc.Helper.RpcInfo: %s", result) - return status, result - end - mutex "lock" - status, result = portmap:Dump(comm) - mutex "done" - comm:Disconnect() - if (not(status)) then - stdnse.print_debug("rpc.Helper.RpcInfo: %s", result) - end + mutex "lock" + + if nmap.registry[host.ip] == nil then + nmap.registry[host.ip] = {} + end + if nmap.registry[host.ip]['portmapper'] == nil then + nmap.registry[host.ip]['portmapper'] = {} + elseif next(nmap.registry[host.ip]['portmapper']) ~= nil then + mutex "done" + return true, nmap.registry[host.ip]['portmapper'] + end - return status, result - end, + status, result = comm:Connect(host, port) + if (not(status)) then + mutex "done" + stdnse.print_debug(4, "rpc.Helper.RpcInfo: %s", result) + return status, result + end + + status, result = portmap:Dump(comm) + comm:Disconnect() + + mutex "done" + if (not(status)) then + stdnse.print_debug(4, "rpc.Helper.RpcInfo: %s", result) + end + + return status, result + end, --- Queries the portmapper for a port for the specified RPC program -- @@ -2644,14 +2660,14 @@ Helper = { status, result = comm:Connect(host, port) if (not(status)) then - stdnse.print_debug("rpc.Helper.GetPortForProgram: %s", result) + stdnse.print_debug(4, "rpc.Helper.GetPortForProgram: %s", result) return status, result end status, result = portmap:GetPort(comm, program_id, protocol, 1 ) comm:Disconnect() if (not(status)) then - stdnse.print_debug("rpc.Helper.GetPortForProgram: %s", result) + stdnse.print_debug(4, "rpc.Helper.GetPortForProgram: %s", result) end return status, result @@ -3023,7 +3039,7 @@ Util = pos, attr.fsid = Util.unmarshall_uint64(data, pos) pos, attr.fileid = Util.unmarshall_nfsfileid3(data, pos) else - stdnse.print_debug("unmarshall_nfsattr: unsupported NFS version %d", + stdnse.print_debug(4, "unmarshall_nfsattr: unsupported NFS version %d", nfsversion) return -1, nil end