diff --git a/nselib/afp.lua b/nselib/afp.lua
index a8a23fd79..5ee74078e 100644
--- a/nselib/afp.lua
+++ b/nselib/afp.lua
@@ -36,24 +36,24 @@
--
-- The short version:
--
--- helper = afp.Helper:new()
--- status, response = helper:OpenSession( host, port )
--- status, response = helper:Login()
--- .. do some fancy AFP stuff ..
--- status, response = helper:Logout()
--- status, response = helper:CloseSession()
+-- helper = afp.Helper:new()
+-- status, response = helper:OpenSession( host, port )
+-- status, response = helper:Login()
+-- .. do some fancy AFP stuff ..
+-- status, response = helper:Logout()
+-- status, response = helper:CloseSession()
--
--
-- Here's the longer version, with some explanatory text. To start using the Helper class,
-- the script has to create it's own instance. We do this by issuing the following:
--
--- helper = afp.Helper:new()
+-- helper = afp.Helper:new()
--
--
-- Next a session to the AFP server must be established, this is done using the OpenSession method of the
-- Helper class, like this:
--
--- status, response = helper:OpenSession( host, port )
+-- status, response = helper:OpenSession( host, port )
--
--
-- The next step needed to be performed is to authenticate to the server. We need to do this even for
@@ -61,26 +61,26 @@
-- authenticate using nil for both username and password. This can be achieved by calling the Login method
-- without any parameters, like this:
--
--- status, response = helper:Login()
+-- status, response = helper:Login()
--
--
-- To authenticate to the server using the username 'admin' and password 'nimda' we do this instead:
--
--- status, response = helper:Login('admin', 'nimda')
+-- status, response = helper:Login('admin', 'nimda')
--
--
-- At this stage we're authenticated and can call any of the AFP functions we're authorized to.
-- For the purpose of this documentation, we will attempt to list the servers share points.
-- We do this by issuing the following:
--
--- status, shares = helper:ListShares()
+-- status, shares = helper:ListShares()
--
--
-- Once we're finnished, we need to logout and close the AFP session this is done by calling the
-- following two methods of the Helper class:
--
--- status, response = helper:Logout()
--- status, response = helper:CloseSession()
+-- status, response = helper:Logout()
+-- status, response = helper:CloseSession()
--
--
-- Consult the documentation of each function to learn more about their respective return values.
@@ -109,7 +109,7 @@
--
-- Revised 03/09/2010 - v0.5 - documentation, documenation and more documentation
-- Revised 04/03/2011 - v0.6 - add support for getting file- sizes, dates and Unix ACLs
--- - moved afp.username & afp.password arguments to library
+-- - moved afp.username & afp.password arguments to library
local bin = require "bin"
local bit = require "bit"
@@ -124,311 +124,311 @@ local HAVE_SSL, openssl = pcall(require,'openssl')
-- Table of valid REQUESTs
local REQUEST = {
- CloseSession = 0x01,
- OpenSession = 0x04,
- Command = 0x02,
- GetStatus = 0x03,
- Write = 0x06,
+ CloseSession = 0x01,
+ OpenSession = 0x04,
+ Command = 0x02,
+ GetStatus = 0x03,
+ Write = 0x06,
}
-- Table of headers flags to be set accordingly in requests and responses
local FLAGS = {
- Request = 0,
- Response = 1
+ Request = 0,
+ Response = 1
}
-- Table of possible AFP_COMMANDs
COMMAND = {
- FPCloseVol = 0x02,
- FPCloseFork = 0x04,
- FPCopyFile = 0x05,
- FPCreateDir = 0x06,
- FPCreateFile = 0x07,
- FPGetSrvrInfo = 0x0f,
- FPGetSrvParms = 0x10,
- FPLogin = 0x12,
- FPLoginCont = 0x13,
- FPLogout = 0x14,
- FPMapId = 0x15,
- FPMapName = 0x16,
- FPGetUserInfo = 0x25,
- FPOpenVol = 0x18,
- FPOpenFork = 0x1a,
- FPGetFileDirParams = 0x22,
- FPChangePassword = 0x24,
- FPReadExt = 0x3c,
- FPWriteExt = 0x3d,
- FPGetAuthMethods = 0x3e,
- FPLoginExt = 0x3f,
- FPEnumerateExt2 = 0x44,
+ FPCloseVol = 0x02,
+ FPCloseFork = 0x04,
+ FPCopyFile = 0x05,
+ FPCreateDir = 0x06,
+ FPCreateFile = 0x07,
+ FPGetSrvrInfo = 0x0f,
+ FPGetSrvParms = 0x10,
+ FPLogin = 0x12,
+ FPLoginCont = 0x13,
+ FPLogout = 0x14,
+ FPMapId = 0x15,
+ FPMapName = 0x16,
+ FPGetUserInfo = 0x25,
+ FPOpenVol = 0x18,
+ FPOpenFork = 0x1a,
+ FPGetFileDirParams = 0x22,
+ FPChangePassword = 0x24,
+ FPReadExt = 0x3c,
+ FPWriteExt = 0x3d,
+ FPGetAuthMethods = 0x3e,
+ FPLoginExt = 0x3f,
+ FPEnumerateExt2 = 0x44,
}
USER_BITMAP = {
- UserId = 0x01,
- PrimaryGroupId = 0x2,
- UUID = 0x4
+ UserId = 0x01,
+ PrimaryGroupId = 0x2,
+ UUID = 0x4
}
VOL_BITMAP = {
- Attributes = 0x1,
- Signature = 0x2,
- CreationDate = 0x4,
- ModificationDate = 0x8,
- BackupDate = 0x10,
- ID = 0x20,
- BytesFree = 0x40,
- BytesTotal = 0x80,
- Name = 0x100,
- ExtendedBytesFree = 0x200,
- ExtendedBytesTotal = 0x400,
- BlockSize = 0x800
+ Attributes = 0x1,
+ Signature = 0x2,
+ CreationDate = 0x4,
+ ModificationDate = 0x8,
+ BackupDate = 0x10,
+ ID = 0x20,
+ BytesFree = 0x40,
+ BytesTotal = 0x80,
+ Name = 0x100,
+ ExtendedBytesFree = 0x200,
+ ExtendedBytesTotal = 0x400,
+ BlockSize = 0x800
}
FILE_BITMAP = {
- Attributes = 0x1,
- ParentDirId = 0x2,
- CreationDate = 0x4,
- ModificationDate = 0x8,
- BackupDate = 0x10,
- FinderInfo = 0x20,
- LongName = 0x40,
- ShortName = 0x80,
- NodeId = 0x100,
- DataForkSize = 0x200,
- ResourceForkSize = 0x400,
- ExtendedDataForkSize = 0x800,
- LaunchLimit = 0x1000,
- UTF8Name = 0x2000,
- ExtendedResourceForkSize = 0x4000,
- UnixPrivileges = 0x8000,
- ALL = 0xFFFF
+ Attributes = 0x1,
+ ParentDirId = 0x2,
+ CreationDate = 0x4,
+ ModificationDate = 0x8,
+ BackupDate = 0x10,
+ FinderInfo = 0x20,
+ LongName = 0x40,
+ ShortName = 0x80,
+ NodeId = 0x100,
+ DataForkSize = 0x200,
+ ResourceForkSize = 0x400,
+ ExtendedDataForkSize = 0x800,
+ LaunchLimit = 0x1000,
+ UTF8Name = 0x2000,
+ ExtendedResourceForkSize = 0x4000,
+ UnixPrivileges = 0x8000,
+ ALL = 0xFFFF
}
DIR_BITMAP = {
- Attributes = 0x1,
- ParentDirId = 0x2,
- CreationDate = 0x4,
- ModificationDate = 0x8,
- BackupDate = 0x10,
- FinderInfo = 0x20,
- LongName = 0x40,
- ShortName = 0x80,
- NodeId = 0x100,
- OffspringCount = 0x200,
- OwnerId = 0x400,
- GroupId = 0x800,
- AccessRights = 0x1000,
- UTF8Name = 0x2000,
- UnixPrivileges = 0x8000,
- ALL = 0xBFFF,
+ Attributes = 0x1,
+ ParentDirId = 0x2,
+ CreationDate = 0x4,
+ ModificationDate = 0x8,
+ BackupDate = 0x10,
+ FinderInfo = 0x20,
+ LongName = 0x40,
+ ShortName = 0x80,
+ NodeId = 0x100,
+ OffspringCount = 0x200,
+ OwnerId = 0x400,
+ GroupId = 0x800,
+ AccessRights = 0x1000,
+ UTF8Name = 0x2000,
+ UnixPrivileges = 0x8000,
+ ALL = 0xBFFF,
}
PATH_TYPE = {
- ShortName = 1,
- LongName = 2,
- UTF8Name = 3,
+ ShortName = 1,
+ LongName = 2,
+ UTF8Name = 3,
}
ACCESS_MODE = {
- Read = 0x1,
- Write = 0x2,
- DenyRead = 0x10,
- DenyWrite = 0x20
+ Read = 0x1,
+ Write = 0x2,
+ DenyRead = 0x10,
+ DenyWrite = 0x20
}
-- Access controls
ACLS = {
- OwnerSearch = 0x1,
- OwnerRead = 0x2,
- OwnerWrite = 0x4,
+ OwnerSearch = 0x1,
+ OwnerRead = 0x2,
+ OwnerWrite = 0x4,
- GroupSearch = 0x100,
- GroupRead = 0x200,
- GroupWrite = 0x400,
+ GroupSearch = 0x100,
+ GroupRead = 0x200,
+ GroupWrite = 0x400,
- EveryoneSearch = 0x10000,
- EveryoneRead = 0x20000,
- EveryoneWrite = 0x40000,
+ EveryoneSearch = 0x10000,
+ EveryoneRead = 0x20000,
+ EveryoneWrite = 0x40000,
- UserSearch = 0x100000,
- UserRead = 0x200000,
- UserWrite = 0x400000,
+ UserSearch = 0x100000,
+ UserRead = 0x200000,
+ UserWrite = 0x400000,
- BlankAccess = 0x10000000,
- UserIsOwner = 0x80000000
+ BlankAccess = 0x10000000,
+ UserIsOwner = 0x80000000
}
-- User authentication modules
UAM =
{
- NoUserAuth = "No User Authent",
- ClearText = "Cleartxt Passwrd",
- RandNum = "Randnum Exchange",
- TwoWayRandNum = "2-Way Randnum",
- DHCAST128 = "DHCAST128",
- DHX2 = "DHX2",
- Kerberos = "Client Krb v2",
- Reconnect = "Recon1",
+ NoUserAuth = "No User Authent",
+ ClearText = "Cleartxt Passwrd",
+ RandNum = "Randnum Exchange",
+ TwoWayRandNum = "2-Way Randnum",
+ DHCAST128 = "DHCAST128",
+ DHX2 = "DHX2",
+ Kerberos = "Client Krb v2",
+ Reconnect = "Recon1",
}
ERROR =
{
- SocketError = 1000,
- CustomError = 0xdeadbeef,
+ SocketError = 1000,
+ CustomError = 0xdeadbeef,
- FPNoErr = 0,
- FPAccessDenied = -5000,
- FPAuthContinue = -5001,
- FPBadUAM = -5002,
- FPBadVersNum = -5003,
- FPBitmapErr = - 5004,
- FPCantMove = - 5005,
- FPEOFErr = -5009,
- FPItemNotFound = -5012,
- FPLockErr = -5013,
- FPMiscErr = -5014,
- FPObjectExists = -5017,
- FPObjectNotFound = -5018,
- FPParamErr = -5019,
- FPUserNotAuth = -5023,
- FPCallNotSupported = -5024,
+ FPNoErr = 0,
+ FPAccessDenied = -5000,
+ FPAuthContinue = -5001,
+ FPBadUAM = -5002,
+ FPBadVersNum = -5003,
+ FPBitmapErr = - 5004,
+ FPCantMove = - 5005,
+ FPEOFErr = -5009,
+ FPItemNotFound = -5012,
+ FPLockErr = -5013,
+ FPMiscErr = -5014,
+ FPObjectExists = -5017,
+ FPObjectNotFound = -5018,
+ FPParamErr = -5019,
+ FPUserNotAuth = -5023,
+ FPCallNotSupported = -5024,
}
MAP_ID =
{
- UserIDToName = 1,
- GroupIDToName = 2,
- UserIDToUTF8Name = 3,
- GroupIDToUTF8Name = 4,
- UserUUIDToUTF8Name = 5,
- GroupUUIDToUTF8Name = 6
+ UserIDToName = 1,
+ GroupIDToName = 2,
+ UserIDToUTF8Name = 3,
+ GroupIDToUTF8Name = 4,
+ UserUUIDToUTF8Name = 5,
+ GroupUUIDToUTF8Name = 6
}
MAP_NAME =
{
- NameToUserID = 1,
- NameToGroupID = 2,
- UTF8NameToUserID = 3,
- UTF8NameToGroupID = 4,
- UTF8NameToUserUUID = 5,
- UTF8NameToGroupUUID = 6
+ NameToUserID = 1,
+ NameToGroupID = 2,
+ UTF8NameToUserID = 3,
+ UTF8NameToGroupID = 4,
+ UTF8NameToUserUUID = 5,
+ UTF8NameToGroupUUID = 6
}
SERVERFLAGS =
{
- CopyFile = 0x01,
- ChangeablePasswords = 0x02,
- NoPasswordSaving = 0x04,
- ServerMessages = 0x08,
- ServerSignature = 0x10,
- TCPoverIP = 0x20,
- ServerNotifications = 0x40,
- Reconnect = 0x80,
- OpenDirectory = 0x100,
- UTF8ServerName = 0x200,
- UUIDs = 0x400,
- SuperClient = 0x8000
+ CopyFile = 0x01,
+ ChangeablePasswords = 0x02,
+ NoPasswordSaving = 0x04,
+ ServerMessages = 0x08,
+ ServerSignature = 0x10,
+ TCPoverIP = 0x20,
+ ServerNotifications = 0x40,
+ Reconnect = 0x80,
+ OpenDirectory = 0x100,
+ UTF8ServerName = 0x200,
+ UUIDs = 0x400,
+ SuperClient = 0x8000
}
local ERROR_MSG = {
- [ERROR.FPAccessDenied]="Access Denied",
- [ERROR.FPAuthContinue]="Authentication is not yet complete",
- [ERROR.FPBadUAM]="Specified UAM is unknown",
- [ERROR.FPBadVersNum]="Server does not support the specified AFP version",
- [ERROR.FPBitmapErr]="Attempt was made to get or set a parameter that cannot be obtained or set with this command, or a required bitmap is null",
- [ERROR.FPCantMove]="Attempt was made to move a directory into one of its descendent directories.",
- [ERROR.FPEOFErr]="No more matches or end of fork reached.",
- [ERROR.FPLockErr]="Some or all of the requested range is locked by another user; a lock range conflict exists.",
- [ERROR.FPMiscErr]="Non-AFP error occurred.",
- [ERROR.FPObjectNotFound]="Input parameters do not point to an existing directory, file, or volume.",
- [ERROR.FPParamErr]="Parameter error.",
- [ERROR.FPObjectExists] = "File or directory already exists.",
- [ERROR.FPUserNotAuth] = "UAM failed (the specified old password doesn't match); no user is logged in yet for the specified session; authentication failed; password is incorrect.",
- [ERROR.FPItemNotFound] = "Specified APPL mapping, comment, or icon was not found in the Desktop database; specified ID is unknown.",
- [ERROR.FPCallNotSupported] = "Server does not support this command.",
+ [ERROR.FPAccessDenied]="Access Denied",
+ [ERROR.FPAuthContinue]="Authentication is not yet complete",
+ [ERROR.FPBadUAM]="Specified UAM is unknown",
+ [ERROR.FPBadVersNum]="Server does not support the specified AFP version",
+ [ERROR.FPBitmapErr]="Attempt was made to get or set a parameter that cannot be obtained or set with this command, or a required bitmap is null",
+ [ERROR.FPCantMove]="Attempt was made to move a directory into one of its descendent directories.",
+ [ERROR.FPEOFErr]="No more matches or end of fork reached.",
+ [ERROR.FPLockErr]="Some or all of the requested range is locked by another user; a lock range conflict exists.",
+ [ERROR.FPMiscErr]="Non-AFP error occurred.",
+ [ERROR.FPObjectNotFound]="Input parameters do not point to an existing directory, file, or volume.",
+ [ERROR.FPParamErr]="Parameter error.",
+ [ERROR.FPObjectExists] = "File or directory already exists.",
+ [ERROR.FPUserNotAuth] = "UAM failed (the specified old password doesn't match); no user is logged in yet for the specified session; authentication failed; password is incorrect.",
+ [ERROR.FPItemNotFound] = "Specified APPL mapping, comment, or icon was not found in the Desktop database; specified ID is unknown.",
+ [ERROR.FPCallNotSupported] = "Server does not support this command.",
}
-- Check if all the bits in flag are set in bitmap.
local function flag_is_set(bitmap, flag)
- return bit.band(bitmap, flag) == flag
+ return bit.band(bitmap, flag) == flag
end
-- Response class returned by all functions in Proto
Response = {
- 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,
- --- Sets the error code
- --
- -- @param code number containing the error code
- setErrorCode = function( self, code )
- self.error_code = code
- end,
+ --- Sets the error code
+ --
+ -- @param code number containing the error code
+ setErrorCode = function( self, code )
+ self.error_code = code
+ end,
- --- Gets the error code
- --
- -- @return code number containing the error code
- getErrorCode = function( self )
- return self.error_code
- end,
+ --- Gets the error code
+ --
+ -- @return code number containing the error code
+ getErrorCode = function( self )
+ return self.error_code
+ end,
- --- Gets the error message
- --
- -- @return msg string containing the error
- getErrorMessage = function(self)
- if self.error_msg then
- return self.error_msg
- else
- return ERROR_MSG[self.error_code] or ("Unknown error (%d) occured"):format(self.error_code)
- end
- end,
+ --- Gets the error message
+ --
+ -- @return msg string containing the error
+ getErrorMessage = function(self)
+ if self.error_msg then
+ return self.error_msg
+ else
+ return ERROR_MSG[self.error_code] or ("Unknown error (%d) occured"):format(self.error_code)
+ end
+ end,
- --- Sets the error message
- --
- -- @param msg string containing the error message
- setErrorMessage = function(self, msg)
- self.error_code = ERROR.CustomError
- self.error_msg = msg
- end,
+ --- Sets the error message
+ --
+ -- @param msg string containing the error message
+ setErrorMessage = function(self, msg)
+ self.error_code = ERROR.CustomError
+ self.error_msg = msg
+ end,
- --- Sets the result
- --
- -- @param result result to set
- setResult = function(self, result)
- self.result = result
- end,
+ --- Sets the result
+ --
+ -- @param result result to set
+ setResult = function(self, result)
+ self.result = result
+ end,
- --- Get the result
- --
- -- @return result
- getResult = function(self)
- return self.result
- end,
+ --- Get the result
+ --
+ -- @return result
+ getResult = function(self)
+ return self.result
+ end,
- --- Sets the packet
- setPacket = function( self, packet )
- self.packet = packet
- end,
+ --- Sets the packet
+ setPacket = function( self, packet )
+ self.packet = packet
+ end,
- getPacket = function( self )
- return self.packet
- end,
+ getPacket = function( self )
+ return self.packet
+ end,
- --- Gets the packet data
- getPacketData = function(self)
- return self.packet.data
- end,
+ --- Gets the packet data
+ getPacketData = function(self)
+ return self.packet.data
+ end,
- --- Gets the packet header
- getPacketHeader = function(self)
- return self.packet.header
- end,
+ --- Gets the packet header
+ getPacketHeader = function(self)
+ return self.packet.header
+ end,
}
--- Proto class containing all AFP specific code
@@ -437,900 +437,900 @@ Response = {
-- http://developer.apple.com/mac/library/documentation/Networking/Reference/AFP_Reference/Reference/reference.html
Proto = {
- RequestId = 1,
-
- new = function(self,o)
- o = o or {}
- setmetatable(o, self)
- self.__index = self
- return o
- end,
-
- setSocket = function(self, socket)
- self.socket = socket
- end,
-
- --- Creates an AFP packet
- --
- -- @param command number should be one of the commands in the COMMAND table
- -- @param data_offset number holding the offset to the data
- -- @param data the actual data of the request
- create_fp_packet = function( self, command, data_offset, data )
- local reserved = 0
- local data = data or ""
- local data_len = data:len()
- local header = bin.pack("CC>SIII", FLAGS.Request, command, self.RequestId, data_offset, data_len, reserved)
-
- self.RequestId = self.RequestId + 1
- return header .. data
- end,
-
- --- Parses the FP header (first 16-bytes of packet)
- --
- -- @param packet string containing the raw packet
- -- @return table with header data containing flags, command,
- -- request_id, error_code, length and reserved fields
- parse_fp_header = function( self, packet )
- local header = {}
- local pos
-
- pos, header.flags, header.command, header.request_id = bin.unpack( "CC>S", packet )
- pos, header.error_code, header.length, header.reserved = bin.unpack( ">i>II", packet:sub(5) )
-
- if header.error_code ~= 0 then
- header.error_msg = ERROR_MSG[header.error_code] or ("Unknown error: %d"):format(header.error_code)
- header.error_msg = "ERROR: " .. header.error_msg
- end
- header.raw = packet:sub(1,16)
- return header
- end,
-
- --- Reads a AFP packet of the socket
- --
- -- @return Response object
- read_fp_packet = function( self )
-
- local packet = {}
- local buf = ""
- local status, response
-
- status, buf = self.socket:receive_bytes(16)
- if ( not status ) then
- response = Response:new()
- response:setErrorCode(ERROR.SocketError)
- response:setErrorMessage(buf)
- return response
- end
-
- packet.header = self:parse_fp_header( buf )
- while buf:len() < packet.header.length + packet.header.raw:len() do
- local tmp
- status, tmp = self.socket:receive_bytes( packet.header.length + 16 - buf:len() )
- if not status then
- response = Response:new()
- response:setErrorCode(ERROR.SocketError)
- response:setErrorMessage(buf)
- return response
- end
- buf = buf .. tmp
- end
-
- packet.data = buf:len() > 16 and buf:sub( 17 ) or ""
- response = Response:new()
- response:setErrorCode(packet.header.error_code)
- response:setPacket(packet)
-
- return response
- end,
-
- --- Sends the raw packet over the socket
- --
- -- @param packet containing the raw data
- -- @return Response object
- send_fp_packet = function( self, packet )
- return self.socket:send(packet)
- end,
-
- --- Sends an DSIOpenSession request to the server and handles the response
- --
- -- @return Response object
- dsi_open_session = function( self, host, port )
- local data_offset = 0
- local option = 0x01 -- Attention Quantum
- local option_len = 4
- local quantum = 1024
- local data, packet, status
-
- data = bin.pack( "CCI", option, option_len, quantum )
- packet = self:create_fp_packet( REQUEST.OpenSession, data_offset, data )
-
- self:send_fp_packet( packet )
- return self:read_fp_packet()
- end,
-
- --- Sends an DSICloseSession request to the server and handles the response
- dsi_close_session = function( self )
- local data_offset = 0
- local option = 0x01 -- Attention Quantum
- local option_len = 4
- local quantum = 1024
- local data, packet, status
-
- data = ""
- packet = self:create_fp_packet( REQUEST.CloseSession, data_offset, data )
-
- self:send_fp_packet( packet )
- end,
-
- -- Sends an FPCopyFile request to the server
- --
- -- @param src_vol number containing the ID of the src file volume
- -- @param srd_did number containing the directory id of the src file
- -- @param src_path string containingt the file path/name of the src file
- -- @param dst_vol number containing the ID of the dst file volume
- -- @param dst_did number containing the id of the dest. directory
- -- @param dst_path string containing the dest path (can be nil or "")
- -- @param new_name string containign the new name of the destination
- -- @return Response object
- fp_copy_file = function(self, src_vol, src_did, src_path, dst_vol, dst_did, dst_path, new_name )
- local pad, data_offset = 0, 0
- local unicode_names, unicode_hint = 0x03, 0x08000103
- local data, packet, response
-
- -- make sure we have empty names rather than nil values
- local dst_path = dst_path or ""
- local src_path = src_path or ""
- local new_name = new_name or ""
-
- data = bin.pack(">CCSISI", COMMAND.FPCopyFile, pad, src_vol, src_did, dst_vol, dst_did )
- data = data .. bin.pack(">CIP", unicode_names, unicode_hint, src_path )
- data = data .. bin.pack(">CIP", unicode_names, unicode_hint, dst_path )
- data = data .. bin.pack(">CIP", unicode_names, unicode_hint, new_name )
-
- packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
- self:send_fp_packet( packet )
- return self:read_fp_packet()
- end,
-
- --- Sends an GetStatus DSI request (which is basically a FPGetSrvrInfo
- -- AFP request) to the server and handles the response
- --
- -- @return status (true or false)
- -- @return table with server information (if status is true) or error string
- -- (if status is false)
- fp_get_server_info = function(self)
- local packet
- local data_offset = 0
- local pad = 0
- local response, result = {}, {}
- local offsets = {}
- local pos
- local _
- local status
-
- local data = bin.pack("CC", COMMAND.FPGetSrvrInfo, 0)
- packet = self:create_fp_packet(REQUEST.GetStatus, data_offset, data)
- self:send_fp_packet(packet)
- response = self:read_fp_packet()
-
- if response:getErrorCode() ~= ERROR.FPNoErr then
- return response
- end
-
- packet = response.packet
-
- -- parse and store the offsets in the 'header'
- pos, offsets.machine_type, offsets.afp_version_count,
- offsets.uam_count, offsets.volume_icon_and_mask
- = bin.unpack(">SSSS", packet.data, pos)
-
- -- the flags are directly in the 'header'
- result.flags = {}
- pos, result.flags.raw = bin.unpack(">S", packet.data, pos)
-
- -- the short server name is stored directly in the 'header' as
- -- well
- pos, result.server_name = bin.unpack("p", packet.data, pos)
-
- -- Server offset should begin at an even boundary see link below
- -- http://developer.apple.com/mac/library/documentation/Networking/Reference/AFP_Reference/Reference/reference.html#//apple_ref/doc/uid/TP40003548-CH3-CHDIEGED
- if (pos + 1) % 2 ~= 0 then
- pos = pos + 1
- end
-
- -- and some more offsets
- pos, offsets.server_signature, offsets.network_addresses_count,
- offsets.directory_names_count, offsets.utf8_server_name
- = bin.unpack(">SSSS", packet.data, pos)
-
- -- this sets up all the server flaqs in the response table as booleans
- result.flags.SuperClient = flag_is_set(result.flags.raw, SERVERFLAGS.SuperClient)
- result.flags.UUIDs = flag_is_set(result.flags.raw, SERVERFLAGS.UUIDs)
- result.flags.UTF8ServerName = flag_is_set(result.flags.raw, SERVERFLAGS.UTF8ServerName)
- result.flags.OpenDirectory = flag_is_set(result.flags.raw, SERVERFLAGS.OpenDirectory)
- result.flags.Reconnect = flag_is_set(result.flags.raw, SERVERFLAGS.Reconnect)
- result.flags.ServerNotifications = flag_is_set(result.flags.raw, SERVERFLAGS.ServerNotifications)
- result.flags.TCPoverIP = flag_is_set(result.flags.raw, SERVERFLAGS.TCPoverIP)
- result.flags.ServerSignature = flag_is_set(result.flags.raw, SERVERFLAGS.ServerSignature)
- result.flags.ServerMessages = flag_is_set(result.flags.raw, SERVERFLAGS.ServerMessages)
- result.flags.NoPasswordSaving = flag_is_set(result.flags.raw, SERVERFLAGS.NoPasswordSaving)
- result.flags.ChangeablePasswords = flag_is_set(result.flags.raw, SERVERFLAGS.ChangeablePasswords)
- result.flags.CopyFile = flag_is_set(result.flags.raw, SERVERFLAGS.CopyFile)
-
- -- store the machine type
- _, result.machine_type = bin.unpack("p", packet.data, offsets.machine_type + 1)
-
- -- this tells us the number of afp versions supported
- pos, result.afp_version_count = bin.unpack("C", packet.data, offsets.afp_version_count + 1)
-
- -- now we loop through them all, storing for the response
- result.afp_versions = {}
- for i = 1,result.afp_version_count do
- pos, _ = bin.unpack("p", packet.data, pos)
- table.insert(result.afp_versions, _)
- end
-
- -- same idea as the afp versions here
- pos, result.uam_count = bin.unpack("C", packet.data, offsets.uam_count + 1)
-
- result.uams = {}
- for i = 1,result.uam_count do
- pos, _ = bin.unpack("p", packet.data, pos)
- table.insert(result.uams, _)
- end
-
- -- volume_icon_and_mask would normally be parsed out here,
- -- however the apple docs say it is deprecated in Mac OS X, so
- -- we don't bother with it
-
- -- server signature is 16 bytes
- result.server_signature = string.sub(packet.data, offsets.server_signature + 1, offsets.server_signature + 16)
-
- -- this is the same idea as afp_version and uam above
- pos, result.network_addresses_count = bin.unpack("C", packet.data, offsets.network_addresses_count + 1)
-
- result.network_addresses = {}
-
- -- gets a little complicated in here, basically each entry has
- -- a length byte, a tag byte, and then the data. We parse
- -- differently based on the tag
- for i = 1, result.network_addresses_count do
- local length
- local tag
-
- pos, length = bin.unpack("C", packet.data, pos)
- pos, tag = bin.unpack("C", packet.data, pos)
-
- if tag == 0x00 then
- -- reserved, shouldn't ever come up, maybe this should
- -- return an error? maybe not, lets just ignore this
- elseif tag == 0x01 then
- -- four byte ip
- local octet = {}
- pos, octet[1], octet[2], octet[3], octet[4] = bin.unpack("CCCC", packet.data, pos)
- table.insert(result.network_addresses, string.format("%d.%d.%d.%d", octet[1], octet[2], octet[3], octet[4]))
- elseif tag == 0x02 then
- -- four byte ip and two byte port
- local octet = {}
- local port
- pos, octet[1], octet[2], octet[3], octet[4], port = bin.unpack(">CCCCS", packet.data, pos)
- table.insert(result.network_addresses, string.format("%d.%d.%d.%d:%d", octet[1], octet[2], octet[3], octet[4], port))
- elseif tag == 0x03 then
- -- ddp address (two byte network, one byte
- -- node, one byte socket) not tested, anyone
- -- use ddp anymore?
- local network
- local node
- local socket
- pos, network = bin.unpack(">S", packet.data, pos)
- pos, node = bin.unpack("C", packet.data, pos)
- pos, socket = bin.unpack("C", packet.data, pos)
- table.insert(result.network_addresses, string.format("ddp %d.%d:%d", network, node, socket))
- elseif tag == 0x04 then
- -- dns name (string)
- local temp
- pos, temp = bin.unpack("z", packet.data:sub(1,pos+length-3), pos)
- table.insert(result.network_addresses, temp)
- elseif tag == 0x05 then
- -- four byte ip and two byte port, client
- -- should use ssh. not tested, should work as it
- -- is the same as tag 0x02
- local octet = {}
- local port
- pos, octet[1], octet[2], octet[3], octet[4], port = bin.unpack(">CCCCS", packet.data, pos)
- table.insert(result.network_addresses, string.format("ssh://%d.%d.%d.%d:%d", octet[1], octet[2], octet[3], octet[4], port))
- elseif tag == 0x06 then
- -- 16 byte ipv6
- -- not tested, but should work (next tag is
- -- tested)
- local octet = {}
- local j
- local addr
-
- for j = 1, 8 do
- pos, octet[j] = bin.unpack(">S", packet.data, pos)
- end
-
- for j = 1, 7 do
- addr = addr .. string.format("%04x:", octet[j])
- end
- addr = addr .. string.format("%04x", octet[8])
-
- table.insert(result.network_addresses, addr)
- elseif tag == 0x07 then
- -- 16 byte ipv6 and two byte port
- local octet = {}
- local port
- local j
- local addr
-
- for j = 1, 8 do
- pos, octet[j] = bin.unpack(">S", packet.data, pos)
- end
- pos, port = bin.unpack(">S", packet.data, pos)
-
- addr = "["
-
- for j = 1, 7 do
- addr = addr .. string.format("%04x:", octet[j])
- end
- addr = addr .. string.format("%04x]:%d", octet[8], port)
-
- table.insert(result.network_addresses, addr)
- end
- end
-
- -- same idea as the others here
- pos, result.directory_names_count = bin.unpack("C", packet.data, offsets.directory_names_count + 1)
-
- result.directory_names = {}
- for i = 1, result.directory_names_count do
- local dirname
- pos, dirname = bin.unpack("p", packet.data, pos)
- table.insert(result.directory_names, dirname)
- end
-
- -- only one utf8 server name. note this string has a two-byte length.
- _, result.utf8_server_name = bin.unpack(">P", packet.data, offsets.utf8_server_name + 1)
- response.result = result
-
- return response
- end,
-
-
- --- Sends an FPGetUserInfo AFP request to the server and handles the response
- --
- -- @return response object with the following result user_bitmap and
- -- uid fields
- fp_get_user_info = function( self )
-
- local packet, pos, status, response
- local data_offset = 0
- local flags = 1 -- Default User
- local uid = 0
- local bitmap = USER_BITMAP.UserId
- local result = {}
-
- local data = bin.pack( "CCI>S", COMMAND.FPGetUserInfo, flags, uid, bitmap )
- packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
-
- self:send_fp_packet( packet )
- response = self:read_fp_packet()
- if response:getErrorCode() ~= ERROR.FPNoErr then
- return response
- end
-
- pos, response.result.user_bitmap, response.result.uid = bin.unpack(">S>I", packet.data)
-
- return response
- end,
-
- --- Sends an FPGetSrvrParms AFP request to the server and handles the response
- --
- -- @return response object with the following result server_time,
- -- vol_count, volumes fields
- fp_get_srvr_parms = function(self)
- local packet, status, data
- local data_offset = 0
- local response = {}
- local pos = 0
- local parms = {}
-
- data = bin.pack("CC", COMMAND.FPGetSrvParms, 0)
- packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
- self:send_fp_packet( packet )
- response = self:read_fp_packet()
-
- if response:getErrorCode() ~= ERROR.FPNoErr then
- return response
- end
-
- data = response:getPacketData()
- pos, parms.server_time, parms.vol_count = bin.unpack("IC", data)
-
- -- we should now be at the leading zero preceeding the first volume name
- -- next is the length of the volume name, move pos there
- pos = pos + 1
-
- parms.volumes = {}
-
- for i=1, parms.vol_count do
- local _, vol_len = bin.unpack("C", data:sub(pos))
- local volume_name = data:sub(pos + 1, pos + 1 + vol_len)
- pos = pos + vol_len + 2
- table.insert(parms.volumes, string.format("%s", volume_name) )
- end
-
- response:setResult(parms)
-
- return response
- end,
-
-
- --- Sends an FPLogin request to the server and handles the response
- --
- -- This function currently only supports the 3.1 through 3.3 protocol versions
- -- It currently supports the following authentication methods:
- -- o No User Authent
- -- o DHCAST128
- --
- -- The DHCAST128 UAM should work against most servers even though it's
- -- superceeded by the DHX2 UAM.
- --
- -- @param afp_version string (AFP3.3|AFP3.2|AFP3.1)
- -- @param uam string containing authentication information
- -- @return Response object
- fp_login = function( self, afp_version, uam, username, password, options )
- local packet, status, data
- local data_offset = 0
- local status, response
-
- if not HAVE_SSL then
- response = Response:new()
- response:setErrorMessage("OpenSSL not available, aborting ...")
- return response
- end
-
- -- currently we only support AFP3.3
- if afp_version == nil or ( afp_version ~= "AFP3.3" and afp_version ~= "AFP3.2" and afp_version ~= "AFP3.1" ) then
- response = Response:new()
- response:setErrorMessage("Incorrect AFP version")
- return response
- end
-
- if ( uam == "No User Authent" ) then
- data = bin.pack( "CCACA", COMMAND.FPLogin, afp_version:len(), afp_version, uam:len(), uam )
- packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
- self:send_fp_packet( packet )
- return self:read_fp_packet( )
- elseif( uam == "DHCAST128" ) then
- local dhx_s2civ, dhx_c2civ = 'CJalbert', 'LWallace'
- local p, g, Ra, Ma, Mb, K, nonce
- local EncData, PlainText, K_bin, auth_response
- local _, Id
- local username = username or ""
- local password = password or ""
-
- if ( bit.mod(username:len(), 2) == 0 ) then
- username = username .. string.char(0)
- end
-
- p = openssl.bignum_hex2bn("BA2873DFB06057D43F2024744CEEE75B")
- g = openssl.bignum_dec2bn("7")
- Ra = openssl.bignum_hex2bn("86F6D3C0B0D63E4B11F113A2F9F19E3BBBF803F28D30087A1450536BE979FD42")
- Ma = openssl.bignum_mod_exp(g, Ra, p)
-
- data = bin.pack( "CpppA", COMMAND.FPLogin, afp_version, uam, username, openssl.bignum_bn2bin(Ma) )
- packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
- self:send_fp_packet( packet )
- response = self:read_fp_packet( )
- if ( response:getErrorCode() ~= ERROR.FPAuthContinue ) then
- return response
- end
-
- if ( response.packet.header.length ~= 50 ) then
- response:setErrorMessage("LoginContinue packet contained invalid data")
- return response
- end
-
- _, Id, Mb, EncData = bin.unpack(">SH16A32", response.packet.data )
-
- Mb = openssl.bignum_hex2bn( Mb )
- K = openssl.bignum_mod_exp (Mb, Ra, p)
- K_bin = openssl.bignum_bn2bin(K)
- nonce = openssl.decrypt("cast5-cbc", K_bin, dhx_s2civ, EncData, false ):sub(1,16)
- nonce = openssl.bignum_add( openssl.bignum_bin2bn(nonce), openssl.bignum_dec2bn("1") )
- PlainText = openssl.bignum_bn2bin(nonce) .. Util.ZeroPad(password, 64)
- auth_response = openssl.encrypt( "cast5-cbc", K_bin, dhx_c2civ, PlainText, true)
-
- data = bin.pack( "CC>SA", COMMAND.FPLoginCont, 0, Id, auth_response )
- packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
- self:send_fp_packet( packet )
- response = self:read_fp_packet( )
- if ( response:getErrorCode() ~= ERROR.FPNoErr ) then
- return response
- end
- return response
- end
- response:setErrorMessage("Unsupported uam: " .. uam or "nil")
- return response
- end,
-
- -- Terminates sessions and frees server resources established by FPLoginand FPLoginExt.
- --
- -- @return response object
- fp_logout = function( self )
- local packet, data, response
- local data_offset, pad = 0, 0
-
- data = bin.pack("CC", COMMAND.FPLogout, pad)
- packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
- self:send_fp_packet( packet )
- return self:read_fp_packet( )
- end,
-
- --- Sends an FPOpenVol request to the server and handles the response
- --
- -- @param bitmap number bitmask of volume information to request
- -- @param volume_name string containing the volume name to query
- -- @return response object with the following result bitmap and
- -- volume_id fields
- fp_open_vol = function( self, bitmap, volume_name )
- local packet, status, pos, data
- local data_offset, pad = 0, 0
- local response, volume = {}, {}
-
- data = bin.pack("CC>SCA", COMMAND.FPOpenVol, pad, bitmap, volume_name:len(), volume_name )
- packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
- self:send_fp_packet( packet )
- response = self:read_fp_packet()
- if response:getErrorCode() ~= ERROR.FPNoErr then
- return response
- end
-
- pos, volume.bitmap, volume.volume_id = bin.unpack(">S>S", response.packet.data)
- response:setResult(volume)
- return response
- end,
-
-
- --- Sends an FPGetFileDirParms request to the server and handles the response
- --
- -- @param volume_id number containing the id of the volume to query
- -- @param did number containing the id of the directory to query
- -- @param file_bitmap number bitmask of file information to query
- -- @param dir_bitmap number bitmask of directory information to query
- -- @param path string containing the name of the directory to query
- -- @return response object with the following result file_bitmap, dir_bitmap,
- -- file_type and (dir or file tables) depending on whether
- -- did is a file or directory
- fp_get_file_dir_parms = function( self, volume_id, did, file_bitmap, dir_bitmap, path )
-
- local packet, status, data
- local data_offset = 0
- local pad = 0
- local response, parms = {}, {}
- local pos
-
- if ( did == nil ) then
- response = Response:new()
- response:setErrorMessage("No Directory Id supplied")
- return response
- end
-
- if ( volume_id == nil ) then
- response = Response:new()
- response:setErrorMessage("No Volume Id supplied")
- return response
- end
-
- data = bin.pack("CC>S>I>S>SCCAC", COMMAND.FPGetFileDirParams, pad, volume_id, did, file_bitmap, dir_bitmap, path.type, path.len, path.name, 0)
- packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
- self:send_fp_packet( packet )
- response = self:read_fp_packet()
-
- if response:getErrorCode() ~= ERROR.FPNoErr then
- return response
- end
-
- pos, parms.file_bitmap, parms.dir_bitmap, parms.file_type, pad = bin.unpack( ">S>SCC", response.packet.data )
-
- -- file or dir?
- if ( parms.file_type == 0x80 ) then
- pos, parms.dir = Util.decode_dir_bitmap( parms.dir_bitmap, response.packet.data, pos )
- else
- -- file
- pos, parms.file = Util.decode_file_bitmap( parms.file_bitmap, response.packet.data, pos )
- end
-
- response:setResult(parms)
- return response
- end,
-
- --- Sends an FPEnumerateExt2 request to the server and handles the response
- --
- -- @param volume_id number containing the id of the volume to query
- -- @param did number containing the id of the directory to query
- -- @param file_bitmap number bitmask of file information to query
- -- @param dir_bitmap number bitmask of directory information to query
- -- @param req_count number
- -- @param start_index number
- -- @param reply_size number
- -- @param path string containing the name of the directory to query
- -- @return response object with the following result set to a table of tables containing
- -- file_bitmap, dir_bitmap, req_count fields
- fp_enumerate_ext2 = function( self, volume_id, did, file_bitmap, dir_bitmap, req_count, start_index, reply_size, path )
-
- local packet, pos, _, status
- local data_offset = 0
- local pad = 0
- local response,records = {}, {}
-
- local data = bin.pack( "CC>S>I>S>S", COMMAND.FPEnumerateExt2, pad, volume_id, did, file_bitmap, dir_bitmap )
- data = data .. bin.pack( ">S>I>ICCA", req_count, start_index, reply_size, path.type, path.len, path.name )
- packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
-
- self:send_fp_packet( packet )
- response = self:read_fp_packet( )
-
- if response:getErrorCode() ~= ERROR.FPNoErr then
- return response
- end
-
- pos, file_bitmap, dir_bitmap, req_count = bin.unpack(">S>S>S", response.packet.data)
-
- records = {}
-
- for i=1, req_count do
- local record = {}
- local len, _, ftype
-
- pos, len, ftype, _ = bin.unpack(">SCC", response.packet.data, pos)
-
- if ( ftype == 0x80 ) then
- _, record = Util.decode_dir_bitmap( dir_bitmap, response.packet.data, pos )
- else
- -- file
- _, record = Util.decode_file_bitmap( file_bitmap, response.packet.data, pos )
- end
-
- if bit.mod( len, 2 ) ~= 0 then
- len = len + 1
- end
-
- pos = pos + ( len - 4 )
-
- record.type = ftype
- table.insert(records, record)
- end
-
- response:setResult(records)
- return response
- end,
-
- --- Sends an FPOpenFork request to the server and handles the response
- --
- -- @param flag number
- -- @param volume_id number containing the id of the volume to query
- -- @param did number containing the id of the directory to query
- -- @param file_bitmap number bitmask of file information to query
- -- @param access_mode number containing bitmask of options from ACCESS_MODE
- -- @param path string containing the name of the directory to query
- -- @return response object with the following result contents file_bitmap and fork_id
- fp_open_fork = function( self, flag, volume_id, did, file_bitmap, access_mode, path )
-
- local packet, _
- local data_offset = 0
- local pad = 0
- local response, fork = {}, {}
-
- local data = bin.pack( "CC>S>I>S>S", COMMAND.FPOpenFork, flag, volume_id, did, file_bitmap, access_mode )
-
- if path.type == PATH_TYPE.LongName then
- data = data .. bin.pack( "CCA", path.type, path.len, path.name )
- end
-
- if path.type == PATH_TYPE.UTF8Name then
- local unicode_hint = 0x08000103
- data = data .. bin.pack( "C>I>SA", path.type, unicode_hint, path.len, path.name )
- end
-
- packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
- self:send_fp_packet( packet )
- response = self:read_fp_packet()
-
- if response:getErrorCode() ~= ERROR.FPNoErr then
- return response
- end
-
- _, fork.file_bitmap, fork.fork_id = bin.unpack(">S>S", response.packet.data)
- response:setResult(fork)
- return response
- end,
-
- --- FPCloseFork
- --
- -- @param fork number containing the fork to close
- -- @return response object
- fp_close_fork = function( self, fork )
- local packet
- local data_offset = 0
- local pad = 0
- local response = {}
-
- local data = bin.pack( "CC>S", COMMAND.FPCloseFork, pad, fork )
-
- packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
- self:send_fp_packet( packet )
- return self:read_fp_packet( )
- end,
-
- --- FPCreateDir
- --
- -- @param vol_id number containing the volume id
- -- @param dir_id number containing the directory id
- -- @param path string containing the name of the directory
- -- @return response object
- fp_create_dir = function( self, vol_id, dir_id, path )
- local packet
- local data_offset, pad = 0, 0
- local response = {}
-
- local data = bin.pack( "CC>S>ICp", COMMAND.FPCreateDir, pad, vol_id, dir_id, path.type, path.name )
-
- packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
- self:send_fp_packet( packet )
- return self:read_fp_packet( )
- end,
-
- --- Sends an FPCloseVol request to the server and handles the response
- --
- -- @param volume_id number containing the id of the volume to close
- -- @return response object
- fp_close_vol = function( self, volume_id )
- local packet
- local data_offset, pad = 0, 0
- local response = {}
-
- local data = bin.pack( "CC>S", COMMAND.FPCloseVol, pad, volume_id )
-
- packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
- self:send_fp_packet( packet )
- return self:read_fp_packet( )
- end,
-
- --- FPReadExt
- --
- -- @param fork number containing the open fork
- -- @param offset number containing the offset from where writing should start. Negative value indicates offset from the end of the fork
- -- @param count number containing the number of bytes to be written
- -- @return response object
- fp_read_ext = function( self, fork, offset, count )
- local pad = 0
- local packet, response
- local data_offset = 0
- local block_size = 1024
- local data = bin.pack( "CC>S>L>L", COMMAND.FPReadExt, pad, fork, offset, count )
-
- packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
- self:send_fp_packet( packet )
- response = self:read_fp_packet( )
-
- if ( response:getErrorCode() == ERROR.FPEOFErr and response.packet.header.length > 0 ) then
- response:setErrorCode( ERROR.FPNoErr )
- end
-
- response:setResult( response.packet.data )
- return response
- end,
-
- --- FPWriteExt
- --
- -- @param flag number indicates whether Offset is relative to the beginning or end of the fork.
- -- @param fork number containing the open fork
- -- @param offset number containing the offset from where writing should start. Negative value indicates offset from the end of the fork
- -- @param count number containing the number of bytes to be written
- -- @param fdata string containing the data to be written
- -- @return response object
- fp_write_ext = function( self, flag, fork, offset, count, fdata )
- local packet
- local data_offset = 20
- local data
-
- if count > fdata:len() then
- local err = Response:new()
- err:setErrorMessage("fp_write_ext: Count is greater than the amount of data")
- return err
- end
- if count < 0 then
- local err = Response:new()
- err:setErrorMessage("fp_write_ext: Count must exceed zero")
- return err
- end
-
- data = bin.pack( "CC>S>L>LA", COMMAND.FPWriteExt, flag, fork, offset, count, fdata )
- packet = self:create_fp_packet( REQUEST.Write, data_offset, data )
- self:send_fp_packet( packet )
- return self:read_fp_packet( )
- end,
-
- --- FPCreateFile
- --
- -- @param flag number where 0 indicates a soft create and 1 indicates a hard create.
- -- @param vol_id number containing the volume id
- -- @param did number containing the ancestor directory id
- -- @param path string containing the path, including the volume, path and file name
- -- @return response object
- fp_create_file = function(self, flag, vol_id, did, path )
- local packet
- local data_offset = 0
- local data = bin.pack( "CC>S>ICCA" , COMMAND.FPCreateFile, flag, vol_id, did, path.type, path.len, path.name )
-
- packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
- self:send_fp_packet( packet )
- return self:read_fp_packet()
- end,
-
- --- FPMapId
- --
- -- @param subfunc number containing the subfunction to call
- -- @param id number containing th id to translate
- -- @return response object with the id in the result field
- fp_map_id = function( self, subfunc, id )
- local packet, response
- local data_offset = 0
- local data = bin.pack( "CC", COMMAND.FPMapId, subfunc )
- local _, len
-
- if ( subfunc == MAP_ID.UserUUIDToUTF8Name or subfunc == MAP_ID.GroupUUIDToUTF8Name ) then
- data = data .. bin.pack(">L", id)
- else
- data = data .. bin.pack(">I", id)
- end
-
- packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
- self:send_fp_packet( packet )
- response = self:read_fp_packet( )
-
- if response:getErrorCode() ~= ERROR.FPNoErr then
- return response
- end
-
- -- Netatalk returns the name with 1-byte length prefix,
- -- Mac OS has a 2-byte (UTF-8) length prefix
- local _, len = bin.unpack("C", response.packet.data)
-
- -- if length is zero assume 2-byte length (UTF-8 name)
- if len == 0 then
- response:setResult( select(2, bin.unpack(">P", response.packet.data )) )
- else
- response:setResult( select(2, bin.unpack("p", response.packet.data )) )
- end
- return response
- end,
-
- --- FPMapName
- --
- -- @param subfunc number containing the subfunction to call
- -- @param name string containing name to map
- -- @return response object with the mapped name in the result field
- fp_map_name = function( self, subfunc, name )
- local packet
- local data_offset = 0
- local data = bin.pack( "CC>SA", COMMAND.FPMapName, subfunc, name:len(), name )
- local response
-
- packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
- self:send_fp_packet( packet )
- response = self:read_fp_packet( )
-
- if response:getErrorCode() ~= ERROR.FPNoErr then
- return response
- end
-
- response:setResult( select(2, bin.unpack(">I", response.packet.data)))
- return response
- end,
+ RequestId = 1,
+
+ new = function(self,o)
+ o = o or {}
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
+
+ setSocket = function(self, socket)
+ self.socket = socket
+ end,
+
+ --- Creates an AFP packet
+ --
+ -- @param command number should be one of the commands in the COMMAND table
+ -- @param data_offset number holding the offset to the data
+ -- @param data the actual data of the request
+ create_fp_packet = function( self, command, data_offset, data )
+ local reserved = 0
+ local data = data or ""
+ local data_len = data:len()
+ local header = bin.pack("CC>SIII", FLAGS.Request, command, self.RequestId, data_offset, data_len, reserved)
+
+ self.RequestId = self.RequestId + 1
+ return header .. data
+ end,
+
+ --- Parses the FP header (first 16-bytes of packet)
+ --
+ -- @param packet string containing the raw packet
+ -- @return table with header data containing flags, command,
+ -- request_id, error_code, length and reserved fields
+ parse_fp_header = function( self, packet )
+ local header = {}
+ local pos
+
+ pos, header.flags, header.command, header.request_id = bin.unpack( "CC>S", packet )
+ pos, header.error_code, header.length, header.reserved = bin.unpack( ">i>II", packet:sub(5) )
+
+ if header.error_code ~= 0 then
+ header.error_msg = ERROR_MSG[header.error_code] or ("Unknown error: %d"):format(header.error_code)
+ header.error_msg = "ERROR: " .. header.error_msg
+ end
+ header.raw = packet:sub(1,16)
+ return header
+ end,
+
+ --- Reads a AFP packet of the socket
+ --
+ -- @return Response object
+ read_fp_packet = function( self )
+
+ local packet = {}
+ local buf = ""
+ local status, response
+
+ status, buf = self.socket:receive_bytes(16)
+ if ( not status ) then
+ response = Response:new()
+ response:setErrorCode(ERROR.SocketError)
+ response:setErrorMessage(buf)
+ return response
+ end
+
+ packet.header = self:parse_fp_header( buf )
+ while buf:len() < packet.header.length + packet.header.raw:len() do
+ local tmp
+ status, tmp = self.socket:receive_bytes( packet.header.length + 16 - buf:len() )
+ if not status then
+ response = Response:new()
+ response:setErrorCode(ERROR.SocketError)
+ response:setErrorMessage(buf)
+ return response
+ end
+ buf = buf .. tmp
+ end
+
+ packet.data = buf:len() > 16 and buf:sub( 17 ) or ""
+ response = Response:new()
+ response:setErrorCode(packet.header.error_code)
+ response:setPacket(packet)
+
+ return response
+ end,
+
+ --- Sends the raw packet over the socket
+ --
+ -- @param packet containing the raw data
+ -- @return Response object
+ send_fp_packet = function( self, packet )
+ return self.socket:send(packet)
+ end,
+
+ --- Sends an DSIOpenSession request to the server and handles the response
+ --
+ -- @return Response object
+ dsi_open_session = function( self, host, port )
+ local data_offset = 0
+ local option = 0x01 -- Attention Quantum
+ local option_len = 4
+ local quantum = 1024
+ local data, packet, status
+
+ data = bin.pack( "CCI", option, option_len, quantum )
+ packet = self:create_fp_packet( REQUEST.OpenSession, data_offset, data )
+
+ self:send_fp_packet( packet )
+ return self:read_fp_packet()
+ end,
+
+ --- Sends an DSICloseSession request to the server and handles the response
+ dsi_close_session = function( self )
+ local data_offset = 0
+ local option = 0x01 -- Attention Quantum
+ local option_len = 4
+ local quantum = 1024
+ local data, packet, status
+
+ data = ""
+ packet = self:create_fp_packet( REQUEST.CloseSession, data_offset, data )
+
+ self:send_fp_packet( packet )
+ end,
+
+ -- Sends an FPCopyFile request to the server
+ --
+ -- @param src_vol number containing the ID of the src file volume
+ -- @param srd_did number containing the directory id of the src file
+ -- @param src_path string containingt the file path/name of the src file
+ -- @param dst_vol number containing the ID of the dst file volume
+ -- @param dst_did number containing the id of the dest. directory
+ -- @param dst_path string containing the dest path (can be nil or "")
+ -- @param new_name string containign the new name of the destination
+ -- @return Response object
+ fp_copy_file = function(self, src_vol, src_did, src_path, dst_vol, dst_did, dst_path, new_name )
+ local pad, data_offset = 0, 0
+ local unicode_names, unicode_hint = 0x03, 0x08000103
+ local data, packet, response
+
+ -- make sure we have empty names rather than nil values
+ local dst_path = dst_path or ""
+ local src_path = src_path or ""
+ local new_name = new_name or ""
+
+ data = bin.pack(">CCSISI", COMMAND.FPCopyFile, pad, src_vol, src_did, dst_vol, dst_did )
+ data = data .. bin.pack(">CIP", unicode_names, unicode_hint, src_path )
+ data = data .. bin.pack(">CIP", unicode_names, unicode_hint, dst_path )
+ data = data .. bin.pack(">CIP", unicode_names, unicode_hint, new_name )
+
+ packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
+ self:send_fp_packet( packet )
+ return self:read_fp_packet()
+ end,
+
+ --- Sends an GetStatus DSI request (which is basically a FPGetSrvrInfo
+ -- AFP request) to the server and handles the response
+ --
+ -- @return status (true or false)
+ -- @return table with server information (if status is true) or error string
+ -- (if status is false)
+ fp_get_server_info = function(self)
+ local packet
+ local data_offset = 0
+ local pad = 0
+ local response, result = {}, {}
+ local offsets = {}
+ local pos
+ local _
+ local status
+
+ local data = bin.pack("CC", COMMAND.FPGetSrvrInfo, 0)
+ packet = self:create_fp_packet(REQUEST.GetStatus, data_offset, data)
+ self:send_fp_packet(packet)
+ response = self:read_fp_packet()
+
+ if response:getErrorCode() ~= ERROR.FPNoErr then
+ return response
+ end
+
+ packet = response.packet
+
+ -- parse and store the offsets in the 'header'
+ pos, offsets.machine_type, offsets.afp_version_count,
+ offsets.uam_count, offsets.volume_icon_and_mask
+ = bin.unpack(">SSSS", packet.data, pos)
+
+ -- the flags are directly in the 'header'
+ result.flags = {}
+ pos, result.flags.raw = bin.unpack(">S", packet.data, pos)
+
+ -- the short server name is stored directly in the 'header' as
+ -- well
+ pos, result.server_name = bin.unpack("p", packet.data, pos)
+
+ -- Server offset should begin at an even boundary see link below
+ -- http://developer.apple.com/mac/library/documentation/Networking/Reference/AFP_Reference/Reference/reference.html#//apple_ref/doc/uid/TP40003548-CH3-CHDIEGED
+ if (pos + 1) % 2 ~= 0 then
+ pos = pos + 1
+ end
+
+ -- and some more offsets
+ pos, offsets.server_signature, offsets.network_addresses_count,
+ offsets.directory_names_count, offsets.utf8_server_name
+ = bin.unpack(">SSSS", packet.data, pos)
+
+ -- this sets up all the server flaqs in the response table as booleans
+ result.flags.SuperClient = flag_is_set(result.flags.raw, SERVERFLAGS.SuperClient)
+ result.flags.UUIDs = flag_is_set(result.flags.raw, SERVERFLAGS.UUIDs)
+ result.flags.UTF8ServerName = flag_is_set(result.flags.raw, SERVERFLAGS.UTF8ServerName)
+ result.flags.OpenDirectory = flag_is_set(result.flags.raw, SERVERFLAGS.OpenDirectory)
+ result.flags.Reconnect = flag_is_set(result.flags.raw, SERVERFLAGS.Reconnect)
+ result.flags.ServerNotifications = flag_is_set(result.flags.raw, SERVERFLAGS.ServerNotifications)
+ result.flags.TCPoverIP = flag_is_set(result.flags.raw, SERVERFLAGS.TCPoverIP)
+ result.flags.ServerSignature = flag_is_set(result.flags.raw, SERVERFLAGS.ServerSignature)
+ result.flags.ServerMessages = flag_is_set(result.flags.raw, SERVERFLAGS.ServerMessages)
+ result.flags.NoPasswordSaving = flag_is_set(result.flags.raw, SERVERFLAGS.NoPasswordSaving)
+ result.flags.ChangeablePasswords = flag_is_set(result.flags.raw, SERVERFLAGS.ChangeablePasswords)
+ result.flags.CopyFile = flag_is_set(result.flags.raw, SERVERFLAGS.CopyFile)
+
+ -- store the machine type
+ _, result.machine_type = bin.unpack("p", packet.data, offsets.machine_type + 1)
+
+ -- this tells us the number of afp versions supported
+ pos, result.afp_version_count = bin.unpack("C", packet.data, offsets.afp_version_count + 1)
+
+ -- now we loop through them all, storing for the response
+ result.afp_versions = {}
+ for i = 1,result.afp_version_count do
+ pos, _ = bin.unpack("p", packet.data, pos)
+ table.insert(result.afp_versions, _)
+ end
+
+ -- same idea as the afp versions here
+ pos, result.uam_count = bin.unpack("C", packet.data, offsets.uam_count + 1)
+
+ result.uams = {}
+ for i = 1,result.uam_count do
+ pos, _ = bin.unpack("p", packet.data, pos)
+ table.insert(result.uams, _)
+ end
+
+ -- volume_icon_and_mask would normally be parsed out here,
+ -- however the apple docs say it is deprecated in Mac OS X, so
+ -- we don't bother with it
+
+ -- server signature is 16 bytes
+ result.server_signature = string.sub(packet.data, offsets.server_signature + 1, offsets.server_signature + 16)
+
+ -- this is the same idea as afp_version and uam above
+ pos, result.network_addresses_count = bin.unpack("C", packet.data, offsets.network_addresses_count + 1)
+
+ result.network_addresses = {}
+
+ -- gets a little complicated in here, basically each entry has
+ -- a length byte, a tag byte, and then the data. We parse
+ -- differently based on the tag
+ for i = 1, result.network_addresses_count do
+ local length
+ local tag
+
+ pos, length = bin.unpack("C", packet.data, pos)
+ pos, tag = bin.unpack("C", packet.data, pos)
+
+ if tag == 0x00 then
+ -- reserved, shouldn't ever come up, maybe this should
+ -- return an error? maybe not, lets just ignore this
+ elseif tag == 0x01 then
+ -- four byte ip
+ local octet = {}
+ pos, octet[1], octet[2], octet[3], octet[4] = bin.unpack("CCCC", packet.data, pos)
+ table.insert(result.network_addresses, string.format("%d.%d.%d.%d", octet[1], octet[2], octet[3], octet[4]))
+ elseif tag == 0x02 then
+ -- four byte ip and two byte port
+ local octet = {}
+ local port
+ pos, octet[1], octet[2], octet[3], octet[4], port = bin.unpack(">CCCCS", packet.data, pos)
+ table.insert(result.network_addresses, string.format("%d.%d.%d.%d:%d", octet[1], octet[2], octet[3], octet[4], port))
+ elseif tag == 0x03 then
+ -- ddp address (two byte network, one byte
+ -- node, one byte socket) not tested, anyone
+ -- use ddp anymore?
+ local network
+ local node
+ local socket
+ pos, network = bin.unpack(">S", packet.data, pos)
+ pos, node = bin.unpack("C", packet.data, pos)
+ pos, socket = bin.unpack("C", packet.data, pos)
+ table.insert(result.network_addresses, string.format("ddp %d.%d:%d", network, node, socket))
+ elseif tag == 0x04 then
+ -- dns name (string)
+ local temp
+ pos, temp = bin.unpack("z", packet.data:sub(1,pos+length-3), pos)
+ table.insert(result.network_addresses, temp)
+ elseif tag == 0x05 then
+ -- four byte ip and two byte port, client
+ -- should use ssh. not tested, should work as it
+ -- is the same as tag 0x02
+ local octet = {}
+ local port
+ pos, octet[1], octet[2], octet[3], octet[4], port = bin.unpack(">CCCCS", packet.data, pos)
+ table.insert(result.network_addresses, string.format("ssh://%d.%d.%d.%d:%d", octet[1], octet[2], octet[3], octet[4], port))
+ elseif tag == 0x06 then
+ -- 16 byte ipv6
+ -- not tested, but should work (next tag is
+ -- tested)
+ local octet = {}
+ local j
+ local addr
+
+ for j = 1, 8 do
+ pos, octet[j] = bin.unpack(">S", packet.data, pos)
+ end
+
+ for j = 1, 7 do
+ addr = addr .. string.format("%04x:", octet[j])
+ end
+ addr = addr .. string.format("%04x", octet[8])
+
+ table.insert(result.network_addresses, addr)
+ elseif tag == 0x07 then
+ -- 16 byte ipv6 and two byte port
+ local octet = {}
+ local port
+ local j
+ local addr
+
+ for j = 1, 8 do
+ pos, octet[j] = bin.unpack(">S", packet.data, pos)
+ end
+ pos, port = bin.unpack(">S", packet.data, pos)
+
+ addr = "["
+
+ for j = 1, 7 do
+ addr = addr .. string.format("%04x:", octet[j])
+ end
+ addr = addr .. string.format("%04x]:%d", octet[8], port)
+
+ table.insert(result.network_addresses, addr)
+ end
+ end
+
+ -- same idea as the others here
+ pos, result.directory_names_count = bin.unpack("C", packet.data, offsets.directory_names_count + 1)
+
+ result.directory_names = {}
+ for i = 1, result.directory_names_count do
+ local dirname
+ pos, dirname = bin.unpack("p", packet.data, pos)
+ table.insert(result.directory_names, dirname)
+ end
+
+ -- only one utf8 server name. note this string has a two-byte length.
+ _, result.utf8_server_name = bin.unpack(">P", packet.data, offsets.utf8_server_name + 1)
+ response.result = result
+
+ return response
+ end,
+
+
+ --- Sends an FPGetUserInfo AFP request to the server and handles the response
+ --
+ -- @return response object with the following result user_bitmap and
+ -- uid fields
+ fp_get_user_info = function( self )
+
+ local packet, pos, status, response
+ local data_offset = 0
+ local flags = 1 -- Default User
+ local uid = 0
+ local bitmap = USER_BITMAP.UserId
+ local result = {}
+
+ local data = bin.pack( "CCI>S", COMMAND.FPGetUserInfo, flags, uid, bitmap )
+ packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
+
+ self:send_fp_packet( packet )
+ response = self:read_fp_packet()
+ if response:getErrorCode() ~= ERROR.FPNoErr then
+ return response
+ end
+
+ pos, response.result.user_bitmap, response.result.uid = bin.unpack(">S>I", packet.data)
+
+ return response
+ end,
+
+ --- Sends an FPGetSrvrParms AFP request to the server and handles the response
+ --
+ -- @return response object with the following result server_time,
+ -- vol_count, volumes fields
+ fp_get_srvr_parms = function(self)
+ local packet, status, data
+ local data_offset = 0
+ local response = {}
+ local pos = 0
+ local parms = {}
+
+ data = bin.pack("CC", COMMAND.FPGetSrvParms, 0)
+ packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
+ self:send_fp_packet( packet )
+ response = self:read_fp_packet()
+
+ if response:getErrorCode() ~= ERROR.FPNoErr then
+ return response
+ end
+
+ data = response:getPacketData()
+ pos, parms.server_time, parms.vol_count = bin.unpack("IC", data)
+
+ -- we should now be at the leading zero preceeding the first volume name
+ -- next is the length of the volume name, move pos there
+ pos = pos + 1
+
+ parms.volumes = {}
+
+ for i=1, parms.vol_count do
+ local _, vol_len = bin.unpack("C", data:sub(pos))
+ local volume_name = data:sub(pos + 1, pos + 1 + vol_len)
+ pos = pos + vol_len + 2
+ table.insert(parms.volumes, string.format("%s", volume_name) )
+ end
+
+ response:setResult(parms)
+
+ return response
+ end,
+
+
+ --- Sends an FPLogin request to the server and handles the response
+ --
+ -- This function currently only supports the 3.1 through 3.3 protocol versions
+ -- It currently supports the following authentication methods:
+ -- o No User Authent
+ -- o DHCAST128
+ --
+ -- The DHCAST128 UAM should work against most servers even though it's
+ -- superceeded by the DHX2 UAM.
+ --
+ -- @param afp_version string (AFP3.3|AFP3.2|AFP3.1)
+ -- @param uam string containing authentication information
+ -- @return Response object
+ fp_login = function( self, afp_version, uam, username, password, options )
+ local packet, status, data
+ local data_offset = 0
+ local status, response
+
+ if not HAVE_SSL then
+ response = Response:new()
+ response:setErrorMessage("OpenSSL not available, aborting ...")
+ return response
+ end
+
+ -- currently we only support AFP3.3
+ if afp_version == nil or ( afp_version ~= "AFP3.3" and afp_version ~= "AFP3.2" and afp_version ~= "AFP3.1" ) then
+ response = Response:new()
+ response:setErrorMessage("Incorrect AFP version")
+ return response
+ end
+
+ if ( uam == "No User Authent" ) then
+ data = bin.pack( "CCACA", COMMAND.FPLogin, afp_version:len(), afp_version, uam:len(), uam )
+ packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
+ self:send_fp_packet( packet )
+ return self:read_fp_packet( )
+ elseif( uam == "DHCAST128" ) then
+ local dhx_s2civ, dhx_c2civ = 'CJalbert', 'LWallace'
+ local p, g, Ra, Ma, Mb, K, nonce
+ local EncData, PlainText, K_bin, auth_response
+ local _, Id
+ local username = username or ""
+ local password = password or ""
+
+ if ( bit.mod(username:len(), 2) == 0 ) then
+ username = username .. string.char(0)
+ end
+
+ p = openssl.bignum_hex2bn("BA2873DFB06057D43F2024744CEEE75B")
+ g = openssl.bignum_dec2bn("7")
+ Ra = openssl.bignum_hex2bn("86F6D3C0B0D63E4B11F113A2F9F19E3BBBF803F28D30087A1450536BE979FD42")
+ Ma = openssl.bignum_mod_exp(g, Ra, p)
+
+ data = bin.pack( "CpppA", COMMAND.FPLogin, afp_version, uam, username, openssl.bignum_bn2bin(Ma) )
+ packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
+ self:send_fp_packet( packet )
+ response = self:read_fp_packet( )
+ if ( response:getErrorCode() ~= ERROR.FPAuthContinue ) then
+ return response
+ end
+
+ if ( response.packet.header.length ~= 50 ) then
+ response:setErrorMessage("LoginContinue packet contained invalid data")
+ return response
+ end
+
+ _, Id, Mb, EncData = bin.unpack(">SH16A32", response.packet.data )
+
+ Mb = openssl.bignum_hex2bn( Mb )
+ K = openssl.bignum_mod_exp (Mb, Ra, p)
+ K_bin = openssl.bignum_bn2bin(K)
+ nonce = openssl.decrypt("cast5-cbc", K_bin, dhx_s2civ, EncData, false ):sub(1,16)
+ nonce = openssl.bignum_add( openssl.bignum_bin2bn(nonce), openssl.bignum_dec2bn("1") )
+ PlainText = openssl.bignum_bn2bin(nonce) .. Util.ZeroPad(password, 64)
+ auth_response = openssl.encrypt( "cast5-cbc", K_bin, dhx_c2civ, PlainText, true)
+
+ data = bin.pack( "CC>SA", COMMAND.FPLoginCont, 0, Id, auth_response )
+ packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
+ self:send_fp_packet( packet )
+ response = self:read_fp_packet( )
+ if ( response:getErrorCode() ~= ERROR.FPNoErr ) then
+ return response
+ end
+ return response
+ end
+ response:setErrorMessage("Unsupported uam: " .. uam or "nil")
+ return response
+ end,
+
+ -- Terminates sessions and frees server resources established by FPLoginand FPLoginExt.
+ --
+ -- @return response object
+ fp_logout = function( self )
+ local packet, data, response
+ local data_offset, pad = 0, 0
+
+ data = bin.pack("CC", COMMAND.FPLogout, pad)
+ packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
+ self:send_fp_packet( packet )
+ return self:read_fp_packet( )
+ end,
+
+ --- Sends an FPOpenVol request to the server and handles the response
+ --
+ -- @param bitmap number bitmask of volume information to request
+ -- @param volume_name string containing the volume name to query
+ -- @return response object with the following result bitmap and
+ -- volume_id fields
+ fp_open_vol = function( self, bitmap, volume_name )
+ local packet, status, pos, data
+ local data_offset, pad = 0, 0
+ local response, volume = {}, {}
+
+ data = bin.pack("CC>SCA", COMMAND.FPOpenVol, pad, bitmap, volume_name:len(), volume_name )
+ packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
+ self:send_fp_packet( packet )
+ response = self:read_fp_packet()
+ if response:getErrorCode() ~= ERROR.FPNoErr then
+ return response
+ end
+
+ pos, volume.bitmap, volume.volume_id = bin.unpack(">S>S", response.packet.data)
+ response:setResult(volume)
+ return response
+ end,
+
+
+ --- Sends an FPGetFileDirParms request to the server and handles the response
+ --
+ -- @param volume_id number containing the id of the volume to query
+ -- @param did number containing the id of the directory to query
+ -- @param file_bitmap number bitmask of file information to query
+ -- @param dir_bitmap number bitmask of directory information to query
+ -- @param path string containing the name of the directory to query
+ -- @return response object with the following result file_bitmap, dir_bitmap,
+ -- file_type and (dir or file tables) depending on whether
+ -- did is a file or directory
+ fp_get_file_dir_parms = function( self, volume_id, did, file_bitmap, dir_bitmap, path )
+
+ local packet, status, data
+ local data_offset = 0
+ local pad = 0
+ local response, parms = {}, {}
+ local pos
+
+ if ( did == nil ) then
+ response = Response:new()
+ response:setErrorMessage("No Directory Id supplied")
+ return response
+ end
+
+ if ( volume_id == nil ) then
+ response = Response:new()
+ response:setErrorMessage("No Volume Id supplied")
+ return response
+ end
+
+ data = bin.pack("CC>S>I>S>SCCAC", COMMAND.FPGetFileDirParams, pad, volume_id, did, file_bitmap, dir_bitmap, path.type, path.len, path.name, 0)
+ packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
+ self:send_fp_packet( packet )
+ response = self:read_fp_packet()
+
+ if response:getErrorCode() ~= ERROR.FPNoErr then
+ return response
+ end
+
+ pos, parms.file_bitmap, parms.dir_bitmap, parms.file_type, pad = bin.unpack( ">S>SCC", response.packet.data )
+
+ -- file or dir?
+ if ( parms.file_type == 0x80 ) then
+ pos, parms.dir = Util.decode_dir_bitmap( parms.dir_bitmap, response.packet.data, pos )
+ else
+ -- file
+ pos, parms.file = Util.decode_file_bitmap( parms.file_bitmap, response.packet.data, pos )
+ end
+
+ response:setResult(parms)
+ return response
+ end,
+
+ --- Sends an FPEnumerateExt2 request to the server and handles the response
+ --
+ -- @param volume_id number containing the id of the volume to query
+ -- @param did number containing the id of the directory to query
+ -- @param file_bitmap number bitmask of file information to query
+ -- @param dir_bitmap number bitmask of directory information to query
+ -- @param req_count number
+ -- @param start_index number
+ -- @param reply_size number
+ -- @param path string containing the name of the directory to query
+ -- @return response object with the following result set to a table of tables containing
+ -- file_bitmap, dir_bitmap, req_count fields
+ fp_enumerate_ext2 = function( self, volume_id, did, file_bitmap, dir_bitmap, req_count, start_index, reply_size, path )
+
+ local packet, pos, _, status
+ local data_offset = 0
+ local pad = 0
+ local response,records = {}, {}
+
+ local data = bin.pack( "CC>S>I>S>S", COMMAND.FPEnumerateExt2, pad, volume_id, did, file_bitmap, dir_bitmap )
+ data = data .. bin.pack( ">S>I>ICCA", req_count, start_index, reply_size, path.type, path.len, path.name )
+ packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
+
+ self:send_fp_packet( packet )
+ response = self:read_fp_packet( )
+
+ if response:getErrorCode() ~= ERROR.FPNoErr then
+ return response
+ end
+
+ pos, file_bitmap, dir_bitmap, req_count = bin.unpack(">S>S>S", response.packet.data)
+
+ records = {}
+
+ for i=1, req_count do
+ local record = {}
+ local len, _, ftype
+
+ pos, len, ftype, _ = bin.unpack(">SCC", response.packet.data, pos)
+
+ if ( ftype == 0x80 ) then
+ _, record = Util.decode_dir_bitmap( dir_bitmap, response.packet.data, pos )
+ else
+ -- file
+ _, record = Util.decode_file_bitmap( file_bitmap, response.packet.data, pos )
+ end
+
+ if bit.mod( len, 2 ) ~= 0 then
+ len = len + 1
+ end
+
+ pos = pos + ( len - 4 )
+
+ record.type = ftype
+ table.insert(records, record)
+ end
+
+ response:setResult(records)
+ return response
+ end,
+
+ --- Sends an FPOpenFork request to the server and handles the response
+ --
+ -- @param flag number
+ -- @param volume_id number containing the id of the volume to query
+ -- @param did number containing the id of the directory to query
+ -- @param file_bitmap number bitmask of file information to query
+ -- @param access_mode number containing bitmask of options from ACCESS_MODE
+ -- @param path string containing the name of the directory to query
+ -- @return response object with the following result contents file_bitmap and fork_id
+ fp_open_fork = function( self, flag, volume_id, did, file_bitmap, access_mode, path )
+
+ local packet, _
+ local data_offset = 0
+ local pad = 0
+ local response, fork = {}, {}
+
+ local data = bin.pack( "CC>S>I>S>S", COMMAND.FPOpenFork, flag, volume_id, did, file_bitmap, access_mode )
+
+ if path.type == PATH_TYPE.LongName then
+ data = data .. bin.pack( "CCA", path.type, path.len, path.name )
+ end
+
+ if path.type == PATH_TYPE.UTF8Name then
+ local unicode_hint = 0x08000103
+ data = data .. bin.pack( "C>I>SA", path.type, unicode_hint, path.len, path.name )
+ end
+
+ packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
+ self:send_fp_packet( packet )
+ response = self:read_fp_packet()
+
+ if response:getErrorCode() ~= ERROR.FPNoErr then
+ return response
+ end
+
+ _, fork.file_bitmap, fork.fork_id = bin.unpack(">S>S", response.packet.data)
+ response:setResult(fork)
+ return response
+ end,
+
+ --- FPCloseFork
+ --
+ -- @param fork number containing the fork to close
+ -- @return response object
+ fp_close_fork = function( self, fork )
+ local packet
+ local data_offset = 0
+ local pad = 0
+ local response = {}
+
+ local data = bin.pack( "CC>S", COMMAND.FPCloseFork, pad, fork )
+
+ packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
+ self:send_fp_packet( packet )
+ return self:read_fp_packet( )
+ end,
+
+ --- FPCreateDir
+ --
+ -- @param vol_id number containing the volume id
+ -- @param dir_id number containing the directory id
+ -- @param path string containing the name of the directory
+ -- @return response object
+ fp_create_dir = function( self, vol_id, dir_id, path )
+ local packet
+ local data_offset, pad = 0, 0
+ local response = {}
+
+ local data = bin.pack( "CC>S>ICp", COMMAND.FPCreateDir, pad, vol_id, dir_id, path.type, path.name )
+
+ packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
+ self:send_fp_packet( packet )
+ return self:read_fp_packet( )
+ end,
+
+ --- Sends an FPCloseVol request to the server and handles the response
+ --
+ -- @param volume_id number containing the id of the volume to close
+ -- @return response object
+ fp_close_vol = function( self, volume_id )
+ local packet
+ local data_offset, pad = 0, 0
+ local response = {}
+
+ local data = bin.pack( "CC>S", COMMAND.FPCloseVol, pad, volume_id )
+
+ packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
+ self:send_fp_packet( packet )
+ return self:read_fp_packet( )
+ end,
+
+ --- FPReadExt
+ --
+ -- @param fork number containing the open fork
+ -- @param offset number containing the offset from where writing should start. Negative value indicates offset from the end of the fork
+ -- @param count number containing the number of bytes to be written
+ -- @return response object
+ fp_read_ext = function( self, fork, offset, count )
+ local pad = 0
+ local packet, response
+ local data_offset = 0
+ local block_size = 1024
+ local data = bin.pack( "CC>S>L>L", COMMAND.FPReadExt, pad, fork, offset, count )
+
+ packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
+ self:send_fp_packet( packet )
+ response = self:read_fp_packet( )
+
+ if ( response:getErrorCode() == ERROR.FPEOFErr and response.packet.header.length > 0 ) then
+ response:setErrorCode( ERROR.FPNoErr )
+ end
+
+ response:setResult( response.packet.data )
+ return response
+ end,
+
+ --- FPWriteExt
+ --
+ -- @param flag number indicates whether Offset is relative to the beginning or end of the fork.
+ -- @param fork number containing the open fork
+ -- @param offset number containing the offset from where writing should start. Negative value indicates offset from the end of the fork
+ -- @param count number containing the number of bytes to be written
+ -- @param fdata string containing the data to be written
+ -- @return response object
+ fp_write_ext = function( self, flag, fork, offset, count, fdata )
+ local packet
+ local data_offset = 20
+ local data
+
+ if count > fdata:len() then
+ local err = Response:new()
+ err:setErrorMessage("fp_write_ext: Count is greater than the amount of data")
+ return err
+ end
+ if count < 0 then
+ local err = Response:new()
+ err:setErrorMessage("fp_write_ext: Count must exceed zero")
+ return err
+ end
+
+ data = bin.pack( "CC>S>L>LA", COMMAND.FPWriteExt, flag, fork, offset, count, fdata )
+ packet = self:create_fp_packet( REQUEST.Write, data_offset, data )
+ self:send_fp_packet( packet )
+ return self:read_fp_packet( )
+ end,
+
+ --- FPCreateFile
+ --
+ -- @param flag number where 0 indicates a soft create and 1 indicates a hard create.
+ -- @param vol_id number containing the volume id
+ -- @param did number containing the ancestor directory id
+ -- @param path string containing the path, including the volume, path and file name
+ -- @return response object
+ fp_create_file = function(self, flag, vol_id, did, path )
+ local packet
+ local data_offset = 0
+ local data = bin.pack( "CC>S>ICCA" , COMMAND.FPCreateFile, flag, vol_id, did, path.type, path.len, path.name )
+
+ packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
+ self:send_fp_packet( packet )
+ return self:read_fp_packet()
+ end,
+
+ --- FPMapId
+ --
+ -- @param subfunc number containing the subfunction to call
+ -- @param id number containing th id to translate
+ -- @return response object with the id in the result field
+ fp_map_id = function( self, subfunc, id )
+ local packet, response
+ local data_offset = 0
+ local data = bin.pack( "CC", COMMAND.FPMapId, subfunc )
+ local _, len
+
+ if ( subfunc == MAP_ID.UserUUIDToUTF8Name or subfunc == MAP_ID.GroupUUIDToUTF8Name ) then
+ data = data .. bin.pack(">L", id)
+ else
+ data = data .. bin.pack(">I", id)
+ end
+
+ packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
+ self:send_fp_packet( packet )
+ response = self:read_fp_packet( )
+
+ if response:getErrorCode() ~= ERROR.FPNoErr then
+ return response
+ end
+
+ -- Netatalk returns the name with 1-byte length prefix,
+ -- Mac OS has a 2-byte (UTF-8) length prefix
+ local _, len = bin.unpack("C", response.packet.data)
+
+ -- if length is zero assume 2-byte length (UTF-8 name)
+ if len == 0 then
+ response:setResult( select(2, bin.unpack(">P", response.packet.data )) )
+ else
+ response:setResult( select(2, bin.unpack("p", response.packet.data )) )
+ end
+ return response
+ end,
+
+ --- FPMapName
+ --
+ -- @param subfunc number containing the subfunction to call
+ -- @param name string containing name to map
+ -- @return response object with the mapped name in the result field
+ fp_map_name = function( self, subfunc, name )
+ local packet
+ local data_offset = 0
+ local data = bin.pack( "CC>SA", COMMAND.FPMapName, subfunc, name:len(), name )
+ local response
+
+ packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
+ self:send_fp_packet( packet )
+ response = self:read_fp_packet( )
+
+ if response:getErrorCode() ~= ERROR.FPNoErr then
+ return response
+ end
+
+ response:setResult( select(2, bin.unpack(">I", response.packet.data)))
+ return response
+ end,
}
--- The helper class wraps the protocol class and their functions. It contains
@@ -1338,779 +1338,779 @@ Proto = {
-- minimizing the need to fully understand the AFP low-level protocol details.
Helper = {
- --- Creates a new helper object
- new = function(self,o)
- local o = {}
- setmetatable(o, self)
- self.__index = self
- o.username = stdnse.get_script_args("afp.username")
- o.password = stdnse.get_script_args("afp.password")
- return o
- end,
-
- --- Connects to the remote server and establishes a new AFP session
- --
- -- @param host table as recieved by the action function of the script
- -- @param port table as recieved by the action function of the script
- -- @return status boolean
- -- @return string containing error message (if status is false)
- OpenSession = function( self, host, port )
- local status, response
-
- self.socket = nmap.new_socket()
- self.socket:set_timeout( 5000 )
- status = self.socket:connect(host, port)
- if not status then
- return false, "Socket connection failed"
- end
-
- self.proto = Proto:new( { socket=self.socket} )
- response = self.proto:dsi_open_session(self.socket)
-
- if response:getErrorCode() ~= ERROR.FPNoErr then
- self.socket:close()
- return false, response:getErrorMessage()
- end
-
- return true
- end,
-
- --- Closes the AFP session and then the socket
- --
- -- @return status boolean
- -- @return string containing error message (if status is false)
- CloseSession = function( self )
- local status, packet = self.proto:dsi_close_session( )
- self.socket:close()
-
- return status, packet
- end,
-
- --- Terminates the connection, withou closing the AFP session
- --
- -- @return status (always true)
- -- @return string (always "")
- Terminate = function( self )
- self.socket:close()
- return true,""
- end,
-
- --- Logs in to an AFP service
- --
- -- @param username (optional) string containing the username
- -- @param password (optional) string containing the user password
- -- @param options table containing additional options uam
- Login = function( self, username, password, options )
- local uam = ( options and options.UAM ) and options.UAM or "DHCAST128"
- local response
-
- -- username and password arguments override the ones supplied using the
- -- script arguments afp.username and afp.password
- local username = username or self.username
- local password = password or self.password
-
- if ( username and uam == "DHCAST128" ) then
- response = self.proto:fp_login( "AFP3.1", "DHCAST128", username, password )
- elseif( username ) then
- return false, ("Unsupported UAM: %s"):format(uam)
- else
- response = self.proto:fp_login( "AFP3.1", "No User Authent" )
- end
-
- if response:getErrorCode() ~= ERROR.FPNoErr then
- return false, response:getErrorMessage()
- end
-
- return true, "Success"
- end,
-
- --- Logs out from the AFP service
- Logout = function(self)
- return self.proto:fp_logout()
- end,
-
- --- Walks the directory tree specified by str_path and returns the node information
- --
- -- @param str_path string containing the directory
- -- @return status boolean true on success, otherwise false
- -- @return item table containing node information DirectoryId and DirectoryName
- WalkDirTree = function( self, str_path )
- local status, response, path
- local elements = stdnse.strsplit( "/", str_path )
- local f_bm = FILE_BITMAP.NodeId + FILE_BITMAP.ParentDirId + FILE_BITMAP.LongName
- local d_bm = DIR_BITMAP.NodeId + DIR_BITMAP.ParentDirId + DIR_BITMAP.LongName
- local item = { DirectoryId = 2 }
-
- response = self.proto:fp_open_vol( VOL_BITMAP.ID, elements[1] )
- if response:getErrorCode() ~= ERROR.FPNoErr then
- return false, response:getErrorMessage()
- end
-
- item.VolumeId = response.result.volume_id
- item.DirectoryName = str_path
-
- for i=2, #elements do
- path = { ['type']=PATH_TYPE.LongName, name=elements[i], len=elements[i]:len() }
- response = self.proto:fp_get_file_dir_parms( item.VolumeId, item.DirectoryId, f_bm, d_bm, path )
- if response:getErrorCode() ~= ERROR.FPNoErr then
- return false, response:getErrorMessage()
- end
- item.DirectoryId = response.result.dir.NodeId
- item.DirectoryName = response.result.dir.LongName
- end
-
- return true, item
- end,
-
- --- Reads a file on the AFP server
- --
- -- @param str_path string containing the AFP sharepoint, path and filename eg. HR/Documents/File.doc
- -- @return status boolean true on success, false on failure
- -- @return content string containing the file contents
- ReadFile = function( self, str_path )
- local status, response, fork, content, vol_name
- local offset, count, did = 0, 1024, 2
- local status, path, vol_id
- local p = Util.SplitPath( str_path )
-
- status, response = self:WalkDirTree( p.dir )
- if ( not status ) then
- return false, response
- end
-
- vol_id = response.VolumeId
- did = response.DirectoryId
-
- path = { ['type']=PATH_TYPE.LongName, name=p.file, len=p.file:len() }
-
- response = self.proto:fp_open_fork(0, vol_id, did, 0, ACCESS_MODE.Read, path )
- if response:getErrorCode() ~= ERROR.FPNoErr then
- return false, response:getErrorMessage()
- end
-
- fork = response.result.fork_id
- content = ""
-
- while true do
- response = self.proto:fp_read_ext( fork, offset, count )
- if response:getErrorCode() ~= ERROR.FPNoErr then
- break
- end
- content = content .. response.result
- offset = offset + count
- end
-
- response = self.proto:fp_close_fork( fork )
- if response:getErrorCode() ~= ERROR.FPNoErr then
- return false, response:getErrorMessage()
- end
-
- return true, content
- end,
-
- --- Writes a file to the AFP server
- --
- -- @param str_path string containing the AFP sharepoint, path and filename eg. HR/Documents/File.doc
- -- @param fdata string containing the data to write to the file
- -- @return status boolean true on success, false on failure
- -- @return error string containing error message if status is false
- WriteFile = function( self, str_path, fdata )
- local status, response, fork, content
- local offset, count = 1, 1024
- local status, vol_id, did, path
- local p = Util.SplitPath( str_path )
-
- status, response = self:WalkDirTree( p.dir )
- vol_id = response.VolumeId
- did = response.DirectoryId
-
- if ( not status ) then
- return false, response
- end
-
- path = { ['type']=PATH_TYPE.LongName, name=p.file, len=p.file:len() }
-
- status, response = self.proto:fp_create_file( 0, vol_id, did, path )
- if not status then
- if ( response.header.error_code ~= ERROR.FPObjectExists ) then
- return false, response.header.error_msg
- end
- end
-
- response = self.proto:fp_open_fork( 0, vol_id, did, 0, ACCESS_MODE.Write, path )
- if response:getErrorCode() ~= ERROR.FPNoErr then
- return false, response:getErrorMessage()
- end
-
- fork = response.result.fork_id
-
- response = self.proto:fp_write_ext( 0, fork, 0, fdata:len(), fdata )
-
- return true, nil
- end,
-
- --- Maps a user id (uid) to a user name
- --
- -- @param uid number containing the uid to resolve
- -- @return status boolean true on success, false on failure
- -- @return username string on success
- -- error string on failure
- UIDToName = function( self, uid )
- local response = self.proto:fp_map_id( MAP_ID.UserIDToName, uid )
- if response:getErrorCode() ~= ERROR.FPNoErr then
- return false, response:getErrorMessage()
- end
- return true, response.result
- end,
-
- --- Maps a group id (gid) to group name
- --
- -- @param gid number containing the gid to lookup
- -- @return status boolean true on success, false on failure
- -- @return groupname string on success
- -- error string on failure
- GIDToName = function( self, gid )
- local response = self.proto:fp_map_id( MAP_ID.GroupIDToName, gid )
- if response:getErrorCode() ~= ERROR.FPNoErr then
- return false, response:getErrorMessage()
- end
- return true, response.result
- end,
-
- --- Maps a username to a UID
- --
- -- @param name string containing the username to map to an UID
- -- @return status boolean true on success, false on failure
- -- @return UID number on success
- -- error string on failure
- NameToUID = function( self, name )
- local response = self.proto:fp_map_name( MAP_NAME.NameToUserID, name )
- if response:getErrorCode() ~= ERROR.FPNoErr then
- return false, response:getErrorMessage()
- end
- return true, response.result
- end,
-
- --- List the contents of a directory
- --
- -- @param str_path string containing the sharepoint and directory names
- -- @param options table options containing zero or more of the options
- -- max_depth and dironly
- -- @param depth number containing the current depth (used when called recursively)
- -- @param parent table containing information about the parent object (used when called recursively)
- -- @return status boolean true on success, false on failure
- -- @return dir table containing a table for each directory item with the following type,
- -- name and id
- Dir = function( self, str_path, options, depth, parent )
- local status, result
- local depth = depth or 1
- local options = options or { max_depth = 1 }
- local response, records
- local f_bm = FILE_BITMAP.NodeId + FILE_BITMAP.ParentDirId + FILE_BITMAP.LongName
- local d_bm = DIR_BITMAP.NodeId + DIR_BITMAP.ParentDirId + DIR_BITMAP.LongName
- local path = { ['type']=PATH_TYPE.LongName, name="", len=0 }
-
- local TYPE_DIR = 0x80
-
- if ( parent == nil ) then
- status, response = self:WalkDirTree( str_path )
- if ( not status ) then
- return false, response
- end
-
- parent = {}
- parent.vol_id = response.VolumeId
- parent.did = response.DirectoryId
- parent.dir_name = response.DirectoryName or ""
- parent.out_tbl = {}
- end
-
- if ( options and options.max_depth and options.max_depth > 0 and options.max_depth < depth ) then
- return false, "Max Depth Reached"
- end
-
- response = self.proto:fp_enumerate_ext2( parent.vol_id, parent.did, f_bm, d_bm, 1000, 1, 52800, path)
-
- if response:getErrorCode() ~= ERROR.FPNoErr then
- return false, response:getErrorMessage()
- end
-
- records = response.result or {}
- local dir_item = {}
-
- for _, record in ipairs( records ) do
- if ( options and options.dironly ) then
- if ( record.type == TYPE_DIR ) then
- table.insert( dir_item, { ['type'] = record.type, ['name'] = record.LongName, ['id'] = record.NodeId } )
- end
- else
- table.insert( dir_item, { ['type'] = record.type, ['name'] = record.LongName, ['id'] = record.NodeId } )
- end
- if ( record.type == TYPE_DIR ) then
- self:Dir("", options, depth + 1, { vol_id = parent.vol_id, did=record.NodeId, dir_name=record.LongName, out_tbl=dir_item} )
- end
- end
-
- table.insert( parent.out_tbl, dir_item )
-
- return true, parent.out_tbl
- end,
-
- --- Displays a directory tree
- --
- -- @param str_path string containing the sharepoint and the directory
- -- @param options table options containing zero or more of the options
- -- max_depth and dironly
- -- @return dirtree table containing the directories
- DirTree = function( self, str_path, options )
- local options = options or {}
- options.dironly = true
- return self:Dir( str_path, options )
- end,
-
- --- List the AFP sharepoints
- --
- -- @return volumes table containing the sharepoints
- ListShares = function( self )
- local response
- response = self.proto:fp_get_srvr_parms( )
-
- if response:getErrorCode() ~= ERROR.FPNoErr then
- return false, response:getErrorMessage()
- end
-
- return true, response.result.volumes
- end,
-
- --- Determine the sharepoint permissions
- --
- -- @param vol_name string containing the name of the volume
- -- @return status boolean true on success, false on failure
- -- @return acls table containing the volume acls as returned by acls_to_long_string
- GetSharePermissions = function( self, vol_name )
- local status, response, vol_id, acls
-
- response = self.proto:fp_open_vol( VOL_BITMAP.ID, vol_name )
-
- if response:getErrorCode() == ERROR.FPNoErr then
- local vol_id
- local path = {}
-
- vol_id = response.result.volume_id
- path.type = PATH_TYPE.LongName
- path.name = ""
- path.len = path.name:len()
-
- response = self.proto:fp_get_file_dir_parms( vol_id, 2, FILE_BITMAP.ALL, DIR_BITMAP.ALL, path )
- if response:getErrorCode() == ERROR.FPNoErr then
- if ( response.result.dir and response.result.dir.AccessRights ) then
- acls = Util.acls_to_long_string(response.result.dir.AccessRights)
- acls.name = nil
- end
- end
- self.proto:fp_close_vol( vol_id )
- end
-
- return true, acls
- end,
-
- --- Gets the Unix permissions of a file
- -- @param vol_name string containing the name of the volume
- -- @param str_path string containing the name of the file
- -- @return status true on success, false on failure
- -- @return acls table (on success) containing the following fields
- -- uid - a numeric user identifier
- -- gid - a numeric group identifier
- -- privs - a string value representing the permissions
- -- eg: drwx------
- -- @return err string (on failure) containing the error message
- GetFileUnixPermissions = function(self, vol_name, str_path)
- local response = self.proto:fp_open_vol( VOL_BITMAP.ID, vol_name )
-
- if ( response:getErrorCode() ~= ERROR.FPNoErr ) then
- return false, response:getErrorMessage()
- end
-
- local vol_id = response.result.volume_id
- local path = { type = PATH_TYPE.LongName, name = str_path, len = #str_path }
- response = self.proto:fp_get_file_dir_parms( vol_id, 2, FILE_BITMAP.UnixPrivileges, DIR_BITMAP.UnixPrivileges, path )
- if ( response:getErrorCode() ~= ERROR.FPNoErr ) then
- return false, response:getErrorMessage()
- end
-
- local item = ( response.result.file ) and response.result.file or response.result.dir
- local item_type = ( response.result.file ) and "-" or "d"
- local privs = ( item.UnixPrivileges and item.UnixPrivileges.ua_permissions ) and
- item.UnixPrivileges.ua_permissions
- if ( privs ) then
- local uid = item.UnixPrivileges.uid
- local gid = item.UnixPrivileges.gid
- local str_privs = item_type .. Util.decode_unix_privs(privs)
- return true, { uid = uid, gid = gid, privs = str_privs }
- end
- end,
-
- --- Gets the Unix permissions of a file
- -- @param vol_name string containing the name of the volume
- -- @param str_path string containing the name of the file
- -- @return status true on success, false on failure
- -- @return size containing the size of the file in bytes
- -- @return err string (on failure) containing the error message
- GetFileSize = function( self, vol_name, str_path )
- local response = self.proto:fp_open_vol( VOL_BITMAP.ID, vol_name )
-
- if ( response:getErrorCode() ~= ERROR.FPNoErr ) then
- return false, response:getErrorMessage()
- end
-
- local vol_id = response.result.volume_id
- local path = { type = PATH_TYPE.LongName, name = str_path, len = #str_path }
- response = self.proto:fp_get_file_dir_parms( vol_id, 2, FILE_BITMAP.ExtendedDataForkSize, 0, path )
- if ( response:getErrorCode() ~= ERROR.FPNoErr ) then
- return false, response:getErrorMessage()
- end
-
- return true, ( response.result.file and
- response.result.file.ExtendedDataForkSize) and
- response.result.file.ExtendedDataForkSize or 0
- end,
-
-
- --- Returns the creation, modification and backup dates of a file
- -- @param vol_name string containing the name of the volume
- -- @param str_path string containing the name of the file
- -- @return status true on success, false on failure
- -- @return dates table containing the following fields:
- -- create - Creation date of the file
- -- modify - Modification date of the file
- -- backup - Date of last backup
- -- @return err string (on failure) containing the error message
- GetFileDates = function( self, vol_name, str_path )
- local response = self.proto:fp_open_vol( VOL_BITMAP.ID, vol_name )
-
- if ( response:getErrorCode() ~= ERROR.FPNoErr ) then
- return false, response:getErrorMessage()
- end
-
- local vol_id = response.result.volume_id
- local path = { type = PATH_TYPE.LongName, name = str_path, len = #str_path }
- local f_bm = FILE_BITMAP.CreationDate + FILE_BITMAP.ModificationDate + FILE_BITMAP.BackupDate
- local d_bm = DIR_BITMAP.CreationDate + DIR_BITMAP.ModificationDate + DIR_BITMAP.BackupDate
- response = self.proto:fp_get_file_dir_parms( vol_id, 2, f_bm, d_bm, path )
- if ( response:getErrorCode() ~= ERROR.FPNoErr ) then
- return false, response:getErrorMessage()
- end
-
- local item = ( response.result.file ) and response.result.file or response.result.dir
-
- local diff = os.time{year=2000, month=1, day=1, hour=0} - os.time{year=1970, month=1, day=1, hour=0}
- local create = os.date("%Y-%m-%d %H:%M", item.CreationDate + diff)
- local backup = os.date("%Y-%m-%d %H:%M", item.BackupDate )
- local modify = os.date("%Y-%m-%d %H:%M", item.ModificationDate + diff )
-
- return true, { create = create, backup = backup, modify = modify }
- end,
-
- --- Creates a new directory on the AFP sharepoint
- --
- -- @param str_path containing the sharepoint and the directory
- -- @return status boolean true on success, false on failure
- -- @return dirId number containing the new directory id
- CreateDir = function( self, str_path )
- local status, response, vol_id, did
- local p = Util.SplitPath( str_path )
- local path = { ['type']=PATH_TYPE.LongName, name=p.file, len=p.file:len() }
-
-
- status, response = self:WalkDirTree( p.dir )
- if not status then
- return false, response
- end
-
- response = self.proto:fp_create_dir( response.VolumeId, response.DirectoryId, path )
- if response:getErrorCode() ~= ERROR.FPNoErr then
- return false, response:getErrorMessage()
- end
-
- return true, response
- end,
+ --- Creates a new helper object
+ new = function(self,o)
+ local o = {}
+ setmetatable(o, self)
+ self.__index = self
+ o.username = stdnse.get_script_args("afp.username")
+ o.password = stdnse.get_script_args("afp.password")
+ return o
+ end,
+
+ --- Connects to the remote server and establishes a new AFP session
+ --
+ -- @param host table as recieved by the action function of the script
+ -- @param port table as recieved by the action function of the script
+ -- @return status boolean
+ -- @return string containing error message (if status is false)
+ OpenSession = function( self, host, port )
+ local status, response
+
+ self.socket = nmap.new_socket()
+ self.socket:set_timeout( 5000 )
+ status = self.socket:connect(host, port)
+ if not status then
+ return false, "Socket connection failed"
+ end
+
+ self.proto = Proto:new( { socket=self.socket} )
+ response = self.proto:dsi_open_session(self.socket)
+
+ if response:getErrorCode() ~= ERROR.FPNoErr then
+ self.socket:close()
+ return false, response:getErrorMessage()
+ end
+
+ return true
+ end,
+
+ --- Closes the AFP session and then the socket
+ --
+ -- @return status boolean
+ -- @return string containing error message (if status is false)
+ CloseSession = function( self )
+ local status, packet = self.proto:dsi_close_session( )
+ self.socket:close()
+
+ return status, packet
+ end,
+
+ --- Terminates the connection, withou closing the AFP session
+ --
+ -- @return status (always true)
+ -- @return string (always "")
+ Terminate = function( self )
+ self.socket:close()
+ return true,""
+ end,
+
+ --- Logs in to an AFP service
+ --
+ -- @param username (optional) string containing the username
+ -- @param password (optional) string containing the user password
+ -- @param options table containing additional options uam
+ Login = function( self, username, password, options )
+ local uam = ( options and options.UAM ) and options.UAM or "DHCAST128"
+ local response
+
+ -- username and password arguments override the ones supplied using the
+ -- script arguments afp.username and afp.password
+ local username = username or self.username
+ local password = password or self.password
+
+ if ( username and uam == "DHCAST128" ) then
+ response = self.proto:fp_login( "AFP3.1", "DHCAST128", username, password )
+ elseif( username ) then
+ return false, ("Unsupported UAM: %s"):format(uam)
+ else
+ response = self.proto:fp_login( "AFP3.1", "No User Authent" )
+ end
+
+ if response:getErrorCode() ~= ERROR.FPNoErr then
+ return false, response:getErrorMessage()
+ end
+
+ return true, "Success"
+ end,
+
+ --- Logs out from the AFP service
+ Logout = function(self)
+ return self.proto:fp_logout()
+ end,
+
+ --- Walks the directory tree specified by str_path and returns the node information
+ --
+ -- @param str_path string containing the directory
+ -- @return status boolean true on success, otherwise false
+ -- @return item table containing node information DirectoryId and DirectoryName
+ WalkDirTree = function( self, str_path )
+ local status, response, path
+ local elements = stdnse.strsplit( "/", str_path )
+ local f_bm = FILE_BITMAP.NodeId + FILE_BITMAP.ParentDirId + FILE_BITMAP.LongName
+ local d_bm = DIR_BITMAP.NodeId + DIR_BITMAP.ParentDirId + DIR_BITMAP.LongName
+ local item = { DirectoryId = 2 }
+
+ response = self.proto:fp_open_vol( VOL_BITMAP.ID, elements[1] )
+ if response:getErrorCode() ~= ERROR.FPNoErr then
+ return false, response:getErrorMessage()
+ end
+
+ item.VolumeId = response.result.volume_id
+ item.DirectoryName = str_path
+
+ for i=2, #elements do
+ path = { ['type']=PATH_TYPE.LongName, name=elements[i], len=elements[i]:len() }
+ response = self.proto:fp_get_file_dir_parms( item.VolumeId, item.DirectoryId, f_bm, d_bm, path )
+ if response:getErrorCode() ~= ERROR.FPNoErr then
+ return false, response:getErrorMessage()
+ end
+ item.DirectoryId = response.result.dir.NodeId
+ item.DirectoryName = response.result.dir.LongName
+ end
+
+ return true, item
+ end,
+
+ --- Reads a file on the AFP server
+ --
+ -- @param str_path string containing the AFP sharepoint, path and filename eg. HR/Documents/File.doc
+ -- @return status boolean true on success, false on failure
+ -- @return content string containing the file contents
+ ReadFile = function( self, str_path )
+ local status, response, fork, content, vol_name
+ local offset, count, did = 0, 1024, 2
+ local status, path, vol_id
+ local p = Util.SplitPath( str_path )
+
+ status, response = self:WalkDirTree( p.dir )
+ if ( not status ) then
+ return false, response
+ end
+
+ vol_id = response.VolumeId
+ did = response.DirectoryId
+
+ path = { ['type']=PATH_TYPE.LongName, name=p.file, len=p.file:len() }
+
+ response = self.proto:fp_open_fork(0, vol_id, did, 0, ACCESS_MODE.Read, path )
+ if response:getErrorCode() ~= ERROR.FPNoErr then
+ return false, response:getErrorMessage()
+ end
+
+ fork = response.result.fork_id
+ content = ""
+
+ while true do
+ response = self.proto:fp_read_ext( fork, offset, count )
+ if response:getErrorCode() ~= ERROR.FPNoErr then
+ break
+ end
+ content = content .. response.result
+ offset = offset + count
+ end
+
+ response = self.proto:fp_close_fork( fork )
+ if response:getErrorCode() ~= ERROR.FPNoErr then
+ return false, response:getErrorMessage()
+ end
+
+ return true, content
+ end,
+
+ --- Writes a file to the AFP server
+ --
+ -- @param str_path string containing the AFP sharepoint, path and filename eg. HR/Documents/File.doc
+ -- @param fdata string containing the data to write to the file
+ -- @return status boolean true on success, false on failure
+ -- @return error string containing error message if status is false
+ WriteFile = function( self, str_path, fdata )
+ local status, response, fork, content
+ local offset, count = 1, 1024
+ local status, vol_id, did, path
+ local p = Util.SplitPath( str_path )
+
+ status, response = self:WalkDirTree( p.dir )
+ vol_id = response.VolumeId
+ did = response.DirectoryId
+
+ if ( not status ) then
+ return false, response
+ end
+
+ path = { ['type']=PATH_TYPE.LongName, name=p.file, len=p.file:len() }
+
+ status, response = self.proto:fp_create_file( 0, vol_id, did, path )
+ if not status then
+ if ( response.header.error_code ~= ERROR.FPObjectExists ) then
+ return false, response.header.error_msg
+ end
+ end
+
+ response = self.proto:fp_open_fork( 0, vol_id, did, 0, ACCESS_MODE.Write, path )
+ if response:getErrorCode() ~= ERROR.FPNoErr then
+ return false, response:getErrorMessage()
+ end
+
+ fork = response.result.fork_id
+
+ response = self.proto:fp_write_ext( 0, fork, 0, fdata:len(), fdata )
+
+ return true, nil
+ end,
+
+ --- Maps a user id (uid) to a user name
+ --
+ -- @param uid number containing the uid to resolve
+ -- @return status boolean true on success, false on failure
+ -- @return username string on success
+ -- error string on failure
+ UIDToName = function( self, uid )
+ local response = self.proto:fp_map_id( MAP_ID.UserIDToName, uid )
+ if response:getErrorCode() ~= ERROR.FPNoErr then
+ return false, response:getErrorMessage()
+ end
+ return true, response.result
+ end,
+
+ --- Maps a group id (gid) to group name
+ --
+ -- @param gid number containing the gid to lookup
+ -- @return status boolean true on success, false on failure
+ -- @return groupname string on success
+ -- error string on failure
+ GIDToName = function( self, gid )
+ local response = self.proto:fp_map_id( MAP_ID.GroupIDToName, gid )
+ if response:getErrorCode() ~= ERROR.FPNoErr then
+ return false, response:getErrorMessage()
+ end
+ return true, response.result
+ end,
+
+ --- Maps a username to a UID
+ --
+ -- @param name string containing the username to map to an UID
+ -- @return status boolean true on success, false on failure
+ -- @return UID number on success
+ -- error string on failure
+ NameToUID = function( self, name )
+ local response = self.proto:fp_map_name( MAP_NAME.NameToUserID, name )
+ if response:getErrorCode() ~= ERROR.FPNoErr then
+ return false, response:getErrorMessage()
+ end
+ return true, response.result
+ end,
+
+ --- List the contents of a directory
+ --
+ -- @param str_path string containing the sharepoint and directory names
+ -- @param options table options containing zero or more of the options
+ -- max_depth and dironly
+ -- @param depth number containing the current depth (used when called recursively)
+ -- @param parent table containing information about the parent object (used when called recursively)
+ -- @return status boolean true on success, false on failure
+ -- @return dir table containing a table for each directory item with the following type,
+ -- name and id
+ Dir = function( self, str_path, options, depth, parent )
+ local status, result
+ local depth = depth or 1
+ local options = options or { max_depth = 1 }
+ local response, records
+ local f_bm = FILE_BITMAP.NodeId + FILE_BITMAP.ParentDirId + FILE_BITMAP.LongName
+ local d_bm = DIR_BITMAP.NodeId + DIR_BITMAP.ParentDirId + DIR_BITMAP.LongName
+ local path = { ['type']=PATH_TYPE.LongName, name="", len=0 }
+
+ local TYPE_DIR = 0x80
+
+ if ( parent == nil ) then
+ status, response = self:WalkDirTree( str_path )
+ if ( not status ) then
+ return false, response
+ end
+
+ parent = {}
+ parent.vol_id = response.VolumeId
+ parent.did = response.DirectoryId
+ parent.dir_name = response.DirectoryName or ""
+ parent.out_tbl = {}
+ end
+
+ if ( options and options.max_depth and options.max_depth > 0 and options.max_depth < depth ) then
+ return false, "Max Depth Reached"
+ end
+
+ response = self.proto:fp_enumerate_ext2( parent.vol_id, parent.did, f_bm, d_bm, 1000, 1, 52800, path)
+
+ if response:getErrorCode() ~= ERROR.FPNoErr then
+ return false, response:getErrorMessage()
+ end
+
+ records = response.result or {}
+ local dir_item = {}
+
+ for _, record in ipairs( records ) do
+ if ( options and options.dironly ) then
+ if ( record.type == TYPE_DIR ) then
+ table.insert( dir_item, { ['type'] = record.type, ['name'] = record.LongName, ['id'] = record.NodeId } )
+ end
+ else
+ table.insert( dir_item, { ['type'] = record.type, ['name'] = record.LongName, ['id'] = record.NodeId } )
+ end
+ if ( record.type == TYPE_DIR ) then
+ self:Dir("", options, depth + 1, { vol_id = parent.vol_id, did=record.NodeId, dir_name=record.LongName, out_tbl=dir_item} )
+ end
+ end
+
+ table.insert( parent.out_tbl, dir_item )
+
+ return true, parent.out_tbl
+ end,
+
+ --- Displays a directory tree
+ --
+ -- @param str_path string containing the sharepoint and the directory
+ -- @param options table options containing zero or more of the options
+ -- max_depth and dironly
+ -- @return dirtree table containing the directories
+ DirTree = function( self, str_path, options )
+ local options = options or {}
+ options.dironly = true
+ return self:Dir( str_path, options )
+ end,
+
+ --- List the AFP sharepoints
+ --
+ -- @return volumes table containing the sharepoints
+ ListShares = function( self )
+ local response
+ response = self.proto:fp_get_srvr_parms( )
+
+ if response:getErrorCode() ~= ERROR.FPNoErr then
+ return false, response:getErrorMessage()
+ end
+
+ return true, response.result.volumes
+ end,
+
+ --- Determine the sharepoint permissions
+ --
+ -- @param vol_name string containing the name of the volume
+ -- @return status boolean true on success, false on failure
+ -- @return acls table containing the volume acls as returned by acls_to_long_string
+ GetSharePermissions = function( self, vol_name )
+ local status, response, vol_id, acls
+
+ response = self.proto:fp_open_vol( VOL_BITMAP.ID, vol_name )
+
+ if response:getErrorCode() == ERROR.FPNoErr then
+ local vol_id
+ local path = {}
+
+ vol_id = response.result.volume_id
+ path.type = PATH_TYPE.LongName
+ path.name = ""
+ path.len = path.name:len()
+
+ response = self.proto:fp_get_file_dir_parms( vol_id, 2, FILE_BITMAP.ALL, DIR_BITMAP.ALL, path )
+ if response:getErrorCode() == ERROR.FPNoErr then
+ if ( response.result.dir and response.result.dir.AccessRights ) then
+ acls = Util.acls_to_long_string(response.result.dir.AccessRights)
+ acls.name = nil
+ end
+ end
+ self.proto:fp_close_vol( vol_id )
+ end
+
+ return true, acls
+ end,
+
+ --- Gets the Unix permissions of a file
+ -- @param vol_name string containing the name of the volume
+ -- @param str_path string containing the name of the file
+ -- @return status true on success, false on failure
+ -- @return acls table (on success) containing the following fields
+ -- uid - a numeric user identifier
+ -- gid - a numeric group identifier
+ -- privs - a string value representing the permissions
+ -- eg: drwx------
+ -- @return err string (on failure) containing the error message
+ GetFileUnixPermissions = function(self, vol_name, str_path)
+ local response = self.proto:fp_open_vol( VOL_BITMAP.ID, vol_name )
+
+ if ( response:getErrorCode() ~= ERROR.FPNoErr ) then
+ return false, response:getErrorMessage()
+ end
+
+ local vol_id = response.result.volume_id
+ local path = { type = PATH_TYPE.LongName, name = str_path, len = #str_path }
+ response = self.proto:fp_get_file_dir_parms( vol_id, 2, FILE_BITMAP.UnixPrivileges, DIR_BITMAP.UnixPrivileges, path )
+ if ( response:getErrorCode() ~= ERROR.FPNoErr ) then
+ return false, response:getErrorMessage()
+ end
+
+ local item = ( response.result.file ) and response.result.file or response.result.dir
+ local item_type = ( response.result.file ) and "-" or "d"
+ local privs = ( item.UnixPrivileges and item.UnixPrivileges.ua_permissions ) and
+ item.UnixPrivileges.ua_permissions
+ if ( privs ) then
+ local uid = item.UnixPrivileges.uid
+ local gid = item.UnixPrivileges.gid
+ local str_privs = item_type .. Util.decode_unix_privs(privs)
+ return true, { uid = uid, gid = gid, privs = str_privs }
+ end
+ end,
+
+ --- Gets the Unix permissions of a file
+ -- @param vol_name string containing the name of the volume
+ -- @param str_path string containing the name of the file
+ -- @return status true on success, false on failure
+ -- @return size containing the size of the file in bytes
+ -- @return err string (on failure) containing the error message
+ GetFileSize = function( self, vol_name, str_path )
+ local response = self.proto:fp_open_vol( VOL_BITMAP.ID, vol_name )
+
+ if ( response:getErrorCode() ~= ERROR.FPNoErr ) then
+ return false, response:getErrorMessage()
+ end
+
+ local vol_id = response.result.volume_id
+ local path = { type = PATH_TYPE.LongName, name = str_path, len = #str_path }
+ response = self.proto:fp_get_file_dir_parms( vol_id, 2, FILE_BITMAP.ExtendedDataForkSize, 0, path )
+ if ( response:getErrorCode() ~= ERROR.FPNoErr ) then
+ return false, response:getErrorMessage()
+ end
+
+ return true, ( response.result.file and
+ response.result.file.ExtendedDataForkSize) and
+ response.result.file.ExtendedDataForkSize or 0
+ end,
+
+
+ --- Returns the creation, modification and backup dates of a file
+ -- @param vol_name string containing the name of the volume
+ -- @param str_path string containing the name of the file
+ -- @return status true on success, false on failure
+ -- @return dates table containing the following fields:
+ -- create - Creation date of the file
+ -- modify - Modification date of the file
+ -- backup - Date of last backup
+ -- @return err string (on failure) containing the error message
+ GetFileDates = function( self, vol_name, str_path )
+ local response = self.proto:fp_open_vol( VOL_BITMAP.ID, vol_name )
+
+ if ( response:getErrorCode() ~= ERROR.FPNoErr ) then
+ return false, response:getErrorMessage()
+ end
+
+ local vol_id = response.result.volume_id
+ local path = { type = PATH_TYPE.LongName, name = str_path, len = #str_path }
+ local f_bm = FILE_BITMAP.CreationDate + FILE_BITMAP.ModificationDate + FILE_BITMAP.BackupDate
+ local d_bm = DIR_BITMAP.CreationDate + DIR_BITMAP.ModificationDate + DIR_BITMAP.BackupDate
+ response = self.proto:fp_get_file_dir_parms( vol_id, 2, f_bm, d_bm, path )
+ if ( response:getErrorCode() ~= ERROR.FPNoErr ) then
+ return false, response:getErrorMessage()
+ end
+
+ local item = ( response.result.file ) and response.result.file or response.result.dir
+
+ local diff = os.time{year=2000, month=1, day=1, hour=0} - os.time{year=1970, month=1, day=1, hour=0}
+ local create = os.date("%Y-%m-%d %H:%M", item.CreationDate + diff)
+ local backup = os.date("%Y-%m-%d %H:%M", item.BackupDate )
+ local modify = os.date("%Y-%m-%d %H:%M", item.ModificationDate + diff )
+
+ return true, { create = create, backup = backup, modify = modify }
+ end,
+
+ --- Creates a new directory on the AFP sharepoint
+ --
+ -- @param str_path containing the sharepoint and the directory
+ -- @return status boolean true on success, false on failure
+ -- @return dirId number containing the new directory id
+ CreateDir = function( self, str_path )
+ local status, response, vol_id, did
+ local p = Util.SplitPath( str_path )
+ local path = { ['type']=PATH_TYPE.LongName, name=p.file, len=p.file:len() }
+
+
+ status, response = self:WalkDirTree( p.dir )
+ if not status then
+ return false, response
+ end
+
+ response = self.proto:fp_create_dir( response.VolumeId, response.DirectoryId, path )
+ if response:getErrorCode() ~= ERROR.FPNoErr then
+ return false, response:getErrorMessage()
+ end
+
+ return true, response
+ end,
}
--- Util class, containing some static functions used by Helper and Proto
Util =
{
- --- Pads a string with zeroes
- --
- -- @param str string containing the string to be padded
- -- @param len number containing the length of the new string
- -- @return str string containing the new string
- ZeroPad = function( str, len )
- if len < str:len() then
- return
- end
+ --- Pads a string with zeroes
+ --
+ -- @param str string containing the string to be padded
+ -- @param len number containing the length of the new string
+ -- @return str string containing the new string
+ ZeroPad = function( str, len )
+ if len < str:len() then
+ return
+ end
- for i=1, len - str:len() do
- str = str .. string.char(0)
- end
+ for i=1, len - str:len() do
+ str = str .. string.char(0)
+ end
- return str
- end,
+ return str
+ end,
- --- Splits a path into two pieces, directory and file
- --
- -- @param str_path string containing the path to split
- -- @return dir table containing dir and file
- SplitPath = function( str_path )
- local elements = stdnse.strsplit("/", str_path)
- local dir, file = "", ""
+ --- Splits a path into two pieces, directory and file
+ --
+ -- @param str_path string containing the path to split
+ -- @return dir table containing dir and file
+ SplitPath = function( str_path )
+ local elements = stdnse.strsplit("/", str_path)
+ local dir, file = "", ""
- if #elements < 2 then
- return nil
- end
+ if #elements < 2 then
+ return nil
+ end
- file = elements[#elements]
+ file = elements[#elements]
- table.remove( elements, #elements )
- dir = stdnse.strjoin( "/", elements )
+ table.remove( elements, #elements )
+ dir = stdnse.strjoin( "/", elements )
- return { ['dir']=dir, ['file']=file }
+ return { ['dir']=dir, ['file']=file }
- end,
+ end,
- --- Converts a group bitmask of Search, Read and Write to table
- --
- -- @param acls number containing bitmasked acls
- -- @return table of ACLs
- acl_group_to_long_string = function(acls)
+ --- Converts a group bitmask of Search, Read and Write to table
+ --
+ -- @param acls number containing bitmasked acls
+ -- @return table of ACLs
+ acl_group_to_long_string = function(acls)
- local acl_table = {}
+ local acl_table = {}
- if bit.band( acls, ACLS.OwnerSearch ) == ACLS.OwnerSearch then
- table.insert( acl_table, "Search")
- end
+ if bit.band( acls, ACLS.OwnerSearch ) == ACLS.OwnerSearch then
+ table.insert( acl_table, "Search")
+ end
- if bit.band( acls, ACLS.OwnerRead ) == ACLS.OwnerRead then
- table.insert( acl_table, "Read")
- end
+ if bit.band( acls, ACLS.OwnerRead ) == ACLS.OwnerRead then
+ table.insert( acl_table, "Read")
+ end
- if bit.band( acls, ACLS.OwnerWrite ) == ACLS.OwnerWrite then
- table.insert( acl_table, "Write")
- end
+ if bit.band( acls, ACLS.OwnerWrite ) == ACLS.OwnerWrite then
+ table.insert( acl_table, "Write")
+ end
- return acl_table
- end,
+ return acl_table
+ end,
- --- Converts a numeric acl to string
- --
- -- @param acls number containig acls as recieved from fp_get_file_dir_parms
- -- @return table of long ACLs
- acls_to_long_string = function( acls )
+ --- Converts a numeric acl to string
+ --
+ -- @param acls number containig acls as recieved from fp_get_file_dir_parms
+ -- @return table of long ACLs
+ acls_to_long_string = function( acls )
- local owner = Util.acl_group_to_long_string( bit.band( acls, 255 ) )
- local group = Util.acl_group_to_long_string( bit.band( bit.rshift(acls, 8), 255 ) )
- local everyone = Util.acl_group_to_long_string( bit.band( bit.rshift(acls, 16), 255 ) )
- local user = Util.acl_group_to_long_string( bit.band( bit.rshift(acls, 24), 255 ) )
+ local owner = Util.acl_group_to_long_string( bit.band( acls, 255 ) )
+ local group = Util.acl_group_to_long_string( bit.band( bit.rshift(acls, 8), 255 ) )
+ local everyone = Util.acl_group_to_long_string( bit.band( bit.rshift(acls, 16), 255 ) )
+ local user = Util.acl_group_to_long_string( bit.band( bit.rshift(acls, 24), 255 ) )
- local blank = bit.band( acls, ACLS.BlankAccess ) == ACLS.BlankAccess and "Blank" or nil
- local isowner = bit.band( acls, ACLS.UserIsOwner ) == ACLS.UserIsOwner and "IsOwner" or nil
+ local blank = bit.band( acls, ACLS.BlankAccess ) == ACLS.BlankAccess and "Blank" or nil
+ local isowner = bit.band( acls, ACLS.UserIsOwner ) == ACLS.UserIsOwner and "IsOwner" or nil
- local options = {}
+ local options = {}
- if blank then
- table.insert(options, "Blank")
- end
+ if blank then
+ table.insert(options, "Blank")
+ end
- if isowner then
- table.insert(options, "IsOwner")
- end
+ if isowner then
+ table.insert(options, "IsOwner")
+ end
- local acls_tbl = {}
+ local acls_tbl = {}
- table.insert( acls_tbl, string.format( "Owner: %s", stdnse.strjoin(",", owner) ) )
- table.insert( acls_tbl, string.format( "Group: %s", stdnse.strjoin(",", group) ) )
- table.insert( acls_tbl, string.format( "Everyone: %s", stdnse.strjoin(",", everyone) ) )
- table.insert( acls_tbl, string.format( "User: %s", stdnse.strjoin(",", user) ) )
+ table.insert( acls_tbl, string.format( "Owner: %s", stdnse.strjoin(",", owner) ) )
+ table.insert( acls_tbl, string.format( "Group: %s", stdnse.strjoin(",", group) ) )
+ table.insert( acls_tbl, string.format( "Everyone: %s", stdnse.strjoin(",", everyone) ) )
+ table.insert( acls_tbl, string.format( "User: %s", stdnse.strjoin(",", user) ) )
- if #options > 0 then
- table.insert( acls_tbl, string.format( "Options: %s", stdnse.strjoin(",", options ) ) )
- end
+ if #options > 0 then
+ table.insert( acls_tbl, string.format( "Options: %s", stdnse.strjoin(",", options ) ) )
+ end
- return acls_tbl
+ return acls_tbl
- end,
+ end,
- --- Decodes the UnixPrivileges.ua_permissions value
- --
- -- @param privs number containing the UnixPrivileges.ua_permissions value
- -- @return string containing the ACL characters
- decode_unix_privs = function( privs )
- local owner = ( bit.band( privs, ACLS.OwnerRead ) == ACLS.OwnerRead ) and "r" or "-"
- owner = owner .. (( bit.band( privs, ACLS.OwnerWrite ) == ACLS.OwnerWrite ) and "w" or "-")
- owner = owner .. (( bit.band( privs, ACLS.OwnerSearch ) == ACLS.OwnerSearch ) and "x" or "-")
+ --- Decodes the UnixPrivileges.ua_permissions value
+ --
+ -- @param privs number containing the UnixPrivileges.ua_permissions value
+ -- @return string containing the ACL characters
+ decode_unix_privs = function( privs )
+ local owner = ( bit.band( privs, ACLS.OwnerRead ) == ACLS.OwnerRead ) and "r" or "-"
+ owner = owner .. (( bit.band( privs, ACLS.OwnerWrite ) == ACLS.OwnerWrite ) and "w" or "-")
+ owner = owner .. (( bit.band( privs, ACLS.OwnerSearch ) == ACLS.OwnerSearch ) and "x" or "-")
- local group = ( bit.band( privs, ACLS.GroupRead ) == ACLS.GroupRead ) and "r" or "-"
- group = group .. (( bit.band( privs, ACLS.GroupWrite ) == ACLS.GroupWrite ) and "w" or "-")
- group = group .. (( bit.band( privs, ACLS.GroupSearch ) == ACLS.GroupSearch ) and "x" or "-")
+ local group = ( bit.band( privs, ACLS.GroupRead ) == ACLS.GroupRead ) and "r" or "-"
+ group = group .. (( bit.band( privs, ACLS.GroupWrite ) == ACLS.GroupWrite ) and "w" or "-")
+ group = group .. (( bit.band( privs, ACLS.GroupSearch ) == ACLS.GroupSearch ) and "x" or "-")
- local other = ( bit.band( privs, ACLS.EveryoneRead ) == ACLS.EveryoneRead ) and "r" or "-"
- other = other .. (( bit.band( privs, ACLS.EveryoneWrite ) == ACLS.EveryoneWrite ) and "w" or "-")
- other = other .. (( bit.band( privs, ACLS.EveryoneSearch ) == ACLS.EveryoneSearch ) and "x" or "-")
+ local other = ( bit.band( privs, ACLS.EveryoneRead ) == ACLS.EveryoneRead ) and "r" or "-"
+ other = other .. (( bit.band( privs, ACLS.EveryoneWrite ) == ACLS.EveryoneWrite ) and "w" or "-")
+ other = other .. (( bit.band( privs, ACLS.EveryoneSearch ) == ACLS.EveryoneSearch ) and "x" or "-")
- return owner .. group .. other
- end,
+ return owner .. group .. other
+ end,
- --- Decodes a file bitmap
- --
- -- @param bitmap number containing the bitmap
- -- @param data string containing the data to be decoded
- -- @param pos number containing the offset into data
- -- @return pos number containing the new offset after decoding
- -- @return file table containing the decoded values
- decode_file_bitmap = function( bitmap, data, pos )
- local file = {}
+ --- Decodes a file bitmap
+ --
+ -- @param bitmap number containing the bitmap
+ -- @param data string containing the data to be decoded
+ -- @param pos number containing the offset into data
+ -- @return pos number containing the new offset after decoding
+ -- @return file table containing the decoded values
+ decode_file_bitmap = function( bitmap, data, pos )
+ local file = {}
- if ( bit.band( bitmap, FILE_BITMAP.Attributes ) == FILE_BITMAP.Attributes ) then
- pos, file.Attributes = bin.unpack(">S", data, pos )
- end
- if ( bit.band( bitmap, FILE_BITMAP.ParentDirId ) == FILE_BITMAP.ParentDirId ) then
- pos, file.ParentDirId = bin.unpack(">I", data, pos )
- end
- if ( bit.band( bitmap, FILE_BITMAP.CreationDate ) == FILE_BITMAP.CreationDate ) then
- pos, file.CreationDate = bin.unpack(">I", data, pos )
- end
- if ( bit.band( bitmap, FILE_BITMAP.ModificationDate ) == FILE_BITMAP.ModificationDate ) then
- pos, file.ModificationDate = bin.unpack(">I", data, pos )
- end
- if ( bit.band( bitmap, FILE_BITMAP.BackupDate ) == FILE_BITMAP.BackupDate ) then
- pos, file.BackupDate = bin.unpack(">I", data, pos )
- end
- if ( bit.band( bitmap, FILE_BITMAP.FinderInfo ) == FILE_BITMAP.FinderInfo ) then
- pos, file.FinderInfo = bin.unpack("A32", data, pos )
- end
- if ( bit.band( bitmap, FILE_BITMAP.LongName ) == FILE_BITMAP.LongName ) then
- local offset, p, name
- pos, offset = bin.unpack(">S", data, pos)
- p, file.LongName = bin.unpack("p", data, offset + pos - 1)
- end
- if ( bit.band( bitmap, FILE_BITMAP.ShortName ) == FILE_BITMAP.ShortName ) then
- local offset, p, name
- pos, offset = bin.unpack(">S", data, pos)
- p, file.ShortName = bin.unpack("p", data, offset + pos - 1)
- end
- if ( bit.band( bitmap, FILE_BITMAP.NodeId ) == FILE_BITMAP.NodeId ) then
- pos, file.NodeId = bin.unpack(">I", data, pos )
- end
- if ( bit.band( bitmap, FILE_BITMAP.DataForkSize ) == FILE_BITMAP.DataForkSize ) then
- pos, file.DataForkSize = bin.unpack(">I", data, pos )
- end
- if ( bit.band( bitmap, FILE_BITMAP.ResourceForkSize ) == FILE_BITMAP.ResourceForkSize ) then
- pos, file.ResourceForkSize = bin.unpack(">I", data, pos )
- end
- if ( bit.band( bitmap, FILE_BITMAP.ExtendedDataForkSize ) == FILE_BITMAP.ExtendedDataForkSize ) then
- pos, file.ExtendedDataForkSize = bin.unpack(">L", data, pos )
- end
- if ( bit.band( bitmap, FILE_BITMAP.LaunchLimit ) == FILE_BITMAP.LaunchLimit ) then
- -- should not be set as it's deprecated according to:
- -- http://developer.apple.com/mac/library/documentation/Networking/Reference/AFP_Reference/Reference/reference.html#//apple_ref/doc/c_ref/kFPLaunchLimitBit
- end
- if ( bit.band( bitmap, FILE_BITMAP.UTF8Name ) == FILE_BITMAP.UTF8Name ) then
- local offset, p, name
- pos, offset = bin.unpack(">S", data, pos)
- p, file.UTF8Name = bin.unpack("p", data, offset + pos - 1)
- end
- if ( bit.band( bitmap, FILE_BITMAP.ExtendedResourceForkSize ) == FILE_BITMAP.ExtendedResourceForkSize ) then
- pos, file.ExtendedResourceForkSize = bin.unpack(">L", data, pos )
- end
- if ( bit.band( bitmap, FILE_BITMAP.UnixPrivileges ) == FILE_BITMAP.UnixPrivileges ) then
- local unixprivs = {}
- pos, unixprivs.uid, unixprivs.gid,
- unixprivs.permissions, unixprivs.ua_permissions = bin.unpack(">IIII", data, pos )
- file.UnixPrivileges = unixprivs
- end
- return pos, file
- end,
+ if ( bit.band( bitmap, FILE_BITMAP.Attributes ) == FILE_BITMAP.Attributes ) then
+ pos, file.Attributes = bin.unpack(">S", data, pos )
+ end
+ if ( bit.band( bitmap, FILE_BITMAP.ParentDirId ) == FILE_BITMAP.ParentDirId ) then
+ pos, file.ParentDirId = bin.unpack(">I", data, pos )
+ end
+ if ( bit.band( bitmap, FILE_BITMAP.CreationDate ) == FILE_BITMAP.CreationDate ) then
+ pos, file.CreationDate = bin.unpack(">I", data, pos )
+ end
+ if ( bit.band( bitmap, FILE_BITMAP.ModificationDate ) == FILE_BITMAP.ModificationDate ) then
+ pos, file.ModificationDate = bin.unpack(">I", data, pos )
+ end
+ if ( bit.band( bitmap, FILE_BITMAP.BackupDate ) == FILE_BITMAP.BackupDate ) then
+ pos, file.BackupDate = bin.unpack(">I", data, pos )
+ end
+ if ( bit.band( bitmap, FILE_BITMAP.FinderInfo ) == FILE_BITMAP.FinderInfo ) then
+ pos, file.FinderInfo = bin.unpack("A32", data, pos )
+ end
+ if ( bit.band( bitmap, FILE_BITMAP.LongName ) == FILE_BITMAP.LongName ) then
+ local offset, p, name
+ pos, offset = bin.unpack(">S", data, pos)
+ p, file.LongName = bin.unpack("p", data, offset + pos - 1)
+ end
+ if ( bit.band( bitmap, FILE_BITMAP.ShortName ) == FILE_BITMAP.ShortName ) then
+ local offset, p, name
+ pos, offset = bin.unpack(">S", data, pos)
+ p, file.ShortName = bin.unpack("p", data, offset + pos - 1)
+ end
+ if ( bit.band( bitmap, FILE_BITMAP.NodeId ) == FILE_BITMAP.NodeId ) then
+ pos, file.NodeId = bin.unpack(">I", data, pos )
+ end
+ if ( bit.band( bitmap, FILE_BITMAP.DataForkSize ) == FILE_BITMAP.DataForkSize ) then
+ pos, file.DataForkSize = bin.unpack(">I", data, pos )
+ end
+ if ( bit.band( bitmap, FILE_BITMAP.ResourceForkSize ) == FILE_BITMAP.ResourceForkSize ) then
+ pos, file.ResourceForkSize = bin.unpack(">I", data, pos )
+ end
+ if ( bit.band( bitmap, FILE_BITMAP.ExtendedDataForkSize ) == FILE_BITMAP.ExtendedDataForkSize ) then
+ pos, file.ExtendedDataForkSize = bin.unpack(">L", data, pos )
+ end
+ if ( bit.band( bitmap, FILE_BITMAP.LaunchLimit ) == FILE_BITMAP.LaunchLimit ) then
+ -- should not be set as it's deprecated according to:
+ -- http://developer.apple.com/mac/library/documentation/Networking/Reference/AFP_Reference/Reference/reference.html#//apple_ref/doc/c_ref/kFPLaunchLimitBit
+ end
+ if ( bit.band( bitmap, FILE_BITMAP.UTF8Name ) == FILE_BITMAP.UTF8Name ) then
+ local offset, p, name
+ pos, offset = bin.unpack(">S", data, pos)
+ p, file.UTF8Name = bin.unpack("p", data, offset + pos - 1)
+ end
+ if ( bit.band( bitmap, FILE_BITMAP.ExtendedResourceForkSize ) == FILE_BITMAP.ExtendedResourceForkSize ) then
+ pos, file.ExtendedResourceForkSize = bin.unpack(">L", data, pos )
+ end
+ if ( bit.band( bitmap, FILE_BITMAP.UnixPrivileges ) == FILE_BITMAP.UnixPrivileges ) then
+ local unixprivs = {}
+ pos, unixprivs.uid, unixprivs.gid,
+ unixprivs.permissions, unixprivs.ua_permissions = bin.unpack(">IIII", data, pos )
+ file.UnixPrivileges = unixprivs
+ end
+ return pos, file
+ end,
- --- Decodes a directory bitmap
- --
- -- @param bitmap number containing the bitmap
- -- @param data string containing the data to be decoded
- -- @param pos number containing the offset into data
- -- @return pos number containing the new offset after decoding
- -- @return dir table containing the decoded values
- decode_dir_bitmap = function( bitmap, data, pos )
- local dir = {}
+ --- Decodes a directory bitmap
+ --
+ -- @param bitmap number containing the bitmap
+ -- @param data string containing the data to be decoded
+ -- @param pos number containing the offset into data
+ -- @return pos number containing the new offset after decoding
+ -- @return dir table containing the decoded values
+ decode_dir_bitmap = function( bitmap, data, pos )
+ local dir = {}
- if ( bit.band( bitmap, DIR_BITMAP.Attributes ) == DIR_BITMAP.Attributes ) then
- pos, dir.Attributes = bin.unpack(">S", data, pos )
- end
- if ( bit.band( bitmap, DIR_BITMAP.ParentDirId ) == DIR_BITMAP.ParentDirId ) then
- pos, dir.ParentDirId = bin.unpack(">I", data, pos )
- end
- if ( bit.band( bitmap, DIR_BITMAP.CreationDate ) == DIR_BITMAP.CreationDate ) then
- pos, dir.CreationDate = bin.unpack(">I", data, pos )
- end
- if ( bit.band( bitmap, DIR_BITMAP.ModificationDate ) == DIR_BITMAP.ModificationDate ) then
- pos, dir.ModificationDate = bin.unpack(">I", data, pos )
- end
- if ( bit.band( bitmap, DIR_BITMAP.BackupDate ) == DIR_BITMAP.BackupDate ) then
- pos, dir.BackupDate = bin.unpack(">I", data, pos )
- end
- if ( bit.band( bitmap, DIR_BITMAP.FinderInfo ) == DIR_BITMAP.FinderInfo ) then
- pos, dir.FinderInfo = bin.unpack("A32", data, pos )
- end
- if ( bit.band( bitmap, DIR_BITMAP.LongName ) == DIR_BITMAP.LongName ) then
- local offset, p, name
- pos, offset = bin.unpack(">S", data, pos)
+ if ( bit.band( bitmap, DIR_BITMAP.Attributes ) == DIR_BITMAP.Attributes ) then
+ pos, dir.Attributes = bin.unpack(">S", data, pos )
+ end
+ if ( bit.band( bitmap, DIR_BITMAP.ParentDirId ) == DIR_BITMAP.ParentDirId ) then
+ pos, dir.ParentDirId = bin.unpack(">I", data, pos )
+ end
+ if ( bit.band( bitmap, DIR_BITMAP.CreationDate ) == DIR_BITMAP.CreationDate ) then
+ pos, dir.CreationDate = bin.unpack(">I", data, pos )
+ end
+ if ( bit.band( bitmap, DIR_BITMAP.ModificationDate ) == DIR_BITMAP.ModificationDate ) then
+ pos, dir.ModificationDate = bin.unpack(">I", data, pos )
+ end
+ if ( bit.band( bitmap, DIR_BITMAP.BackupDate ) == DIR_BITMAP.BackupDate ) then
+ pos, dir.BackupDate = bin.unpack(">I", data, pos )
+ end
+ if ( bit.band( bitmap, DIR_BITMAP.FinderInfo ) == DIR_BITMAP.FinderInfo ) then
+ pos, dir.FinderInfo = bin.unpack("A32", data, pos )
+ end
+ if ( bit.band( bitmap, DIR_BITMAP.LongName ) == DIR_BITMAP.LongName ) then
+ local offset, p, name
+ pos, offset = bin.unpack(">S", data, pos)
- -- TODO: This really needs to be adressed someway
- -- Barely, never, ever happens, which makes it difficult to pin down
- -- http://developer.apple.com/mac/library/documentation/Networking/Reference/
- -- AFP_Reference/Reference/reference.html#//apple_ref/doc/uid/TP40003548-CH3-CHDBEHBG [URL is wrapped]
- local justkidding = select(2, bin.unpack(">I", data, pos + 4))
- if ( justkidding ~= 0 ) then
- offset = 5
- end
+ -- TODO: This really needs to be adressed someway
+ -- Barely, never, ever happens, which makes it difficult to pin down
+ -- http://developer.apple.com/mac/library/documentation/Networking/Reference/
+ -- AFP_Reference/Reference/reference.html#//apple_ref/doc/uid/TP40003548-CH3-CHDBEHBG [URL is wrapped]
+ local justkidding = select(2, bin.unpack(">I", data, pos + 4))
+ if ( justkidding ~= 0 ) then
+ offset = 5
+ end
- p, dir.LongName = bin.unpack("p", data, offset + pos - 1)
- end
- if ( bit.band( bitmap, DIR_BITMAP.ShortName ) == DIR_BITMAP.ShortName ) then
- local offset, p, name
- pos, offset = bin.unpack(">S", data, pos)
- p, dir.ShortName = bin.unpack("p", data, offset + pos - 1)
- end
- if ( bit.band( bitmap, DIR_BITMAP.NodeId ) == DIR_BITMAP.NodeId ) then
- pos, dir.NodeId = bin.unpack(">I", data, pos )
- end
- if ( bit.band( bitmap, DIR_BITMAP.OffspringCount ) == DIR_BITMAP.OffspringCount ) then
- pos, dir.OffspringCount = bin.unpack(">S", data, pos )
- end
- if ( bit.band( bitmap, DIR_BITMAP.OwnerId ) == DIR_BITMAP.OwnerId ) then
- pos, dir.OwnerId = bin.unpack(">I", data, pos )
- end
- if ( bit.band( bitmap, DIR_BITMAP.GroupId ) == DIR_BITMAP.GroupId ) then
- pos, dir.GroupId = bin.unpack(">I", data, pos )
- end
- if ( bit.band( bitmap, DIR_BITMAP.AccessRights ) == DIR_BITMAP.AccessRights ) then
- pos, dir.AccessRights = bin.unpack(">I", data, pos )
- end
- if ( bit.band( bitmap, DIR_BITMAP.UTF8Name ) == DIR_BITMAP.UTF8Name ) then
- local offset, p, name
- pos, offset = bin.unpack(">S", data, pos)
- p, dir.UTF8Name = bin.unpack("p", data, offset + pos - 1)
- end
- if ( bit.band( bitmap, DIR_BITMAP.UnixPrivileges ) == DIR_BITMAP.UnixPrivileges ) then
- local unixprivs = {}
+ p, dir.LongName = bin.unpack("p", data, offset + pos - 1)
+ end
+ if ( bit.band( bitmap, DIR_BITMAP.ShortName ) == DIR_BITMAP.ShortName ) then
+ local offset, p, name
+ pos, offset = bin.unpack(">S", data, pos)
+ p, dir.ShortName = bin.unpack("p", data, offset + pos - 1)
+ end
+ if ( bit.band( bitmap, DIR_BITMAP.NodeId ) == DIR_BITMAP.NodeId ) then
+ pos, dir.NodeId = bin.unpack(">I", data, pos )
+ end
+ if ( bit.band( bitmap, DIR_BITMAP.OffspringCount ) == DIR_BITMAP.OffspringCount ) then
+ pos, dir.OffspringCount = bin.unpack(">S", data, pos )
+ end
+ if ( bit.band( bitmap, DIR_BITMAP.OwnerId ) == DIR_BITMAP.OwnerId ) then
+ pos, dir.OwnerId = bin.unpack(">I", data, pos )
+ end
+ if ( bit.band( bitmap, DIR_BITMAP.GroupId ) == DIR_BITMAP.GroupId ) then
+ pos, dir.GroupId = bin.unpack(">I", data, pos )
+ end
+ if ( bit.band( bitmap, DIR_BITMAP.AccessRights ) == DIR_BITMAP.AccessRights ) then
+ pos, dir.AccessRights = bin.unpack(">I", data, pos )
+ end
+ if ( bit.band( bitmap, DIR_BITMAP.UTF8Name ) == DIR_BITMAP.UTF8Name ) then
+ local offset, p, name
+ pos, offset = bin.unpack(">S", data, pos)
+ p, dir.UTF8Name = bin.unpack("p", data, offset + pos - 1)
+ end
+ if ( bit.band( bitmap, DIR_BITMAP.UnixPrivileges ) == DIR_BITMAP.UnixPrivileges ) then
+ local unixprivs = {}
- pos, unixprivs.uid, unixprivs.gid,
- unixprivs.permissions, unixprivs.ua_permissions = bin.unpack(">I>I>I>I", data, pos )
- dir.UnixPrivileges = unixprivs
- end
- return pos, dir
- end,
+ pos, unixprivs.uid, unixprivs.gid,
+ unixprivs.permissions, unixprivs.ua_permissions = bin.unpack(">I>I>I>I", data, pos )
+ dir.UnixPrivileges = unixprivs
+ end
+ return pos, dir
+ end,
}
diff --git a/nselib/ajp.lua b/nselib/ajp.lua
index c65ba0ecc..becd4c964 100644
--- a/nselib/ajp.lua
+++ b/nselib/ajp.lua
@@ -18,507 +18,507 @@ _ENV = stdnse.module("ajp", stdnse.seeall)
AJP = {
- -- The magic prefix that has to be present in all requests
- Magic = 0x1234,
+ -- The magic prefix that has to be present in all requests
+ Magic = 0x1234,
- -- Methods encoded as numeric values
- Method = {
- ['OPTIONS'] = 1,
- ['GET'] = 2,
- ['HEAD'] = 3,
- ['POST'] = 4,
- ['PUT'] = 5,
- ['DELETE'] = 6,
- ['TRACE'] = 7,
- ['PROPFIND'] = 8,
- ['PROPPATCH'] = 9,
- ['MKCOL'] = 10,
- ['COPY'] = 11,
- ['MOVE'] = 12,
- ['LOCK'] = 13,
- ['UNLOCK'] = 14,
- ['ACL'] = 15,
- ['REPORT'] = 16,
- ['VERSION-CONTROL'] = 17,
- ['CHECKIN'] = 18,
- ['CHECKOUT'] = 19,
- ['UNCHECKOUT'] = 20,
- ['SEARCH'] = 21,
- ['MKWORKSPACE'] = 22,
- ['UPDATE'] = 23,
- ['LABEL'] = 24,
- ['MERGE'] = 25,
- ['BASELINE_CONTROL'] = 26,
- ['MKACTIVITY'] = 27,
- },
+ -- Methods encoded as numeric values
+ Method = {
+ ['OPTIONS'] = 1,
+ ['GET'] = 2,
+ ['HEAD'] = 3,
+ ['POST'] = 4,
+ ['PUT'] = 5,
+ ['DELETE'] = 6,
+ ['TRACE'] = 7,
+ ['PROPFIND'] = 8,
+ ['PROPPATCH'] = 9,
+ ['MKCOL'] = 10,
+ ['COPY'] = 11,
+ ['MOVE'] = 12,
+ ['LOCK'] = 13,
+ ['UNLOCK'] = 14,
+ ['ACL'] = 15,
+ ['REPORT'] = 16,
+ ['VERSION-CONTROL'] = 17,
+ ['CHECKIN'] = 18,
+ ['CHECKOUT'] = 19,
+ ['UNCHECKOUT'] = 20,
+ ['SEARCH'] = 21,
+ ['MKWORKSPACE'] = 22,
+ ['UPDATE'] = 23,
+ ['LABEL'] = 24,
+ ['MERGE'] = 25,
+ ['BASELINE_CONTROL'] = 26,
+ ['MKACTIVITY'] = 27,
+ },
- -- Request codes
- Code = {
- FORWARD_REQUEST = 2,
- SEND_BODY = 3,
- SEND_HEADERS = 4,
- END_RESPONSE = 5,
- SHUTDOWN = 7,
- PING = 8,
- CPING = 10,
- },
+ -- Request codes
+ Code = {
+ FORWARD_REQUEST = 2,
+ SEND_BODY = 3,
+ SEND_HEADERS = 4,
+ END_RESPONSE = 5,
+ SHUTDOWN = 7,
+ PING = 8,
+ CPING = 10,
+ },
- -- Request attributes
- Attribute = {
- CONTEXT = 0x01,
- SERVLET_PATH = 0x02,
- REMOTE_USER = 0x03,
- AUTH_TYPE = 0x04,
- QUERY_STRING = 0x05,
- JVM_ROUTE = 0x06,
- SSL_CERT = 0x07,
- SSL_CIPHER = 0x08,
- SSL_SESSION = 0x09,
- REQ_ATTRIBUTE= 0x0A,
- SSL_KEY_SIZE = 0x0B,
- ARE_DONE = 0xFF,
- },
+ -- Request attributes
+ Attribute = {
+ CONTEXT = 0x01,
+ SERVLET_PATH = 0x02,
+ REMOTE_USER = 0x03,
+ AUTH_TYPE = 0x04,
+ QUERY_STRING = 0x05,
+ JVM_ROUTE = 0x06,
+ SSL_CERT = 0x07,
+ SSL_CIPHER = 0x08,
+ SSL_SESSION = 0x09,
+ REQ_ATTRIBUTE= 0x0A,
+ SSL_KEY_SIZE = 0x0B,
+ ARE_DONE = 0xFF,
+ },
- ForwardRequest = {
+ ForwardRequest = {
- -- Common headers encoded as numeric values
- Header = {
- ['accept'] = 0xA001,
- ['accept-charset'] = 0xA002,
- ['accept-encoding'] = 0xA003,
- ['accept-language'] = 0xA004,
- ['authorization'] = 0xA005,
- ['connection'] = 0xA006,
- ['content-type'] = 0xA007,
- ['content-length'] = 0xA008,
- ['cookie'] = 0xA009,
- ['cookie2'] = 0xA00A,
- ['host'] = 0xA00B,
- ['pragma'] = 0xA00C,
- ['referer'] = 0xA00D,
- ['user-agent'] = 0xA00E,
- },
+ -- Common headers encoded as numeric values
+ Header = {
+ ['accept'] = 0xA001,
+ ['accept-charset'] = 0xA002,
+ ['accept-encoding'] = 0xA003,
+ ['accept-language'] = 0xA004,
+ ['authorization'] = 0xA005,
+ ['connection'] = 0xA006,
+ ['content-type'] = 0xA007,
+ ['content-length'] = 0xA008,
+ ['cookie'] = 0xA009,
+ ['cookie2'] = 0xA00A,
+ ['host'] = 0xA00B,
+ ['pragma'] = 0xA00C,
+ ['referer'] = 0xA00D,
+ ['user-agent'] = 0xA00E,
+ },
- new = function(self, host, port, method, uri, headers, attributes, options)
- local o = {
- host = host,
- magic = 0x1234,
- length = 0,
- code = AJP.Code.FORWARD_REQUEST,
- method = AJP.Method[method],
- version = "HTTP/1.1",
- uri = uri,
- raddr = options.raddr or "127.0.0.1",
- rhost = options.rhost or "",
- srv = host.ip,
- port = port.number,
- is_ssl = (port.service == "https"),
- headers = headers or {},
- attributes = attributes or {},
- }
- setmetatable(o, self)
- self.__index = self
+ new = function(self, host, port, method, uri, headers, attributes, options)
+ local o = {
+ host = host,
+ magic = 0x1234,
+ length = 0,
+ code = AJP.Code.FORWARD_REQUEST,
+ method = AJP.Method[method],
+ version = "HTTP/1.1",
+ uri = uri,
+ raddr = options.raddr or "127.0.0.1",
+ rhost = options.rhost or "",
+ srv = host.ip,
+ port = port.number,
+ is_ssl = (port.service == "https"),
+ headers = headers or {},
+ attributes = attributes or {},
+ }
+ setmetatable(o, self)
+ self.__index = self
return o
- end,
+ end,
- __tostring = function(self)
+ __tostring = function(self)
- -- encodes a string, prefixing it with a 2-byte length
- -- and suffixing it with a zero. P-encoding can't be used
- -- as the zero terminator should not be counted in the length
- local function encstr(str)
- if ( not(str) or #str == 0 ) then
- return bin.pack(">S", 0xFFFF)
- end
- return bin.pack(">Sz", #str, str)
- end
+ -- encodes a string, prefixing it with a 2-byte length
+ -- and suffixing it with a zero. P-encoding can't be used
+ -- as the zero terminator should not be counted in the length
+ local function encstr(str)
+ if ( not(str) or #str == 0 ) then
+ return bin.pack(">S", 0xFFFF)
+ end
+ return bin.pack(">Sz", #str, str)
+ end
- -- count the number of headers
- local function headerCount()
- local i = 0
- for _, _ in pairs(self.headers) do i = i + 1 end
- return i
- end
+ -- count the number of headers
+ local function headerCount()
+ local i = 0
+ for _, _ in pairs(self.headers) do i = i + 1 end
+ return i
+ end
- -- add host header if it's missing
- if ( not(self.headers['host']) ) then
- self.headers['host'] = stdnse.get_hostname(self.host)
- end
+ -- add host header if it's missing
+ if ( not(self.headers['host']) ) then
+ self.headers['host'] = stdnse.get_hostname(self.host)
+ end
- -- add keep-alive connection header if missing
- if ( not(self.headers['connection']) ) then
- self.headers['connection'] = "keep-alive"
- end
+ -- add keep-alive connection header if missing
+ if ( not(self.headers['connection']) ) then
+ self.headers['connection'] = "keep-alive"
+ end
- local p_url = url.parse(self.uri)
+ local p_url = url.parse(self.uri)
- -- save the magic and data for last
- local data = bin.pack(">CCAAAAASCS", self.code, self.method,
- encstr(self.version), encstr(p_url.path), encstr(self.raddr),
- encstr(self.rhost), encstr(self.srv),
- self.port, (self.is_ssl and 1 or 0),
- headerCount())
+ -- save the magic and data for last
+ local data = bin.pack(">CCAAAAASCS", self.code, self.method,
+ encstr(self.version), encstr(p_url.path), encstr(self.raddr),
+ encstr(self.rhost), encstr(self.srv),
+ self.port, (self.is_ssl and 1 or 0),
+ headerCount())
- -- encode headers
- for k, v in pairs(self.headers) do
- local header = AJP.ForwardRequest.Header[k:lower()] or k
- if ( "string" == type(header) ) then
- data = data .. bin.pack(">Sz", #header, header)
- else
- data = data .. bin.pack(">S", header)
- end
+ -- encode headers
+ for k, v in pairs(self.headers) do
+ local header = AJP.ForwardRequest.Header[k:lower()] or k
+ if ( "string" == type(header) ) then
+ data = data .. bin.pack(">Sz", #header, header)
+ else
+ data = data .. bin.pack(">S", header)
+ end
- data = data .. encstr(v)
- end
+ data = data .. encstr(v)
+ end
- -- encode attributes
- if ( p_url.query ) then
- data = data .. bin.pack("C", AJP.Attribute.QUERY_STRING)
- data = data .. encstr(p_url.query)
- end
+ -- encode attributes
+ if ( p_url.query ) then
+ data = data .. bin.pack("C", AJP.Attribute.QUERY_STRING)
+ data = data .. encstr(p_url.query)
+ end
- -- terminate the attribute list
- data = data .. bin.pack("C", AJP.Attribute.ARE_DONE)
+ -- terminate the attribute list
+ data = data .. bin.pack("C", AJP.Attribute.ARE_DONE)
- -- returns the AJP request as a string
- return bin.pack(">SSA", AJP.Magic, #data, data)
- end,
+ -- returns the AJP request as a string
+ return bin.pack(">SSA", AJP.Magic, #data, data)
+ end,
- },
+ },
- Response = {
+ Response = {
- Header = {
- ['Content-Type'] = 0xA001,
- ['Content-Language'] = 0xA002,
- ['Content-Length'] = 0xA003,
- ['Date'] = 0xA004,
- ['Last-Modified'] = 0xA005,
- ['Location'] = 0xA006,
- ['Set-Cookie'] = 0xA007,
- ['Set-Cookie2'] = 0xA008,
- ['Servlet-Engine'] = 0xA009,
- ['Status'] = 0xA00A,
- ['WWW-Authenticate'] = 0xA00B,
- },
+ Header = {
+ ['Content-Type'] = 0xA001,
+ ['Content-Language'] = 0xA002,
+ ['Content-Length'] = 0xA003,
+ ['Date'] = 0xA004,
+ ['Last-Modified'] = 0xA005,
+ ['Location'] = 0xA006,
+ ['Set-Cookie'] = 0xA007,
+ ['Set-Cookie2'] = 0xA008,
+ ['Servlet-Engine'] = 0xA009,
+ ['Status'] = 0xA00A,
+ ['WWW-Authenticate'] = 0xA00B,
+ },
- SendHeaders = {
+ SendHeaders = {
- new = function(self)
- local o = { headers = {}, rawheaders = {} }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ new = function(self)
+ local o = { headers = {}, rawheaders = {} }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- parse = function(data)
- local sh = AJP.Response.SendHeaders:new()
- local pos = 6
- local status_msg, hdr_count
+ parse = function(data)
+ local sh = AJP.Response.SendHeaders:new()
+ local pos = 6
+ local status_msg, hdr_count
- pos, sh.status = bin.unpack(">S", data, pos)
- pos, status_msg = bin.unpack(">P", data, pos)
- pos = pos + 1
- sh['status-line'] = ("AJP/1.3 %d %s"):format(sh.status, status_msg)
+ pos, sh.status = bin.unpack(">S", data, pos)
+ pos, status_msg = bin.unpack(">P", data, pos)
+ pos = pos + 1
+ sh['status-line'] = ("AJP/1.3 %d %s"):format(sh.status, status_msg)
- pos, hdr_count = bin.unpack(">S", data, pos)
+ pos, hdr_count = bin.unpack(">S", data, pos)
- local function headerById(id)
- for k, v in pairs(AJP.Response.Header) do
- if ( v == id ) then return k end
- end
- end
+ local function headerById(id)
+ for k, v in pairs(AJP.Response.Header) do
+ if ( v == id ) then return k end
+ end
+ end
- for i=1, hdr_count do
- local key, val, len
- pos, len = bin.unpack(">S", data, pos)
+ for i=1, hdr_count do
+ local key, val, len
+ pos, len = bin.unpack(">S", data, pos)
- if ( len < 0xA000 ) then
- pos, key = bin.unpack("A"..len, data, pos)
- pos = pos + 1
- else
- key = headerById(len)
- end
+ if ( len < 0xA000 ) then
+ pos, key = bin.unpack("A"..len, data, pos)
+ pos = pos + 1
+ else
+ key = headerById(len)
+ end
- pos, val = bin.unpack(">P", data, pos)
- pos = pos + 1
+ pos, val = bin.unpack(">P", data, pos)
+ pos = pos + 1
- sh.headers[key:lower()] = val
+ sh.headers[key:lower()] = val
- -- to keep the order, in which the headers were received,
- -- add them to the rawheader table as well. This is based
- -- on the same principle as the http library, however the
- -- difference being that we have to "construct" the "raw"
- -- format of the header, as we're receiving kvp's.
- table.insert(sh.rawheaders, ("%s: %s"):format(key,val))
- end
- return sh
- end,
+ -- to keep the order, in which the headers were received,
+ -- add them to the rawheader table as well. This is based
+ -- on the same principle as the http library, however the
+ -- difference being that we have to "construct" the "raw"
+ -- format of the header, as we're receiving kvp's.
+ table.insert(sh.rawheaders, ("%s: %s"):format(key,val))
+ end
+ return sh
+ end,
- },
+ },
- },
+ },
}
-- The Comm class handles sending and receiving AJP requests/responses
Comm = {
- -- Creates a new Comm instance
- new = function(self, host, port, options)
- local o = { host = host, port = port, options = options or {}}
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new Comm instance
+ new = function(self, host, port, options)
+ local o = { host = host, port = port, options = options or {}}
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Connects to the AJP server
- --
- -- @return status true on success, false on failure
- -- @return err string containing error message on failure
- connect = function(self)
- self.socket = nmap.new_socket()
- self.socket:set_timeout(self.options.timeout or 5000)
- return self.socket:connect(self.host, self.port)
- end,
+ -- Connects to the AJP server
+ --
+ -- @return status true on success, false on failure
+ -- @return err string containing error message on failure
+ connect = function(self)
+ self.socket = nmap.new_socket()
+ self.socket:set_timeout(self.options.timeout or 5000)
+ return self.socket:connect(self.host, self.port)
+ end,
- -- Sends a request to the server
- --
- -- @param req instance of object that can be serialized with tostring
- -- @return status true on succes, false on failure
- -- @return err string containing error message on failure
- send = function(self, req)
- return self.socket:send(tostring(req))
- end,
+ -- Sends a request to the server
+ --
+ -- @param req instance of object that can be serialized with tostring
+ -- @return status true on succes, false on failure
+ -- @return err string containing error message on failure
+ send = function(self, req)
+ return self.socket:send(tostring(req))
+ end,
- -- Receives an AJP response from the server
- --
- -- @return status true on succes, false on failure
- -- @return response table containing the following fields, or string
- -- containing error message on failure
- -- status - status of response (see HTTP status codes)
- -- status-line - the complete status line (eg. 200 OK)
- -- body - the response body as string
- -- headers - table of response headers
- --
- receive = function(self)
- local response = {}
- while(true) do
- local status, buf = self.socket:receive_buf(match.numbytes(4), true)
- if ( not(status) ) then
- return false, "Failed to receive response from server"
- end
- local pos, magic, length = bin.unpack(">A2S", buf)
- if ( magic ~= "AB" ) then
- return false, ("Invalid magic received from server (%s)"):format(magic)
- end
- local status, data = self.socket:receive_buf(match.numbytes(length), true)
- if ( not(status) ) then
- return false, "Failed to receive response from server"
- end
+ -- Receives an AJP response from the server
+ --
+ -- @return status true on succes, false on failure
+ -- @return response table containing the following fields, or string
+ -- containing error message on failure
+ -- status - status of response (see HTTP status codes)
+ -- status-line - the complete status line (eg. 200 OK)
+ -- body - the response body as string
+ -- headers - table of response headers
+ --
+ receive = function(self)
+ local response = {}
+ while(true) do
+ local status, buf = self.socket:receive_buf(match.numbytes(4), true)
+ if ( not(status) ) then
+ return false, "Failed to receive response from server"
+ end
+ local pos, magic, length = bin.unpack(">A2S", buf)
+ if ( magic ~= "AB" ) then
+ return false, ("Invalid magic received from server (%s)"):format(magic)
+ end
+ local status, data = self.socket:receive_buf(match.numbytes(length), true)
+ if ( not(status) ) then
+ return false, "Failed to receive response from server"
+ end
- local pos, code = bin.unpack("C", data)
- if ( AJP.Code.SEND_HEADERS == code ) then
- local sh = AJP.Response.SendHeaders.parse(buf .. data)
- response = sh
- elseif( AJP.Code.SEND_BODY == code ) then
- response.body = select(2, bin.unpack(">P", data, pos))
- elseif( AJP.Code.END_RESPONSE == code ) then
- break
- end
- end
- return true, response
- end,
+ local pos, code = bin.unpack("C", data)
+ if ( AJP.Code.SEND_HEADERS == code ) then
+ local sh = AJP.Response.SendHeaders.parse(buf .. data)
+ response = sh
+ elseif( AJP.Code.SEND_BODY == code ) then
+ response.body = select(2, bin.unpack(">P", data, pos))
+ elseif( AJP.Code.END_RESPONSE == code ) then
+ break
+ end
+ end
+ return true, response
+ end,
- -- Closes the socket
- close = function(self)
- return self.socket:close()
- end,
+ -- Closes the socket
+ close = function(self)
+ return self.socket:close()
+ end,
}
Helper = {
- --- Creates a new AJP Helper instance
- --
- -- @param host table
- -- @param port table
- -- @param opt
- -- @return o new Helper instance
- new = function(self, host, port, opt)
- local o = { host = host, port = port, opt = opt or {} }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ --- Creates a new AJP Helper instance
+ --
+ -- @param host table
+ -- @param port table
+ -- @param opt
+ -- @return o new Helper instance
+ new = function(self, host, port, opt)
+ local o = { host = host, port = port, opt = opt or {} }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- --- Connects to the AJP server
- --
- -- @return status true on success, false on failure
- -- @return err string containing error message on failure
- connect = function(self)
- self.comm = Comm:new(self.host, self.port, self.opt)
- return self.comm:connect()
- end,
+ --- Connects to the AJP server
+ --
+ -- @return status true on success, false on failure
+ -- @return err string containing error message on failure
+ connect = function(self)
+ self.comm = Comm:new(self.host, self.port, self.opt)
+ return self.comm:connect()
+ end,
- getOption = function(self, options, key)
+ getOption = function(self, options, key)
- -- first check options, then global self.opt
- if ( options and options[key] ) then
- return options[key]
- elseif ( self.opt and self.opt[key] ) then
- return self.opt[key]
- end
+ -- first check options, then global self.opt
+ if ( options and options[key] ) then
+ return options[key]
+ elseif ( self.opt and self.opt[key] ) then
+ return self.opt[key]
+ end
- end,
+ end,
- --- Sends an AJP request to the server
- --
- -- @param url string containing the URL to query
- -- @param headers table containing optional headers
- -- @param attributes table containing optional attributes
- -- @param options table with request specific options
- -- @return status true on succes, false on failure
- -- @return response table (@see Comm.receive), or string containing error
- -- message on failure
- request = function(self, method, url, headers, attributes, options)
- local status, lhost, lport, rhost, rport = self.comm.socket:get_info()
- if ( not(status) ) then
- return false, "Failed to get socket information"
- end
+ --- Sends an AJP request to the server
+ --
+ -- @param url string containing the URL to query
+ -- @param headers table containing optional headers
+ -- @param attributes table containing optional attributes
+ -- @param options table with request specific options
+ -- @return status true on succes, false on failure
+ -- @return response table (@see Comm.receive), or string containing error
+ -- message on failure
+ request = function(self, method, url, headers, attributes, options)
+ local status, lhost, lport, rhost, rport = self.comm.socket:get_info()
+ if ( not(status) ) then
+ return false, "Failed to get socket information"
+ end
- local request = AJP.ForwardRequest:new(self.host, self.port, method, url, headers, attributes, { raddr = rhost })
- if ( not(self.comm:send(request)) ) then
- return false, "Failed to send request to server"
- end
- local status, result = self.comm:receive()
+ local request = AJP.ForwardRequest:new(self.host, self.port, method, url, headers, attributes, { raddr = rhost })
+ if ( not(self.comm:send(request)) ) then
+ return false, "Failed to send request to server"
+ end
+ local status, result = self.comm:receive()
- -- support Basic authentication
- if ( status and result.status == 401 and result.headers['www-authenticate'] ) then
+ -- support Basic authentication
+ if ( status and result.status == 401 and result.headers['www-authenticate'] ) then
- local auth = self:getOption(options, "auth")
- if ( not(auth) or not(auth.username) and not(auth.password) ) then
- stdnse.print_debug(2, "No authentication information")
- return status, result
- end
+ local auth = self:getOption(options, "auth")
+ if ( not(auth) or not(auth.username) and not(auth.password) ) then
+ stdnse.print_debug(2, "No authentication information")
+ return status, result
+ end
- local challenges = http.parse_www_authenticate(result.headers['www-authenticate'])
- local scheme
- for _, challenge in ipairs(challenges or {}) do
- if ( challenge and challenge.scheme and challenge.scheme:lower() == "basic") then
- scheme = challenge.scheme:lower()
- break
- end
- end
+ local challenges = http.parse_www_authenticate(result.headers['www-authenticate'])
+ local scheme
+ for _, challenge in ipairs(challenges or {}) do
+ if ( challenge and challenge.scheme and challenge.scheme:lower() == "basic") then
+ scheme = challenge.scheme:lower()
+ break
+ end
+ end
- if ( not(scheme) ) then
- stdnse.print_debug(2, "Could not find a supported authentication scheme")
- elseif ( "basic" ~= scheme ) then
- stdnse.print_debug(2, "Unsupported authentication scheme: %s", scheme)
- else
- headers = headers or {}
- headers["Authorization"] = ("Basic %s"):format(base64.enc(auth.username .. ":" .. auth.password))
- request = AJP.ForwardRequest:new(self.host, self.port, method, url, headers, attributes, { raddr = rhost })
- if ( not(self.comm:send(request)) ) then
- return false, "Failed to send request to server"
- end
- status, result = self.comm:receive()
- end
+ if ( not(scheme) ) then
+ stdnse.print_debug(2, "Could not find a supported authentication scheme")
+ elseif ( "basic" ~= scheme ) then
+ stdnse.print_debug(2, "Unsupported authentication scheme: %s", scheme)
+ else
+ headers = headers or {}
+ headers["Authorization"] = ("Basic %s"):format(base64.enc(auth.username .. ":" .. auth.password))
+ request = AJP.ForwardRequest:new(self.host, self.port, method, url, headers, attributes, { raddr = rhost })
+ if ( not(self.comm:send(request)) ) then
+ return false, "Failed to send request to server"
+ end
+ status, result = self.comm:receive()
+ end
- end
- return status, result
- end,
+ end
+ return status, result
+ end,
- --- Sends an AJP GET request to the server
- --
- -- @param url string containing the URL to query
- -- @param headers table containing optional headers
- -- @param attributes table containing optional attributes
- -- @param options table with request specific options
- -- @return status true on succes, false on failure
- -- @return response table (@see Comm.receive), or string containing error
- -- message on failure
- get = function(self, url, headers, attributes, options)
- return self:request("GET", url, headers, attributes, options)
- end,
+ --- Sends an AJP GET request to the server
+ --
+ -- @param url string containing the URL to query
+ -- @param headers table containing optional headers
+ -- @param attributes table containing optional attributes
+ -- @param options table with request specific options
+ -- @return status true on succes, false on failure
+ -- @return response table (@see Comm.receive), or string containing error
+ -- message on failure
+ get = function(self, url, headers, attributes, options)
+ return self:request("GET", url, headers, attributes, options)
+ end,
- --- Sends an AJP HEAD request to the server
- --
- -- @param url string containing the URL to query
- -- @param headers table containing optional headers
- -- @param attributes table containing optional attributes
- -- @param options table with request specific options
- -- @return status true on succes, false on failure
- -- @return response table (@see Comm.receive), or string containing error
- -- message on failure
- head = function(self, url, headers, attributes, options)
- return self:request("HEAD", url, headers, attributes, options)
- end,
+ --- Sends an AJP HEAD request to the server
+ --
+ -- @param url string containing the URL to query
+ -- @param headers table containing optional headers
+ -- @param attributes table containing optional attributes
+ -- @param options table with request specific options
+ -- @return status true on succes, false on failure
+ -- @return response table (@see Comm.receive), or string containing error
+ -- message on failure
+ head = function(self, url, headers, attributes, options)
+ return self:request("HEAD", url, headers, attributes, options)
+ end,
- --- Sends an AJP TRACE request to the server
- --
- -- @param url string containing the URL to query
- -- @param headers table containing optional headers
- -- @param attributes table containing optional attributes
- -- @param options table with request specific options
- -- @return status true on succes, false on failure
- -- @return response table (@see Comm.receive), or string containing error
- -- message on failure
- trace = function(self, url, headers, attributes, options)
- return self:request("TRACE", url, headers, attributes, options)
- end,
+ --- Sends an AJP TRACE request to the server
+ --
+ -- @param url string containing the URL to query
+ -- @param headers table containing optional headers
+ -- @param attributes table containing optional attributes
+ -- @param options table with request specific options
+ -- @return status true on succes, false on failure
+ -- @return response table (@see Comm.receive), or string containing error
+ -- message on failure
+ trace = function(self, url, headers, attributes, options)
+ return self:request("TRACE", url, headers, attributes, options)
+ end,
- --- Sends an AJP PUT request to the server
- --
- -- @param url string containing the URL to query
- -- @param headers table containing optional headers
- -- @param attributes table containing optional attributes
- -- @param options table with request specific options
- -- @return status true on succes, false on failure
- -- @return response table (@see Comm.receive), or string containing error
- -- message on failure
- put = function(self, url, headers, attributes, options)
- return self:request("PUT", url, headers, attributes, options)
- end,
+ --- Sends an AJP PUT request to the server
+ --
+ -- @param url string containing the URL to query
+ -- @param headers table containing optional headers
+ -- @param attributes table containing optional attributes
+ -- @param options table with request specific options
+ -- @return status true on succes, false on failure
+ -- @return response table (@see Comm.receive), or string containing error
+ -- message on failure
+ put = function(self, url, headers, attributes, options)
+ return self:request("PUT", url, headers, attributes, options)
+ end,
- --- Sends an AJP DELETE request to the server
- --
- -- @param url string containing the URL to query
- -- @param headers table containing optional headers
- -- @param attributes table containing optional attributes
- -- @param options table with request specific options
- -- @return status true on succes, false on failure
- -- @return response table (@see Comm.receive), or string containing error
- -- message on failure
- delete = function(self, url, headers, attributes, options)
- return self:request("DELETE", url, headers, attributes, options)
- end,
+ --- Sends an AJP DELETE request to the server
+ --
+ -- @param url string containing the URL to query
+ -- @param headers table containing optional headers
+ -- @param attributes table containing optional attributes
+ -- @param options table with request specific options
+ -- @return status true on succes, false on failure
+ -- @return response table (@see Comm.receive), or string containing error
+ -- message on failure
+ delete = function(self, url, headers, attributes, options)
+ return self:request("DELETE", url, headers, attributes, options)
+ end,
- --- Sends an AJP OPTIONS request to the server
- --
- -- @param url string containing the URL to query
- -- @param headers table containing optional headers
- -- @param attributes table containing optional attributes
- -- @param options table with request specific options
- -- @return status true on succes, false on failure
- -- @return response table (@see Comm.receive), or string containing error
- -- message on failure
- options = function(self, url, headers, attributes, options)
- return self:request("OPTIONS", url, headers, attributes, options)
- end,
+ --- Sends an AJP OPTIONS request to the server
+ --
+ -- @param url string containing the URL to query
+ -- @param headers table containing optional headers
+ -- @param attributes table containing optional attributes
+ -- @param options table with request specific options
+ -- @return status true on succes, false on failure
+ -- @return response table (@see Comm.receive), or string containing error
+ -- message on failure
+ options = function(self, url, headers, attributes, options)
+ return self:request("OPTIONS", url, headers, attributes, options)
+ end,
- -- should only work against 127.0.0.1
- shutdownContainer = function(self)
- self.comm:send(bin.pack("H", "1234000107"))
- self.comm:receive()
- end,
+ -- should only work against 127.0.0.1
+ shutdownContainer = function(self)
+ self.comm:send(bin.pack("H", "1234000107"))
+ self.comm:receive()
+ end,
- --- Disconnects from the server
- close = function(self)
- return self.comm:close()
- end,
+ --- Disconnects from the server
+ close = function(self)
+ return self.comm:close()
+ end,
}
diff --git a/nselib/amqp.lua b/nselib/amqp.lua
index 17f2d6d84..aa2a741d5 100644
--- a/nselib/amqp.lua
+++ b/nselib/amqp.lua
@@ -66,7 +66,7 @@ AMQP = {
local data, status, msg
status, msg = self.amqpsocket:connect(self.host, self.port, "tcp")
- return status, msg
+ return status, msg
end,
--- Disconnects the AMQP socket
@@ -337,7 +337,7 @@ AMQPSocket =
retries = 3,
new = function(self)
- local o = {}
+ local o = {}
setmetatable(o, self)
self.__index = self
o.Socket = nmap.new_socket()
@@ -371,7 +371,7 @@ AMQPSocket =
-- @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
+ -- err containing error message if status is false
recv = function( self, count )
local status, data
diff --git a/nselib/asn1.lua b/nselib/asn1.lua
index b285eda5b..2dc7f0f22 100644
--- a/nselib/asn1.lua
+++ b/nselib/asn1.lua
@@ -11,8 +11,8 @@
-- Version 0.3
-- Created 01/12/2010 - v0.1 - Created by Patrik Karlsson
-- Revised 01/28/2010 - v0.2 - Adapted to create a framework for SNMP, LDAP and future protocols
--- Revised 02/02/2010 - v0.3 - Changes: o Re-designed so that ASN1Encoder and ASN1Decoder are separate classes
--- o Each script or library should now create it's own Encoder and Decoder instance
+-- Revised 02/02/2010 - v0.3 - Changes: o Re-designed so that ASN1Encoder and ASN1Decoder are separate classes
+-- o Each script or library should now create it's own Encoder and Decoder instance
--
local bin = require "bin"
@@ -24,252 +24,252 @@ local table = require "table"
_ENV = stdnse.module("asn1", stdnse.seeall)
BERCLASS = {
- Universal = 0,
- Application = 64,
- ContextSpecific = 128,
- Private = 192
+ Universal = 0,
+ Application = 64,
+ ContextSpecific = 128,
+ Private = 192
}
--- The decoder class
--
ASN1Decoder = {
- 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,
- --- Tells the decoder to stop if it detects an error while decoding
- -- this should probably be the default, but some scripts depend on being
- -- able to decode stuff while lacking proper ASN1 decoding functions.
- --
- -- @param val boolean, true if decoding should stop on error,
- -- otherwise false (default)
- setStopOnError = function(self, val)
- self.stoponerror = val
- end,
+ --- Tells the decoder to stop if it detects an error while decoding
+ -- this should probably be the default, but some scripts depend on being
+ -- able to decode stuff while lacking proper ASN1 decoding functions.
+ --
+ -- @param val boolean, true if decoding should stop on error,
+ -- otherwise false (default)
+ setStopOnError = function(self, val)
+ self.stoponerror = val
+ end,
- --- Registers the base simple type decoders
- --
- registerBaseDecoders = function(self)
- self.decoder = {}
+ --- Registers the base simple type decoders
+ --
+ registerBaseDecoders = function(self)
+ self.decoder = {}
- -- Boolean
- self.decoder["01"] = function( self, encStr, elen, pos )
- local val = bin.unpack("H", encStr, pos)
- if val ~= "FF" then
- return pos, true
- else
- return pos, false
- end
- end
+ -- Boolean
+ self.decoder["01"] = function( self, encStr, elen, pos )
+ local val = bin.unpack("H", encStr, pos)
+ if val ~= "FF" then
+ return pos, true
+ else
+ return pos, false
+ end
+ end
- -- Integer
- self.decoder["02"] = function( self, encStr, elen, pos )
- return self.decodeInt(encStr, elen, pos)
- end
+ -- Integer
+ self.decoder["02"] = function( self, encStr, elen, pos )
+ return self.decodeInt(encStr, elen, pos)
+ end
- -- Octet String
- self.decoder["04"] = function( self, encStr, elen, pos )
- return bin.unpack("A" .. elen, encStr, pos)
- end
+ -- Octet String
+ self.decoder["04"] = function( self, encStr, elen, pos )
+ return bin.unpack("A" .. elen, encStr, pos)
+ end
- -- Null
- self.decoder["05"] = function( self, encStr, elen, pos )
- return pos, false
- end
+ -- Null
+ self.decoder["05"] = function( self, encStr, elen, pos )
+ return pos, false
+ end
- -- Object Identifier
- self.decoder["06"] = function( self, encStr, elen, pos )
- return self:decodeOID( encStr, elen, pos )
- end
+ -- Object Identifier
+ self.decoder["06"] = function( self, encStr, elen, pos )
+ return self:decodeOID( encStr, elen, pos )
+ end
- -- Context specific tags
- --
- self.decoder["30"] = function( self, encStr, elen, pos )
- return self:decodeSeq(encStr, elen, pos)
- end
- end,
+ -- Context specific tags
+ --
+ self.decoder["30"] = function( self, encStr, elen, pos )
+ return self:decodeSeq(encStr, elen, pos)
+ end
+ end,
- --- Allows for registration of additional tag decoders
- --
- -- @param tagDecoders table containing decoding functions @see tagDecoders
- registerTagDecoders = function(self, tagDecoders)
- self:registerBaseDecoders()
- for k, v in pairs(tagDecoders) do
- self.decoder[k] = v
- end
- end,
+ --- Allows for registration of additional tag decoders
+ --
+ -- @param tagDecoders table containing decoding functions @see tagDecoders
+ registerTagDecoders = function(self, tagDecoders)
+ self:registerBaseDecoders()
+ for k, v in pairs(tagDecoders) do
+ self.decoder[k] = v
+ end
+ end,
- --- Decodes the ASN.1's built-in simple types
- --
- -- @param encStr Encoded string.
- -- @param pos Current position in the string.
- -- @return The position after decoding
- -- @return The decoded value(s).
- decode = function(self, encStr, pos)
+ --- Decodes the ASN.1's built-in simple types
+ --
+ -- @param encStr Encoded string.
+ -- @param pos Current position in the string.
+ -- @return The position after decoding
+ -- @return The decoded value(s).
+ decode = function(self, encStr, pos)
- local etype, elen
- local newpos = pos
+ local etype, elen
+ local newpos = pos
- newpos, etype = bin.unpack("H1", encStr, newpos)
- newpos, elen = self.decodeLength(encStr, newpos)
+ newpos, etype = bin.unpack("H1", encStr, newpos)
+ newpos, elen = self.decodeLength(encStr, newpos)
- if self.decoder[etype] then
- return self.decoder[etype]( self, encStr, elen, newpos )
- else
- stdnse.print_debug("no decoder for etype: " .. etype)
- return newpos, nil
- end
- end,
+ if self.decoder[etype] then
+ return self.decoder[etype]( self, encStr, elen, newpos )
+ else
+ stdnse.print_debug("no decoder for etype: " .. etype)
+ return newpos, nil
+ end
+ end,
- ---
- -- Decodes length part of encoded value according to ASN.1 basic encoding
- -- rules.
- -- @param encStr Encoded string.
- -- @param pos Current position in the string.
- -- @return The position after decoding.
- -- @return The length of the following value.
- decodeLength = function(encStr, pos)
- local elen
- pos, elen = bin.unpack('C', encStr, pos)
- if (elen > 128) then
- elen = elen - 128
- local elenCalc = 0
- local elenNext
- for i = 1, elen do
- elenCalc = elenCalc * 256
- pos, elenNext = bin.unpack("C", encStr, pos)
- elenCalc = elenCalc + elenNext
- end
- elen = elenCalc
- end
- return pos, elen
- end,
+ ---
+ -- Decodes length part of encoded value according to ASN.1 basic encoding
+ -- rules.
+ -- @param encStr Encoded string.
+ -- @param pos Current position in the string.
+ -- @return The position after decoding.
+ -- @return The length of the following value.
+ decodeLength = function(encStr, pos)
+ local elen
+ pos, elen = bin.unpack('C', encStr, pos)
+ if (elen > 128) then
+ elen = elen - 128
+ local elenCalc = 0
+ local elenNext
+ for i = 1, elen do
+ elenCalc = elenCalc * 256
+ pos, elenNext = bin.unpack("C", encStr, pos)
+ elenCalc = elenCalc + elenNext
+ end
+ elen = elenCalc
+ end
+ return pos, elen
+ end,
- ---
- -- Decodes a sequence according to ASN.1 basic encoding rules.
- -- @param encStr Encoded string.
- -- @param len Length of sequence in bytes.
- -- @param pos Current position in the string.
- -- @return The position after decoding.
- -- @return The decoded sequence as a table.
- decodeSeq = function(self, encStr, len, pos)
- local seq = {}
- local sPos = 1
- local sStr
- pos, sStr = bin.unpack("A" .. len, encStr, pos)
- while (sPos < len) do
- local newSeq
- sPos, newSeq = self:decode(sStr, sPos)
- if ( not(newSeq) and self.stoponerror ) then break end
- table.insert(seq, newSeq)
- end
- return pos, seq
- end,
+ ---
+ -- Decodes a sequence according to ASN.1 basic encoding rules.
+ -- @param encStr Encoded string.
+ -- @param len Length of sequence in bytes.
+ -- @param pos Current position in the string.
+ -- @return The position after decoding.
+ -- @return The decoded sequence as a table.
+ decodeSeq = function(self, encStr, len, pos)
+ local seq = {}
+ local sPos = 1
+ local sStr
+ pos, sStr = bin.unpack("A" .. len, encStr, pos)
+ while (sPos < len) do
+ local newSeq
+ sPos, newSeq = self:decode(sStr, sPos)
+ if ( not(newSeq) and self.stoponerror ) then break end
+ table.insert(seq, newSeq)
+ end
+ return pos, seq
+ end,
- -- Decode one component of an OID from a byte string. 7 bits of the component
- -- are stored in each octet, most significant first, with the eigth bit set in
- -- all octets but the last. These encoding rules come from
- -- http://luca.ntop.org/Teaching/Appunti/asn1.html, section 5.9 OBJECT
- -- IDENTIFIER.
- decode_oid_component = function(encStr, pos)
- local octet
- local n = 0
+ -- Decode one component of an OID from a byte string. 7 bits of the component
+ -- are stored in each octet, most significant first, with the eigth bit set in
+ -- all octets but the last. These encoding rules come from
+ -- http://luca.ntop.org/Teaching/Appunti/asn1.html, section 5.9 OBJECT
+ -- IDENTIFIER.
+ decode_oid_component = function(encStr, pos)
+ local octet
+ local n = 0
- repeat
- pos, octet = bin.unpack("C", encStr, pos)
- n = n * 128 + bit.band(0x7F, octet)
- until octet < 128
+ repeat
+ pos, octet = bin.unpack("C", encStr, pos)
+ n = n * 128 + bit.band(0x7F, octet)
+ until octet < 128
- return pos, n
- end,
+ return pos, n
+ end,
- --- Decodes an OID from a sequence of bytes.
- --
- -- @param encStr Encoded string.
- -- @param len Length of sequence in bytes.
- -- @param pos Current position in the string.
- -- @return The position after decoding.
- -- @return The OID as an array.
- decodeOID = function(self, encStr, len, pos)
- local last
- local oid = {}
- local octet
+ --- Decodes an OID from a sequence of bytes.
+ --
+ -- @param encStr Encoded string.
+ -- @param len Length of sequence in bytes.
+ -- @param pos Current position in the string.
+ -- @return The position after decoding.
+ -- @return The OID as an array.
+ decodeOID = function(self, encStr, len, pos)
+ local last
+ local oid = {}
+ local octet
- last = pos + len - 1
- if pos <= last then
- oid._snmp = '06'
- pos, octet = bin.unpack("C", encStr, pos)
- oid[2] = math.fmod(octet, 40)
- octet = octet - oid[2]
- oid[1] = octet/40
- end
+ last = pos + len - 1
+ if pos <= last then
+ oid._snmp = '06'
+ pos, octet = bin.unpack("C", encStr, pos)
+ oid[2] = math.fmod(octet, 40)
+ octet = octet - oid[2]
+ oid[1] = octet/40
+ end
- while pos <= last do
- local c
- pos, c = self.decode_oid_component(encStr, pos)
- oid[#oid + 1] = c
- end
+ while pos <= last do
+ local c
+ pos, c = self.decode_oid_component(encStr, pos)
+ oid[#oid + 1] = c
+ end
- return pos, oid
- end,
+ return pos, oid
+ end,
- ---
- -- Decodes length part of encoded value according to ASN.1 basic encoding
- -- rules.
- -- @param encStr Encoded string.
- -- @param pos Current position in the string.
- -- @return The position after decoding.
- -- @return The length of the following value.
- decodeLength = function(encStr, pos)
- local elen
- pos, elen = bin.unpack('C', encStr, pos)
- if (elen > 128) then
- elen = elen - 128
- local elenCalc = 0
- local elenNext
- for i = 1, elen do
- elenCalc = elenCalc * 256
- pos, elenNext = bin.unpack("C", encStr, pos)
- elenCalc = elenCalc + elenNext
- end
- elen = elenCalc
- end
- return pos, elen
- end,
+ ---
+ -- Decodes length part of encoded value according to ASN.1 basic encoding
+ -- rules.
+ -- @param encStr Encoded string.
+ -- @param pos Current position in the string.
+ -- @return The position after decoding.
+ -- @return The length of the following value.
+ decodeLength = function(encStr, pos)
+ local elen
+ pos, elen = bin.unpack('C', encStr, pos)
+ if (elen > 128) then
+ elen = elen - 128
+ local elenCalc = 0
+ local elenNext
+ for i = 1, elen do
+ elenCalc = elenCalc * 256
+ pos, elenNext = bin.unpack("C", encStr, pos)
+ elenCalc = elenCalc + elenNext
+ end
+ elen = elenCalc
+ end
+ return pos, elen
+ end,
- ---
- -- Decodes an Integer according to ASN.1 basic encoding rules.
- -- @param encStr Encoded string.
- -- @param len Length of integer in bytes.
- -- @param pos Current position in the string.
- -- @return The position after decoding.
- -- @return The decoded integer.
- decodeInt = function(encStr, len, pos)
- local hexStr
- pos, hexStr = bin.unpack("H" .. len, encStr, pos)
- local value = tonumber(hexStr, 16)
- if (value >= math.pow(256, len)/2) then
- value = value - math.pow(256, len)
- end
- return pos, value
- end,
+ ---
+ -- Decodes an Integer according to ASN.1 basic encoding rules.
+ -- @param encStr Encoded string.
+ -- @param len Length of integer in bytes.
+ -- @param pos Current position in the string.
+ -- @return The position after decoding.
+ -- @return The decoded integer.
+ decodeInt = function(encStr, len, pos)
+ local hexStr
+ pos, hexStr = bin.unpack("H" .. len, encStr, pos)
+ local value = tonumber(hexStr, 16)
+ if (value >= math.pow(256, len)/2) then
+ value = value - math.pow(256, len)
+ end
+ return pos, value
+ end,
- ---
- -- Decodes an SNMP packet or a part of it according to ASN.1 basic encoding
- -- rules.
- -- @param encStr Encoded string.
- -- @param pos Current position in the string.
- -- @return The decoded value(s).
- dec = function(self, encStr, pos)
- local result
- local _
- _, result = self:decode(encStr, pos)
- return result
- end,
+ ---
+ -- Decodes an SNMP packet or a part of it according to ASN.1 basic encoding
+ -- rules.
+ -- @param encStr Encoded string.
+ -- @param pos Current position in the string.
+ -- @return The decoded value(s).
+ dec = function(self, encStr, pos)
+ local result
+ local _
+ _, result = self:decode(encStr, pos)
+ return result
+ end,
}
@@ -277,162 +277,162 @@ ASN1Decoder = {
--
ASN1Encoder = {
- new = function(self)
- local o = {}
- setmetatable(o, self)
- self.__index = self
- o:registerBaseEncoders()
- return o
- end,
+ new = function(self)
+ local o = {}
+ setmetatable(o, self)
+ self.__index = self
+ o:registerBaseEncoders()
+ return o
+ end,
- ---
- -- Encodes an ASN1 sequence, the value of 30 below breaks down as
- -- 0x30 = 00110000 = 00 1 10000
- -- hex binary Universal Constructed value Data Type = SEQUENCE (16)
- encodeSeq = function(self, seqData)
- return bin.pack('HAA' , '30', self.encodeLength(#seqData), seqData)
- end,
+ ---
+ -- Encodes an ASN1 sequence, the value of 30 below breaks down as
+ -- 0x30 = 00110000 = 00 1 10000
+ -- hex binary Universal Constructed value Data Type = SEQUENCE (16)
+ encodeSeq = function(self, seqData)
+ return bin.pack('HAA' , '30', self.encodeLength(#seqData), seqData)
+ end,
- ---
- -- Encodes a given value according to ASN.1 basic encoding rules for SNMP
- -- packet creation.
- -- @param val Value to be encoded.
- -- @return Encoded value.
- encode = function(self, val)
- local vtype = type(val)
+ ---
+ -- Encodes a given value according to ASN.1 basic encoding rules for SNMP
+ -- packet creation.
+ -- @param val Value to be encoded.
+ -- @return Encoded value.
+ encode = function(self, val)
+ local vtype = type(val)
- if self.encoder[vtype] then
- return self.encoder[vtype](self,val)
- else
- return nil
- end
+ if self.encoder[vtype] then
+ return self.encoder[vtype](self,val)
+ else
+ return nil
+ end
- return ''
- end,
+ return ''
+ end,
- --- Allows for registration of additional tag encoders
- --
- -- @param tagEncoders table containing encoding functions @see tagEncoders
- registerTagEncoders = function(self, tagEncoders)
- self:registerBaseEncoders()
- for k, v in pairs(tagEncoders) do
- self.encoder[k] = v
- end
- end,
+ --- Allows for registration of additional tag encoders
+ --
+ -- @param tagEncoders table containing encoding functions @see tagEncoders
+ registerTagEncoders = function(self, tagEncoders)
+ self:registerBaseEncoders()
+ for k, v in pairs(tagEncoders) do
+ self.encoder[k] = v
+ end
+ end,
- -- ASN.1 Simple types encoders
- registerBaseEncoders = function(self)
- self.encoder = {}
+ -- ASN.1 Simple types encoders
+ registerBaseEncoders = function(self)
+ self.encoder = {}
- -- Bolean encoder
- self.encoder['boolean'] = function( self, val )
- if val then
- return bin.pack('H','01 01 FF')
- else
- return bin.pack('H', '01 01 00')
- end
- end
+ -- Bolean encoder
+ self.encoder['boolean'] = function( self, val )
+ if val then
+ return bin.pack('H','01 01 FF')
+ else
+ return bin.pack('H', '01 01 00')
+ end
+ end
- -- Table encoder
- self.encoder['table'] = function( self, val )
- assert('table' == type(val), "val is not a table")
- assert(#val.type > 0, "Table is missing the type field")
- assert(val.value ~= nil, "Table is missing the value field")
- return bin.pack("HAA", val.type, self.encodeLength(#val.value), val.value)
- end
+ -- Table encoder
+ self.encoder['table'] = function( self, val )
+ assert('table' == type(val), "val is not a table")
+ assert(#val.type > 0, "Table is missing the type field")
+ assert(val.value ~= nil, "Table is missing the value field")
+ return bin.pack("HAA", val.type, self.encodeLength(#val.value), val.value)
+ end
- -- Integer encoder
- self.encoder['number'] = function( self, val )
- local ival = self.encodeInt(val)
- local len = self.encodeLength(#ival)
- return bin.pack('HAA', '02', len, ival)
- end
+ -- Integer encoder
+ self.encoder['number'] = function( self, val )
+ local ival = self.encodeInt(val)
+ local len = self.encodeLength(#ival)
+ return bin.pack('HAA', '02', len, ival)
+ end
- -- Octet String encoder
- self.encoder['string'] = function( self, val )
- local len = self.encodeLength(#val)
- return bin.pack('HAA', '04', len, val)
- end
+ -- Octet String encoder
+ self.encoder['string'] = function( self, val )
+ local len = self.encodeLength(#val)
+ return bin.pack('HAA', '04', len, val)
+ end
- -- Null encoder
- self.encoder['nil'] = function( self, val )
- return bin.pack('H', '05 00')
- end
+ -- Null encoder
+ self.encoder['nil'] = function( self, val )
+ return bin.pack('H', '05 00')
+ end
- end,
+ end,
- -- Encode one component of an OID as a byte string. 7 bits of the component are
- -- stored in each octet, most significant first, with the eigth bit set in all
- -- octets but the last. These encoding rules come from
- -- http://luca.ntop.org/Teaching/Appunti/asn1.html, section 5.9 OBJECT
- -- IDENTIFIER.
- encode_oid_component = function(n)
- local parts = {}
- parts[1] = string.char(bit.mod(n, 128))
- while n >= 128 do
- n = bit.rshift(n, 7)
- parts[#parts + 1] = string.char(bit.mod(n, 128) + 0x80)
- end
- return string.reverse(table.concat(parts))
- end,
+ -- Encode one component of an OID as a byte string. 7 bits of the component are
+ -- stored in each octet, most significant first, with the eigth bit set in all
+ -- octets but the last. These encoding rules come from
+ -- http://luca.ntop.org/Teaching/Appunti/asn1.html, section 5.9 OBJECT
+ -- IDENTIFIER.
+ encode_oid_component = function(n)
+ local parts = {}
+ parts[1] = string.char(bit.mod(n, 128))
+ while n >= 128 do
+ n = bit.rshift(n, 7)
+ parts[#parts + 1] = string.char(bit.mod(n, 128) + 0x80)
+ end
+ return string.reverse(table.concat(parts))
+ end,
- ---
- -- Encodes an Integer according to ASN.1 basic encoding rules.
- -- @param val Value to be encoded.
- -- @return Encoded integer.
- encodeInt = function(val)
- local lsb = 0
- if val > 0 then
- local valStr = ""
- while (val > 0) do
- lsb = math.fmod(val, 256)
- valStr = valStr .. bin.pack("C", lsb)
- val = math.floor(val/256)
- end
- if lsb > 127 then -- two's complement collision
- valStr = valStr .. bin.pack("H", "00")
- end
+ ---
+ -- Encodes an Integer according to ASN.1 basic encoding rules.
+ -- @param val Value to be encoded.
+ -- @return Encoded integer.
+ encodeInt = function(val)
+ local lsb = 0
+ if val > 0 then
+ local valStr = ""
+ while (val > 0) do
+ lsb = math.fmod(val, 256)
+ valStr = valStr .. bin.pack("C", lsb)
+ val = math.floor(val/256)
+ end
+ if lsb > 127 then -- two's complement collision
+ valStr = valStr .. bin.pack("H", "00")
+ end
- return string.reverse(valStr)
- elseif val < 0 then
- local i = 1
- local tcval = val + 256 -- two's complement
- while tcval <= 127 do
- tcval = tcval + (math.pow(256, i) * 255)
- i = i+1
- end
- local valStr = ""
- while (tcval > 0) do
- lsb = math.fmod(tcval, 256)
- valStr = valStr .. bin.pack("C", lsb)
- tcval = math.floor(tcval/256)
- end
- return string.reverse(valStr)
- else -- val == 0
- return bin.pack("x")
- end
- end,
+ return string.reverse(valStr)
+ elseif val < 0 then
+ local i = 1
+ local tcval = val + 256 -- two's complement
+ while tcval <= 127 do
+ tcval = tcval + (math.pow(256, i) * 255)
+ i = i+1
+ end
+ local valStr = ""
+ while (tcval > 0) do
+ lsb = math.fmod(tcval, 256)
+ valStr = valStr .. bin.pack("C", lsb)
+ tcval = math.floor(tcval/256)
+ end
+ return string.reverse(valStr)
+ else -- val == 0
+ return bin.pack("x")
+ end
+ end,
- ---
- -- Encodes the length part of a ASN.1 encoding triplet using the "primitive,
- -- definite-length" method.
- -- @param len Length to be encoded.
- -- @return Encoded length value.
- encodeLength = function(len)
- if len < 128 then
- return string.char(len)
- else
- local parts = {}
+ ---
+ -- Encodes the length part of a ASN.1 encoding triplet using the "primitive,
+ -- definite-length" method.
+ -- @param len Length to be encoded.
+ -- @return Encoded length value.
+ encodeLength = function(len)
+ if len < 128 then
+ return string.char(len)
+ else
+ local parts = {}
- while len > 0 do
- parts[#parts + 1] = string.char(bit.mod(len, 256))
- len = bit.rshift(len, 8)
- end
+ while len > 0 do
+ parts[#parts + 1] = string.char(bit.mod(len, 256))
+ len = bit.rshift(len, 8)
+ end
- assert(#parts < 128)
- return string.char(#parts + 0x80) .. string.reverse(table.concat(parts))
- end
- end
+ assert(#parts < 128)
+ return string.char(#parts + 0x80) .. string.reverse(table.concat(parts))
+ end
+ end
}
@@ -446,13 +446,13 @@ ASN1Encoder = {
-- @return number to be used with encode
function BERtoInt(class, constructed, number)
- local asn1_type = class + number
+ local asn1_type = class + number
- if constructed == true then
- asn1_type = asn1_type + 32
- end
+ if constructed == true then
+ asn1_type = asn1_type + 32
+ end
- return asn1_type
+ return asn1_type
end
---
@@ -462,25 +462,25 @@ end
-- @return table with the following entries class, constructed,
-- primitive and number
function intToBER( i )
- local ber = {}
+ local ber = {}
- if bit.band( i, BERCLASS.Application ) == BERCLASS.Application then
- ber.class = BERCLASS.Application
- elseif bit.band( i, BERCLASS.ContextSpecific ) == BERCLASS.ContextSpecific then
- ber.class = BERCLASS.ContextSpecific
- elseif bit.band( i, BERCLASS.Private ) == BERCLASS.Private then
- ber.class = BERCLASS.Private
- else
- ber.class = BERCLASS.Universal
- end
- if bit.band( i, 32 ) == 32 then
- ber.constructed = true
- ber.number = i - ber.class - 32
- else
- ber.primitive = true
- ber.number = i - ber.class
- end
- return ber
+ if bit.band( i, BERCLASS.Application ) == BERCLASS.Application then
+ ber.class = BERCLASS.Application
+ elseif bit.band( i, BERCLASS.ContextSpecific ) == BERCLASS.ContextSpecific then
+ ber.class = BERCLASS.ContextSpecific
+ elseif bit.band( i, BERCLASS.Private ) == BERCLASS.Private then
+ ber.class = BERCLASS.Private
+ else
+ ber.class = BERCLASS.Universal
+ end
+ if bit.band( i, 32 ) == 32 then
+ ber.constructed = true
+ ber.number = i - ber.class - 32
+ else
+ ber.primitive = true
+ ber.number = i - ber.class
+ end
+ return ber
end
diff --git a/nselib/base32.lua b/nselib/base32.lua
index bc85f3e8e..dd4e9fd53 100644
--- a/nselib/base32.lua
+++ b/nselib/base32.lua
@@ -22,11 +22,11 @@ _ENV = stdnse.module("base32", stdnse.seeall)
local b32standard = {
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
- 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
- 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
- 'Y', 'Z', '2', '3', '4', '5', '6', '7',
- }
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+ 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+ 'Y', 'Z', '2', '3', '4', '5', '6', '7',
+}
local b32dcstandard = {} -- efficency
b32dcstandard['A'] = '00000'
@@ -117,8 +117,8 @@ local concat = table.concat
-- @param bits String of five bits to be encoded.
-- @return Encoded character.
local function b32enc5bit(bits)
- local byte = tonumber(bits, 2) + 1
- return b32table[byte]
+ local byte = tonumber(bits, 2) + 1
+ return b32table[byte]
end
@@ -127,9 +127,9 @@ end
-- @param b32byte A single base32-encoded character.
-- @return String of five decoded bits.
local function b32dec5bit(b32byte)
- local bits = b32dctable[b32byte]
- if bits then return bits end
- return ''
+ local bits = b32dctable[b32byte]
+ if bits then return bits end
+ return ''
end
@@ -139,32 +139,32 @@ end
-- @param hexExtend pass true to use the hex extended char set
-- @return Base32-encoded string.
function enc(bdata, hexExtend)
- local _, bitstring = bunpack(">B".. #bdata,bdata)
- local b32dataBuf = {}
+ local _, bitstring = bunpack(">B".. #bdata,bdata)
+ local b32dataBuf = {}
- if hexExtend then
- b32table = b32hexExtend
- b32dctable = b32dchexExtend
- end
+ if hexExtend then
+ b32table = b32hexExtend
+ b32dctable = b32dchexExtend
+ end
- while #bitstring > 4 do
- append(b32dataBuf,b32enc5bit(substr(bitstring,1,5)))
- bitstring = substr(bitstring,6)
- end
- if #bitstring == 1 then
- append(b32dataBuf, b32enc5bit(bitstring .. "0000"))
- append(b32dataBuf, '====')
- elseif #bitstring == 2 then
- append(b32dataBuf, b32enc5bit(bitstring .. "000") )
- append(b32dataBuf, '=')
- elseif #bitstring == 3 then
- append(b32dataBuf, b32enc5bit(bitstring .. "00") )
- append(b32dataBuf, "======")
- elseif #bitstring == 4 then
- append(b32dataBuf, b32enc5bit(bitstring .. "0") )
- append(b32dataBuf, '===')
- end
- return concat(b32dataBuf)
+ while #bitstring > 4 do
+ append(b32dataBuf,b32enc5bit(substr(bitstring,1,5)))
+ bitstring = substr(bitstring,6)
+ end
+ if #bitstring == 1 then
+ append(b32dataBuf, b32enc5bit(bitstring .. "0000"))
+ append(b32dataBuf, '====')
+ elseif #bitstring == 2 then
+ append(b32dataBuf, b32enc5bit(bitstring .. "000") )
+ append(b32dataBuf, '=')
+ elseif #bitstring == 3 then
+ append(b32dataBuf, b32enc5bit(bitstring .. "00") )
+ append(b32dataBuf, "======")
+ elseif #bitstring == 4 then
+ append(b32dataBuf, b32enc5bit(bitstring .. "0") )
+ append(b32dataBuf, '===')
+ end
+ return concat(b32dataBuf)
end
@@ -174,27 +174,27 @@ end
-- @param hexExtend pass true to use the hex extended char set
-- @return Decoded data.
function dec(b32data, hexExtend)
- local bdataBuf = {}
- local pos = 1
- local byte
- local nbyte = ''
+ local bdataBuf = {}
+ local pos = 1
+ local byte
+ local nbyte = ''
- if hexExtend then
- b32table = b32hexExtend
- b32dctable = b32dchexExtend
- end
+ if hexExtend then
+ b32table = b32hexExtend
+ b32dctable = b32dchexExtend
+ end
- for pos = 1, #b32data do -- while pos <= string.len(b32data) do
- byte = b32dec5bit(substr(b32data, pos, pos))
- if not byte then return end
- nbyte = nbyte .. byte
- if #nbyte >= 8 then
- append(bdataBuf, bpack("B", substr(nbyte, 1, 8)))
- nbyte = substr(nbyte, 9)
- end
--- pos = pos + 1
- end
- return concat(bdataBuf)
+ for pos = 1, #b32data do -- while pos <= string.len(b32data) do
+ byte = b32dec5bit(substr(b32data, pos, pos))
+ if not byte then return end
+ nbyte = nbyte .. byte
+ if #nbyte >= 8 then
+ append(bdataBuf, bpack("B", substr(nbyte, 1, 8)))
+ nbyte = substr(nbyte, 9)
+ end
+ -- pos = pos + 1
+ end
+ return concat(bdataBuf)
end
-return _ENV;
\ No newline at end of file
+return _ENV;
diff --git a/nselib/base64.lua b/nselib/base64.lua
index 7d0bed1b1..20601c428 100644
--- a/nselib/base64.lua
+++ b/nselib/base64.lua
@@ -16,15 +16,15 @@ _ENV = stdnse.module("base64", stdnse.seeall)
local b64table = {
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
- 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
- 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
- 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
- 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
- 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
- 'w', 'x', 'y', 'z', '0', '1', '2', '3',
- '4', '5', '6', '7', '8', '9', '+', '/'
- }
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+ 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+ 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+ 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+ 'w', 'x', 'y', 'z', '0', '1', '2', '3',
+ '4', '5', '6', '7', '8', '9', '+', '/'
+}
local b64dctable = {} -- efficency
b64dctable['A'] = '000000'
@@ -104,13 +104,13 @@ local concat = table.concat
-- @param bits String of six bits to be encoded.
-- @return Encoded character.
local function b64enc6bit(bits)
- -- local byte
- -- local _, byte = bunpack("C", bpack("B", "00" .. bits))
- --
+ -- local byte
+ -- local _, byte = bunpack("C", bpack("B", "00" .. bits))
+ --
- -- more efficient, does the same (nb: add one to byte moved up one line):
- local byte = tonumber(bits, 2) + 1
- return b64table[byte]
+ -- more efficient, does the same (nb: add one to byte moved up one line):
+ local byte = tonumber(bits, 2) + 1
+ return b64table[byte]
end
@@ -119,9 +119,9 @@ end
-- @param b64byte A single base64-encoded character.
-- @return String of six decoded bits.
local function b64dec6bit(b64byte)
- local bits = b64dctable[b64byte]
- if bits then return bits end
- return ''
+ local bits = b64dctable[b64byte]
+ if bits then return bits end
+ return ''
end
@@ -130,29 +130,29 @@ end
-- @param bdata Data to be encoded.
-- @return Base64-encoded string.
function enc(bdata)
- local pos = 1
- local byte
- local nbyte = ''
- -- local nbuffer = {}
- local b64dataBuf = {}
- while pos <= #bdata do
- pos, byte = bunpack("B1", bdata, pos)
- nbyte = nbyte .. byte
- append(b64dataBuf, b64enc6bit(substr(nbyte, 1, 6)))
- nbyte = substr(nbyte,7)
- if (#nbyte == 6) then
- append(b64dataBuf, b64enc6bit(nbyte))
- nbyte = ''
- end
- end
- if #nbyte == 2 then
- append(b64dataBuf, b64enc6bit(nbyte .. "0000") )
- append(b64dataBuf, "==")
- elseif #nbyte == 4 then
- append(b64dataBuf, b64enc6bit(nbyte .. "00"))
- append(b64dataBuf, '=')
- end
- return concat(b64dataBuf)
+ local pos = 1
+ local byte
+ local nbyte = ''
+ -- local nbuffer = {}
+ local b64dataBuf = {}
+ while pos <= #bdata do
+ pos, byte = bunpack("B1", bdata, pos)
+ nbyte = nbyte .. byte
+ append(b64dataBuf, b64enc6bit(substr(nbyte, 1, 6)))
+ nbyte = substr(nbyte,7)
+ if (#nbyte == 6) then
+ append(b64dataBuf, b64enc6bit(nbyte))
+ nbyte = ''
+ end
+ end
+ if #nbyte == 2 then
+ append(b64dataBuf, b64enc6bit(nbyte .. "0000") )
+ append(b64dataBuf, "==")
+ elseif #nbyte == 4 then
+ append(b64dataBuf, b64enc6bit(nbyte .. "00"))
+ append(b64dataBuf, '=')
+ end
+ return concat(b64dataBuf)
end
@@ -161,21 +161,21 @@ end
-- @param b64data Base64 encoded data.
-- @return Decoded data.
function dec(b64data)
- local bdataBuf = {}
- local pos = 1
- local byte
- local nbyte = ''
- for pos = 1, #b64data do -- while pos <= #b64data do
- byte = b64dec6bit(substr(b64data, pos, pos))
- if not byte then return end
- nbyte = nbyte .. byte
- if #nbyte >= 8 then
- append(bdataBuf, bpack("B", substr(nbyte, 1, 8)))
- nbyte = substr(nbyte, 9)
- end
--- pos = pos + 1
- end
- return concat(bdataBuf)
+ local bdataBuf = {}
+ local pos = 1
+ local byte
+ local nbyte = ''
+ for pos = 1, #b64data do -- while pos <= #b64data do
+ byte = b64dec6bit(substr(b64data, pos, pos))
+ if not byte then return end
+ nbyte = nbyte .. byte
+ if #nbyte >= 8 then
+ append(bdataBuf, bpack("B", substr(nbyte, 1, 8)))
+ nbyte = substr(nbyte, 9)
+ end
+ -- pos = pos + 1
+ end
+ return concat(bdataBuf)
end
diff --git a/nselib/bjnp.lua b/nselib/bjnp.lua
index 5f5b43a5e..f9a0ac2a8 100644
--- a/nselib/bjnp.lua
+++ b/nselib/bjnp.lua
@@ -20,343 +20,343 @@ _ENV = stdnse.module("bjnp", stdnse.seeall)
BJNP = {
- -- The common BJNP header
- Header = {
+ -- The common BJNP header
+ Header = {
- new = function(self, o)
- o = o or {}
- o = {
- id = o.id or "BJNP",
- type = o.type or 1,
- code = o.code,
- seq = o.seq or 1,
- session = o.session or 0,
- length = o.length or 0,
- }
- assert(o.code, "code argument required")
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ new = function(self, o)
+ o = o or {}
+ o = {
+ id = o.id or "BJNP",
+ type = o.type or 1,
+ code = o.code,
+ seq = o.seq or 1,
+ session = o.session or 0,
+ length = o.length or 0,
+ }
+ assert(o.code, "code argument required")
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- parse = function(data)
- local hdr = BJNP.Header:new({ code = -1 })
- local pos
+ parse = function(data)
+ local hdr = BJNP.Header:new({ code = -1 })
+ local pos
- pos, hdr.id, hdr.type, hdr.code,
- hdr.seq, hdr.session, hdr.length = bin.unpack(">A4CCISI", data)
- return hdr
- end,
+ pos, hdr.id, hdr.type, hdr.code,
+ hdr.seq, hdr.session, hdr.length = bin.unpack(">A4CCISI", data)
+ return hdr
+ end,
- __tostring = function(self)
- return bin.pack(">ACCISI",
- self.id,
- self.type,
- self.code,
- self.seq,
- self.session,
- self.length
- )
- end
- },
+ __tostring = function(self)
+ return bin.pack(">ACCISI",
+ self.id,
+ self.type,
+ self.code,
+ self.seq,
+ self.session,
+ self.length
+ )
+ end
+ },
- -- Scanner related code
- Scanner = {
+ -- Scanner related code
+ Scanner = {
- Code = {
- DISCOVER = 1,
- IDENTITY = 48,
- },
+ Code = {
+ DISCOVER = 1,
+ IDENTITY = 48,
+ },
- Request = {
+ Request = {
- Discover = {
+ Discover = {
- new = function(self)
- local o = { header = BJNP.Header:new( { type = 2, code = BJNP.Scanner.Code.DISCOVER }) }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ new = function(self)
+ local o = { header = BJNP.Header:new( { type = 2, code = BJNP.Scanner.Code.DISCOVER }) }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- __tostring = function(self)
- return tostring(self.header)
- end,
- },
+ __tostring = function(self)
+ return tostring(self.header)
+ end,
+ },
- Identity = {
+ Identity = {
- new = function(self)
- local o = { header = BJNP.Header:new( { type = 2, code = BJNP.Scanner.Code.IDENTITY, length = 4 }), data = 0 }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ new = function(self)
+ local o = { header = BJNP.Header:new( { type = 2, code = BJNP.Scanner.Code.IDENTITY, length = 4 }), data = 0 }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- __tostring = function(self)
- return tostring(self.header) .. bin.pack(">I", self.data)
- end,
- }
+ __tostring = function(self)
+ return tostring(self.header) .. bin.pack(">I", self.data)
+ end,
+ }
- },
+ },
- Response = {
+ Response = {
- Identity = {
+ Identity = {
- new = function(self)
- local o = {}
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ new = function(self)
+ local o = {}
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- parse = function(data)
- local identity = BJNP.Scanner.Response.Identity:new()
- identity.header = BJNP.Header.parse(data)
+ parse = function(data)
+ local identity = BJNP.Scanner.Response.Identity:new()
+ identity.header = BJNP.Header.parse(data)
- local pos = #tostring(identity.header) + 1
- local pos, len = bin.unpack(">S", data, pos)
- if ( len ) then
- pos, identity.data = bin.unpack("A" .. len - 2, data, pos)
- return identity
- end
- end,
+ local pos = #tostring(identity.header) + 1
+ local pos, len = bin.unpack(">S", data, pos)
+ if ( len ) then
+ pos, identity.data = bin.unpack("A" .. len - 2, data, pos)
+ return identity
+ end
+ end,
- }
+ }
- }
+ }
- },
+ },
- -- Printer related code
- Printer = {
+ -- Printer related code
+ Printer = {
- Code = {
- DISCOVER = 1,
- IDENTITY = 48,
- },
+ Code = {
+ DISCOVER = 1,
+ IDENTITY = 48,
+ },
- Request = {
+ Request = {
- Discover = {
- new = function(self)
- local o = { header = BJNP.Header:new( { code = BJNP.Printer.Code.DISCOVER }) }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ Discover = {
+ new = function(self)
+ local o = { header = BJNP.Header:new( { code = BJNP.Printer.Code.DISCOVER }) }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- __tostring = function(self)
- return tostring(self.header)
- end,
- },
+ __tostring = function(self)
+ return tostring(self.header)
+ end,
+ },
- Identity = {
+ Identity = {
- new = function(self)
- local o = { header = BJNP.Header:new( { code = BJNP.Printer.Code.IDENTITY }) }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ new = function(self)
+ local o = { header = BJNP.Header:new( { code = BJNP.Printer.Code.IDENTITY }) }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- __tostring = function(self)
- return tostring(self.header)
- end,
- }
+ __tostring = function(self)
+ return tostring(self.header)
+ end,
+ }
- },
+ },
- Response = {
+ Response = {
- Identity = {
+ Identity = {
- new = function(self)
- local o = {}
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ new = function(self)
+ local o = {}
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- parse = function(data)
- local identity = BJNP.Printer.Response.Identity:new()
- identity.header = BJNP.Header.parse(data)
+ parse = function(data)
+ local identity = BJNP.Printer.Response.Identity:new()
+ identity.header = BJNP.Header.parse(data)
- local pos = #tostring(identity.header) + 1
- local pos, len = bin.unpack(">S", data, pos)
- if ( len ) then
- pos, identity.data = bin.unpack("A" .. len - 2, data, pos)
- return identity
- end
- end,
+ local pos = #tostring(identity.header) + 1
+ local pos, len = bin.unpack(">S", data, pos)
+ if ( len ) then
+ pos, identity.data = bin.unpack("A" .. len - 2, data, pos)
+ return identity
+ end
+ end,
- }
+ }
- },
+ },
- }
+ }
}
-- Helper class, the main script writer interface
Helper = {
- -- Creates a new Helper instance
- -- @param host table
- -- @param port table
- -- @param options table containing one or more of the following fields;
- -- timeout - the timeout in milliseconds for socket communication
- -- bcast - instructs the library that the host is a broadcast
- -- address
- -- @return o new instance of Helper
- new = function(self, host, port, options)
- local o = {
- host = host, port = port, options = options or {}
- }
- o.options.timeout = o.options.timeout or 5000
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new Helper instance
+ -- @param host table
+ -- @param port table
+ -- @param options table containing one or more of the following fields;
+ -- timeout - the timeout in milliseconds for socket communication
+ -- bcast - instructs the library that the host is a broadcast
+ -- address
+ -- @return o new instance of Helper
+ new = function(self, host, port, options)
+ local o = {
+ host = host, port = port, options = options or {}
+ }
+ o.options.timeout = o.options.timeout or 5000
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Connects the socket to the device
- -- This should always be called, regardless if the broadcast option is set
- -- or not.
- --
- -- @return status, true on success, false on failure
- -- @return err string containing the error message if status is false
- connect = function(self)
- self.socket = nmap.new_socket(( self.options.bcast and "udp" ))
- self.socket:set_timeout(self.options.timeout)
- if ( not(self.options.bcast) ) then
- return self.socket:connect(self.host, self.port)
- end
- return true
- end,
+ -- Connects the socket to the device
+ -- This should always be called, regardless if the broadcast option is set
+ -- or not.
+ --
+ -- @return status, true on success, false on failure
+ -- @return err string containing the error message if status is false
+ connect = function(self)
+ self.socket = nmap.new_socket(( self.options.bcast and "udp" ))
+ self.socket:set_timeout(self.options.timeout)
+ if ( not(self.options.bcast) ) then
+ return self.socket:connect(self.host, self.port)
+ end
+ return true
+ end,
- -- Discover network devices using either broadcast or unicast
- -- @param packet discovery packet (printer or scanner)
- -- @return status, true on success, false on failure
- -- @return devices table containing discovered devices when status is true
- -- errmsg string containing the error message when status is false
- discoverDevice = function(self, packet)
- if ( not(self.options.bcast) ) then
- if ( not(self.socket:send(tostring(packet))) ) then
- return false, "Failed to send request to server"
- end
- else
- if ( not(self.socket:sendto(self.host, self.port, tostring(packet))) ) then
- return false, "Failed to send request to server"
- end
- end
- -- discover run in loop
- local devices, tmp = {}, {}
- local start = os.time()
- while( true ) do
- local status, data = self.socket:receive()
- if ( not(status) or ( os.time() - start > ( self.options.timeout/1000 - 1 ) )) then
- break
- end
- local status, _, _, rhost = self.socket:get_info()
- tmp[rhost] = true
- end
- for host in pairs(tmp) do table.insert(devices, host) end
- return true, ( self.options.bcast and devices or ( #devices > 0 and devices[1] ))
- end,
+ -- Discover network devices using either broadcast or unicast
+ -- @param packet discovery packet (printer or scanner)
+ -- @return status, true on success, false on failure
+ -- @return devices table containing discovered devices when status is true
+ -- errmsg string containing the error message when status is false
+ discoverDevice = function(self, packet)
+ if ( not(self.options.bcast) ) then
+ if ( not(self.socket:send(tostring(packet))) ) then
+ return false, "Failed to send request to server"
+ end
+ else
+ if ( not(self.socket:sendto(self.host, self.port, tostring(packet))) ) then
+ return false, "Failed to send request to server"
+ end
+ end
+ -- discover run in loop
+ local devices, tmp = {}, {}
+ local start = os.time()
+ while( true ) do
+ local status, data = self.socket:receive()
+ if ( not(status) or ( os.time() - start > ( self.options.timeout/1000 - 1 ) )) then
+ break
+ end
+ local status, _, _, rhost = self.socket:get_info()
+ tmp[rhost] = true
+ end
+ for host in pairs(tmp) do table.insert(devices, host) end
+ return true, ( self.options.bcast and devices or ( #devices > 0 and devices[1] ))
+ end,
- -- Discover BJNP supporting scanners
- discoverScanner = function(self)
- return self:discoverDevice(BJNP.Scanner.Request.Discover:new())
- end,
+ -- Discover BJNP supporting scanners
+ discoverScanner = function(self)
+ return self:discoverDevice(BJNP.Scanner.Request.Discover:new())
+ end,
- -- Discover BJNP supporting printers
- discoverPrinter = function(self)
- return self:discoverDevice(BJNP.Printer.Request.Discover:new())
- end,
+ -- Discover BJNP supporting printers
+ discoverPrinter = function(self)
+ return self:discoverDevice(BJNP.Printer.Request.Discover:new())
+ end,
- -- Gets a printer identity (additional information)
- -- @param devtype string containing either the string printer or scanner
- -- @return status, true on success, false on failure
- -- @return attribs table containing device attributes when status is true
- -- errmsg string containing the error message when status is false
- getDeviceIdentity = function(self, devtype)
- -- Were currenlty only decoding this as I don't know what the other cruft is
- local attrib_names = {
- ["scanner"] = {
- { ['MFG'] = "Manufacturer" },
- { ['MDL'] = "Model" },
- { ['DES'] = "Description" },
- { ['CMD'] = "Command" },
- },
- ["printer"] = {
- { ['MFG'] = "Manufacturer" },
- { ['MDL'] = "Model" },
- { ['DES'] = "Description" },
- { ['VER'] = "Firmware version" },
- { ['CMD'] = "Command" },
- }
- }
- local identity
- if ( "printer" == devtype ) then
- identity = BJNP.Printer.Request.Identity:new()
- elseif ( "scanner" == devtype ) then
- identity = BJNP.Scanner.Request.Identity:new()
- end
- assert(not(self.options.bcast), "getIdentity is not supported for broadcast")
- if ( not(self.socket:send(tostring(identity))) ) then
- return false, "Failed to send request to server"
- end
- local status, data = self.socket:receive()
- if ( not(status) ) then
- return false, "Failed to receive response from server"
- end
+ -- Gets a printer identity (additional information)
+ -- @param devtype string containing either the string printer or scanner
+ -- @return status, true on success, false on failure
+ -- @return attribs table containing device attributes when status is true
+ -- errmsg string containing the error message when status is false
+ getDeviceIdentity = function(self, devtype)
+ -- Were currenlty only decoding this as I don't know what the other cruft is
+ local attrib_names = {
+ ["scanner"] = {
+ { ['MFG'] = "Manufacturer" },
+ { ['MDL'] = "Model" },
+ { ['DES'] = "Description" },
+ { ['CMD'] = "Command" },
+ },
+ ["printer"] = {
+ { ['MFG'] = "Manufacturer" },
+ { ['MDL'] = "Model" },
+ { ['DES'] = "Description" },
+ { ['VER'] = "Firmware version" },
+ { ['CMD'] = "Command" },
+ }
+ }
+ local identity
+ if ( "printer" == devtype ) then
+ identity = BJNP.Printer.Request.Identity:new()
+ elseif ( "scanner" == devtype ) then
+ identity = BJNP.Scanner.Request.Identity:new()
+ end
+ assert(not(self.options.bcast), "getIdentity is not supported for broadcast")
+ if ( not(self.socket:send(tostring(identity))) ) then
+ return false, "Failed to send request to server"
+ end
+ local status, data = self.socket:receive()
+ if ( not(status) ) then
+ return false, "Failed to receive response from server"
+ end
- local identity
- if ( "printer" == devtype ) then
- identity = BJNP.Printer.Response.Identity.parse(data)
- elseif ( "scanner" == devtype ) then
- identity = BJNP.Scanner.Response.Identity.parse(data)
- end
- if ( not(identity) ) then
- return false, "Failed to parse identity"
- end
- local attrs, kvps = {}, {}
+ local identity
+ if ( "printer" == devtype ) then
+ identity = BJNP.Printer.Response.Identity.parse(data)
+ elseif ( "scanner" == devtype ) then
+ identity = BJNP.Scanner.Response.Identity.parse(data)
+ end
+ if ( not(identity) ) then
+ return false, "Failed to parse identity"
+ end
+ local attrs, kvps = {}, {}
- for k, v in ipairs(stdnse.strsplit(";", identity.data)) do
- local nm, val = v:match("^([^:]*):(.*)$")
- if ( nm ) then kvps[nm] = val end
- end
+ for k, v in ipairs(stdnse.strsplit(";", identity.data)) do
+ local nm, val = v:match("^([^:]*):(.*)$")
+ if ( nm ) then kvps[nm] = val end
+ end
- for _, attrib in ipairs(attrib_names[devtype]) do
- local short, long = next(attrib)
- if ( kvps[short] ) then
- table.insert(attrs, ("%s: %s"):format(long, kvps[short]))
- end
- end
+ for _, attrib in ipairs(attrib_names[devtype]) do
+ local short, long = next(attrib)
+ if ( kvps[short] ) then
+ table.insert(attrs, ("%s: %s"):format(long, kvps[short]))
+ end
+ end
- return true, attrs
- end,
+ return true, attrs
+ end,
- -- Retrieves information related to the printer
- getPrinterIdentity = function(self)
- return self:getDeviceIdentity("printer")
- end,
+ -- Retrieves information related to the printer
+ getPrinterIdentity = function(self)
+ return self:getDeviceIdentity("printer")
+ end,
- -- Retrieves information related to the scanner
- getScannerIdentity = function(self)
- return self:getDeviceIdentity("scanner")
- end,
+ -- Retrieves information related to the scanner
+ getScannerIdentity = function(self)
+ return self:getDeviceIdentity("scanner")
+ end,
- -- Closes the connection
- -- @return status, true on success, false on failure
- -- @return errmsg string containing the error message when status is false
- close = function(self)
- return self.socket:close()
- end
+ -- Closes the connection
+ -- @return status, true on success, false on failure
+ -- @return errmsg string containing the error message when status is false
+ close = function(self)
+ return self.socket:close()
+ end
}
diff --git a/nselib/citrixxml.lua b/nselib/citrixxml.lua
index c559b47a2..8d9c2bb57 100644
--- a/nselib/citrixxml.lua
+++ b/nselib/citrixxml.lua
@@ -30,23 +30,23 @@ _ENV = stdnse.module("citrixxml", stdnse.seeall)
-- @return string an e
function decode_xml_document(xmldata)
- local hexval
+ local hexval
- if not xmldata then
- return ""
- end
+ if not xmldata then
+ return ""
+ end
- local newstr = xmldata
+ local newstr = xmldata
- for m in xmldata:gmatch("(%d+;)") do
- hexval = m:match("(%d+)")
+ for m in xmldata:gmatch("(%d+;)") do
+ hexval = m:match("(%d+)")
- if ( hexval ) then
- newstr = xmldata:gsub(m, string.char(hexval))
- end
- end
+ if ( hexval ) then
+ newstr = xmldata:gsub(m, string.char(hexval))
+ end
+ end
- return newstr
+ return newstr
end
@@ -60,12 +60,12 @@ end
--
function send_citrix_xml_request(host, port, xmldata)
- local response = http.post( host, port, "/scripts/WPnBr.dll", { header={["Content-Type"]="text/xml"}}, nil, xmldata)
+ local response = http.post( host, port, "/scripts/WPnBr.dll", { header={["Content-Type"]="text/xml"}}, nil, xmldata)
- -- this is *probably* not the right way to do stuff
- -- decoding should *probably* only be done on XML-values
- -- this is *probably* defined in the standard, for anyone interested
- return decode_xml_document(response.body)
+ -- this is *probably* not the right way to do stuff
+ -- decoding should *probably* only be done on XML-values
+ -- this is *probably* defined in the standard, for anyone interested
+ return decode_xml_document(response.body)
end
@@ -81,13 +81,13 @@ end
--
function request_server_farm_data( host, port )
- local xmldata = "\r\n"
- xmldata = xmldata .. "\r\n"
- xmldata = xmldata .. ""
- xmldata = xmldata .. ""
- xmldata = xmldata .. "\r\n"
+ local xmldata = "\r\n"
+ xmldata = xmldata .. "\r\n"
+ xmldata = xmldata .. ""
+ xmldata = xmldata .. ""
+ xmldata = xmldata .. "\r\n"
- return send_citrix_xml_request(host, port, xmldata)
+ return send_citrix_xml_request(host, port, xmldata)
end
--- Parses the response from the request_server_farm_data request
@@ -96,14 +96,14 @@ end
--
function parse_server_farm_data_response( response )
- local farms = {}
+ local farms = {}
- response = response:gsub("\r?\n","")
- for farm in response:gmatch("([^<]+)") do
- table.insert(farms, farm)
- end
+ response = response:gsub("\r?\n","")
+ for farm in response:gmatch("([^<]+)") do
+ table.insert(farms, farm)
+ end
- return farms
+ return farms
end
@@ -121,37 +121,37 @@ end
--
function request_appdata(host, port, params)
- -- setup the mandatory parameters if they're missing
- local scope = params['Scope'] or "onelevel"
- local server_type = params['ServerType'] or "all"
- local client_type = params['ClientType'] or "ica30"
- local desired_details = params['DesiredDetails'] or nil
+ -- setup the mandatory parameters if they're missing
+ local scope = params['Scope'] or "onelevel"
+ local server_type = params['ServerType'] or "all"
+ local client_type = params['ClientType'] or "ica30"
+ local desired_details = params['DesiredDetails'] or nil
- local xmldata = "\r\n"
- xmldata = xmldata .. "\r\n"
- xmldata = xmldata .. ""
- xmldata = xmldata .. ""
- xmldata = xmldata .. ""
- xmldata = xmldata .. "" .. server_type .. ""
- xmldata = xmldata .. "" .. client_type .. ""
+ local xmldata = "\r\n"
+ xmldata = xmldata .. "\r\n"
+ xmldata = xmldata .. ""
+ xmldata = xmldata .. ""
+ xmldata = xmldata .. ""
+ xmldata = xmldata .. "" .. server_type .. ""
+ xmldata = xmldata .. "" .. client_type .. ""
- if desired_details then
- if type(desired_details) == "string" then
- xmldata = xmldata .. "" .. desired_details .. ""
- elseif type(desired_details) == "table" then
- for _, v in ipairs(desired_details) do
- xmldata = xmldata .. "" .. v .. ""
- end
- else
- assert(desired_details)
- end
+ if desired_details then
+ if type(desired_details) == "string" then
+ xmldata = xmldata .. "" .. desired_details .. ""
+ elseif type(desired_details) == "table" then
+ for _, v in ipairs(desired_details) do
+ xmldata = xmldata .. "" .. v .. ""
+ end
+ else
+ assert(desired_details)
+ end
- end
+ end
- xmldata = xmldata .. ""
- xmldata = xmldata .. "\r\n"
+ xmldata = xmldata .. ""
+ xmldata = xmldata .. "\r\n"
- return send_citrix_xml_request(host, port, xmldata)
+ return send_citrix_xml_request(host, port, xmldata)
end
@@ -161,56 +161,56 @@ end
-- @return table containing settings extracted from the accesslist section of the response
local function extract_appdata_acls(xmldata)
- local acls = {}
- local users = {}
- local groups = {}
+ local acls = {}
+ local users = {}
+ local groups = {}
- for acl in xmldata:gmatch("(.-)") do
+ for acl in xmldata:gmatch("(.-)") do
- if acl:match("AnonymousUser") then
- table.insert(users, "Anonymous")
- else
+ if acl:match("AnonymousUser") then
+ table.insert(users, "Anonymous")
+ else
- for user in acl:gmatch("(.-)") do
- local user_name = user:match("(.-)") or ""
- local domain_name = user:match("(.-)") or ""
+ for user in acl:gmatch("(.-)") do
+ local user_name = user:match("(.-)") or ""
+ local domain_name = user:match("(.-)") or ""
- if user_name:len() > 0 then
- if domain_name:len() > 0 then
- domain_name = domain_name .. "\\"
- end
- table.insert(users, domain_name .. user_name)
- end
+ if user_name:len() > 0 then
+ if domain_name:len() > 0 then
+ domain_name = domain_name .. "\\"
+ end
+ table.insert(users, domain_name .. user_name)
+ end
- end
+ end
- for group in acl:gmatch("(.-)") do
+ for group in acl:gmatch("(.-)") do
- local group_name = group:match("(.-)") or ""
- local domain_name = group:match("(.-)") or ""
+ local group_name = group:match("(.-)") or ""
+ local domain_name = group:match("(.-)") or ""
- if group_name:len() > 0 then
- if domain_name:len() > 0 then
- domain_name = domain_name .. "\\"
- end
- table.insert(groups, domain_name .. group_name)
- end
+ if group_name:len() > 0 then
+ if domain_name:len() > 0 then
+ domain_name = domain_name .. "\\"
+ end
+ table.insert(groups, domain_name .. group_name)
+ end
- end
+ end
- end
+ end
- if #users> 0 then
- acls['User'] = users
- end
- if #groups>0 then
- acls['Group'] = groups
- end
+ if #users> 0 then
+ acls['User'] = users
+ end
+ if #groups>0 then
+ acls['Group'] = groups
+ end
- end
+ end
- return acls
+ return acls
end
@@ -221,21 +221,21 @@ end
-- @return table containing settings extracted from the settings section of the response
local function extract_appdata_settings(xmldata)
- local settings = {}
+ local settings = {}
- settings['appisdisabled'] = xmldata:match("")
- settings['appisdesktop'] = xmldata:match("")
+ settings['appisdisabled'] = xmldata:match("")
+ settings['appisdesktop'] = xmldata:match("")
- for s in xmldata:gmatch("(.-)") do
- settings['Encryption'] = s:match("(.-)")
- settings['AppOnDesktop'] = s:match("")
- settings['AppInStartmenu'] = s:match("")
- settings['PublisherName'] = s:match("(.-)")
- settings['SSLEnabled'] = s:match("(.-)")
- settings['RemoteAccessEnabled'] = s:match("(.-)")
- end
+ for s in xmldata:gmatch("(.-)") do
+ settings['Encryption'] = s:match("(.-)")
+ settings['AppOnDesktop'] = s:match("")
+ settings['AppInStartmenu'] = s:match("")
+ settings['PublisherName'] = s:match("(.-)")
+ settings['SSLEnabled'] = s:match("(.-)")
+ settings['RemoteAccessEnabled'] = s:match("(.-)")
+ end
- return settings
+ return settings
end
@@ -245,23 +245,23 @@ end
-- @return table containing nestled tables closely resembling the DOM model of the XML response
function parse_appdata_response(xmldata)
- local apps = {}
- xmldata = xmldata:gsub("\r?\n",""):gsub(">%s+<", "><")
+ local apps = {}
+ xmldata = xmldata:gsub("\r?\n",""):gsub(">%s+<", "><")
- for AppData in xmldata:gmatch("(.-)") do
+ for AppData in xmldata:gmatch("(.-)") do
- local app_name = AppData:match("(.-)") or ""
- local app = {}
+ local app_name = AppData:match("(.-)") or ""
+ local app = {}
- app['FName'] = app_name
- app['AccessList'] = extract_appdata_acls(AppData)
- app['Settings'] = extract_appdata_settings(AppData)
+ app['FName'] = app_name
+ app['AccessList'] = extract_appdata_acls(AppData)
+ app['Settings'] = extract_appdata_settings(AppData)
- table.insert(apps, app)
+ table.insert(apps, app)
- end
+ end
- return apps
+ return apps
end
--
@@ -270,25 +270,25 @@ end
--
function request_address(host, port, flags, appname)
- local xmldata = "\r\n"
- xmldata = xmldata .. "\r\n"
- xmldata = xmldata .. ""
- xmldata = xmldata .. ""
+ local xmldata = "\r\n"
+ xmldata = xmldata .. "\r\n"
+ xmldata = xmldata .. ""
+ xmldata = xmldata .. ""
- if flags then
- xmldata = xmldata .. "" .. flags .. ""
- end
+ if flags then
+ xmldata = xmldata .. "" .. flags .. ""
+ end
- if appname then
- xmldata = xmldata .. ""
- xmldata = xmldata .. "" .. appname .. ""
- xmldata = xmldata .. ""
- end
+ if appname then
+ xmldata = xmldata .. ""
+ xmldata = xmldata .. "" .. appname .. ""
+ xmldata = xmldata .. ""
+ end
- xmldata = xmldata .. ""
- xmldata = xmldata .. "\r\n"
+ xmldata = xmldata .. ""
+ xmldata = xmldata .. "\r\n"
- return send_citrix_xml_request(host, port, xmldata)
+ return send_citrix_xml_request(host, port, xmldata)
end
--- Request information about the Citrix protocol
@@ -304,27 +304,27 @@ end
--
function request_server_data(host, port, params)
- local params = params or {}
- local server_type = params.ServerType or {"all"}
- local client_type = params.ClientType or {"all"}
+ local params = params or {}
+ local server_type = params.ServerType or {"all"}
+ local client_type = params.ClientType or {"all"}
- local xmldata = "\r\n"
- xmldata = xmldata .. "\r\n"
- xmldata = xmldata .. ""
- xmldata = xmldata .. ""
+ local xmldata = "\r\n"
+ xmldata = xmldata .. "\r\n"
+ xmldata = xmldata .. ""
+ xmldata = xmldata .. ""
- for _, srvtype in pairs(server_type) do
- xmldata = xmldata .. "" .. srvtype .. ""
- end
+ for _, srvtype in pairs(server_type) do
+ xmldata = xmldata .. "" .. srvtype .. ""
+ end
- for _, clitype in pairs(client_type) do
- xmldata = xmldata .. "" .. clitype .. ""
- end
+ for _, clitype in pairs(client_type) do
+ xmldata = xmldata .. "" .. clitype .. ""
+ end
- xmldata = xmldata .. ""
- xmldata = xmldata .. "\r\n"
+ xmldata = xmldata .. ""
+ xmldata = xmldata .. "\r\n"
- return send_citrix_xml_request(host, port, xmldata)
+ return send_citrix_xml_request(host, port, xmldata)
end
--- Parses the response from the request_server_data request
@@ -333,14 +333,14 @@ end
--
function parse_server_data_response(response)
- local servers = {}
+ local servers = {}
- response = response:gsub("\r?\n","")
- for s in response:gmatch("([^<]+)") do
- table.insert(servers, s)
- end
+ response = response:gsub("\r?\n","")
+ for s in response:gmatch("([^<]+)") do
+ table.insert(servers, s)
+ end
- return servers
+ return servers
end
@@ -357,22 +357,22 @@ end
--
function request_protocol_info( host, port, params )
- local params = params or {}
+ local params = params or {}
- local xmldata = "\r\n"
- xmldata = xmldata .. "\r\n"
- xmldata = xmldata .. ""
- xmldata = xmldata .. ""
+ local xmldata = "\r\n"
+ xmldata = xmldata .. "\r\n"
+ xmldata = xmldata .. ""
+ xmldata = xmldata .. ""
- if params['ServerAddress'] then
- xmldata = xmldata .. ""
- xmldata = xmldata .. params['ServerAddress'] .. ""
- end
+ if params['ServerAddress'] then
+ xmldata = xmldata .. ""
+ xmldata = xmldata .. params['ServerAddress'] .. ""
+ end
- xmldata = xmldata .. ""
- xmldata = xmldata .. "\r\n"
+ xmldata = xmldata .. ""
+ xmldata = xmldata .. "\r\n"
- return send_citrix_xml_request(host, port, xmldata)
+ return send_citrix_xml_request(host, port, xmldata)
end
--- Request capability information
@@ -387,14 +387,14 @@ end
--
function request_capabilities( host, port )
- local xmldata = "\r\n"
- xmldata = xmldata .. "\r\n"
- xmldata = xmldata .. ""
- xmldata = xmldata .. ""
- xmldata = xmldata .. ""
- xmldata = xmldata .. "\r\n"
+ local xmldata = "\r\n"
+ xmldata = xmldata .. "\r\n"
+ xmldata = xmldata .. ""
+ xmldata = xmldata .. ""
+ xmldata = xmldata .. ""
+ xmldata = xmldata .. "\r\n"
- return send_citrix_xml_request(host, port, xmldata)
+ return send_citrix_xml_request(host, port, xmldata)
end
--- Parses the response from the request_capabilities request
@@ -403,14 +403,14 @@ end
--
function parse_capabilities_response(response)
- local servers = {}
+ local servers = {}
- response = response:gsub("\r?\n","")
- for s in response:gmatch("([^<]+)") do
- table.insert(servers, s)
- end
+ response = response:gsub("\r?\n","")
+ for s in response:gmatch("([^<]+)") do
+ table.insert(servers, s)
+ end
- return servers
+ return servers
end
@@ -428,32 +428,32 @@ end
--
function request_validate_credentials(host, port, params )
- local params = params or {}
- local credentials = params['Credentials'] or {}
+ local params = params or {}
+ local credentials = params['Credentials'] or {}
- local xmldata = "\r\n"
- xmldata = xmldata .. "\r\n"
- xmldata = xmldata .. ""
- xmldata = xmldata .. ""
- xmldata = xmldata .. ""
+ local xmldata = "\r\n"
+ xmldata = xmldata .. "\r\n"
+ xmldata = xmldata .. ""
+ xmldata = xmldata .. ""
+ xmldata = xmldata .. ""
- if credentials['UserName'] then
- xmldata = xmldata .. "" .. credentials['UserName'] .. ""
- end
+ if credentials['UserName'] then
+ xmldata = xmldata .. "" .. credentials['UserName'] .. ""
+ end
- if credentials['Password'] then
- xmldata = xmldata .. "" .. credentials['Password'] .. ""
- end
+ if credentials['Password'] then
+ xmldata = xmldata .. "" .. credentials['Password'] .. ""
+ end
- if credentials['Domain'] then
- xmldata = xmldata .. "" .. credentials['Domain'] .. ""
- end
+ if credentials['Domain'] then
+ xmldata = xmldata .. "" .. credentials['Domain'] .. ""
+ end
- xmldata = xmldata .. ""
- xmldata = xmldata .. ""
- xmldata = xmldata .. "\r\n"
+ xmldata = xmldata .. ""
+ xmldata = xmldata .. ""
+ xmldata = xmldata .. "\r\n"
- return send_citrix_xml_request(host, port, xmldata)
+ return send_citrix_xml_request(host, port, xmldata)
end
@@ -463,14 +463,14 @@ end
-- @return table containing the results
--
function parse_validate_credentials_response(response)
- local tblResult = {}
+ local tblResult = {}
- response = response:gsub("\r?\n","")
- tblResult['DaysUntilPasswordExpiry'] = response:match("(.+)")
- tblResult['ShowPasswordExpiryWarning'] = response:match("(.+)")
- tblResult['ErrorId'] = response:match("(.+)")
+ response = response:gsub("\r?\n","")
+ tblResult['DaysUntilPasswordExpiry'] = response:match("(.+)")
+ tblResult['ShowPasswordExpiryWarning'] = response:match("(.+)")
+ tblResult['ErrorId'] = response:match("(.+)")
- return tblResult
+ return tblResult
end
@@ -485,53 +485,53 @@ end
--
function request_reconnect_session_data(host, port, params)
- local params = params or {}
- local Credentials = params.Credentials or {}
+ local params = params or {}
+ local Credentials = params.Credentials or {}
- params.ServerType = params.ServerType or {}
- params.ClientType = params.ClientType or {}
+ params.ServerType = params.ServerType or {}
+ params.ClientType = params.ClientType or {}
- local xmldata = "\r\n"
- xmldata = xmldata .. "\r\n"
- xmldata = xmldata .. ""
- xmldata = xmldata .. ""
+ local xmldata = "\r\n"
+ xmldata = xmldata .. "\r\n"
+ xmldata = xmldata .. ""
+ xmldata = xmldata .. ""
- xmldata = xmldata .. ""
+ xmldata = xmldata .. ""
- if Credentials.UserName then
- xmldata = xmldata .. "" .. Credentials.UserName .. ""
- end
+ if Credentials.UserName then
+ xmldata = xmldata .. "" .. Credentials.UserName .. ""
+ end
- if Credentials.Password then
- xmldata = xmldata .. "" .. Credentials.Password .. ""
- end
+ if Credentials.Password then
+ xmldata = xmldata .. "" .. Credentials.Password .. ""
+ end
- if Credentials.Domain then
- xmldata = xmldata .. "" .. Credentials.Domain .. ""
- end
+ if Credentials.Domain then
+ xmldata = xmldata .. "" .. Credentials.Domain .. ""
+ end
- xmldata = xmldata .. ""
+ xmldata = xmldata .. ""
- if params.ClientName then
- xmldata = xmldata .. "" .. params.ClientName .. ""
- end
+ if params.ClientName then
+ xmldata = xmldata .. "" .. params.ClientName .. ""
+ end
- if params.DeviceId then
- xmldata = xmldata .. "" .. params.DeviceId .. ""
- end
+ if params.DeviceId then
+ xmldata = xmldata .. "" .. params.DeviceId .. ""
+ end
- for _, srvtype in pairs(params.ServerType) do
- xmldata = xmldata .. "" .. srvtype .. ""
- end
+ for _, srvtype in pairs(params.ServerType) do
+ xmldata = xmldata .. "" .. srvtype .. ""
+ end
- for _, clitype in pairs(params.ClientType) do
- xmldata = xmldata .. "" .. clitype .. ""
- end
+ for _, clitype in pairs(params.ClientType) do
+ xmldata = xmldata .. "" .. clitype .. ""
+ end
- xmldata = xmldata .. ""
- xmldata = xmldata .. "\r\n"
+ xmldata = xmldata .. ""
+ xmldata = xmldata .. "\r\n"
- return send_citrix_xml_request(host, port, xmldata)
+ return send_citrix_xml_request(host, port, xmldata)
end
diff --git a/nselib/cvs.lua b/nselib/cvs.lua
index 6a338c93a..6ca28c7d6 100644
--- a/nselib/cvs.lua
+++ b/nselib/cvs.lua
@@ -18,80 +18,80 @@ _ENV = stdnse.module("cvs", stdnse.seeall)
Helper = {
- new = function(self, host, port)
- local o = { host = host, port = port }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ new = function(self, host, port)
+ local o = { host = host, port = port }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- connect = function(self)
- self.socket = nmap.new_socket()
- return self.socket:connect(self.host, self.port)
- end,
+ connect = function(self)
+ self.socket = nmap.new_socket()
+ return self.socket:connect(self.host, self.port)
+ end,
- login = function(self, repo, user, pass )
- local auth_tab = {}
- assert(repo, "No repository was specified")
- assert(user, "No user was specified")
- assert(pass, "No pass was specified")
+ login = function(self, repo, user, pass )
+ local auth_tab = {}
+ assert(repo, "No repository was specified")
+ assert(user, "No user was specified")
+ assert(pass, "No pass was specified")
- -- Add a leading slash if it's missing
- if ( repo:sub(1,1) ~= "/" ) then repo = "/" .. repo end
+ -- Add a leading slash if it's missing
+ if ( repo:sub(1,1) ~= "/" ) then repo = "/" .. repo end
- table.insert(auth_tab, "BEGIN AUTH REQUEST")
- table.insert(auth_tab, repo)
- table.insert(auth_tab, user)
- table.insert(auth_tab, Util.pwscramble(pass))
- table.insert(auth_tab, "END AUTH REQUEST")
+ table.insert(auth_tab, "BEGIN AUTH REQUEST")
+ table.insert(auth_tab, repo)
+ table.insert(auth_tab, user)
+ table.insert(auth_tab, Util.pwscramble(pass))
+ table.insert(auth_tab, "END AUTH REQUEST")
- local data = stdnse.strjoin("\n", auth_tab) .. "\n"
- local status = self.socket:send(data)
- if ( not(status) ) then return false, "Failed to send login request" end
+ local data = stdnse.strjoin("\n", auth_tab) .. "\n"
+ local status = self.socket:send(data)
+ if ( not(status) ) then return false, "Failed to send login request" end
- local status, response = self.socket:receive()
- if ( not(status) ) then return false, "Failed to read login response" end
+ local status, response = self.socket:receive()
+ if ( not(status) ) then return false, "Failed to read login response" end
- if ( response == "I LOVE YOU\n" ) then return true end
- return false, response
- end,
+ if ( response == "I LOVE YOU\n" ) then return true end
+ return false, response
+ end,
- close = function(self)
- return self.socket:close()
- end
+ close = function(self)
+ return self.socket:close()
+ end
}
Util = {
- --- Scrambles a password
- --
- -- @param password string containing the password to scramble
- pwscramble = function(password)
- local shifts = {
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 114,120, 53, 79, 96,109, 72,108, 70, 64, 76, 67,116, 74, 68, 87,
- 111, 52, 75,119, 49, 34, 82, 81, 95, 65,112, 86,118,110,122,105,
- 41, 57, 83, 43, 46,102, 40, 89, 38,103, 45, 50, 42,123, 91, 35,
- 125, 55, 54, 66,124,126, 59, 47, 92, 71,115, 78, 88,107,106, 56,
- 36,121,117,104,101,100, 69, 73, 99, 63, 94, 93, 39, 37, 61, 48,
- 58,113, 32, 90, 44, 98, 60, 51, 33, 97, 62, 77, 84, 80, 85,223,
- 225,216,187,166,229,189,222,188,141,249,148,200,184,136,248,190,
- 199,170,181,204,138,232,218,183,255,234,220,247,213,203,226,193,
- 174,172,228,252,217,201,131,230,197,211,145,238,161,179,160,212,
- 207,221,254,173,202,146,224,151,140,196,205,130,135,133,143,246,
- 192,159,244,239,185,168,215,144,139,165,180,157,147,186,214,176,
- 227,231,219,169,175,156,206,198,129,164,150,210,154,177,134,127,
- 182,128,158,208,162,132,167,209,149,241,153,251,237,236,171,195,
- 243,233,253,240,194,250,191,155,142,137,245,235,163,242,178,152 };
+ --- Scrambles a password
+ --
+ -- @param password string containing the password to scramble
+ pwscramble = function(password)
+ local shifts = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 114,120, 53, 79, 96,109, 72,108, 70, 64, 76, 67,116, 74, 68, 87,
+ 111, 52, 75,119, 49, 34, 82, 81, 95, 65,112, 86,118,110,122,105,
+ 41, 57, 83, 43, 46,102, 40, 89, 38,103, 45, 50, 42,123, 91, 35,
+ 125, 55, 54, 66,124,126, 59, 47, 92, 71,115, 78, 88,107,106, 56,
+ 36,121,117,104,101,100, 69, 73, 99, 63, 94, 93, 39, 37, 61, 48,
+ 58,113, 32, 90, 44, 98, 60, 51, 33, 97, 62, 77, 84, 80, 85,223,
+ 225,216,187,166,229,189,222,188,141,249,148,200,184,136,248,190,
+ 199,170,181,204,138,232,218,183,255,234,220,247,213,203,226,193,
+ 174,172,228,252,217,201,131,230,197,211,145,238,161,179,160,212,
+ 207,221,254,173,202,146,224,151,140,196,205,130,135,133,143,246,
+ 192,159,244,239,185,168,215,144,139,165,180,157,147,186,214,176,
+ 227,231,219,169,175,156,206,198,129,164,150,210,154,177,134,127,
+ 182,128,158,208,162,132,167,209,149,241,153,251,237,236,171,195,
+ 243,233,253,240,194,250,191,155,142,137,245,235,163,242,178,152 };
- local result = ""
- for i = 1, #password do
- result = result .. string.char(shifts[password:byte(i)+1])
- end
- return 'A' .. result
- end
+ local result = ""
+ for i = 1, #password do
+ result = result .. string.char(shifts[password:byte(i)+1])
+ end
+ return 'A' .. result
+ end
}
diff --git a/nselib/datafiles.lua b/nselib/datafiles.lua
index 66793b209..d4133ee8a 100644
--- a/nselib/datafiles.lua
+++ b/nselib/datafiles.lua
@@ -24,12 +24,12 @@ _ENV = stdnse.module("datafiles", stdnse.seeall)
-- @name common_files
-- @see parse_file
local common_files = {
- ["nmap-rpc"] = { [function(ln) return tonumber( ln:match( "^%s*[^%s#]+%s+(%d+)" ) ) end] = "^%s*([^%s#]+)%s+%d+" },
- ["nmap-protocols"] = { [function(ln) return tonumber( ln:match( "^%s*[^%s#]+%s+(%d+)" ) ) end] = "^%s*([^%s#]+)%s+%d+" },
- ["nmap-services"] = { ["tcp"] = { [function(ln) return tonumber( ln:match( "^%s*[^%s#]+%s+(%d+)/tcp" ) ) end] = "^%s*([^%s#]+)%s+%d+/tcp" },
- ["udp"] = { [function(ln) return tonumber( ln:match( "^%s*[^%s#]+%s+(%d+)/udp" ) ) end] = "^%s*([^%s#]+)%s+%d+/udp" }
- },
- ["nmap-mac-prefixes"] = { [ "^%s*(%w+)%s+[^#]+" ] = "^%s*%w+%s+([^#]+)" }
+ ["nmap-rpc"] = { [function(ln) return tonumber( ln:match( "^%s*[^%s#]+%s+(%d+)" ) ) end] = "^%s*([^%s#]+)%s+%d+" },
+ ["nmap-protocols"] = { [function(ln) return tonumber( ln:match( "^%s*[^%s#]+%s+(%d+)" ) ) end] = "^%s*([^%s#]+)%s+%d+" },
+ ["nmap-services"] = { ["tcp"] = { [function(ln) return tonumber( ln:match( "^%s*[^%s#]+%s+(%d+)/tcp" ) ) end] = "^%s*([^%s#]+)%s+%d+/tcp" },
+ ["udp"] = { [function(ln) return tonumber( ln:match( "^%s*[^%s#]+%s+(%d+)/udp" ) ) end] = "^%s*([^%s#]+)%s+%d+/udp" }
+ },
+ ["nmap-mac-prefixes"] = { [ "^%s*(%w+)%s+[^#]+" ] = "^%s*%w+%s+([^#]+)" }
}
diff --git a/nselib/dnssd.lua b/nselib/dnssd.lua
index 873afbaf5..3376b5a5e 100644
--- a/nselib/dnssd.lua
+++ b/nselib/dnssd.lua
@@ -49,347 +49,347 @@ _ENV = stdnse.module("dnssd", stdnse.seeall)
Util = {
- --- Compare function used for sorting IP-addresses
- --
- -- @param a table containing first item
- -- @param b table containing second item
- -- @return true if a is less than b
- ipCompare = function(a, b)
- return ipOps.compare_ip(a, "lt", b)
- end,
+ --- Compare function used for sorting IP-addresses
+ --
+ -- @param a table containing first item
+ -- @param b table containing second item
+ -- @return true if a is less than b
+ ipCompare = function(a, b)
+ return ipOps.compare_ip(a, "lt", b)
+ end,
- --- Function used to compare discovered DNS services so they can be sorted
- --
- -- @param a table containing first item
- -- @param b table containing second item
- -- @return true if the port of a is less than the port of b
- serviceCompare = function(a, b)
- -- if no port is found use 999999 for comparing, this way all services
- -- without ports and device information gets printed at the end
- local port_a = a.name:match("^(%d+)") or 999999
- local port_b = b.name:match("^(%d+)") or 999999
+ --- Function used to compare discovered DNS services so they can be sorted
+ --
+ -- @param a table containing first item
+ -- @param b table containing second item
+ -- @return true if the port of a is less than the port of b
+ serviceCompare = function(a, b)
+ -- if no port is found use 999999 for comparing, this way all services
+ -- without ports and device information gets printed at the end
+ local port_a = a.name:match("^(%d+)") or 999999
+ local port_b = b.name:match("^(%d+)") or 999999
- if ( tonumber(port_a) < tonumber(port_b) ) then
- return true
- end
- return false
- end,
+ if ( tonumber(port_a) < tonumber(port_b) ) then
+ return true
+ end
+ return false
+ end,
- --- Creates a service host table
- --
- -- ['_ftp._tcp.local'] = {10.10.10.10,20.20.20.20}
- -- ['_http._tcp.local'] = {30.30.30.30,40.40.40.40}
- --
- -- @param response containing multiple responses from dns.query
- -- @return services table containing the service name as a key and all host addresses as value
- createSvcHostTbl = function( response )
- local services = {}
- -- Create unique table of services
- for _, r in ipairs( response ) do
- -- do we really have mutliple responses?
- if ( not(r.output) ) then return end
- for _, svc in ipairs(r.output ) do
- services[svc] = services[svc] or {}
- table.insert(services[svc], r.peer)
- end
- end
+ --- Creates a service host table
+ --
+ -- ['_ftp._tcp.local'] = {10.10.10.10,20.20.20.20}
+ -- ['_http._tcp.local'] = {30.30.30.30,40.40.40.40}
+ --
+ -- @param response containing multiple responses from dns.query
+ -- @return services table containing the service name as a key and all host addresses as value
+ createSvcHostTbl = function( response )
+ local services = {}
+ -- Create unique table of services
+ for _, r in ipairs( response ) do
+ -- do we really have mutliple responses?
+ if ( not(r.output) ) then return end
+ for _, svc in ipairs(r.output ) do
+ services[svc] = services[svc] or {}
+ table.insert(services[svc], r.peer)
+ end
+ end
- return services
- end,
+ return services
+ end,
- --- Creates a unique list of services
- --
- -- @param response containing a single or multiple responses from
- -- dns.query
- -- @return array of strings containing service names
- getUniqueServices = function( response )
- local services = {}
+ --- Creates a unique list of services
+ --
+ -- @param response containing a single or multiple responses from
+ -- dns.query
+ -- @return array of strings containing service names
+ getUniqueServices = function( response )
+ local services = {}
- for _, r in ipairs(response) do
- if ( r.output ) then
- for _, svc in ipairs(r.output) do services[svc] = true end
- else
- services[r] = true
- end
- end
+ for _, r in ipairs(response) do
+ if ( r.output ) then
+ for _, svc in ipairs(r.output) do services[svc] = true end
+ else
+ services[r] = true
+ end
+ end
- return services
- end,
+ return services
+ end,
- --- Returns the amount of currenlty active threads
- --
- -- @param threads table containing the list of threads
- -- @return count number containing the number of non-dead threads
- threadCount = function( threads )
- local count = 0
+ --- Returns the amount of currenlty active threads
+ --
+ -- @param threads table containing the list of threads
+ -- @return count number containing the number of non-dead threads
+ threadCount = function( threads )
+ local count = 0
- for thread in pairs(threads) do
- if ( coroutine.status(thread) == "dead" ) then
- threads[thread] = nil
- else
- count = count + 1
- end
- end
- return count
- end
+ for thread in pairs(threads) do
+ if ( coroutine.status(thread) == "dead" ) then
+ threads[thread] = nil
+ else
+ count = count + 1
+ end
+ end
+ return count
+ end
}
Comm = {
- --- Gets a record from both the Answer and Additional section
- --
- -- @param dtype DNS resource record type.
- -- @param response Decoded DNS response.
- -- @param retAll If true, return all entries, not just the first.
- -- @return True if one or more answers of the required type were found - otherwise false.
- -- @return Answer according to the answer fetcher for dtype or an Error message.
- getRecordType = function( dtype, response, retAll )
+ --- Gets a record from both the Answer and Additional section
+ --
+ -- @param dtype DNS resource record type.
+ -- @param response Decoded DNS response.
+ -- @param retAll If true, return all entries, not just the first.
+ -- @return True if one or more answers of the required type were found - otherwise false.
+ -- @return Answer according to the answer fetcher for dtype or an Error message.
+ getRecordType = function( dtype, response, retAll )
- local result = {}
- local status1, answers = dns.findNiceAnswer( dtype, response, retAll )
+ local result = {}
+ local status1, answers = dns.findNiceAnswer( dtype, response, retAll )
- if status1 then
- if retAll then
- for _, v in ipairs(answers) do
- table.insert(result, string.format("%s", v) )
- end
- else
- return true, answers
- end
- end
+ if status1 then
+ if retAll then
+ for _, v in ipairs(answers) do
+ table.insert(result, string.format("%s", v) )
+ end
+ else
+ return true, answers
+ end
+ end
- local status2, answers = dns.findNiceAdditional( dtype, response, retAll )
+ local status2, answers = dns.findNiceAdditional( dtype, response, retAll )
- if status2 then
- if retAll then
- for _, v in ipairs(answers) do
- table.insert(result, v)
- end
- else
- return true, answers
- end
- end
+ if status2 then
+ if retAll then
+ for _, v in ipairs(answers) do
+ table.insert(result, v)
+ end
+ else
+ return true, answers
+ end
+ end
- if not status1 and not status2 then
- return false, answers
- end
+ if not status1 and not status2 then
+ return false, answers
+ end
- return true, result
+ return true, result
- end,
+ end,
- --- Send a query for a particular service and store the response in a table
- --
- -- @param host string containing the ip to connect to
- -- @param port number containing the port to connect to
- -- @param svc the service record to retrieve
- -- @param multiple true if responses from multiple hosts are expected
- -- @param svcresponse table to which results are stored
- queryService = function( host, port, svc, multiple, svcresponse )
- local condvar = nmap.condvar(svcresponse)
- local status, response = dns.query( svc, { port = port, host = host, dtype="PTR", retPkt=true, retAll=true, multiple=multiple, sendCount=1, timeout=2000} )
- if not status then
- stdnse.print_debug("Failed to query service: %s; Error: %s", svc, response)
- return
- end
- svcresponse[svc] = svcresponse[svc] or {}
- if ( multiple ) then
- for _, r in ipairs(response) do
- table.insert( svcresponse[svc], r )
- end
- else
- svcresponse[svc] = response
- end
- condvar("broadcast")
- end,
+ --- Send a query for a particular service and store the response in a table
+ --
+ -- @param host string containing the ip to connect to
+ -- @param port number containing the port to connect to
+ -- @param svc the service record to retrieve
+ -- @param multiple true if responses from multiple hosts are expected
+ -- @param svcresponse table to which results are stored
+ queryService = function( host, port, svc, multiple, svcresponse )
+ local condvar = nmap.condvar(svcresponse)
+ local status, response = dns.query( svc, { port = port, host = host, dtype="PTR", retPkt=true, retAll=true, multiple=multiple, sendCount=1, timeout=2000} )
+ if not status then
+ stdnse.print_debug("Failed to query service: %s; Error: %s", svc, response)
+ return
+ end
+ svcresponse[svc] = svcresponse[svc] or {}
+ if ( multiple ) then
+ for _, r in ipairs(response) do
+ table.insert( svcresponse[svc], r )
+ end
+ else
+ svcresponse[svc] = response
+ end
+ condvar("broadcast")
+ end,
- --- Decodes a record received from the queryService function
- --
- -- @param response as returned by queryService
- -- @param result table into which the decoded output should be stored
- decodeRecords = function( response, result )
- local service, deviceinfo = {}, {}
- local txt = {}
- local ipv6, srv, address, port, proto
+ --- Decodes a record received from the queryService function
+ --
+ -- @param response as returned by queryService
+ -- @param result table into which the decoded output should be stored
+ decodeRecords = function( response, result )
+ local service, deviceinfo = {}, {}
+ local txt = {}
+ local ipv6, srv, address, port, proto
- local record = ( #response.questions > 0 and response.questions[1].dname ) and response.questions[1].dname or ""
+ local record = ( #response.questions > 0 and response.questions[1].dname ) and response.questions[1].dname or ""
- local status, ip = Comm.getRecordType( dns.types.A, response, false )
- if status then address = ip end
+ local status, ip = Comm.getRecordType( dns.types.A, response, false )
+ if status then address = ip end
- status, ipv6 = Comm.getRecordType( dns.types.AAAA, response, false )
- if status then
- address = address or ""
- address = address .. " " .. ipv6
- end
+ status, ipv6 = Comm.getRecordType( dns.types.AAAA, response, false )
+ if status then
+ address = address or ""
+ address = address .. " " .. ipv6
+ end
- status, txt = Comm.getRecordType( dns.types.TXT, response, true )
- if status then
- for _, v in ipairs(txt) do
- if v:len() > 0 then
- table.insert(service, v)
- end
- end
- end
+ status, txt = Comm.getRecordType( dns.types.TXT, response, true )
+ if status then
+ for _, v in ipairs(txt) do
+ if v:len() > 0 then
+ table.insert(service, v)
+ end
+ end
+ end
- status, srv = Comm.getRecordType( dns.types.SRV, response, false )
- if status then
- local srvparams = stdnse.strsplit( ":", srv )
+ status, srv = Comm.getRecordType( dns.types.SRV, response, false )
+ if status then
+ local srvparams = stdnse.strsplit( ":", srv )
- if #srvparams > 3 then
- port = srvparams[3]
- end
- end
+ if #srvparams > 3 then
+ port = srvparams[3]
+ end
+ end
- if address then
- table.insert( service, ("Address=%s"):format( address ) )
- end
+ if address then
+ table.insert( service, ("Address=%s"):format( address ) )
+ end
- if record == "_device-info._tcp.local" then
- service.name = "Device Information"
- deviceinfo = service
- table.insert(result, deviceinfo)
- else
- local serviceparams = stdnse.strsplit("[.]", record)
+ if record == "_device-info._tcp.local" then
+ service.name = "Device Information"
+ deviceinfo = service
+ table.insert(result, deviceinfo)
+ else
+ local serviceparams = stdnse.strsplit("[.]", record)
- if #serviceparams > 2 then
- local servicename = serviceparams[1]:sub(2)
- local proto = serviceparams[2]:sub(2)
+ if #serviceparams > 2 then
+ local servicename = serviceparams[1]:sub(2)
+ local proto = serviceparams[2]:sub(2)
- if port == nil or proto == nil or servicename == nil then
- service.name = record
- else
- service.name = string.format( "%s/%s %s", port, proto, servicename)
- end
- end
- table.insert( result, service )
- end
- end,
+ if port == nil or proto == nil or servicename == nil then
+ service.name = record
+ else
+ service.name = string.format( "%s/%s %s", port, proto, servicename)
+ end
+ end
+ table.insert( result, service )
+ end
+ end,
- --- Query the mDNS resolvers for a list of their services
- --
- -- @param host table as received by the action function
- -- @param port number specifying the port to connect to
- -- @param multiple receive multiple responses (multicast)
- -- @return True if a dns response was received and contained an answer of
- -- the requested type, or the decoded dns response was requested
- -- (retPkt) and is being returned - or False otherwise.
- -- @return String answer of the requested type, Table of answers or a
- -- String error message of one of the following:
- -- "No Such Name", "No Servers", "No Answers",
- -- "Unable to handle response"
- queryAllServices = function( host, port, multiple )
- local sendCount, timeout = 1, 2000
- if ( multiple ) then
- sendCount, timeout = 2, 5000
- end
- return dns.query( "_services._dns-sd._udp.local", { port = port, host = ( host.ip or host ), dtype="PTR", retAll=true, multiple=multiple, sendCount=sendCount, timeout=timeout } )
- end,
+ --- Query the mDNS resolvers for a list of their services
+ --
+ -- @param host table as received by the action function
+ -- @param port number specifying the port to connect to
+ -- @param multiple receive multiple responses (multicast)
+ -- @return True if a dns response was received and contained an answer of
+ -- the requested type, or the decoded dns response was requested
+ -- (retPkt) and is being returned - or False otherwise.
+ -- @return String answer of the requested type, Table of answers or a
+ -- String error message of one of the following:
+ -- "No Such Name", "No Servers", "No Answers",
+ -- "Unable to handle response"
+ queryAllServices = function( host, port, multiple )
+ local sendCount, timeout = 1, 2000
+ if ( multiple ) then
+ sendCount, timeout = 2, 5000
+ end
+ return dns.query( "_services._dns-sd._udp.local", { port = port, host = ( host.ip or host ), dtype="PTR", retAll=true, multiple=multiple, sendCount=sendCount, timeout=timeout } )
+ end,
}
Helper = {
- --- Creates a new helper instance
- --
- -- @param host string containing the host name or ip
- -- @param port number containing the port to connect to
- -- @return o a new instance of Helper
- new = function( self, host, port )
- local o = {}
- setmetatable(o, self)
- self.__index = self
- o.host = host
- o.port = port
- o.mcast = false
- return o
- end,
+ --- Creates a new helper instance
+ --
+ -- @param host string containing the host name or ip
+ -- @param port number containing the port to connect to
+ -- @return o a new instance of Helper
+ new = function( self, host, port )
+ local o = {}
+ setmetatable(o, self)
+ self.__index = self
+ o.host = host
+ o.port = port
+ o.mcast = false
+ return o
+ end,
- --- Instructs the helper to use unconnected sockets supporting multicast
- --
- -- @param mcast boolean true if multicast is to be used, false otherwise
- setMulticast = function( self, mcast )
- assert( type(mcast)=="boolean", "mcast has to be either true or false")
- self.mcast = mcast
- end,
+ --- Instructs the helper to use unconnected sockets supporting multicast
+ --
+ -- @param mcast boolean true if multicast is to be used, false otherwise
+ setMulticast = function( self, mcast )
+ assert( type(mcast)=="boolean", "mcast has to be either true or false")
+ self.mcast = mcast
+ end,
- --- Performs a DNS-SD query against a host
- --
- -- @param host table as received by the action function
- -- @param port number specifying the port to connect to
- -- @param service string or table with the service(s) to query eg.
- -- _ssh._tcp.local, _afpovertcp._tcp.local
- -- if nil defaults to _services._dns-sd._udp.local (all)
- -- @param mcast boolean true if a multicast query is to be done
- -- @return status true on success, false on failure
- -- @return response table suitable for stdnse.format_output
- queryServices = function( self, service )
- local result = {}
- local status, response
- local mcast = self.mcast
- local port = self.port or 5353
- local family = nmap.address_family()
- local host = mcast and (family=="inet6" and "ff02::fb" or "224.0.0.251") or self.host
- local service = service or stdnse.get_script_args('dnssd.services')
+ --- Performs a DNS-SD query against a host
+ --
+ -- @param host table as received by the action function
+ -- @param port number specifying the port to connect to
+ -- @param service string or table with the service(s) to query eg.
+ -- _ssh._tcp.local, _afpovertcp._tcp.local
+ -- if nil defaults to _services._dns-sd._udp.local (all)
+ -- @param mcast boolean true if a multicast query is to be done
+ -- @return status true on success, false on failure
+ -- @return response table suitable for stdnse.format_output
+ queryServices = function( self, service )
+ local result = {}
+ local status, response
+ local mcast = self.mcast
+ local port = self.port or 5353
+ local family = nmap.address_family()
+ local host = mcast and (family=="inet6" and "ff02::fb" or "224.0.0.251") or self.host
+ local service = service or stdnse.get_script_args('dnssd.services')
- if ( not(service) ) then
- status, response = Comm.queryAllServices( host, port, mcast )
- if ( not(status) ) then return status, response end
- else
- if ( 'string' == type(service) ) then
- response = { service }
- elseif ( 'table' == type(service) ) then
- response = service
- end
- end
+ if ( not(service) ) then
+ status, response = Comm.queryAllServices( host, port, mcast )
+ if ( not(status) ) then return status, response end
+ else
+ if ( 'string' == type(service) ) then
+ response = { service }
+ elseif ( 'table' == type(service) ) then
+ response = service
+ end
+ end
- response = Util.getUniqueServices(response)
+ response = Util.getUniqueServices(response)
- local svcresponse = {}
- local condvar = nmap.condvar( svcresponse )
- local threads = {}
+ local svcresponse = {}
+ local condvar = nmap.condvar( svcresponse )
+ local threads = {}
- for svc in pairs(response) do
- local co = stdnse.new_thread( Comm.queryService, (host.ip or host), port, svc, mcast, svcresponse )
- threads[co] = true
- end
+ for svc in pairs(response) do
+ local co = stdnse.new_thread( Comm.queryService, (host.ip or host), port, svc, mcast, svcresponse )
+ threads[co] = true
+ end
- -- Wait for all threads to finish running
- while Util.threadCount(threads)>0 do condvar("wait") end
+ -- Wait for all threads to finish running
+ while Util.threadCount(threads)>0 do condvar("wait") end
- local ipsvctbl = {}
- if ( mcast ) then
- -- Process all records that were returned
- for svcname, response in pairs(svcresponse) do
- for _, r in ipairs( response ) do
- ipsvctbl[r.peer] = ipsvctbl[r.peer] or {}
- Comm.decodeRecords( r.output, ipsvctbl[r.peer] )
- end
- end
- else
- -- Process all records that were returned
- for svcname, response in pairs(svcresponse) do
- Comm.decodeRecords( response, result )
- end
- end
+ local ipsvctbl = {}
+ if ( mcast ) then
+ -- Process all records that were returned
+ for svcname, response in pairs(svcresponse) do
+ for _, r in ipairs( response ) do
+ ipsvctbl[r.peer] = ipsvctbl[r.peer] or {}
+ Comm.decodeRecords( r.output, ipsvctbl[r.peer] )
+ end
+ end
+ else
+ -- Process all records that were returned
+ for svcname, response in pairs(svcresponse) do
+ Comm.decodeRecords( response, result )
+ end
+ end
- if ( mcast ) then
- -- Restructure and build our output table
- for ip, svctbl in pairs( ipsvctbl ) do
- table.sort(svctbl, Util.serviceCompare)
- svctbl.name = ip
- if target.ALLOW_NEW_TARGETS then target.add(ip) end
- table.insert( result, svctbl )
- end
- table.sort( result, Util.ipCompare )
- else
- -- sort the tables per port
- table.sort( result, Util.serviceCompare )
- end
- return true, result
- end,
+ if ( mcast ) then
+ -- Restructure and build our output table
+ for ip, svctbl in pairs( ipsvctbl ) do
+ table.sort(svctbl, Util.serviceCompare)
+ svctbl.name = ip
+ if target.ALLOW_NEW_TARGETS then target.add(ip) end
+ table.insert( result, svctbl )
+ end
+ table.sort( result, Util.ipCompare )
+ else
+ -- sort the tables per port
+ table.sort( result, Util.serviceCompare )
+ end
+ return true, result
+ end,
}
diff --git a/nselib/eap.lua b/nselib/eap.lua
index b36ad9a9b..5ae5e5cb8 100644
--- a/nselib/eap.lua
+++ b/nselib/eap.lua
@@ -20,7 +20,7 @@
-- local packet = eap.parse(l2_data .. l3_data3)
-- if packet then
-- if packet.eap.type == eap.eap_t.IDENTITY and packet.eap.code == eap.code_t.REQUEST then
--- eap.send_identity_response(iface, packet.eap.id, "anonymous")
+-- eap.send_identity_response(iface, packet.eap.id, "anonymous")
-- end
-- end
--
@@ -49,242 +49,242 @@ local EAPOL_HEADER_SIZE = 4
local EAP_HEADER_SIZE = 5
eapol_t = {
- PACKET = 0,
- START = 1,
- LOGOFF = 2,
- KEY = 3,
- ASF = 4,
+ PACKET = 0,
+ START = 1,
+ LOGOFF = 2,
+ KEY = 3,
+ ASF = 4,
}
eapol_str = {
- [0] = "EAP Packet",
- [1] = "EAPOL Start",
- [2] = "EAPOL Logoff",
- [3] = "EAPOL Key",
- [4] = "EAPOL Encapsulated ASF Alert",
+ [0] = "EAP Packet",
+ [1] = "EAPOL Start",
+ [2] = "EAPOL Logoff",
+ [3] = "EAPOL Key",
+ [4] = "EAPOL Encapsulated ASF Alert",
}
code_t = {
- REQUEST = 1,
- RESPONSE = 2,
- SUCCESS = 3,
- FAILURE = 4,
- INITIATE = 5,
- FINISH = 6,
+ REQUEST = 1,
+ RESPONSE = 2,
+ SUCCESS = 3,
+ FAILURE = 4,
+ INITIATE = 5,
+ FINISH = 6,
}
code_str = {
- [1] = "Request",
- [2] = "Response",
- [3] = "Success",
- [4] = "Failure",
- [5] = "Initiate",
- [6] = "Finish",
+ [1] = "Request",
+ [2] = "Response",
+ [3] = "Success",
+ [4] = "Failure",
+ [5] = "Initiate",
+ [6] = "Finish",
}
eap_t = {
- IDENTITY = 1,
- NAK = 3,
- MD5 = 4,
- TLS = 13,
- TTLS = 21,
- PEAP = 25,
- MSCHAP = 29,
+ IDENTITY = 1,
+ NAK = 3,
+ MD5 = 4,
+ TLS = 13,
+ TTLS = 21,
+ PEAP = 25,
+ MSCHAP = 29,
}
eap_str = {
- [0] = "Reserved",
- [1] = "Identity",
- [2] = "Notification",
- [3] = "Legacy Nak",
- [4] = "MD5-Challenge",
- [5] = "One-Time Password (OTP)",
- [6] = "Generic Token Card (GTC)",
- [7] = "Allocated",
- [8] = "Allocated",
- [9] = "RSA Public Key Authentication",
- [10] = "DSS Unilateral",
- [11] = "KEA",
- [12] = "KEA-VALIDATE",
- [13] = "EAP-TLS",
- [14] = "Defender Token (AXENT)",
- [15] = "RSA Security SecurID EAP",
- [16] = "Arcot Systems EAP",
- [17] = "EAP-Cisco Wireless",
- [18] = "GSM Subscriber Identity Modules (EAP-SIM)",
- [19] = "SRP-SHA1",
- [20] = "Unassigned",
- [21] = "EAP-TTLS",
- [22] = "Remote Access Service",
- [23] = "EAP-AKA Authentication",
- [24] = "EAP-3Com Wireless",
- [25] = "PEAP",
- [26] = "MS-EAP-Authentication",
- [27] = "Mutual Authentication w/Key Exchange (MAKE)",
- [28] = "CRYPTOCard",
- [29] = "EAP-MSCHAP-V2",
- [30] = "DynamID",
- [31] = "Rob EAP",
- [32] = "Protected One-Time Password",
- [33] = "MS-Authentication-TLV",
- [34] = "SentriNET",
- [35] = "EAP-Actiontec Wireless",
- [36] = "Cogent Systems Biometrics Authentication EAP",
- [37] = "AirFortress EAP",
- [38] = "EAP-HTTP Digest",
- [39] = "SecureSuite EAP",
- [40] = "DeviceConnect EAP",
- [41] = "EAP-SPEKE",
- [42] = "EAP-MOBAC",
- [43] = "EAP-FAST",
- [44] = "ZoneLabs EAP (ZLXEAP)",
- [45] = "EAP-Link",
- [46] = "EAP-PAX",
- [47] = "EAP-PSK",
- [48] = "EAP-SAKE",
- [49] = "EAP-IKEv2",
- [50] = "EAP-AKA'",
- [51] = "EAP-GPSK",
- [52] = "EAP-pwd",
- [53] = "EAP-EKE Version 1",
- -- 54-253 Unassigned
- [254] = "Reserved for the Expanded Type",
- [255] = "Experimental",
+ [0] = "Reserved",
+ [1] = "Identity",
+ [2] = "Notification",
+ [3] = "Legacy Nak",
+ [4] = "MD5-Challenge",
+ [5] = "One-Time Password (OTP)",
+ [6] = "Generic Token Card (GTC)",
+ [7] = "Allocated",
+ [8] = "Allocated",
+ [9] = "RSA Public Key Authentication",
+ [10] = "DSS Unilateral",
+ [11] = "KEA",
+ [12] = "KEA-VALIDATE",
+ [13] = "EAP-TLS",
+ [14] = "Defender Token (AXENT)",
+ [15] = "RSA Security SecurID EAP",
+ [16] = "Arcot Systems EAP",
+ [17] = "EAP-Cisco Wireless",
+ [18] = "GSM Subscriber Identity Modules (EAP-SIM)",
+ [19] = "SRP-SHA1",
+ [20] = "Unassigned",
+ [21] = "EAP-TTLS",
+ [22] = "Remote Access Service",
+ [23] = "EAP-AKA Authentication",
+ [24] = "EAP-3Com Wireless",
+ [25] = "PEAP",
+ [26] = "MS-EAP-Authentication",
+ [27] = "Mutual Authentication w/Key Exchange (MAKE)",
+ [28] = "CRYPTOCard",
+ [29] = "EAP-MSCHAP-V2",
+ [30] = "DynamID",
+ [31] = "Rob EAP",
+ [32] = "Protected One-Time Password",
+ [33] = "MS-Authentication-TLV",
+ [34] = "SentriNET",
+ [35] = "EAP-Actiontec Wireless",
+ [36] = "Cogent Systems Biometrics Authentication EAP",
+ [37] = "AirFortress EAP",
+ [38] = "EAP-HTTP Digest",
+ [39] = "SecureSuite EAP",
+ [40] = "DeviceConnect EAP",
+ [41] = "EAP-SPEKE",
+ [42] = "EAP-MOBAC",
+ [43] = "EAP-FAST",
+ [44] = "ZoneLabs EAP (ZLXEAP)",
+ [45] = "EAP-Link",
+ [46] = "EAP-PAX",
+ [47] = "EAP-PSK",
+ [48] = "EAP-SAKE",
+ [49] = "EAP-IKEv2",
+ [50] = "EAP-AKA'",
+ [51] = "EAP-GPSK",
+ [52] = "EAP-pwd",
+ [53] = "EAP-EKE Version 1",
+ -- 54-253 Unassigned
+ [254] = "Reserved for the Expanded Type",
+ [255] = "Experimental",
}
local make_eapol = function (arg)
- if not arg.type then arg.type = eapol_t.PACKET end
- if not arg.version then arg.version = 1 end
- if not arg.payload then arg.payload = "" end
- if not arg.src then return nil end
+ if not arg.type then arg.type = eapol_t.PACKET end
+ if not arg.version then arg.version = 1 end
+ if not arg.payload then arg.payload = "" end
+ if not arg.src then return nil end
- local p = packet.Frame:new()
- p.mac_src = arg.src
- p.mac_dst = packet.mactobin(ETHER_BROADCAST)
- p.ether_type = ETHER_TYPE_EAPOL
+ local p = packet.Frame:new()
+ p.mac_src = arg.src
+ p.mac_dst = packet.mactobin(ETHER_BROADCAST)
+ p.ether_type = ETHER_TYPE_EAPOL
- local bin_payload = bin.pack(">A",arg.payload)
- p.buf = bin.pack("C",arg.version) .. bin.pack("C",arg.type) .. bin.pack(">S",bin_payload:len()).. bin_payload
- p:build_ether_frame()
- return p.frame_buf
+ local bin_payload = bin.pack(">A",arg.payload)
+ p.buf = bin.pack("C",arg.version) .. bin.pack("C",arg.type) .. bin.pack(">S",bin_payload:len()).. bin_payload
+ p:build_ether_frame()
+ return p.frame_buf
end
local make_eap = function (arg)
- if not arg.code then arg.code = code_t.REQUEST end
- if not arg.id then arg.id = math.random(0,255) end
- if not arg.type then arg.type = eap_t.IDENTITY end
- if not arg.payload then arg.payload = "" end
- if not arg.header then return nil end
+ if not arg.code then arg.code = code_t.REQUEST end
+ if not arg.id then arg.id = math.random(0,255) end
+ if not arg.type then arg.type = eap_t.IDENTITY end
+ if not arg.payload then arg.payload = "" end
+ if not arg.header then return nil end
- local bin_payload = bin.pack(">A",arg.payload)
- arg.header.payload = bin.pack("C",arg.code) .. bin.pack("C",arg.id) .. bin.pack(">S",bin_payload:len() + EAP_HEADER_SIZE).. bin.pack("C",arg.type) .. bin_payload
+ local bin_payload = bin.pack(">A",arg.payload)
+ arg.header.payload = bin.pack("C",arg.code) .. bin.pack("C",arg.id) .. bin.pack(">S",bin_payload:len() + EAP_HEADER_SIZE).. bin.pack("C",arg.type) .. bin_payload
- local v = make_eapol(arg.header)
- stdnse.print_debug(2, "make eapol %s", arg.header.src)
+ local v = make_eapol(arg.header)
+ stdnse.print_debug(2, "make eapol %s", arg.header.src)
- return v
+ return v
end
parse = function (packet)
- local tb = {}
- local _
+ local tb = {}
+ local _
- stdnse.print_debug(2, "packet size: 0x%x", #packet )
+ stdnse.print_debug(2, "packet size: 0x%x", #packet )
- -- parsing ethernet header
- _, tb.mac_src, tb.mac_dst, tb.ether_type = bin.unpack(">A6A6S", packet)
- _, tb.mac_src_str, tb.mac_dst_str = bin.unpack(">H6H6", packet)
+ -- parsing ethernet header
+ _, tb.mac_src, tb.mac_dst, tb.ether_type = bin.unpack(">A6A6S", packet)
+ _, tb.mac_src_str, tb.mac_dst_str = bin.unpack(">H6H6", packet)
- -- parsing eapol header
- _, tb.version, tb.type, tb.length = bin.unpack(">CCS", packet, ETHER_HEADER_SIZE + 1)
+ -- parsing eapol header
+ _, tb.version, tb.type, tb.length = bin.unpack(">CCS", packet, ETHER_HEADER_SIZE + 1)
- stdnse.print_debug(1, "mac_src: %s, mac_dest: %s, ether_type: 0x%X",
- tb.mac_src_str, tb.mac_dst_str, tb.ether_type)
+ stdnse.print_debug(1, "mac_src: %s, mac_dest: %s, ether_type: 0x%X",
+ tb.mac_src_str, tb.mac_dst_str, tb.ether_type)
- if tb.ether_type ~= ETHER_TYPE_EAPOL_N then return nil, "not an eapol packet" end
+ if tb.ether_type ~= ETHER_TYPE_EAPOL_N then return nil, "not an eapol packet" end
- stdnse.print_debug(2, "version: %X, type: %s, length: 0x%X",
- tb.version, eapol_str[tb.type] or "unknown",
- tb.length)
+ stdnse.print_debug(2, "version: %X, type: %s, length: 0x%X",
+ tb.version, eapol_str[tb.type] or "unknown",
+ tb.length)
- tb.eap = {}
+ tb.eap = {}
- if tb.length > 0 then
- -- parsing body
+ if tb.length > 0 then
+ -- parsing body
- _, tb.eap.code, tb.eap.id, tb.eap.length, tb.eap.type = bin.unpack(">CCSC", packet,
- ETHER_HEADER_SIZE + EAPOL_HEADER_SIZE + 1)
- stdnse.print_debug(2, "code: %s, id: 0x%X, length: 0x%X, type: %s",
- code_str[tb.eap.code] or "unknown",
- tb.eap.id, tb.eap.length, eap_str[tb.eap.type] or "unknown" )
- if tb.length ~= tb.eap.length then
- stdnse.print_debug(1, "WARNING length mismatch: 0x%X and 0x%X", tb.length, tb.eap.length )
- end
- end
+ _, tb.eap.code, tb.eap.id, tb.eap.length, tb.eap.type = bin.unpack(">CCSC", packet,
+ ETHER_HEADER_SIZE + EAPOL_HEADER_SIZE + 1)
+ stdnse.print_debug(2, "code: %s, id: 0x%X, length: 0x%X, type: %s",
+ code_str[tb.eap.code] or "unknown",
+ tb.eap.id, tb.eap.length, eap_str[tb.eap.type] or "unknown" )
+ if tb.length ~= tb.eap.length then
+ stdnse.print_debug(1, "WARNING length mismatch: 0x%X and 0x%X", tb.length, tb.eap.length )
+ end
+ end
- tb.eap.body = {}
+ tb.eap.body = {}
- -- parsing payload
- if tb.length > 5 and tb.eap.type == eap_t.IDENTITY then
- _, tb.eap.body.identity = bin.unpack("z", packet,
- ETHER_HEADER_SIZE + EAPOL_HEADER_SIZE + EAP_HEADER_SIZE + 1)
- stdnse.print_debug(1, "identity: %s", tb.eap.body.identity )
- end
+ -- parsing payload
+ if tb.length > 5 and tb.eap.type == eap_t.IDENTITY then
+ _, tb.eap.body.identity = bin.unpack("z", packet,
+ ETHER_HEADER_SIZE + EAPOL_HEADER_SIZE + EAP_HEADER_SIZE + 1)
+ stdnse.print_debug(1, "identity: %s", tb.eap.body.identity )
+ end
- if tb.length > 5 and tb.eap.type == eap_t.MD5 then
- _, tb.eap.body.challenge = bin.unpack("p", packet, ETHER_HEADER_SIZE + EAPOL_HEADER_SIZE + EAP_HEADER_SIZE + 1)
- end
+ if tb.length > 5 and tb.eap.type == eap_t.MD5 then
+ _, tb.eap.body.challenge = bin.unpack("p", packet, ETHER_HEADER_SIZE + EAPOL_HEADER_SIZE + EAP_HEADER_SIZE + 1)
+ end
- return tb
+ return tb
end
send_identity_response = function (iface, id, identity)
- if not iface then
- stdnse.print_debug(1, "no interface given")
- return
- end
+ if not iface then
+ stdnse.print_debug(1, "no interface given")
+ return
+ end
- local dnet = nmap.new_dnet()
- local tb = {src = iface.mac, type = eapol_t.PACKET}
- local response = make_eap{header = tb, code = code_t.RESPONSE, type = eap_t.IDENTITY, id = id, payload = identity}
+ local dnet = nmap.new_dnet()
+ local tb = {src = iface.mac, type = eapol_t.PACKET}
+ local response = make_eap{header = tb, code = code_t.RESPONSE, type = eap_t.IDENTITY, id = id, payload = identity}
- dnet:ethernet_open(iface.device)
- dnet:ethernet_send(response)
- dnet:ethernet_close()
+ dnet:ethernet_open(iface.device)
+ dnet:ethernet_send(response)
+ dnet:ethernet_close()
end
send_nak_response = function (iface, id, auth)
- if not iface then
- stdnse.print_debug(1, "no interface given")
- return
- end
+ if not iface then
+ stdnse.print_debug(1, "no interface given")
+ return
+ end
- local dnet = nmap.new_dnet()
- local tb = {src = iface.mac, type = eapol_t.PACKET}
- local response = make_eap{header = tb, code = code_t.RESPONSE, type = eap_t.NAK, id = id, payload = bin.pack("C",auth)}
+ local dnet = nmap.new_dnet()
+ local tb = {src = iface.mac, type = eapol_t.PACKET}
+ local response = make_eap{header = tb, code = code_t.RESPONSE, type = eap_t.NAK, id = id, payload = bin.pack("C",auth)}
- dnet:ethernet_open(iface.device)
- dnet:ethernet_send(response)
- dnet:ethernet_close()
+ dnet:ethernet_open(iface.device)
+ dnet:ethernet_send(response)
+ dnet:ethernet_close()
end
send_start = function (iface)
- if not iface then
- stdnse.print_debug(1, "no interface given")
- return
- end
+ if not iface then
+ stdnse.print_debug(1, "no interface given")
+ return
+ end
- local dnet = nmap.new_dnet()
- local start = make_eapol{type = eapol_t.START, src = iface.mac}
+ local dnet = nmap.new_dnet()
+ local start = make_eapol{type = eapol_t.START, src = iface.mac}
- dnet:ethernet_open(iface.device)
- dnet:ethernet_send(start)
- dnet:ethernet_close()
+ dnet:ethernet_open(iface.device)
+ dnet:ethernet_send(start)
+ dnet:ethernet_close()
end
diff --git a/nselib/eigrp.lua b/nselib/eigrp.lua
index 1732c4005..6014933f5 100644
--- a/nselib/eigrp.lua
+++ b/nselib/eigrp.lua
@@ -15,375 +15,375 @@ _ENV = stdnse.module("eigrp", stdnse.seeall)
-- TLV Type constants
TLV = {
- PARAM = 0x0001,
- AUTH = 0x0002,
- SEQ = 0x0003,
- SWVER = 0x0004,
- MSEQ = 0x0005,
- STUB = 0x0006,
- TERM = 0x0007,
- TIDLIST = 0x0008,
- REQ = 0x0101,
- INT = 0x0102,
- EXT = 0x0103,
- COM = 0x0104,
- INT6 = 0x0402,
- EXT6 = 0x0403,
- COM6 = 0x0404,
+ PARAM = 0x0001,
+ AUTH = 0x0002,
+ SEQ = 0x0003,
+ SWVER = 0x0004,
+ MSEQ = 0x0005,
+ STUB = 0x0006,
+ TERM = 0x0007,
+ TIDLIST = 0x0008,
+ REQ = 0x0101,
+ INT = 0x0102,
+ EXT = 0x0103,
+ COM = 0x0104,
+ INT6 = 0x0402,
+ EXT6 = 0x0403,
+ COM6 = 0x0404,
}
-- External protocols constants
EXT_PROTO = {
- NULL = 0x00,
- IGRP = 0x01,
- EIGRP = 0x02,
- Static = 0x03,
- RIP = 0x04,
- HELLO = 0x05,
- OSPF = 0x06,
- ISIS = 0x07,
- EGP = 0x08,
- BGP = 0x09,
- IDRP = 0x10,
- Connected = 0x11,
+ NULL = 0x00,
+ IGRP = 0x01,
+ EIGRP = 0x02,
+ Static = 0x03,
+ RIP = 0x04,
+ HELLO = 0x05,
+ OSPF = 0x06,
+ ISIS = 0x07,
+ EGP = 0x08,
+ BGP = 0x09,
+ IDRP = 0x10,
+ Connected = 0x11,
}
-- Packets opcode constants
OPCODE = {
- UPDATE = 0x01,
- RESERVED = 0x02,
- QUERY = 0x03,
- REPLY = 0x04,
- HELLO = 0x05,
+ UPDATE = 0x01,
+ RESERVED = 0x02,
+ QUERY = 0x03,
+ REPLY = 0x04,
+ HELLO = 0x05,
}
-- The EIGRP Class
EIGRP = {
- --- Creates a new instance of EIGRP class.
- -- @param opcode integer Opcode. Defaults to 5 (Hello)
- -- @param as integer Autonomous System. Defaults to 0.
- -- @param routerid integer virtual router ID. defaults to 0.
- -- @param flags integer flags field value. Defaults to 0.
- -- @param seq integer sequence value. Defaults to 0.
- -- @param ack integer acknowledge value. Defaults to 0.
- -- @param Checksum integer EIGRP packet checksum. Calculated automatically
- -- if not manually set.
- -- @param Table TLVs table.
- -- @return o Instance of EIGRP
- new = function(self, opcode, as, routerid, flags, seq, ack, checksum, tlvs)
- local o = {
- ver = 2,
- opcode = opcode or TLV.HELLO,
- as = as or 0,
- routerid = routerid or 0,
- flags = flags or 0,
- seq = seq or 0x00,
- ack = ack or 0x00,
- checksum = checksum,
- tlvs = tlvs or {},
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ --- Creates a new instance of EIGRP class.
+ -- @param opcode integer Opcode. Defaults to 5 (Hello)
+ -- @param as integer Autonomous System. Defaults to 0.
+ -- @param routerid integer virtual router ID. defaults to 0.
+ -- @param flags integer flags field value. Defaults to 0.
+ -- @param seq integer sequence value. Defaults to 0.
+ -- @param ack integer acknowledge value. Defaults to 0.
+ -- @param Checksum integer EIGRP packet checksum. Calculated automatically
+ -- if not manually set.
+ -- @param Table TLVs table.
+ -- @return o Instance of EIGRP
+ new = function(self, opcode, as, routerid, flags, seq, ack, checksum, tlvs)
+ local o = {
+ ver = 2,
+ opcode = opcode or TLV.HELLO,
+ as = as or 0,
+ routerid = routerid or 0,
+ flags = flags or 0,
+ seq = seq or 0x00,
+ ack = ack or 0x00,
+ checksum = checksum,
+ tlvs = tlvs or {},
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- --- Parses a raw eigrp packet and returns a structred response.
- -- @param eigrp_raw string EIGRP Raw packet.
- -- @return response table Structured eigrp packet.
- parse = function(eigrp_raw)
- if type(eigrp_raw) ~= 'string' then
- stdnse.print_debug("eigrp.lua: parse input should be string.")
- return
- end
- if #eigrp_raw < 20 then
- stdnse.print_debug("eigrp.lua: raw packet size lower then 20.")
- return
- end
- local tlv
- local eigrp_packet = {}
- local index = 1
- index, eigrp_packet.ver = bin.unpack(">C", eigrp_raw, index)
- index, eigrp_packet.opcode = bin.unpack(">C", eigrp_raw, index)
- index, eigrp_packet.checksum = bin.unpack(">S", eigrp_raw, index)
- index, eigrp_packet.flags = bin.unpack(">I", eigrp_raw, index)
- index, eigrp_packet.seq = bin.unpack(">I", eigrp_raw, index)
- index, eigrp_packet.ack = bin.unpack(">I", eigrp_raw, index)
- index, eigrp_packet.routerid = bin.unpack(">S", eigrp_raw, index)
- index, eigrp_packet.as = bin.unpack(">S", eigrp_raw, index)
- eigrp_packet.tlvs = {}
- while index < #eigrp_raw do
- tlv = {}
- index, tlv.type = bin.unpack(">S", eigrp_raw, index)
- index, tlv.length = bin.unpack(">S", eigrp_raw, index)
- if tlv.length == 0x00 then
- -- In case someone wants to DoS us :)
- stdnse.print_debug("eigrp.lua: stopped parsing due to null TLV length.")
- break
- end
- if tlv.type == TLV.PARAM then
- -- Parameters
- local k = {}
- index, k[1], k[2], k[3], k[4], k[5], k[6] = bin.unpack(">CCCCCC", eigrp_raw, index)
- index, tlv.htime = bin.unpack(">S", eigrp_raw, index)
- index = index + tlv.length - 12
- elseif tlv.type == TLV.AUTH then
- index, tlv.authtype = bin.unpack(">S", eigrp_raw, index)
- index, tlv.authlen = bin.unpack(">S", eigrp_raw, index)
- index, tlv.keyid = bin.unpack(">I", eigrp_raw, index)
- index, tlv.keyseq = bin.unpack(">I", eigrp_raw, index)
- -- Null pad == tlv.length - What was already parsed - authlen
- index, tlv.digest = bin.unpack(">S", eigrp_raw, index + (tlv.length - tlv.authlen - index + 1))
- elseif tlv.type == TLV.SEQ then
- -- Sequence
- index, tlv.addlen = bin.unpack(">S", eigrp_raw, index)
- index, tlv.address = bin.unpack("C", eigrp_raw, index)
- index, tlv.minv = bin.unpack(">C", eigrp_raw, index)
- index, tlv.majtlv = bin.unpack(">C", eigrp_raw, index)
- index, tlv.mintlv = bin.unpack(">C", eigrp_raw, index)
- index = index + tlv.length - 8
- elseif tlv.type == TLV.MSEQ then
- -- Next Multicast Sequence
- index, tlv.mseq = bin.unpack(">I", eigrp_raw, index)
- index = index + tlv.length - 8
- elseif tlv.type == TLV.STUB then
- -- TODO
- stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
- index = index + tlv.length - 4
- elseif tlv.type == TLV.TERM then
- -- TODO
- stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
- index = index + tlv.length - 4
- elseif tlv.type == TLV.TIDLIST then
- -- TODO
- stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
- index = index + tlv.length - 4
- elseif tlv.type == TLV.REQ then
- -- TODO
- stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
- index = index + tlv.length - 4
- elseif tlv.type == TLV.INT then
- -- Internal Route
- index, tlv.nexth = bin.unpack("S", eigrp_raw, index + 15)
- -- Destination varies in length
- -- e.g trailing 0's are omitted
- -- if length = 29 => destination is 4 bytes
- -- if length = 28 => destination is 3 bytes
- -- if length = 27 => destination is 2 bytes
- -- if length = 26 => destination is 1 byte
- local dst = {}
- index, dst[1], dst[2], dst[3], dst[4] = bin.unpack(">C" .. 4 + tlv.length - 29, eigrp_raw, index)
- for i=2,4 do
- if not dst[i] then
- dst[i] = '0'
- end
- end
- tlv.dst = dst[1] .. '.' .. dst[2] .. '.' .. dst[3] .. '.' .. dst[4]
- elseif tlv.type == TLV.EXT then
- -- External Route
- index, tlv.nexth = bin.unpack("I", eigrp_raw, index)
- index, tlv.tag = bin.unpack(">I", eigrp_raw, index)
- index, tlv.emetric = bin.unpack(">I", eigrp_raw, index)
- -- Skip 2 reserved bytes
- index, tlv.eproto = bin.unpack(">C", eigrp_raw, index + 2)
- index, tlv.eflags = bin.unpack(">C", eigrp_raw, index)
- index, tlv.lmetrics = bin.unpack(">L"..2, eigrp_raw, index)
- index, tlv.mask = bin.unpack(">C", eigrp_raw, index)
- -- Destination varies in length
- -- if length = 49 => destination is 4 bytes
- -- if length = 48 => destination is 3 bytes
- -- if length = 47 => destination is 2 bytes
- -- if length = 46 => destination is 1 byte
- local dst = {}
- index, dst[1], dst[2], dst[3], dst[4] = bin.unpack(">C" .. 4 + tlv.length - 49, eigrp_raw, index)
- for i=2,4 do
- if not dst[i] then
- dst[i] = '0'
- end
- end
- tlv.dst = dst[1] .. '.' .. dst[2] .. '.' .. dst[3] .. '.' .. dst[4]
- elseif tlv.type == TLV.COM then
- -- TODO
- stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
- index = index + tlv.length - 4
- elseif tlv.type == TLV.INT6 then
- -- TODO
- stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
- index = index + tlv.length - 4
- elseif tlv.type == TLV.EXT6 then
- -- TODO
- stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
- index = index + tlv.length - 4
- elseif tlv.type == TLV.COM6 then
- -- TODO
- stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
- index = index + tlv.length - 4
- else
- stdnse.print_debug("eigrp.lua: eigrp.lua: TLV type %d unknown.", tlv.type)
- index = index + tlv.length - 4
- end
- table.insert(eigrp_packet.tlvs, tlv)
- end
- return eigrp_packet
- end,
+ --- Parses a raw eigrp packet and returns a structred response.
+ -- @param eigrp_raw string EIGRP Raw packet.
+ -- @return response table Structured eigrp packet.
+ parse = function(eigrp_raw)
+ if type(eigrp_raw) ~= 'string' then
+ stdnse.print_debug("eigrp.lua: parse input should be string.")
+ return
+ end
+ if #eigrp_raw < 20 then
+ stdnse.print_debug("eigrp.lua: raw packet size lower then 20.")
+ return
+ end
+ local tlv
+ local eigrp_packet = {}
+ local index = 1
+ index, eigrp_packet.ver = bin.unpack(">C", eigrp_raw, index)
+ index, eigrp_packet.opcode = bin.unpack(">C", eigrp_raw, index)
+ index, eigrp_packet.checksum = bin.unpack(">S", eigrp_raw, index)
+ index, eigrp_packet.flags = bin.unpack(">I", eigrp_raw, index)
+ index, eigrp_packet.seq = bin.unpack(">I", eigrp_raw, index)
+ index, eigrp_packet.ack = bin.unpack(">I", eigrp_raw, index)
+ index, eigrp_packet.routerid = bin.unpack(">S", eigrp_raw, index)
+ index, eigrp_packet.as = bin.unpack(">S", eigrp_raw, index)
+ eigrp_packet.tlvs = {}
+ while index < #eigrp_raw do
+ tlv = {}
+ index, tlv.type = bin.unpack(">S", eigrp_raw, index)
+ index, tlv.length = bin.unpack(">S", eigrp_raw, index)
+ if tlv.length == 0x00 then
+ -- In case someone wants to DoS us :)
+ stdnse.print_debug("eigrp.lua: stopped parsing due to null TLV length.")
+ break
+ end
+ if tlv.type == TLV.PARAM then
+ -- Parameters
+ local k = {}
+ index, k[1], k[2], k[3], k[4], k[5], k[6] = bin.unpack(">CCCCCC", eigrp_raw, index)
+ index, tlv.htime = bin.unpack(">S", eigrp_raw, index)
+ index = index + tlv.length - 12
+ elseif tlv.type == TLV.AUTH then
+ index, tlv.authtype = bin.unpack(">S", eigrp_raw, index)
+ index, tlv.authlen = bin.unpack(">S", eigrp_raw, index)
+ index, tlv.keyid = bin.unpack(">I", eigrp_raw, index)
+ index, tlv.keyseq = bin.unpack(">I", eigrp_raw, index)
+ -- Null pad == tlv.length - What was already parsed - authlen
+ index, tlv.digest = bin.unpack(">S", eigrp_raw, index + (tlv.length - tlv.authlen - index + 1))
+ elseif tlv.type == TLV.SEQ then
+ -- Sequence
+ index, tlv.addlen = bin.unpack(">S", eigrp_raw, index)
+ index, tlv.address = bin.unpack("C", eigrp_raw, index)
+ index, tlv.minv = bin.unpack(">C", eigrp_raw, index)
+ index, tlv.majtlv = bin.unpack(">C", eigrp_raw, index)
+ index, tlv.mintlv = bin.unpack(">C", eigrp_raw, index)
+ index = index + tlv.length - 8
+ elseif tlv.type == TLV.MSEQ then
+ -- Next Multicast Sequence
+ index, tlv.mseq = bin.unpack(">I", eigrp_raw, index)
+ index = index + tlv.length - 8
+ elseif tlv.type == TLV.STUB then
+ -- TODO
+ stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
+ index = index + tlv.length - 4
+ elseif tlv.type == TLV.TERM then
+ -- TODO
+ stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
+ index = index + tlv.length - 4
+ elseif tlv.type == TLV.TIDLIST then
+ -- TODO
+ stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
+ index = index + tlv.length - 4
+ elseif tlv.type == TLV.REQ then
+ -- TODO
+ stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
+ index = index + tlv.length - 4
+ elseif tlv.type == TLV.INT then
+ -- Internal Route
+ index, tlv.nexth = bin.unpack("S", eigrp_raw, index + 15)
+ -- Destination varies in length
+ -- e.g trailing 0's are omitted
+ -- if length = 29 => destination is 4 bytes
+ -- if length = 28 => destination is 3 bytes
+ -- if length = 27 => destination is 2 bytes
+ -- if length = 26 => destination is 1 byte
+ local dst = {}
+ index, dst[1], dst[2], dst[3], dst[4] = bin.unpack(">C" .. 4 + tlv.length - 29, eigrp_raw, index)
+ for i=2,4 do
+ if not dst[i] then
+ dst[i] = '0'
+ end
+ end
+ tlv.dst = dst[1] .. '.' .. dst[2] .. '.' .. dst[3] .. '.' .. dst[4]
+ elseif tlv.type == TLV.EXT then
+ -- External Route
+ index, tlv.nexth = bin.unpack("I", eigrp_raw, index)
+ index, tlv.tag = bin.unpack(">I", eigrp_raw, index)
+ index, tlv.emetric = bin.unpack(">I", eigrp_raw, index)
+ -- Skip 2 reserved bytes
+ index, tlv.eproto = bin.unpack(">C", eigrp_raw, index + 2)
+ index, tlv.eflags = bin.unpack(">C", eigrp_raw, index)
+ index, tlv.lmetrics = bin.unpack(">L"..2, eigrp_raw, index)
+ index, tlv.mask = bin.unpack(">C", eigrp_raw, index)
+ -- Destination varies in length
+ -- if length = 49 => destination is 4 bytes
+ -- if length = 48 => destination is 3 bytes
+ -- if length = 47 => destination is 2 bytes
+ -- if length = 46 => destination is 1 byte
+ local dst = {}
+ index, dst[1], dst[2], dst[3], dst[4] = bin.unpack(">C" .. 4 + tlv.length - 49, eigrp_raw, index)
+ for i=2,4 do
+ if not dst[i] then
+ dst[i] = '0'
+ end
+ end
+ tlv.dst = dst[1] .. '.' .. dst[2] .. '.' .. dst[3] .. '.' .. dst[4]
+ elseif tlv.type == TLV.COM then
+ -- TODO
+ stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
+ index = index + tlv.length - 4
+ elseif tlv.type == TLV.INT6 then
+ -- TODO
+ stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
+ index = index + tlv.length - 4
+ elseif tlv.type == TLV.EXT6 then
+ -- TODO
+ stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
+ index = index + tlv.length - 4
+ elseif tlv.type == TLV.COM6 then
+ -- TODO
+ stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
+ index = index + tlv.length - 4
+ else
+ stdnse.print_debug("eigrp.lua: eigrp.lua: TLV type %d unknown.", tlv.type)
+ index = index + tlv.length - 4
+ end
+ table.insert(eigrp_packet.tlvs, tlv)
+ end
+ return eigrp_packet
+ end,
- --- Adds a TLV table to the table of TLVs.
- -- @param tlv TLV table.
- addTLV = function(self, tlv)
- if type(tlv) == 'table' then
- table.insert(self.tlvs, tlv)
- else
- stdnse.print_debug("eigrp.lua: TLV should be a table, not %s", type(tlv))
- end
- end,
+ --- Adds a TLV table to the table of TLVs.
+ -- @param tlv TLV table.
+ addTLV = function(self, tlv)
+ if type(tlv) == 'table' then
+ table.insert(self.tlvs, tlv)
+ else
+ stdnse.print_debug("eigrp.lua: TLV should be a table, not %s", type(tlv))
+ end
+ end,
- --- Checks if TLV type is one that should contain routing information.
- -- @param tlvtype integer TLV type integer to check.
- -- @return status true if tlvtype is a routing information tlv.
- isRoutingTLV = function(tlvtype)
- if tlvtype == 0x101 or tlvtype == 0x102
- or tlvtype == 0x103 or tlvtype == 0x104
- or tlvtype == 0x402 or tlvtype == 0x403
- or tlvtype == 0x404 then
- return true
- end
- end,
+ --- Checks if TLV type is one that should contain routing information.
+ -- @param tlvtype integer TLV type integer to check.
+ -- @return status true if tlvtype is a routing information tlv.
+ isRoutingTLV = function(tlvtype)
+ if tlvtype == 0x101 or tlvtype == 0x102
+ or tlvtype == 0x103 or tlvtype == 0x104
+ or tlvtype == 0x402 or tlvtype == 0x403
+ or tlvtype == 0x404 then
+ return true
+ end
+ end,
- --- Sets the EIGRP version.
- -- @param ver integer version to set.
- setVersion = function(self, ver)
- self.ver = ver
- end,
- --- Sets the EIGRP Packet opcode
- -- @param opcode integer EIGRP opcode.
- setOpcode = function(self, opcode)
- self.opcode = opcode
- end,
- --- Sets the EIGRP packet checksum
- -- @param integer checksum Checksum to set.
- setChecksum = function(self, checksum)
- self.checksum = checksum
- end,
- --- Sets the EIGRP packet flags field.
- -- @param flags Flags integer value.
- setFlags = function(self, flags)
- self.flags = flags
+ --- Sets the EIGRP version.
+ -- @param ver integer version to set.
+ setVersion = function(self, ver)
+ self.ver = ver
+ end,
+ --- Sets the EIGRP Packet opcode
+ -- @param opcode integer EIGRP opcode.
+ setOpcode = function(self, opcode)
+ self.opcode = opcode
+ end,
+ --- Sets the EIGRP packet checksum
+ -- @param integer checksum Checksum to set.
+ setChecksum = function(self, checksum)
+ self.checksum = checksum
+ end,
+ --- Sets the EIGRP packet flags field.
+ -- @param flags Flags integer value.
+ setFlags = function(self, flags)
+ self.flags = flags
end,
--- Sets the EIGRP packet sequence field.
-- @param seq EIGRP sequence.
setSequence = function(self, seq)
- self.seq = seq
+ self.seq = seq
end,
--- Sets the EIGRP Packet acknowledge field.
-- @param ack EIGRP acknowledge.
setAcknowledge = function(self, ack)
- self.ack = ack
+ self.ack = ack
end,
--- Sets the EIGRP Packet Virtual Router ID.
-- @param routerid EIGRP Virtual Router ID.
setRouterID = function(self, routerid)
- self.routerid = routerid
+ self.routerid = routerid
end,
--- Sets the EIGRP Packet Autonomous System.
-- @param as EIGRP A.S.
setAS = function(self, as)
- self.as = as
+ self.as = as
end,
--- Sets the EIGRP Packet tlvs
-- @param tlvs table of EIGRP tlvs.
setTlvs = function(self, tlvs)
- self.tlvs = tlvs
+ self.tlvs = tlvs
end,
--- Converts the request to a string suitable to be sent over a socket.
-- @return data string containing the complete request to send over the socket
__tostring = function(self)
- local data = bin.pack(">C", self.ver) -- Version 2
- data = data .. bin.pack(">C", self.opcode) -- Opcode: Hello
+ local data = bin.pack(">C", self.ver) -- Version 2
+ data = data .. bin.pack(">C", self.opcode) -- Opcode: Hello
- -- If checksum not manually.
- -- set to 0, then calculate it later
- if self.checksum then
- data = data .. bin.pack(">S", self.checksum)
- else
- data = data .. bin.pack(">S", 0x0000) -- Calculated later.
- end
- data = data .. bin.pack(">I", self.flags) -- Flags
- data = data .. bin.pack(">I", self.seq) -- Sequence 0
- data = data .. bin.pack(">I", self.ack) -- Acknowledge 0
- data = data .. bin.pack(">S", self.routerid) -- Virtual Router ID 0
- data = data .. bin.pack(">S", self.as) -- Autonomous system
- for _, tlv in pairs(self.tlvs) do
- if tlv.type == TLV.PARAM then
- data = data .. bin.pack(">S", TLV.PARAM)
- data = data .. bin.pack(">S", 0x000c) -- Length: 12
- data = data .. bin.pack(">CCCCCC", tlv.k[1],tlv.k[2],tlv.k[3],
- tlv.k[4],tlv.k[5],tlv.k[6])
- data = data .. bin.pack(">S", tlv.htime)
- elseif tlv.type == TLV.AUTH then
- -- TODO
- stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
- elseif tlv.type == TLV.SEQ then
- -- TODO
- stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
- elseif tlv.type == TLV.SWVER then
- data = data .. bin.pack(">S", TLV.SWVER)
- data = data .. bin.pack(">S", 0x0008)
- data = data .. bin.pack(">CC", tonumber(tlv.majv), tonumber(tlv.minv))
- data = data .. bin.pack(">CC", tonumber(tlv.majtlv), tonumber(tlv.mintlv))
- elseif tlv.type == TLV.MSEQ then
- -- TODO
- stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
- elseif tlv.type == TLV.STUB then
- -- TODO
- stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
- elseif tlv.type == TLV.TERM then
- -- TODO
- stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
- elseif tlv.type == TLV.TIDLIST then
- -- TODO
- stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
- elseif tlv.type == TLV.REQ then
- -- TODO
- stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
- elseif tlv.type == TLV.INT then
- -- TODO
- stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
- elseif tlv.type == TLV.EXT then
- -- TODO
- stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
- elseif tlv.type == TLV.COM then
- -- TODO
- stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
- elseif tlv.type == TLV.INT6 then
- -- TODO
- stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
- elseif tlv.type == TLV.EXT6 then
- -- TODO
- stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
- elseif tlv.type == TLV.COM6 then
- -- TODO
- stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
- else
- stdnse.print_debug("eigrp.lua: TLV type %d unknown.", tlv.type)
- end
- end
- -- In the end, correct the checksum if not manually set
- if not self.checksum then
- data = data:sub(1,2) .. bin.pack(">S", packet.in_cksum(data)) .. data:sub(5)
- end
- return data
+ -- If checksum not manually.
+ -- set to 0, then calculate it later
+ if self.checksum then
+ data = data .. bin.pack(">S", self.checksum)
+ else
+ data = data .. bin.pack(">S", 0x0000) -- Calculated later.
+ end
+ data = data .. bin.pack(">I", self.flags) -- Flags
+ data = data .. bin.pack(">I", self.seq) -- Sequence 0
+ data = data .. bin.pack(">I", self.ack) -- Acknowledge 0
+ data = data .. bin.pack(">S", self.routerid) -- Virtual Router ID 0
+ data = data .. bin.pack(">S", self.as) -- Autonomous system
+ for _, tlv in pairs(self.tlvs) do
+ if tlv.type == TLV.PARAM then
+ data = data .. bin.pack(">S", TLV.PARAM)
+ data = data .. bin.pack(">S", 0x000c) -- Length: 12
+ data = data .. bin.pack(">CCCCCC", tlv.k[1],tlv.k[2],tlv.k[3],
+ tlv.k[4],tlv.k[5],tlv.k[6])
+ data = data .. bin.pack(">S", tlv.htime)
+ elseif tlv.type == TLV.AUTH then
+ -- TODO
+ stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
+ elseif tlv.type == TLV.SEQ then
+ -- TODO
+ stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
+ elseif tlv.type == TLV.SWVER then
+ data = data .. bin.pack(">S", TLV.SWVER)
+ data = data .. bin.pack(">S", 0x0008)
+ data = data .. bin.pack(">CC", tonumber(tlv.majv), tonumber(tlv.minv))
+ data = data .. bin.pack(">CC", tonumber(tlv.majtlv), tonumber(tlv.mintlv))
+ elseif tlv.type == TLV.MSEQ then
+ -- TODO
+ stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
+ elseif tlv.type == TLV.STUB then
+ -- TODO
+ stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
+ elseif tlv.type == TLV.TERM then
+ -- TODO
+ stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
+ elseif tlv.type == TLV.TIDLIST then
+ -- TODO
+ stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
+ elseif tlv.type == TLV.REQ then
+ -- TODO
+ stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
+ elseif tlv.type == TLV.INT then
+ -- TODO
+ stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
+ elseif tlv.type == TLV.EXT then
+ -- TODO
+ stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
+ elseif tlv.type == TLV.COM then
+ -- TODO
+ stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
+ elseif tlv.type == TLV.INT6 then
+ -- TODO
+ stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
+ elseif tlv.type == TLV.EXT6 then
+ -- TODO
+ stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
+ elseif tlv.type == TLV.COM6 then
+ -- TODO
+ stdnse.print_debug("eigrp.lua: TLV type %d skipped due to no parser.", tlv.type)
+ else
+ stdnse.print_debug("eigrp.lua: TLV type %d unknown.", tlv.type)
+ end
+ end
+ -- In the end, correct the checksum if not manually set
+ if not self.checksum then
+ data = data:sub(1,2) .. bin.pack(">S", packet.in_cksum(data)) .. data:sub(5)
+ end
+ return data
end,
-}
+ }
-return _ENV;
+ return _ENV;
diff --git a/nselib/ftp.lua b/nselib/ftp.lua
index f962af06c..afb715663 100644
--- a/nselib/ftp.lua
+++ b/nselib/ftp.lua
@@ -40,42 +40,42 @@ end
-- @return numeric code or nil.
-- @return text reply or error message.
function read_reply(buffer)
- local readline
- local line, err
- local code, message
- local _, p, tmp
+ local readline
+ local line, err
+ local code, message
+ local _, p, tmp
- line, err = buffer()
- if not line then
- return line, err
- end
+ line, err = buffer()
+ if not line then
+ return line, err
+ end
- -- Single-line response?
- code, message = string.match(line, "^(%d%d%d) (.*)$")
- if code then
- return tonumber(code), message
- end
+ -- Single-line response?
+ code, message = string.match(line, "^(%d%d%d) (.*)$")
+ if code then
+ return tonumber(code), message
+ end
- -- Multi-line response?
- _, p, code, message = string.find(line, "^(%d%d%d)%-(.*)$")
- if p then
- while true do
- line, err = buffer()
- if not line then
- return line, err
- end
- tmp = string.match(line, "^%d%d%d (.*)$")
- if tmp then
- message = message .. "\n" .. tmp
- break
- end
- message = message .. "\n" .. line
- end
+ -- Multi-line response?
+ _, p, code, message = string.find(line, "^(%d%d%d)%-(.*)$")
+ if p then
+ while true do
+ line, err = buffer()
+ if not line then
+ return line, err
+ end
+ tmp = string.match(line, "^%d%d%d (.*)$")
+ if tmp then
+ message = message .. "\n" .. tmp
+ break
+ end
+ message = message .. "\n" .. line
+ end
- return tonumber(code), message
- end
+ return tonumber(code), message
+ end
- return nil, string.format("Unparseable response: %q", line)
+ return nil, string.format("Unparseable response: %q", line)
end
return _ENV;
diff --git a/nselib/gps.lua b/nselib/gps.lua
index 85870d278..b47005178 100644
--- a/nselib/gps.lua
+++ b/nselib/gps.lua
@@ -15,106 +15,106 @@ _ENV = stdnse.module("gps", stdnse.seeall)
NMEA = {
- -- Parser for the RMC sentence
- RMC = {
+ -- Parser for the RMC sentence
+ RMC = {
- parse = function(str)
+ parse = function(str)
- local time, status, latitude, ns_indicator, longitude,
- ew_indicator, speed, course, date, variation,
- ew_variation, checksum = str:match("^%$GPRMC,([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^%*]*)(.*)$")
+ local time, status, latitude, ns_indicator, longitude,
+ ew_indicator, speed, course, date, variation,
+ ew_variation, checksum = str:match("^%$GPRMC,([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^%*]*)(.*)$")
- if ( not(latitude) or not(longitude) ) then
- return
- end
+ if ( not(latitude) or not(longitude) ) then
+ return
+ end
- local deg, min = latitude:match("^(..)(.*)$")
- if ( not(deg) or not(min) ) then
- return
- end
- latitude = tonumber(deg) + (tonumber(min)/60)
+ local deg, min = latitude:match("^(..)(.*)$")
+ if ( not(deg) or not(min) ) then
+ return
+ end
+ latitude = tonumber(deg) + (tonumber(min)/60)
- deg, min = longitude:match("^(..)(.*)$")
- if ( not(deg) or not(min) ) then
- return
- end
- longitude = tonumber(deg) + (tonumber(min)/60)
- if ( ew_indicator == 'W' ) then
- longitude = -longitude
- end
+ deg, min = longitude:match("^(..)(.*)$")
+ if ( not(deg) or not(min) ) then
+ return
+ end
+ longitude = tonumber(deg) + (tonumber(min)/60)
+ if ( ew_indicator == 'W' ) then
+ longitude = -longitude
+ end
- if ( ns_indicator == 'S' ) then
- latitude = -latitude
- end
+ if ( ns_indicator == 'S' ) then
+ latitude = -latitude
+ end
- return { time = time, status = status, latitude = latitude,
- longitude = longitude, speed = speed, course = course,
- date = date, variation = variation,
- ew_variation = ew_variation }
- end,
+ return { time = time, status = status, latitude = latitude,
+ longitude = longitude, speed = speed, course = course,
+ date = date, variation = variation,
+ ew_variation = ew_variation }
+ end,
- },
+ },
- -- Calculates an verifies the message checksum
- --
- -- @param str containing the GPS sentence
- -- @return status true on success, false if the checksum does not match
- -- @return err string if status is false
- checksum = function(str)
- local val = 0
- for c in str:sub(2,-4):gmatch(".") do
- val = bit.bxor(val, string.byte(c))
- end
+ -- Calculates an verifies the message checksum
+ --
+ -- @param str containing the GPS sentence
+ -- @return status true on success, false if the checksum does not match
+ -- @return err string if status is false
+ checksum = function(str)
+ local val = 0
+ for c in str:sub(2,-4):gmatch(".") do
+ val = bit.bxor(val, string.byte(c))
+ end
- if ( str:sub(-2):upper() ~= stdnse.tohex(string.char(val)):upper() ) then
- return false, ("Failed to verify checksum (got: %s; expected: %s)"):format(stdnse.tohex(string.char(val)), str:sub(-2))
- end
- return true
- end,
+ if ( str:sub(-2):upper() ~= stdnse.tohex(string.char(val)):upper() ) then
+ return false, ("Failed to verify checksum (got: %s; expected: %s)"):format(stdnse.tohex(string.char(val)), str:sub(-2))
+ end
+ return true
+ end,
- -- Parses a GPS sentence using the apropriate parser
- --
- -- @param str containing the GPS sentence
- -- @return entry table containing the parsed response or
- -- err string if status is false
- -- @return status true on success, false on failure
- parse = function(str)
+ -- Parses a GPS sentence using the apropriate parser
+ --
+ -- @param str containing the GPS sentence
+ -- @return entry table containing the parsed response or
+ -- err string if status is false
+ -- @return status true on success, false on failure
+ parse = function(str)
- local status, err = NMEA.checksum(str)
- if ( not(status) ) then
- return false, err
- end
+ local status, err = NMEA.checksum(str)
+ if ( not(status) ) then
+ return false, err
+ end
- local prefix = str:match("^%$GP([^,]*)")
- if ( not(prefix) ) then
- return false, "Not a NMEA sentence"
- end
+ local prefix = str:match("^%$GP([^,]*)")
+ if ( not(prefix) ) then
+ return false, "Not a NMEA sentence"
+ end
- if ( NMEA[prefix] and NMEA[prefix].parse ) then
- local e = NMEA[prefix].parse(str)
- if (not(e)) then
- return false, ("Failed to parse entry: %s"):format(str)
- end
- return true, e
- else
- local err = ("No parser for prefix: %s"):format(prefix)
- stdnse.print_debug(2, err)
- return false, err
- end
+ if ( NMEA[prefix] and NMEA[prefix].parse ) then
+ local e = NMEA[prefix].parse(str)
+ if (not(e)) then
+ return false, ("Failed to parse entry: %s"):format(str)
+ end
+ return true, e
+ else
+ local err = ("No parser for prefix: %s"):format(prefix)
+ stdnse.print_debug(2, err)
+ return false, err
+ end
- end
+ end
}
Util = {
- convertTime = function(date, time)
- local d = {}
- d.hour, d.min, d.sec = time:match("(..)(..)(..)")
- d.day, d.month, d.year = date:match("(..)(..)(..)")
- d.year = d.year + 2000
- return os.time(d)
- end
+ convertTime = function(date, time)
+ local d = {}
+ d.hour, d.min, d.sec = time:match("(..)(..)(..)")
+ d.day, d.month, d.year = date:match("(..)(..)(..)")
+ d.year = d.year + 2000
+ return os.time(d)
+ end
}
return _ENV;
diff --git a/nselib/iax2.lua b/nselib/iax2.lua
index 34f8474af..4f8f2f273 100644
--- a/nselib/iax2.lua
+++ b/nselib/iax2.lua
@@ -18,324 +18,324 @@ _ENV = stdnse.module("iax2", stdnse.seeall)
IAX2 = {
- FrameType = {
- IAX = 6,
- },
+ FrameType = {
+ IAX = 6,
+ },
- SubClass = {
- ACK = 0x04,
- REGACK = 0x0f,
- REGREJ = 0x10,
- REGREL = 0x11,
- CALLTOKEN = 0x28,
- },
+ SubClass = {
+ ACK = 0x04,
+ REGACK = 0x0f,
+ REGREJ = 0x10,
+ REGREL = 0x11,
+ CALLTOKEN = 0x28,
+ },
- InfoElement = {
- USERNAME = 0x06,
- CHALLENGE = 0x0f,
- MD5_RESULT = 0x10,
- CALLTOKEN = 0x36,
- },
+ InfoElement = {
+ USERNAME = 0x06,
+ CHALLENGE = 0x0f,
+ MD5_RESULT = 0x10,
+ CALLTOKEN = 0x36,
+ },
- PacketType = {
- FULL = 1,
- },
+ PacketType = {
+ FULL = 1,
+ },
- -- The IAX2 Header
- Header = {
+ -- The IAX2 Header
+ Header = {
- -- Creates a new Header instance
- -- @param src_call number containing the source call
- -- @param dst_call number containing the dest call
- -- @param timestamp number containing a timestamp
- -- @param oseqno number containing the seqno of outgoing packets
- -- @param iseqno number containing the seqno of incoming packets
- -- @param frametype number containing the frame type
- -- @param subclass number containing the subclass type
- new = function(self, src_call, dst_call, timestamp, oseqno, iseqno, frametype, subclass)
- local o = {
- type = IAX2.PacketType.FULL,
- retrans = false,
- src_call = src_call,
- dst_call = dst_call,
- timestamp = timestamp,
- oseqno = oseqno,
- iseqno = iseqno,
- frametype = frametype,
- subclass = subclass,
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new Header instance
+ -- @param src_call number containing the source call
+ -- @param dst_call number containing the dest call
+ -- @param timestamp number containing a timestamp
+ -- @param oseqno number containing the seqno of outgoing packets
+ -- @param iseqno number containing the seqno of incoming packets
+ -- @param frametype number containing the frame type
+ -- @param subclass number containing the subclass type
+ new = function(self, src_call, dst_call, timestamp, oseqno, iseqno, frametype, subclass)
+ local o = {
+ type = IAX2.PacketType.FULL,
+ retrans = false,
+ src_call = src_call,
+ dst_call = dst_call,
+ timestamp = timestamp,
+ oseqno = oseqno,
+ iseqno = iseqno,
+ frametype = frametype,
+ subclass = subclass,
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Parses data, a byte string, and creates a new Header instance
- -- @return header instance of Header
- parse = function(data)
- local header = IAX2.Header:new()
- local pos, frame_type = bin.unpack("C", data)
- if ( bit.band(frame_type, 0x80) == 0 ) then
- print("frame_type", stdnse.tohex(frame_type))
- stdnse.print_debug(2, "Frametype not supported")
- return
- end
- header.type = IAX2.PacketType.FULL
- pos, header.src_call = bin.unpack(">S", data)
- header.src_call = bit.band(header.src_call, 0x7FFF)
+ -- Parses data, a byte string, and creates a new Header instance
+ -- @return header instance of Header
+ parse = function(data)
+ local header = IAX2.Header:new()
+ local pos, frame_type = bin.unpack("C", data)
+ if ( bit.band(frame_type, 0x80) == 0 ) then
+ print("frame_type", stdnse.tohex(frame_type))
+ stdnse.print_debug(2, "Frametype not supported")
+ return
+ end
+ header.type = IAX2.PacketType.FULL
+ pos, header.src_call = bin.unpack(">S", data)
+ header.src_call = bit.band(header.src_call, 0x7FFF)
- local retrans
- pos, retrans = bin.unpack("C", data, pos)
- if ( bit.band(retrans, 0x80) == 8 ) then
- header.retrans = true
- end
- pos, header.dst_call = bin.unpack(">S", data, pos - 1)
- header.dst_call = bit.band(header.dst_call, 0x7FFF)
+ local retrans
+ pos, retrans = bin.unpack("C", data, pos)
+ if ( bit.band(retrans, 0x80) == 8 ) then
+ header.retrans = true
+ end
+ pos, header.dst_call = bin.unpack(">S", data, pos - 1)
+ header.dst_call = bit.band(header.dst_call, 0x7FFF)
- pos, header.timestamp, header.oseqno,
- header.iseqno, header.frametype, header.subclass = bin.unpack(">ICCCC", data, pos)
+ pos, header.timestamp, header.oseqno,
+ header.iseqno, header.frametype, header.subclass = bin.unpack(">ICCCC", data, pos)
- return header
- end,
+ return header
+ end,
- -- Converts the instance to a string
- -- @return str containing the instance
- __tostring = function(self)
- assert(self.src_call < 32767, "Source call exceeds 32767")
- assert(self.dst_call < 32767, "Dest call exceeds 32767")
- local src_call = self.src_call
- local dst_call = self.dst_call
- if ( self.type == IAX2.PacketType.FULL ) then
- src_call = src_call + 32768
- end
- if ( self.retrans ) then
- dst_call = dst_call + 32768
- end
- return bin.pack(">SSICCCC", src_call, dst_call, self.timestamp,
- self.oseqno, self.iseqno, self.frametype, self.subclass)
- end,
- },
+ -- Converts the instance to a string
+ -- @return str containing the instance
+ __tostring = function(self)
+ assert(self.src_call < 32767, "Source call exceeds 32767")
+ assert(self.dst_call < 32767, "Dest call exceeds 32767")
+ local src_call = self.src_call
+ local dst_call = self.dst_call
+ if ( self.type == IAX2.PacketType.FULL ) then
+ src_call = src_call + 32768
+ end
+ if ( self.retrans ) then
+ dst_call = dst_call + 32768
+ end
+ return bin.pack(">SSICCCC", src_call, dst_call, self.timestamp,
+ self.oseqno, self.iseqno, self.frametype, self.subclass)
+ end,
+ },
- -- The IAX2 Request class
- Request = {
+ -- The IAX2 Request class
+ Request = {
- -- Creates a new instance
- -- @param header instance of Header
- new = function(self, header)
- local o = {
- header = header,
- ies = {}
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new instance
+ -- @param header instance of Header
+ new = function(self, header)
+ local o = {
+ header = header,
+ ies = {}
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Sets an Info Element or adds one, in case it's missing
- -- @param key the key value of the IE to add
- -- @param value string containing the value to set or add
- setIE = function(self, key, value)
- for _, ie in ipairs(self.ies or {}) do
- if ( key == ie.type ) then
- ie.value = value
- end
- end
- table.insert(self.ies, { type = key, value = value } )
- end,
+ -- Sets an Info Element or adds one, in case it's missing
+ -- @param key the key value of the IE to add
+ -- @param value string containing the value to set or add
+ setIE = function(self, key, value)
+ for _, ie in ipairs(self.ies or {}) do
+ if ( key == ie.type ) then
+ ie.value = value
+ end
+ end
+ table.insert(self.ies, { type = key, value = value } )
+ end,
- -- Gets an information element
- -- @param key number containing the element number to retrieve
- -- @return ie table containing the info element if it exists
- getIE = function(self, key)
- for _, ie in ipairs(self.ies or {}) do
- if ( key == ie.type ) then
- return ie
- end
- end
- end,
+ -- Gets an information element
+ -- @param key number containing the element number to retrieve
+ -- @return ie table containing the info element if it exists
+ getIE = function(self, key)
+ for _, ie in ipairs(self.ies or {}) do
+ if ( key == ie.type ) then
+ return ie
+ end
+ end
+ end,
- -- Converts the instance to a string
- -- @return str containing the instance
- __tostring = function(self)
- local data = ""
- for _, ie in ipairs(self.ies) do
- data = data .. bin.pack("Cp", ie.type, ie.value )
- end
+ -- Converts the instance to a string
+ -- @return str containing the instance
+ __tostring = function(self)
+ local data = ""
+ for _, ie in ipairs(self.ies) do
+ data = data .. bin.pack("Cp", ie.type, ie.value )
+ end
- return tostring(self.header) .. data
- end,
+ return tostring(self.header) .. data
+ end,
- },
+ },
- -- The IAX2 Response
- Response = {
+ -- The IAX2 Response
+ Response = {
- -- Creates a new instance
- new = function(self)
- local o = { ies = {} }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new instance
+ new = function(self)
+ local o = { ies = {} }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Sets an Info Element or adds one, in case it's missing
- -- @param key the key value of the IE to add
- -- @param value string containing the value to set or add
- setIE = function(self, key, value)
- for _, ie in ipairs(self.ies or {}) do
- if ( key == ie.type ) then
- ie.value = value
- end
- end
- table.insert(self.ies, { type = key, value = value } )
- end,
+ -- Sets an Info Element or adds one, in case it's missing
+ -- @param key the key value of the IE to add
+ -- @param value string containing the value to set or add
+ setIE = function(self, key, value)
+ for _, ie in ipairs(self.ies or {}) do
+ if ( key == ie.type ) then
+ ie.value = value
+ end
+ end
+ table.insert(self.ies, { type = key, value = value } )
+ end,
- -- Gets an information element
- -- @param key number containing the element number to retrieve
- -- @return ie table containing the info element if it exists
- getIE = function(self, key)
- for _, ie in ipairs(self.ies or {}) do
- if ( key == ie.type ) then
- return ie
- end
- end
- end,
+ -- Gets an information element
+ -- @param key number containing the element number to retrieve
+ -- @return ie table containing the info element if it exists
+ getIE = function(self, key)
+ for _, ie in ipairs(self.ies or {}) do
+ if ( key == ie.type ) then
+ return ie
+ end
+ end
+ end,
- -- Parses data, a byte string, and creates a response
- -- @return resp instance of response
- parse = function(data)
- local resp = IAX2.Response:new()
- if ( not(resp) ) then return end
+ -- Parses data, a byte string, and creates a response
+ -- @return resp instance of response
+ parse = function(data)
+ local resp = IAX2.Response:new()
+ if ( not(resp) ) then return end
- resp.header = IAX2.Header.parse(data)
- if ( not(resp.header) ) then return end
+ resp.header = IAX2.Header.parse(data)
+ if ( not(resp.header) ) then return end
- local pos = 13
- resp.ies = {}
- repeat
- local ie = {}
- pos, ie.type, ie.value = bin.unpack(">Cp", data, pos)
- table.insert(resp.ies, ie)
- until( pos > #data )
- return resp
- end,
+ local pos = 13
+ resp.ies = {}
+ repeat
+ local ie = {}
+ pos, ie.type, ie.value = bin.unpack(">Cp", data, pos)
+ table.insert(resp.ies, ie)
+ until( pos > #data )
+ return resp
+ end,
- }
+ }
}
Helper = {
- -- Creates a new Helper instance
- -- @param host table as received by the action method
- -- @param port table as received by the action method
- -- @param options table containing helper options, currently
- -- timeout socket timeout in ms
- -- @return o instance of Helper
- new = function(self, host, port, options)
- local o = { host = host, port = port, options = options or {} }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new Helper instance
+ -- @param host table as received by the action method
+ -- @param port table as received by the action method
+ -- @param options table containing helper options, currently
+ -- timeout socket timeout in ms
+ -- @return o instance of Helper
+ new = function(self, host, port, options)
+ local o = { host = host, port = port, options = options or {} }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Connects the UDP socket to the server
- -- @return status true on success, false on failure
- -- @return err message containing error if status is false
- connect = function(self)
- self.socket = nmap.new_socket()
- self.socket:set_timeout(self.options.timeout or 5000)
- return self.socket:connect(self.host, self.port)
- end,
+ -- Connects the UDP socket to the server
+ -- @return status true on success, false on failure
+ -- @return err message containing error if status is false
+ connect = function(self)
+ self.socket = nmap.new_socket()
+ self.socket:set_timeout(self.options.timeout or 5000)
+ return self.socket:connect(self.host, self.port)
+ end,
- -- Sends a request to the server and receives the response
- -- @param req instance containing the request to send to the server
- -- @return status true on success, false on failure
- -- @return resp instance of response on success,
- -- err containing the error message on failure
- exch = function(self, req)
- local status, err = self.socket:send(tostring(req))
- if ( not(status) ) then
- return false, "Failed to send request to server"
- end
- local status, data = self.socket:receive()
- if ( not(status) ) then
- return false, "Failed to receive response from server"
- end
+ -- Sends a request to the server and receives the response
+ -- @param req instance containing the request to send to the server
+ -- @return status true on success, false on failure
+ -- @return resp instance of response on success,
+ -- err containing the error message on failure
+ exch = function(self, req)
+ local status, err = self.socket:send(tostring(req))
+ if ( not(status) ) then
+ return false, "Failed to send request to server"
+ end
+ local status, data = self.socket:receive()
+ if ( not(status) ) then
+ return false, "Failed to receive response from server"
+ end
- local resp = IAX2.Response.parse(data)
- return true, resp
- end,
+ local resp = IAX2.Response.parse(data)
+ return true, resp
+ end,
- -- Request a session release
- -- @param username string containing the extention (username)
- -- @param password string containing the password
- regRelease = function(self, username, password)
+ -- Request a session release
+ -- @param username string containing the extention (username)
+ -- @param password string containing the password
+ regRelease = function(self, username, password)
- local src_call = math.random(32767)
- local header = IAX2.Header:new(src_call, 0, os.time(), 0, 0, IAX2.FrameType.IAX, IAX2.SubClass.REGREL)
- local regrel = IAX2.Request:new(header)
+ local src_call = math.random(32767)
+ local header = IAX2.Header:new(src_call, 0, os.time(), 0, 0, IAX2.FrameType.IAX, IAX2.SubClass.REGREL)
+ local regrel = IAX2.Request:new(header)
- regrel:setIE(IAX2.InfoElement.USERNAME, username)
- regrel:setIE(IAX2.InfoElement.CALLTOKEN, "")
+ regrel:setIE(IAX2.InfoElement.USERNAME, username)
+ regrel:setIE(IAX2.InfoElement.CALLTOKEN, "")
- local status, resp = self:exch(regrel)
- if ( not(status) ) then
- return false, resp
- end
+ local status, resp = self:exch(regrel)
+ if ( not(status) ) then
+ return false, resp
+ end
- if ( not(resp) or IAX2.SubClass.CALLTOKEN ~= resp.header.subclass ) then
- return false, "Unexpected response"
- end
+ if ( not(resp) or IAX2.SubClass.CALLTOKEN ~= resp.header.subclass ) then
+ return false, "Unexpected response"
+ end
- local token = resp:getIE(IAX2.InfoElement.CALLTOKEN)
- if ( not(token) ) then
- return false, "Failed to get token"
- end
+ local token = resp:getIE(IAX2.InfoElement.CALLTOKEN)
+ if ( not(token) ) then
+ return false, "Failed to get token"
+ end
- regrel:setIE(IAX2.InfoElement.CALLTOKEN, token.value)
- status, resp = self:exch(regrel)
- if ( not(status) ) then
- return false, resp
- end
+ regrel:setIE(IAX2.InfoElement.CALLTOKEN, token.value)
+ status, resp = self:exch(regrel)
+ if ( not(status) ) then
+ return false, resp
+ end
- local challenge = resp:getIE(IAX2.InfoElement.CHALLENGE)
- if ( not(challenge) ) then
- return false, "Failed to retrieve challenge from server"
- end
+ local challenge = resp:getIE(IAX2.InfoElement.CHALLENGE)
+ if ( not(challenge) ) then
+ return false, "Failed to retrieve challenge from server"
+ end
- regrel.header.iseqno = 1
- regrel.header.oseqno = 1
- regrel.header.dst_call = resp.header.src_call
- regrel.ies = {}
+ regrel.header.iseqno = 1
+ regrel.header.oseqno = 1
+ regrel.header.dst_call = resp.header.src_call
+ regrel.ies = {}
- local hash = stdnse.tohex(openssl.md5(challenge.value .. password))
- regrel:setIE(IAX2.InfoElement.USERNAME, username)
- regrel:setIE(IAX2.InfoElement.MD5_RESULT, hash)
+ local hash = stdnse.tohex(openssl.md5(challenge.value .. password))
+ regrel:setIE(IAX2.InfoElement.USERNAME, username)
+ regrel:setIE(IAX2.InfoElement.MD5_RESULT, hash)
- status, resp = self:exch(regrel)
- if ( not(status) ) then
- return false, resp
- end
+ status, resp = self:exch(regrel)
+ if ( not(status) ) then
+ return false, resp
+ end
- if ( IAX2.SubClass.ACK == resp.header.subclass ) then
- local data
- status, data = self.socket:receive()
- resp = IAX2.Response.parse(data)
- end
+ if ( IAX2.SubClass.ACK == resp.header.subclass ) then
+ local data
+ status, data = self.socket:receive()
+ resp = IAX2.Response.parse(data)
+ end
- if ( status and IAX2.SubClass.REGACK == resp.header.subclass ) then
- return true
- end
- return false, "Release failed"
- end,
+ if ( status and IAX2.SubClass.REGACK == resp.header.subclass ) then
+ return true
+ end
+ return false, "Release failed"
+ end,
- -- Close the connection with the server
- -- @return true on success, false on failure
- close = function(self)
- return self.socket:close()
- end,
+ -- Close the connection with the server
+ -- @return true on success, false on failure
+ close = function(self)
+ return self.socket:close()
+ end,
}
diff --git a/nselib/imap.lua b/nselib/imap.lua
index f75bccf38..37f3fbbee 100644
--- a/nselib/imap.lua
+++ b/nselib/imap.lua
@@ -10,19 +10,19 @@
--
-- The following example illustrates the reommended use of the library:
--
--- local helper = imap.Helper:new(host, port)
--- helper:connect()
--- helper:login("user","password","PLAIN")
--- helper:close()
+-- local helper = imap.Helper:new(host, port)
+-- helper:connect()
+-- helper:login("user","password","PLAIN")
+-- helper:close()
--
--
-- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html
-- @author = "Brandon Enright, Patrik Karlsson"
-- Version 0.2
--- Revised 07/15/2011 - v0.2 - added the IMAP and Helper classes
--- added support for LOGIN and AUTHENTICATE
---
+-- Revised 07/15/2011 - v0.2 - added the IMAP and Helper classes
+-- added support for LOGIN and AUTHENTICATE
+--
local base64 = require "base64"
local comm = require "comm"
@@ -34,192 +34,192 @@ _ENV = stdnse.module("imap", stdnse.seeall)
IMAP = {
- --- Creates a new instance of the IMAP class
- --
- -- @param host table as received by the script action method
- -- @param port table as received by the script action method
- -- @param options table containing options, currently
- -- timeout - number containing the seconds to wait for
- -- a response
- new = function(self, host, port, options)
- local o = {
- host = host,
- port = port,
- counter = 1,
- timeout = ( options and options.timeout ) or 10000
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ --- Creates a new instance of the IMAP class
+ --
+ -- @param host table as received by the script action method
+ -- @param port table as received by the script action method
+ -- @param options table containing options, currently
+ -- timeout - number containing the seconds to wait for
+ -- a response
+ new = function(self, host, port, options)
+ local o = {
+ host = host,
+ port = port,
+ counter = 1,
+ timeout = ( options and options.timeout ) or 10000
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- --- Receives a response from the IMAP server
- --
- -- @return status true on success, false on failure
- -- @return data string containing the received data
- receive = function(self)
- local data = ""
- repeat
- local status, tmp = self.socket:receive_buf("\r\n", false)
- if( not(status) ) then return false, tmp end
- data = data .. tmp
- until( tmp:match(("^A%04d"):format(self.counter - 1)) or tmp:match("^%+"))
+ --- Receives a response from the IMAP server
+ --
+ -- @return status true on success, false on failure
+ -- @return data string containing the received data
+ receive = function(self)
+ local data = ""
+ repeat
+ local status, tmp = self.socket:receive_buf("\r\n", false)
+ if( not(status) ) then return false, tmp end
+ data = data .. tmp
+ until( tmp:match(("^A%04d"):format(self.counter - 1)) or tmp:match("^%+"))
- return true, data
- end,
+ return true, data
+ end,
- --- Sends a request to the IMAP server
- --
- -- @param cmd string containing the command to send to the server eg.
- -- eg. (AUTHENTICATE, LOGIN)
- -- @param params string containing the command parameters
- -- @return true on success, false on failure
- -- @return err string containing the error if status was false
- send = function(self, cmd, params)
- local data
- if ( not(params) ) then
- data = ("A%04d %s\r\n"):format(self.counter, cmd)
- else
- data = ("A%04d %s %s\r\n"):format(self.counter, cmd, params)
- end
- local status, err = self.socket:send(data)
- if ( not(status) ) then return false, err end
- self.counter = self.counter + 1
- return true
- end,
+ --- Sends a request to the IMAP server
+ --
+ -- @param cmd string containing the command to send to the server eg.
+ -- eg. (AUTHENTICATE, LOGIN)
+ -- @param params string containing the command parameters
+ -- @return true on success, false on failure
+ -- @return err string containing the error if status was false
+ send = function(self, cmd, params)
+ local data
+ if ( not(params) ) then
+ data = ("A%04d %s\r\n"):format(self.counter, cmd)
+ else
+ data = ("A%04d %s %s\r\n"):format(self.counter, cmd, params)
+ end
+ local status, err = self.socket:send(data)
+ if ( not(status) ) then return false, err end
+ self.counter = self.counter + 1
+ return true
+ end,
- --- Connect to the server
- --
- -- @return status true on success, false on failure
- -- @return banner string containing the server banner
- connect = function(self)
- local socket, banner, opt = comm.tryssl( self.host, self.port, "", { recv_before = true } )
- if ( not(socket) ) then return false, "ERROR: Failed to connect to server" end
- socket:set_timeout(self.timeout)
- if ( not(socket) or not(banner) ) then return false, "ERROR: Failed to connect to server" end
- self.socket = socket
- return true, banner
- end,
+ --- Connect to the server
+ --
+ -- @return status true on success, false on failure
+ -- @return banner string containing the server banner
+ connect = function(self)
+ local socket, banner, opt = comm.tryssl( self.host, self.port, "", { recv_before = true } )
+ if ( not(socket) ) then return false, "ERROR: Failed to connect to server" end
+ socket:set_timeout(self.timeout)
+ if ( not(socket) or not(banner) ) then return false, "ERROR: Failed to connect to server" end
+ self.socket = socket
+ return true, banner
+ end,
- --- Authenticate to the server (non PLAIN text mode)
- -- Currently supported algorithms are CRAM-MD5 and CRAM-SHA1
- --
- -- @param username string containing the username
- -- @param pass string containing the password
- -- @param mech string containing a authentication mechanism, currently
- -- CRAM-MD5 or CRAM-SHA1
- -- @return status true if login was successful, false on failure
- -- @return err string containing the error message if status was false
- authenticate = function(self, username, pass, mech)
- assert( mech == "NTLM" or
- mech == "DIGEST-MD5" or
- mech == "CRAM-MD5" or
- mech == "PLAIN",
- "Unsupported authentication mechanism")
+ --- Authenticate to the server (non PLAIN text mode)
+ -- Currently supported algorithms are CRAM-MD5 and CRAM-SHA1
+ --
+ -- @param username string containing the username
+ -- @param pass string containing the password
+ -- @param mech string containing a authentication mechanism, currently
+ -- CRAM-MD5 or CRAM-SHA1
+ -- @return status true if login was successful, false on failure
+ -- @return err string containing the error message if status was false
+ authenticate = function(self, username, pass, mech)
+ assert( mech == "NTLM" or
+ mech == "DIGEST-MD5" or
+ mech == "CRAM-MD5" or
+ mech == "PLAIN",
+ "Unsupported authentication mechanism")
- local status, err = self:send("AUTHENTICATE", mech)
+ local status, err = self:send("AUTHENTICATE", mech)
- if( not(status) ) then return false, "ERROR: Failed to send data" end
+ if( not(status) ) then return false, "ERROR: Failed to send data" end
- local status, data = self:receive()
- if( not(status) ) then return false, "ERROR: Failed to receive challenge" end
+ local status, data = self:receive()
+ if( not(status) ) then return false, "ERROR: Failed to receive challenge" end
- if ( mech == "NTLM" ) then
- -- sniffed of the wire, seems to always be the same
- -- decodes to some NTLMSSP blob greatness
- status, data = self.socket:send("TlRMTVNTUAABAAAAB7IIogYABgA3AAAADwAPACgAAAAFASgKAAAAD0FCVVNFLUFJUi5MT0NBTERPTUFJTg==\r\n")
- if ( not(status) ) then return false, "ERROR: Failed to send NTLM packet" end
- status, data = self:receive()
- if ( not(status) ) then return false, "ERROR: Failed to receieve NTLM challenge" end
- end
+ if ( mech == "NTLM" ) then
+ -- sniffed of the wire, seems to always be the same
+ -- decodes to some NTLMSSP blob greatness
+ status, data = self.socket:send("TlRMTVNTUAABAAAAB7IIogYABgA3AAAADwAPACgAAAAFASgKAAAAD0FCVVNFLUFJUi5MT0NBTERPTUFJTg==\r\n")
+ if ( not(status) ) then return false, "ERROR: Failed to send NTLM packet" end
+ status, data = self:receive()
+ if ( not(status) ) then return false, "ERROR: Failed to receieve NTLM challenge" end
+ end
- if ( data:match(("^A%04d "):format(self.counter-1)) ) then
- return false, "ERROR: Authentication mechanism not supported"
- end
+ if ( data:match(("^A%04d "):format(self.counter-1)) ) then
+ return false, "ERROR: Authentication mechanism not supported"
+ end
- local digest, auth_data
- if ( not(data:match("^+")) ) then
- return false, "ERROR: Failed to receive proper response from server"
- end
- data = base64.dec(data:match("^+ (.*)"))
+ local digest, auth_data
+ if ( not(data:match("^+")) ) then
+ return false, "ERROR: Failed to receive proper response from server"
+ end
+ data = base64.dec(data:match("^+ (.*)"))
- -- All mechanisms expect username and pass
- -- add the otheronce for those who need them
- local mech_params = { username, pass, data, "imap" }
- auth_data = sasl.Helper:new(mech):encode(table.unpack(mech_params))
- auth_data = base64.enc(auth_data) .. "\r\n"
+ -- All mechanisms expect username and pass
+ -- add the otheronce for those who need them
+ local mech_params = { username, pass, data, "imap" }
+ auth_data = sasl.Helper:new(mech):encode(table.unpack(mech_params))
+ auth_data = base64.enc(auth_data) .. "\r\n"
- status, data = self.socket:send(auth_data)
- if( not(status) ) then return false, "ERROR: Failed to send data" end
+ status, data = self.socket:send(auth_data)
+ if( not(status) ) then return false, "ERROR: Failed to send data" end
- status, data = self:receive()
- if( not(status) ) then return false, "ERROR: Failed to receive data" end
+ status, data = self:receive()
+ if( not(status) ) then return false, "ERROR: Failed to receive data" end
- if ( mech == "DIGEST-MD5" ) then
- local rspauth = data:match("^+ (.*)")
- if ( rspauth ) then
- rspauth = base64.dec(rspauth)
- status, data = self.socket:send("\r\n")
- status, data = self:receive()
- end
- end
- if ( data:match(("^A%04d OK"):format(self.counter - 1)) ) then
- return true
- end
- return false, "Login failed"
- end,
+ if ( mech == "DIGEST-MD5" ) then
+ local rspauth = data:match("^+ (.*)")
+ if ( rspauth ) then
+ rspauth = base64.dec(rspauth)
+ status, data = self.socket:send("\r\n")
+ status, data = self:receive()
+ end
+ end
+ if ( data:match(("^A%04d OK"):format(self.counter - 1)) ) then
+ return true
+ end
+ return false, "Login failed"
+ end,
- --- Login to the server using PLAIN text authentication
- --
- -- @param username string containing the username
- -- @param password string containing the password
- -- @return status true on success, false on failure
- -- @return err string containing the error message if status was false
- login = function(self, username, password)
- local status, err = self:send("LOGIN", ("\"%s\" \"%s\""):format(username, password))
- if( not(status) ) then return false, "ERROR: Failed to send data" end
+ --- Login to the server using PLAIN text authentication
+ --
+ -- @param username string containing the username
+ -- @param password string containing the password
+ -- @return status true on success, false on failure
+ -- @return err string containing the error message if status was false
+ login = function(self, username, password)
+ local status, err = self:send("LOGIN", ("\"%s\" \"%s\""):format(username, password))
+ if( not(status) ) then return false, "ERROR: Failed to send data" end
- local status, data = self:receive()
- if( not(status) ) then return false, "ERROR: Failed to receive data" end
+ local status, data = self:receive()
+ if( not(status) ) then return false, "ERROR: Failed to receive data" end
- if ( data:match(("^A%04d OK"):format(self.counter - 1)) ) then
- return true
- end
- return false, "Login failed"
- end,
+ if ( data:match(("^A%04d OK"):format(self.counter - 1)) ) then
+ return true
+ end
+ return false, "Login failed"
+ end,
- --- Retrieves a list of server capabilities (eg. supported authentication
- -- mechanisms, QUOTA, UIDPLUS, ACL ...)
- --
- -- @return status true on success, false on failure
- -- @return capas array containing the capabilities that are supported
- capabilities = function(self)
- local capas = {}
- local proto = (self.port.version and self.port.version.service_tunnel == "ssl" and "ssl") or "tcp"
- local status, err = self:send("CAPABILITY")
- if( not(status) ) then return false, err end
+ --- Retrieves a list of server capabilities (eg. supported authentication
+ -- mechanisms, QUOTA, UIDPLUS, ACL ...)
+ --
+ -- @return status true on success, false on failure
+ -- @return capas array containing the capabilities that are supported
+ capabilities = function(self)
+ local capas = {}
+ local proto = (self.port.version and self.port.version.service_tunnel == "ssl" and "ssl") or "tcp"
+ local status, err = self:send("CAPABILITY")
+ if( not(status) ) then return false, err end
- local status, line = self:receive()
- if (not(status)) then
- capas.CAPABILITY = false
- else
- while status do
- if ( line:match("^%*%s+CAPABILITY") ) then
- line = line:gsub("^%*%s+CAPABILITY", "")
- for capability in line:gmatch("[%w%+=-]+") do
- capas[capability] = true
- end
- break
- end
- status, line = self.socket:receive()
- end
- end
- return true, capas
- end,
+ local status, line = self:receive()
+ if (not(status)) then
+ capas.CAPABILITY = false
+ else
+ while status do
+ if ( line:match("^%*%s+CAPABILITY") ) then
+ line = line:gsub("^%*%s+CAPABILITY", "")
+ for capability in line:gmatch("[%w%+=-]+") do
+ capas[capability] = true
+ end
+ break
+ end
+ status, line = self.socket:receive()
+ end
+ end
+ return true, capas
+ end,
- --- Closes the connection to the IMAP server
- -- @return true on success, false on failure
- close = function(self) return self.socket:close() end
+ --- Closes the connection to the IMAP server
+ -- @return true on success, false on failure
+ close = function(self) return self.socket:close() end
}
@@ -227,53 +227,53 @@ IMAP = {
-- The helper class, that servers as interface to script writers
Helper = {
- -- @param host table as received by the script action method
- -- @param port table as received by the script action method
- -- @param options table containing options, currently
- -- timeout - number containing the seconds to wait for
- -- a response
- new = function(self, host, port, options)
- local o = { client = IMAP:new( host, port, options ) }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- @param host table as received by the script action method
+ -- @param port table as received by the script action method
+ -- @param options table containing options, currently
+ -- timeout - number containing the seconds to wait for
+ -- a response
+ new = function(self, host, port, options)
+ local o = { client = IMAP:new( host, port, options ) }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- --- Connects to the IMAP server
- -- @return status true on success, false on failure
- connect = function(self)
- return self.client:connect()
- end,
+ --- Connects to the IMAP server
+ -- @return status true on success, false on failure
+ connect = function(self)
+ return self.client:connect()
+ end,
- --- Login to the server using eithe plain-text or using the authentication
- -- mechanism provided in the mech argument.
- --
- -- @param username string containing the username
- -- @param password string containing the password
- -- @param mech [optional] containing the authentication mechanism to use
- -- @return status true on success, false on failure
- login = function(self, username, password, mech)
- if ( not(mech) or mech == "LOGIN" ) then
- return self.client:login(username, password)
- else
- return self.client:authenticate(username, password, mech)
- end
- end,
+ --- Login to the server using eithe plain-text or using the authentication
+ -- mechanism provided in the mech argument.
+ --
+ -- @param username string containing the username
+ -- @param password string containing the password
+ -- @param mech [optional] containing the authentication mechanism to use
+ -- @return status true on success, false on failure
+ login = function(self, username, password, mech)
+ if ( not(mech) or mech == "LOGIN" ) then
+ return self.client:login(username, password)
+ else
+ return self.client:authenticate(username, password, mech)
+ end
+ end,
- --- Retrieves a list of server capabilities (eg. supported authentication
- -- mechanisms, QUOTA, UIDPLUS, ACL ...)
- --
- -- @return status true on success, false on failure
- -- @return capas array containing the capabilities that are supported
- capabilities = function(self)
- return self.client:capabilities()
- end,
+ --- Retrieves a list of server capabilities (eg. supported authentication
+ -- mechanisms, QUOTA, UIDPLUS, ACL ...)
+ --
+ -- @return status true on success, false on failure
+ -- @return capas array containing the capabilities that are supported
+ capabilities = function(self)
+ return self.client:capabilities()
+ end,
- --- Closes the connection to the IMAP server
- -- @return true on success, false on failure
- close = function(self)
- return self.client:close()
- end,
+ --- Closes the connection to the IMAP server
+ -- @return true on success, false on failure
+ close = function(self)
+ return self.client:close()
+ end,
}
diff --git a/nselib/ipp.lua b/nselib/ipp.lua
index d9682932c..296f6f190 100644
--- a/nselib/ipp.lua
+++ b/nselib/ipp.lua
@@ -18,424 +18,424 @@ _ENV = stdnse.module("ipp", stdnse.seeall)
-- The IPP layer
IPP = {
- StatusCode = {
- OK = 0,
- },
+ StatusCode = {
+ OK = 0,
+ },
- State = {
- IPP_JOB_PENDING = 3,
- IPP_JOB_HELD = 4,
- IPP_JOB_PROCESSING = 5,
- IPP_JOB_STOPPED = 6,
- IPP_JOB_CANCELED = 7,
- IPP_JOB_ABORTED = 8,
- IPP_JOB_COMPLETED = 9,
- },
+ State = {
+ IPP_JOB_PENDING = 3,
+ IPP_JOB_HELD = 4,
+ IPP_JOB_PROCESSING = 5,
+ IPP_JOB_STOPPED = 6,
+ IPP_JOB_CANCELED = 7,
+ IPP_JOB_ABORTED = 8,
+ IPP_JOB_COMPLETED = 9,
+ },
- StateName = {
- [3] = "Pending",
- [4] = "Held",
- [5] = "Processing",
- [6] = "Stopped",
- [7] = "Canceled",
- [8] = "Aborted",
- [9] = "Completed",
- },
+ StateName = {
+ [3] = "Pending",
+ [4] = "Held",
+ [5] = "Processing",
+ [6] = "Stopped",
+ [7] = "Canceled",
+ [8] = "Aborted",
+ [9] = "Completed",
+ },
- OperationID = {
- IPP_CANCEL_JOB = 0x0008,
- IPP_GET_JOB_ATTRIBUTES = 0x0009,
- IPP_GET_JOBS = 0x000a,
- CUPS_GET_PRINTERS = 0x4002,
- CUPS_GET_DOCUMENT = 0x4027
- },
+ OperationID = {
+ IPP_CANCEL_JOB = 0x0008,
+ IPP_GET_JOB_ATTRIBUTES = 0x0009,
+ IPP_GET_JOBS = 0x000a,
+ CUPS_GET_PRINTERS = 0x4002,
+ CUPS_GET_DOCUMENT = 0x4027
+ },
- PrinterState = {
- IPP_PRINTER_IDLE = 3,
- IPP_PRINTER_PROCESSING = 4,
- IPP_PRINTER_STOPPED = 5,
- },
+ PrinterState = {
+ IPP_PRINTER_IDLE = 3,
+ IPP_PRINTER_PROCESSING = 4,
+ IPP_PRINTER_STOPPED = 5,
+ },
- Attribute = {
+ Attribute = {
- IPP_TAG_OPERATION = 0x01,
- IPP_TAG_JOB = 0x02,
- IPP_TAG_END = 0x03,
- IPP_TAG_PRINTER = 0x04,
- IPP_TAG_INTEGER = 0x21,
- IPP_TAG_ENUM = 0x23,
- IPP_TAG_NAME = 0x42,
- IPP_TAG_KEYWORD = 0x44,
- IPP_TAG_URI = 0x45,
- IPP_TAG_CHARSET = 0x47,
- IPP_TAG_LANGUAGE = 0x48,
+ IPP_TAG_OPERATION = 0x01,
+ IPP_TAG_JOB = 0x02,
+ IPP_TAG_END = 0x03,
+ IPP_TAG_PRINTER = 0x04,
+ IPP_TAG_INTEGER = 0x21,
+ IPP_TAG_ENUM = 0x23,
+ IPP_TAG_NAME = 0x42,
+ IPP_TAG_KEYWORD = 0x44,
+ IPP_TAG_URI = 0x45,
+ IPP_TAG_CHARSET = 0x47,
+ IPP_TAG_LANGUAGE = 0x48,
- new = function(self, tag, name, value)
- local o = { tag = tag, name = name, value = value }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ new = function(self, tag, name, value)
+ local o = { tag = tag, name = name, value = value }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- parse = function(data, pos)
- local attrib = IPP.Attribute:new()
- local val
- pos, attrib.tag, attrib.name, val = bin.unpack(">CPP", data, pos)
- -- print(attrib.name, stdnse.tohex(val))
- attrib.value = {}
- table.insert(attrib.value, { tag = attrib.tag, val = val })
+ parse = function(data, pos)
+ local attrib = IPP.Attribute:new()
+ local val
+ pos, attrib.tag, attrib.name, val = bin.unpack(">CPP", data, pos)
+ -- print(attrib.name, stdnse.tohex(val))
+ attrib.value = {}
+ table.insert(attrib.value, { tag = attrib.tag, val = val })
- repeat
- local tag, name_len, val
+ repeat
+ local tag, name_len, val
- if ( #data < pos + 3 ) then
- break
- end
+ if ( #data < pos + 3 ) then
+ break
+ end
- pos, tag, name_len = bin.unpack(">CS", data, pos)
- if ( name_len == 0 ) then
- pos, val = bin.unpack(">P", data, pos)
- table.insert(attrib.value, { tag = tag, val = val })
- else
- pos = pos - 3
- end
- until( name_len ~= 0 )
+ pos, tag, name_len = bin.unpack(">CS", data, pos)
+ if ( name_len == 0 ) then
+ pos, val = bin.unpack(">P", data, pos)
+ table.insert(attrib.value, { tag = tag, val = val })
+ else
+ pos = pos - 3
+ end
+ until( name_len ~= 0 )
- -- do minimal decoding
- for i=1, #attrib.value do
- if ( attrib.value[i].tag == IPP.Attribute.IPP_TAG_INTEGER ) then
- attrib.value[i].val = select(2, bin.unpack(">I", attrib.value[i].val))
- elseif ( attrib.value[i].tag == IPP.Attribute.IPP_TAG_ENUM ) then
- attrib.value[i].val = select(2, bin.unpack(">I", attrib.value[i].val))
- end
- end
+ -- do minimal decoding
+ for i=1, #attrib.value do
+ if ( attrib.value[i].tag == IPP.Attribute.IPP_TAG_INTEGER ) then
+ attrib.value[i].val = select(2, bin.unpack(">I", attrib.value[i].val))
+ elseif ( attrib.value[i].tag == IPP.Attribute.IPP_TAG_ENUM ) then
+ attrib.value[i].val = select(2, bin.unpack(">I", attrib.value[i].val))
+ end
+ end
- if ( 1 == #attrib.value ) then
- attrib.value = attrib.value[1].val
- end
- --print(attrib.name, attrib.value, stdnse.tohex(val))
+ if ( 1 == #attrib.value ) then
+ attrib.value = attrib.value[1].val
+ end
+ --print(attrib.name, attrib.value, stdnse.tohex(val))
- return pos, attrib
- end,
+ return pos, attrib
+ end,
- __tostring = function(self)
- if ( "string" == type(self.value) ) then
- return bin.pack(">CSASA", self.tag, #self.name, self.name, #self.value, self.value)
- else
- local data = bin.pack(">CSASA", self.tag, #self.name, self.name, #self.value[1].val, self.value[1].val)
- for i=2, #self.value do
- data = data .. bin.pack(">CSP", self.value[i].tag, 0, self.value[i].val)
- end
- return data
- end
- end
+ __tostring = function(self)
+ if ( "string" == type(self.value) ) then
+ return bin.pack(">CSASA", self.tag, #self.name, self.name, #self.value, self.value)
+ else
+ local data = bin.pack(">CSASA", self.tag, #self.name, self.name, #self.value[1].val, self.value[1].val)
+ for i=2, #self.value do
+ data = data .. bin.pack(">CSP", self.value[i].tag, 0, self.value[i].val)
+ end
+ return data
+ end
+ end
- },
+ },
- -- An attribute group, groups several attributes
- AttributeGroup = {
+ -- An attribute group, groups several attributes
+ AttributeGroup = {
- new = function(self, tag, attribs)
- local o = { tag = tag, attribs = attribs or {} }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ new = function(self, tag, attribs)
+ local o = { tag = tag, attribs = attribs or {} }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- addAttribute = function(self, attrib)
- table.insert(self.attribs, attrib)
- end,
+ addAttribute = function(self, attrib)
+ table.insert(self.attribs, attrib)
+ end,
- --
- -- Gets the first attribute matching name and optionally tag from the
- -- attribute group.
- --
- -- @param name string containing the attribute name
- -- @param tag number containing the attribute tag
- getAttribute = function(self, name, tag)
- for _, attrib in ipairs(self.attribs) do
- if ( attrib.name == name ) then
- if ( not(tag) ) then
- return attrib
- elseif ( tag and attrib.tag == tag ) then
- return attrib
- end
- end
- end
- end,
+ --
+ -- Gets the first attribute matching name and optionally tag from the
+ -- attribute group.
+ --
+ -- @param name string containing the attribute name
+ -- @param tag number containing the attribute tag
+ getAttribute = function(self, name, tag)
+ for _, attrib in ipairs(self.attribs) do
+ if ( attrib.name == name ) then
+ if ( not(tag) ) then
+ return attrib
+ elseif ( tag and attrib.tag == tag ) then
+ return attrib
+ end
+ end
+ end
+ end,
- getAttributeValue = function(self, name, tag)
- for _, attrib in ipairs(self.attribs) do
- if ( attrib.name == name ) then
- if ( not(tag) ) then
- return attrib.value
- elseif ( tag and attrib.tag == tag ) then
- return attrib.value
- end
- end
- end
- end,
+ getAttributeValue = function(self, name, tag)
+ for _, attrib in ipairs(self.attribs) do
+ if ( attrib.name == name ) then
+ if ( not(tag) ) then
+ return attrib.value
+ elseif ( tag and attrib.tag == tag ) then
+ return attrib.value
+ end
+ end
+ end
+ end,
- __tostring = function(self)
- local data = bin.pack("C", self.tag)
+ __tostring = function(self)
+ local data = bin.pack("C", self.tag)
- for _, attrib in ipairs(self.attribs) do
- data = data .. tostring(attrib)
- end
- return data
- end
+ for _, attrib in ipairs(self.attribs) do
+ data = data .. tostring(attrib)
+ end
+ return data
+ end
- },
+ },
- -- The IPP request
- Request = {
+ -- The IPP request
+ Request = {
- new = function(self, opid, reqid)
- local o = {
- version = 0x0101,
- opid = opid,
- reqid = reqid,
- attrib_groups = {},
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ new = function(self, opid, reqid)
+ local o = {
+ version = 0x0101,
+ opid = opid,
+ reqid = reqid,
+ attrib_groups = {},
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- addAttributeGroup = function(self, group)
- table.insert( self.attrib_groups, group )
- end,
+ addAttributeGroup = function(self, group)
+ table.insert( self.attrib_groups, group )
+ end,
- __tostring = function(self)
- local data = bin.pack(">SSI", self.version, self.opid, self.reqid )
+ __tostring = function(self)
+ local data = bin.pack(">SSI", self.version, self.opid, self.reqid )
- for _, group in ipairs(self.attrib_groups) do
- data = data .. tostring(group)
- end
- data = data .. bin.pack("C", IPP.Attribute.IPP_TAG_END)
- return data
- end,
+ for _, group in ipairs(self.attrib_groups) do
+ data = data .. tostring(group)
+ end
+ data = data .. bin.pack("C", IPP.Attribute.IPP_TAG_END)
+ return data
+ end,
- },
+ },
- -- A class to handle responses from the server
- Response = {
+ -- A class to handle responses from the server
+ Response = {
- -- Creates a new instance of response
- new = function(self)
- local o = {}
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new instance of response
+ new = function(self)
+ local o = {}
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- getAttributeGroups = function(self, tag)
- local groups = {}
- for _, v in ipairs(self.attrib_groups or {}) do
- if ( v.tag == tag ) then
- table.insert(groups, v)
- end
- end
- return groups
- end,
+ getAttributeGroups = function(self, tag)
+ local groups = {}
+ for _, v in ipairs(self.attrib_groups or {}) do
+ if ( v.tag == tag ) then
+ table.insert(groups, v)
+ end
+ end
+ return groups
+ end,
- parse = function(data)
- local resp = IPP.Response:new()
- local pos
+ parse = function(data)
+ local resp = IPP.Response:new()
+ local pos
- pos, resp.version, resp.status, resp.reqid = bin.unpack(">SSI", data)
+ pos, resp.version, resp.status, resp.reqid = bin.unpack(">SSI", data)
- resp.attrib_groups = {}
- local group
- repeat
- local tag, attrib
- pos, tag = bin.unpack(">C", data, pos)
+ resp.attrib_groups = {}
+ local group
+ repeat
+ local tag, attrib
+ pos, tag = bin.unpack(">C", data, pos)
- if ( tag == IPP.Attribute.IPP_TAG_OPERATION or
- tag == IPP.Attribute.IPP_TAG_JOB or
- tag == IPP.Attribute.IPP_TAG_PRINTER or
- tag == IPP.Attribute.IPP_TAG_END ) then
+ if ( tag == IPP.Attribute.IPP_TAG_OPERATION or
+ tag == IPP.Attribute.IPP_TAG_JOB or
+ tag == IPP.Attribute.IPP_TAG_PRINTER or
+ tag == IPP.Attribute.IPP_TAG_END ) then
- if ( group ) then
- table.insert(resp.attrib_groups, group)
- group = IPP.AttributeGroup:new(tag)
- else
- group = IPP.AttributeGroup:new(tag)
- end
- else
- pos = pos - 1
- end
+ if ( group ) then
+ table.insert(resp.attrib_groups, group)
+ group = IPP.AttributeGroup:new(tag)
+ else
+ group = IPP.AttributeGroup:new(tag)
+ end
+ else
+ pos = pos - 1
+ end
- if ( not(group) ) then
- stdnse.print_debug(2, "Unexpected tag: %d", tag)
- return
- end
+ if ( not(group) ) then
+ stdnse.print_debug(2, "Unexpected tag: %d", tag)
+ return
+ end
- pos, attrib = IPP.Attribute.parse(data, pos)
- group:addAttribute(attrib)
+ pos, attrib = IPP.Attribute.parse(data, pos)
+ group:addAttribute(attrib)
- until( pos == #data + 1)
+ until( pos == #data + 1)
- return resp
- end,
+ return resp
+ end,
- },
+ },
}
HTTP = {
- Request = function(host, port, request)
- local headers = {
- ['Content-Type'] = 'application/ipp',
- ['User-Agent'] = 'CUPS/1.5.1',
- }
- port.version.service_tunnel = "ssl"
- local http_resp = http.post(host, port, '/', { header = headers }, nil, tostring(request))
- if ( http_resp.status ~= 200 ) then
- return false, "Unexpected response from server"
- end
+ Request = function(host, port, request)
+ local headers = {
+ ['Content-Type'] = 'application/ipp',
+ ['User-Agent'] = 'CUPS/1.5.1',
+ }
+ port.version.service_tunnel = "ssl"
+ local http_resp = http.post(host, port, '/', { header = headers }, nil, tostring(request))
+ if ( http_resp.status ~= 200 ) then
+ return false, "Unexpected response from server"
+ end
- local response = IPP.Response.parse(http_resp.body)
- if ( not(response) ) then
- return false, "Failed to parse response"
- end
+ local response = IPP.Response.parse(http_resp.body)
+ if ( not(response) ) then
+ return false, "Failed to parse response"
+ end
- return true, response
- end,
+ return true, response
+ end,
}
Helper = {
- new = function(self, host, port, options)
- local o = { host = host, port = port, options = options or {} }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ new = function(self, host, port, options)
+ local o = { host = host, port = port, options = options or {} }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- connect = function(self)
- self.socket = nmap.new_socket()
- self.socket:set_timeout(self.options.timeout or 10000)
- return self.socket:connect(self.host, self.port)
- end,
+ connect = function(self)
+ self.socket = nmap.new_socket()
+ self.socket:set_timeout(self.options.timeout or 10000)
+ return self.socket:connect(self.host, self.port)
+ end,
- getPrinters = function(self)
+ getPrinters = function(self)
- local attribs = {
- IPP.Attribute:new(IPP.Attribute.IPP_TAG_CHARSET, "attributes-charset", "utf-8" ),
- IPP.Attribute:new(IPP.Attribute.IPP_TAG_LANGUAGE, "attributes-natural-language", "en"),
- }
+ local attribs = {
+ IPP.Attribute:new(IPP.Attribute.IPP_TAG_CHARSET, "attributes-charset", "utf-8" ),
+ IPP.Attribute:new(IPP.Attribute.IPP_TAG_LANGUAGE, "attributes-natural-language", "en"),
+ }
- local ag = IPP.AttributeGroup:new(IPP.Attribute.IPP_TAG_OPERATION, attribs)
- local request = IPP.Request:new(IPP.OperationID.CUPS_GET_PRINTERS, 1)
- request:addAttributeGroup(ag)
+ local ag = IPP.AttributeGroup:new(IPP.Attribute.IPP_TAG_OPERATION, attribs)
+ local request = IPP.Request:new(IPP.OperationID.CUPS_GET_PRINTERS, 1)
+ request:addAttributeGroup(ag)
- local status, response = HTTP.Request( self.host, self.port, tostring(request) )
- if ( not(response) ) then
- return status, response
- end
+ local status, response = HTTP.Request( self.host, self.port, tostring(request) )
+ if ( not(response) ) then
+ return status, response
+ end
- local printers = {}
+ local printers = {}
- for _, ag in ipairs(response:getAttributeGroups(IPP.Attribute.IPP_TAG_PRINTER)) do
- local attrib = {
- ["printer-name"] = "name",
- ["printer-location"] = "location",
- ["printer-make-and-model"] = "model",
- ["printer-state"] = "state",
- ["queued-job-count"] = "queue_count",
- ["printer-dns-sd-name"] = "dns_sd_name",
- }
+ for _, ag in ipairs(response:getAttributeGroups(IPP.Attribute.IPP_TAG_PRINTER)) do
+ local attrib = {
+ ["printer-name"] = "name",
+ ["printer-location"] = "location",
+ ["printer-make-and-model"] = "model",
+ ["printer-state"] = "state",
+ ["queued-job-count"] = "queue_count",
+ ["printer-dns-sd-name"] = "dns_sd_name",
+ }
- local printer = {}
- for k, v in pairs(attrib) do
- if ( ag:getAttributeValue(k) ) then
- printer[v] = ag:getAttributeValue(k)
- end
- end
- table.insert(printers, printer)
- end
- return true, printers
- end,
+ local printer = {}
+ for k, v in pairs(attrib) do
+ if ( ag:getAttributeValue(k) ) then
+ printer[v] = ag:getAttributeValue(k)
+ end
+ end
+ table.insert(printers, printer)
+ end
+ return true, printers
+ end,
- getQueueInfo = function(self, uri)
- local uri = uri or ("ipp://%s/"):format(self.host.ip)
+ getQueueInfo = function(self, uri)
+ local uri = uri or ("ipp://%s/"):format(self.host.ip)
- local attribs = {
- IPP.Attribute:new(IPP.Attribute.IPP_TAG_CHARSET, "attributes-charset", "utf-8" ),
- IPP.Attribute:new(IPP.Attribute.IPP_TAG_LANGUAGE, "attributes-natural-language", "en-us"),
- IPP.Attribute:new(IPP.Attribute.IPP_TAG_URI, "printer-uri", uri),
- IPP.Attribute:new(IPP.Attribute.IPP_TAG_KEYWORD, "requested-attributes", {
- -- { tag = IPP.Attribute.IPP_TAG_KEYWORD, val = "job-originating-host-name"},
- { tag = IPP.Attribute.IPP_TAG_KEYWORD, val = "com.apple.print.JobInfo.PMJobName"},
- { tag = IPP.Attribute.IPP_TAG_KEYWORD, val = "com.apple.print.JobInfo.PMJobOwner"},
- { tag = IPP.Attribute.IPP_TAG_KEYWORD, val = "job-id" },
- { tag = IPP.Attribute.IPP_TAG_KEYWORD, val = "job-k-octets" },
- { tag = IPP.Attribute.IPP_TAG_KEYWORD, val = "job-name" },
- { tag = IPP.Attribute.IPP_TAG_KEYWORD, val = "job-state" },
- { tag = IPP.Attribute.IPP_TAG_KEYWORD, val = "printer-uri" },
- -- { tag = IPP.Attribute.IPP_TAG_KEYWORD, val = "job-originating-user-name" },
- -- { tag = IPP.Attribute.IPP_TAG_KEYWORD, val = "job-printer-state-message" },
- -- { tag = IPP.Attribute.IPP_TAG_KEYWORD, val = "job-printer-uri" },
- { tag = IPP.Attribute.IPP_TAG_KEYWORD, val = "time-at-creation" } } ),
- IPP.Attribute:new(IPP.Attribute.IPP_TAG_KEYWORD, "which-jobs", "not-completed" )
- }
+ local attribs = {
+ IPP.Attribute:new(IPP.Attribute.IPP_TAG_CHARSET, "attributes-charset", "utf-8" ),
+ IPP.Attribute:new(IPP.Attribute.IPP_TAG_LANGUAGE, "attributes-natural-language", "en-us"),
+ IPP.Attribute:new(IPP.Attribute.IPP_TAG_URI, "printer-uri", uri),
+ IPP.Attribute:new(IPP.Attribute.IPP_TAG_KEYWORD, "requested-attributes", {
+ -- { tag = IPP.Attribute.IPP_TAG_KEYWORD, val = "job-originating-host-name"},
+ { tag = IPP.Attribute.IPP_TAG_KEYWORD, val = "com.apple.print.JobInfo.PMJobName"},
+ { tag = IPP.Attribute.IPP_TAG_KEYWORD, val = "com.apple.print.JobInfo.PMJobOwner"},
+ { tag = IPP.Attribute.IPP_TAG_KEYWORD, val = "job-id" },
+ { tag = IPP.Attribute.IPP_TAG_KEYWORD, val = "job-k-octets" },
+ { tag = IPP.Attribute.IPP_TAG_KEYWORD, val = "job-name" },
+ { tag = IPP.Attribute.IPP_TAG_KEYWORD, val = "job-state" },
+ { tag = IPP.Attribute.IPP_TAG_KEYWORD, val = "printer-uri" },
+ -- { tag = IPP.Attribute.IPP_TAG_KEYWORD, val = "job-originating-user-name" },
+ -- { tag = IPP.Attribute.IPP_TAG_KEYWORD, val = "job-printer-state-message" },
+ -- { tag = IPP.Attribute.IPP_TAG_KEYWORD, val = "job-printer-uri" },
+ { tag = IPP.Attribute.IPP_TAG_KEYWORD, val = "time-at-creation" } } ),
+ IPP.Attribute:new(IPP.Attribute.IPP_TAG_KEYWORD, "which-jobs", "not-completed" )
+ }
- local ag = IPP.AttributeGroup:new(IPP.Attribute.IPP_TAG_OPERATION, attribs)
- local request = IPP.Request:new(IPP.OperationID.IPP_GET_JOBS, 1)
- request:addAttributeGroup(ag)
+ local ag = IPP.AttributeGroup:new(IPP.Attribute.IPP_TAG_OPERATION, attribs)
+ local request = IPP.Request:new(IPP.OperationID.IPP_GET_JOBS, 1)
+ request:addAttributeGroup(ag)
- local status, response = HTTP.Request( self.host, self.port, tostring(request) )
- if ( not(response) ) then
- return status, response
- end
+ local status, response = HTTP.Request( self.host, self.port, tostring(request) )
+ if ( not(response) ) then
+ return status, response
+ end
- local results = {}
- for _, ag in ipairs(response:getAttributeGroups(IPP.Attribute.IPP_TAG_JOB)) do
- local uri = ag:getAttributeValue("printer-uri")
- local printer = uri:match(".*/(.*)$") or "Unknown"
- -- some jobs have mutlitple state attributes, so far the ENUM ones have been correct
- local state = ag:getAttributeValue("job-state", IPP.Attribute.IPP_TAG_ENUM) or ag:getAttributeValue("job-state")
- -- some jobs have multiple id tag, so far the INTEGER type have shown the correct ID
- local id = ag:getAttributeValue("job-id", IPP.Attribute.IPP_TAG_INTEGER) or ag:getAttributeValue("job-id")
- local attr = ag:getAttribute("time-at-creation")
- local tm = ag:getAttributeValue("time-at-creation")
- local size = ag:getAttributeValue("job-k-octets") .. "k"
- local jobname = ag:getAttributeValue("com.apple.print.JobInfo.PMJobName") or "Unknown"
- local owner = ag:getAttributeValue("com.apple.print.JobInfo.PMJobOwner") or "Unknown"
+ local results = {}
+ for _, ag in ipairs(response:getAttributeGroups(IPP.Attribute.IPP_TAG_JOB)) do
+ local uri = ag:getAttributeValue("printer-uri")
+ local printer = uri:match(".*/(.*)$") or "Unknown"
+ -- some jobs have mutlitple state attributes, so far the ENUM ones have been correct
+ local state = ag:getAttributeValue("job-state", IPP.Attribute.IPP_TAG_ENUM) or ag:getAttributeValue("job-state")
+ -- some jobs have multiple id tag, so far the INTEGER type have shown the correct ID
+ local id = ag:getAttributeValue("job-id", IPP.Attribute.IPP_TAG_INTEGER) or ag:getAttributeValue("job-id")
+ local attr = ag:getAttribute("time-at-creation")
+ local tm = ag:getAttributeValue("time-at-creation")
+ local size = ag:getAttributeValue("job-k-octets") .. "k"
+ local jobname = ag:getAttributeValue("com.apple.print.JobInfo.PMJobName") or "Unknown"
+ local owner = ag:getAttributeValue("com.apple.print.JobInfo.PMJobOwner") or "Unknown"
- results[printer] = results[printer] or {}
- table.insert(results[printer], {
- id = id,
- time = os.date("%Y-%m-%d %H:%M:%S", tm),
- state = ( IPP.StateName[tonumber(state)] or "Unknown" ),
- size = size,
- owner = owner,
- jobname = jobname })
- end
+ results[printer] = results[printer] or {}
+ table.insert(results[printer], {
+ id = id,
+ time = os.date("%Y-%m-%d %H:%M:%S", tm),
+ state = ( IPP.StateName[tonumber(state)] or "Unknown" ),
+ size = size,
+ owner = owner,
+ jobname = jobname })
+ end
- local output = {}
- for name, entries in pairs(results) do
- local t = tab.new(5)
- tab.addrow(t, "id", "time", "state", "size (kb)", "owner", "jobname")
- for _, entry in ipairs(entries) do
- tab.addrow(t, entry.id, entry.time, entry.state, entry.size, entry.owner, entry.jobname)
- end
- if ( 1<#t ) then
- table.insert(output, { name = name, tab.dump(t) })
- end
- end
+ local output = {}
+ for name, entries in pairs(results) do
+ local t = tab.new(5)
+ tab.addrow(t, "id", "time", "state", "size (kb)", "owner", "jobname")
+ for _, entry in ipairs(entries) do
+ tab.addrow(t, entry.id, entry.time, entry.state, entry.size, entry.owner, entry.jobname)
+ end
+ if ( 1<#t ) then
+ table.insert(output, { name = name, tab.dump(t) })
+ end
+ end
- return output
- end,
+ return output
+ end,
- close = function(self)
- return self.socket:close()
- end,
+ close = function(self)
+ return self.socket:close()
+ end,
}
return _ENV;
diff --git a/nselib/isns.lua b/nselib/isns.lua
index 8095cb0a7..00fb12fc0 100644
--- a/nselib/isns.lua
+++ b/nselib/isns.lua
@@ -16,550 +16,550 @@ _ENV = stdnse.module("isns", stdnse.seeall);
iSCSI = {
- NodeType = {
- TARGET = 1,
- INITIATOR = 2,
- CONTROL = 4,
- }
+ NodeType = {
+ TARGET = 1,
+ INITIATOR = 2,
+ CONTROL = 4,
+ }
}
Header = {
- VERSION = 1,
+ VERSION = 1,
- --
- -- Creates a header instance
- --
- -- @param func_id number containing the function ID of the message
- -- @param pdu_len number containing the length of the PDU
- -- @param flags number containing the message flags
- -- @param trans_id number containing the transaction id
- -- @param seq_id number containing the sequence id
- -- @return o new class instance
- new = function(self, func_id, pdu_len, flags, trans_id, seq_id)
- local o = {
- ver = Header.VERSION,
- func_id = func_id,
- flags = flags,
- trans_id = trans_id,
- seq_id = seq_id,
- pdu_len = pdu_len,
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ --
+ -- Creates a header instance
+ --
+ -- @param func_id number containing the function ID of the message
+ -- @param pdu_len number containing the length of the PDU
+ -- @param flags number containing the message flags
+ -- @param trans_id number containing the transaction id
+ -- @param seq_id number containing the sequence id
+ -- @return o new class instance
+ new = function(self, func_id, pdu_len, flags, trans_id, seq_id)
+ local o = {
+ ver = Header.VERSION,
+ func_id = func_id,
+ flags = flags,
+ trans_id = trans_id,
+ seq_id = seq_id,
+ pdu_len = pdu_len,
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- --
- -- Parses a opaque string and creates a new Header instance
- --
- -- @param data opaques string containing the raw data
- -- @return hdr new instance of Header
- parse = function(data)
- local hdr = Header:new()
- local pos
+ --
+ -- Parses a opaque string and creates a new Header instance
+ --
+ -- @param data opaques string containing the raw data
+ -- @return hdr new instance of Header
+ parse = function(data)
+ local hdr = Header:new()
+ local pos
- pos, hdr.ver, hdr.func_id, hdr.pdu_len, hdr.flags, hdr.trans_id,
- hdr.seq_id = bin.unpack(">SSSSSS", data)
+ pos, hdr.ver, hdr.func_id, hdr.pdu_len, hdr.flags, hdr.trans_id,
+ hdr.seq_id = bin.unpack(">SSSSSS", data)
- return hdr
- end,
+ return hdr
+ end,
- --
- -- Converts the instance to an opaque string
- -- @return str containing an opaque string
- __tostring = function(self)
- return bin.pack(">SSSSSS", self.ver, self.func_id,
- self.pdu_len, self.flags, self.trans_id, self.seq_id )
- end
+ --
+ -- Converts the instance to an opaque string
+ -- @return str containing an opaque string
+ __tostring = function(self)
+ return bin.pack(">SSSSSS", self.ver, self.func_id,
+ self.pdu_len, self.flags, self.trans_id, self.seq_id )
+ end
}
Attribute = {
- Tag = {
- ISNS_TAG_DELIMITER = 0,
- ISNS_TAG_ENTITY_IDENTIFIER = 1,
- ISNS_TAG_ENTITY_PROTOCOL = 2,
- ISNS_TAG_MGMT_IP_ADDRESS = 3,
- ISNS_TAG_TIMESTAMP = 4,
- ISNS_TAG_PROTOCOL_VERSION_RANGE = 5,
- ISNS_TAG_REGISTRATION_PERIOD = 6,
- ISNS_TAG_ENTITY_INDEX = 7,
- ISNS_TAG_ENTITY_NEXT_INDEX = 8,
- ISNS_TAG_ENTITY_ISAKMP_PHASE_1 = 11,
- ISNS_TAG_ENTITY_CERTIFICATE = 12,
- ISNS_TAG_PORTAL_IP_ADDRESS = 16,
- ISNS_TAG_PORTAL_TCP_UDP_PORT = 17,
- ISNS_TAG_PORTAL_SYMBOLIC_NAME = 18,
- ISNS_TAG_ESI_INTERVAL = 19,
- ISNS_TAG_ESI_PORT = 20,
- ISNS_TAG_PORTAL_INDEX = 22,
- ISNS_TAG_SCN_PORT = 23,
- ISNS_TAG_PORTAL_NEXT_INDEX = 24,
- ISNS_TAG_PORTAL_SECURITY_BITMAP = 27,
- ISNS_TAG_PORTAL_ISAKMP_PHASE_1 = 28,
- ISNS_TAG_PORTAL_ISAKMP_PHASE_2 = 29,
- ISNS_TAG_PORTAL_CERTIFICATE = 31,
- ISNS_TAG_ISCSI_NAME = 32,
- ISNS_TAG_ISCSI_NODE_TYPE = 33,
- ISNS_TAG_ISCSI_ALIAS = 34,
- ISNS_TAG_ISCSI_SCN_BITMAP = 35,
- ISNS_TAG_ISCSI_NODE_INDEX = 36,
- ISNS_TAG_WWNN_TOKEN = 37,
- ISNS_TAG_ISCSI_NODE_NEXT_INDEX = 38,
- ISNS_TAG_ISCSI_AUTHMETHOD = 42,
- ISNS_TAG_PG_ISCSI_NAME = 48,
- ISNS_TAG_PG_PORTAL_IP_ADDR = 49,
- ISNS_TAG_PG_PORTAL_TCP_UDP_PORT = 50,
- ISNS_TAG_PG_TAG = 51,
- ISNS_TAG_PG_INDEX = 52,
- ISNS_TAG_PG_NEXT_INDEX = 53,
- ISNS_TAG_FC_PORT_NAME_WWPN = 64,
- ISNS_TAG_PORT_ID = 65,
- ISNS_TAG_FC_PORT_TYPE = 66,
- ISNS_TAG_SYMBOLIC_PORT_NAME = 67,
- ISNS_TAG_FABRIC_PORT_NAME = 68,
- ISNS_TAG_HARD_ADDRESS = 69,
- ISNS_TAG_PORT_IP_ADDRESS = 70,
- ISNS_TAG_CLASS_OF_SERVICE = 71,
- ISNS_TAG_FC4_TYPES = 72,
- ISNS_TAG_FC4_DESCRIPTOR = 73,
- ISNS_TAG_FC4_FEATURES = 74,
- ISNS_TAG_IFCP_SCN_BITMAP = 75,
- ISNS_TAG_PORT_ROLE = 76,
- ISNS_TAG_PERMANENT_PORT_NAME = 77,
- ISNS_TAG_FC4_TYPE_CODE = 95,
- ISNS_TAG_FC_NODE_NAME_WWNN = 96,
- ISNS_TAG_SYMBOLIC_NODE_NAME = 97,
- ISNS_TAG_NODE_IP_ADDRESS = 98,
- ISNS_TAG_NODE_IPA = 99,
- ISNS_TAG_PROXY_ISCSI_NAME = 101,
- ISNS_TAG_SWITCH_NAME = 128,
- ISNS_TAG_PREFERRED_ID = 129,
- ISNS_TAG_ASSIGNED_ID = 130,
- ISNS_TAG_VIRTUAL_FABRIC_ID = 131,
- ISNS_TAG_SERVER_VENDOR_OUI = 256,
- ISNS_TAG_DD_SET_ID = 2049,
- ISNS_TAG_DD_SET_SYMBOLIC_NAME = 2050,
- ISNS_TAG_DD_SET_STATUS = 2051,
- ISNS_TAG_DD_SET_NEXT_ID = 2052,
- ISNS_TAG_DD_ID = 2065,
- ISNS_TAG_DD_SYMBOLIC_NAME = 2066,
- ISNS_TAG_DD_MEMBER_ISCSI_INDEX = 2067,
- ISNS_TAG_DD_MEMBER_ISCSI_NAME = 2068,
- ISNS_TAG_DD_MEMBER_FC_PORT_NAME = 2069,
- ISNS_TAG_DD_MEMBER_PORTAL_INDEX = 2070,
- ISNS_TAG_DD_MEMBER_PORTAL_IP_ADDR = 2071,
- ISNS_TAG_DD_MEMBER_PORTAL_TCP_UDP_PORT = 2072,
- ISNS_TAG_DD_FEATURES = 2078,
- ISNS_TAG_DD_NEXT_ID = 2079,
- ISNS_VENDOR_SPECIFIC_SERVER_BASE = 257,
- ISNS_VENDOR_SPECIFIC_ENTITY_BASE = 385,
- ISNS_VENDOR_SPECIFIC_PORTAL_BASE = 513,
- ISNS_VENDOR_SPECIFIC_NODE_BASE = 641,
- ISNS_VENDOR_SPECIFIC_DD_BASE = 1024,
- ISNS_VENDOR_SPECIFIC_DDSET_BASE = 1281,
- ISNS_VENDOR_SPECIFIC_OTHER_BASE = 1537,
- },
+ Tag = {
+ ISNS_TAG_DELIMITER = 0,
+ ISNS_TAG_ENTITY_IDENTIFIER = 1,
+ ISNS_TAG_ENTITY_PROTOCOL = 2,
+ ISNS_TAG_MGMT_IP_ADDRESS = 3,
+ ISNS_TAG_TIMESTAMP = 4,
+ ISNS_TAG_PROTOCOL_VERSION_RANGE = 5,
+ ISNS_TAG_REGISTRATION_PERIOD = 6,
+ ISNS_TAG_ENTITY_INDEX = 7,
+ ISNS_TAG_ENTITY_NEXT_INDEX = 8,
+ ISNS_TAG_ENTITY_ISAKMP_PHASE_1 = 11,
+ ISNS_TAG_ENTITY_CERTIFICATE = 12,
+ ISNS_TAG_PORTAL_IP_ADDRESS = 16,
+ ISNS_TAG_PORTAL_TCP_UDP_PORT = 17,
+ ISNS_TAG_PORTAL_SYMBOLIC_NAME = 18,
+ ISNS_TAG_ESI_INTERVAL = 19,
+ ISNS_TAG_ESI_PORT = 20,
+ ISNS_TAG_PORTAL_INDEX = 22,
+ ISNS_TAG_SCN_PORT = 23,
+ ISNS_TAG_PORTAL_NEXT_INDEX = 24,
+ ISNS_TAG_PORTAL_SECURITY_BITMAP = 27,
+ ISNS_TAG_PORTAL_ISAKMP_PHASE_1 = 28,
+ ISNS_TAG_PORTAL_ISAKMP_PHASE_2 = 29,
+ ISNS_TAG_PORTAL_CERTIFICATE = 31,
+ ISNS_TAG_ISCSI_NAME = 32,
+ ISNS_TAG_ISCSI_NODE_TYPE = 33,
+ ISNS_TAG_ISCSI_ALIAS = 34,
+ ISNS_TAG_ISCSI_SCN_BITMAP = 35,
+ ISNS_TAG_ISCSI_NODE_INDEX = 36,
+ ISNS_TAG_WWNN_TOKEN = 37,
+ ISNS_TAG_ISCSI_NODE_NEXT_INDEX = 38,
+ ISNS_TAG_ISCSI_AUTHMETHOD = 42,
+ ISNS_TAG_PG_ISCSI_NAME = 48,
+ ISNS_TAG_PG_PORTAL_IP_ADDR = 49,
+ ISNS_TAG_PG_PORTAL_TCP_UDP_PORT = 50,
+ ISNS_TAG_PG_TAG = 51,
+ ISNS_TAG_PG_INDEX = 52,
+ ISNS_TAG_PG_NEXT_INDEX = 53,
+ ISNS_TAG_FC_PORT_NAME_WWPN = 64,
+ ISNS_TAG_PORT_ID = 65,
+ ISNS_TAG_FC_PORT_TYPE = 66,
+ ISNS_TAG_SYMBOLIC_PORT_NAME = 67,
+ ISNS_TAG_FABRIC_PORT_NAME = 68,
+ ISNS_TAG_HARD_ADDRESS = 69,
+ ISNS_TAG_PORT_IP_ADDRESS = 70,
+ ISNS_TAG_CLASS_OF_SERVICE = 71,
+ ISNS_TAG_FC4_TYPES = 72,
+ ISNS_TAG_FC4_DESCRIPTOR = 73,
+ ISNS_TAG_FC4_FEATURES = 74,
+ ISNS_TAG_IFCP_SCN_BITMAP = 75,
+ ISNS_TAG_PORT_ROLE = 76,
+ ISNS_TAG_PERMANENT_PORT_NAME = 77,
+ ISNS_TAG_FC4_TYPE_CODE = 95,
+ ISNS_TAG_FC_NODE_NAME_WWNN = 96,
+ ISNS_TAG_SYMBOLIC_NODE_NAME = 97,
+ ISNS_TAG_NODE_IP_ADDRESS = 98,
+ ISNS_TAG_NODE_IPA = 99,
+ ISNS_TAG_PROXY_ISCSI_NAME = 101,
+ ISNS_TAG_SWITCH_NAME = 128,
+ ISNS_TAG_PREFERRED_ID = 129,
+ ISNS_TAG_ASSIGNED_ID = 130,
+ ISNS_TAG_VIRTUAL_FABRIC_ID = 131,
+ ISNS_TAG_SERVER_VENDOR_OUI = 256,
+ ISNS_TAG_DD_SET_ID = 2049,
+ ISNS_TAG_DD_SET_SYMBOLIC_NAME = 2050,
+ ISNS_TAG_DD_SET_STATUS = 2051,
+ ISNS_TAG_DD_SET_NEXT_ID = 2052,
+ ISNS_TAG_DD_ID = 2065,
+ ISNS_TAG_DD_SYMBOLIC_NAME = 2066,
+ ISNS_TAG_DD_MEMBER_ISCSI_INDEX = 2067,
+ ISNS_TAG_DD_MEMBER_ISCSI_NAME = 2068,
+ ISNS_TAG_DD_MEMBER_FC_PORT_NAME = 2069,
+ ISNS_TAG_DD_MEMBER_PORTAL_INDEX = 2070,
+ ISNS_TAG_DD_MEMBER_PORTAL_IP_ADDR = 2071,
+ ISNS_TAG_DD_MEMBER_PORTAL_TCP_UDP_PORT = 2072,
+ ISNS_TAG_DD_FEATURES = 2078,
+ ISNS_TAG_DD_NEXT_ID = 2079,
+ ISNS_VENDOR_SPECIFIC_SERVER_BASE = 257,
+ ISNS_VENDOR_SPECIFIC_ENTITY_BASE = 385,
+ ISNS_VENDOR_SPECIFIC_PORTAL_BASE = 513,
+ ISNS_VENDOR_SPECIFIC_NODE_BASE = 641,
+ ISNS_VENDOR_SPECIFIC_DD_BASE = 1024,
+ ISNS_VENDOR_SPECIFIC_DDSET_BASE = 1281,
+ ISNS_VENDOR_SPECIFIC_OTHER_BASE = 1537,
+ },
- --
- -- Creates a new Attribute instance
- --
- -- @param tag number containing the tag number
- -- @param val string containing the tag value
- -- @param len number containing the tag length
- -- @return o new Attribute instance
- new = function(self, tag, val, len)
- local o = { tag = tag, len = ( len or (val and #val or 0) ), val = val or "" }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ --
+ -- Creates a new Attribute instance
+ --
+ -- @param tag number containing the tag number
+ -- @param val string containing the tag value
+ -- @param len number containing the tag length
+ -- @return o new Attribute instance
+ new = function(self, tag, val, len)
+ local o = { tag = tag, len = ( len or (val and #val or 0) ), val = val or "" }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- --
- -- Creates a new Attribute instance
- --
- -- @param data string containing an opaque string of raw data
- -- @return attr new instance of Attribute
- parse = function(data)
- local attr = Attribute:new()
- local pos
+ --
+ -- Creates a new Attribute instance
+ --
+ -- @param data string containing an opaque string of raw data
+ -- @return attr new instance of Attribute
+ parse = function(data)
+ local attr = Attribute:new()
+ local pos
- pos, attr.tag, attr.len = bin.unpack(">II", data)
- pos, attr.val = bin.unpack(">A" .. attr.len, pos)
+ pos, attr.tag, attr.len = bin.unpack(">II", data)
+ pos, attr.val = bin.unpack(">A" .. attr.len, pos)
- return attr
- end,
+ return attr
+ end,
- --
- -- Converts the instance to an opaque string
- -- @return str containing an opaque string
- __tostring = function(self)
- return bin.pack(">IIA", self.tag, self.len, self.val)
- end,
+ --
+ -- Converts the instance to an opaque string
+ -- @return str containing an opaque string
+ __tostring = function(self)
+ return bin.pack(">IIA", self.tag, self.len, self.val)
+ end,
}
Attributes = {
- --
- -- Creates a new Attributes table
- -- @return o new instance of Attributes
- new = function(self)
- local o = { attribs = {} }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ --
+ -- Creates a new Attributes table
+ -- @return o new instance of Attributes
+ new = function(self)
+ local o = { attribs = {} }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- --
- -- Adds a new Attribute to the table
- -- @param tag number containing the tag number
- -- @param val string containing the tag value
- -- @param len number containing the tag length
- add = function(self, tag, val, len)
- table.insert(self, Attribute:new(tag, val, len))
- end,
+ --
+ -- Adds a new Attribute to the table
+ -- @param tag number containing the tag number
+ -- @param val string containing the tag value
+ -- @param len number containing the tag length
+ add = function(self, tag, val, len)
+ table.insert(self, Attribute:new(tag, val, len))
+ end,
- --
- -- Converts the instance to an opaque string
- -- @return str containing an opaque string
- __tostring = function(self)
- local str = ""
- for _, attr in ipairs(self) do
- str = str .. tostring(attr)
- end
- return str
- end,
+ --
+ -- Converts the instance to an opaque string
+ -- @return str containing an opaque string
+ __tostring = function(self)
+ local str = ""
+ for _, attr in ipairs(self) do
+ str = str .. tostring(attr)
+ end
+ return str
+ end,
}
Request = {
- FuncId = {
- DevAttrReg = 0x0001,
- DevAttrQry = 0x0002,
- DevGetNext = 0x0003,
- DevDereg = 0x0004,
- SCNReg = 0x0005,
- SCNDereg = 0x0006,
- SCNEvent = 0x0007,
- SCN = 0x0008,
- DDReg = 0x0009,
- DDDereg = 0x000A,
- DDSReg = 0x000B,
- DDSDereg = 0x000C,
- ESI = 0x000D,
- Heartbeat = 0x000E,
- },
+ FuncId = {
+ DevAttrReg = 0x0001,
+ DevAttrQry = 0x0002,
+ DevGetNext = 0x0003,
+ DevDereg = 0x0004,
+ SCNReg = 0x0005,
+ SCNDereg = 0x0006,
+ SCNEvent = 0x0007,
+ SCN = 0x0008,
+ DDReg = 0x0009,
+ DDDereg = 0x000A,
+ DDSReg = 0x000B,
+ DDSDereg = 0x000C,
+ ESI = 0x000D,
+ Heartbeat = 0x000E,
+ },
- --
- -- Creates a new Request message
- -- @param func_id number containing the function ID of the message
- -- @param flags number containing the message flags
- -- @param data string containing the opaque raw data
- -- @param auth string containing the opaqur raw auth data
- -- @param trans_id number containing the transaction id
- -- @param seq_id number containing the sequence id
- -- @return o new instance of Request
- new = function(self, func_id, flags, data, auth, trans_id, seq_id)
- local o = {
- header = Header:new(func_id, ( data and #data ) or 0, flags, ( trans_id or -1 ), ( seq_id or -1 )),
- data = data or ""
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ --
+ -- Creates a new Request message
+ -- @param func_id number containing the function ID of the message
+ -- @param flags number containing the message flags
+ -- @param data string containing the opaque raw data
+ -- @param auth string containing the opaqur raw auth data
+ -- @param trans_id number containing the transaction id
+ -- @param seq_id number containing the sequence id
+ -- @return o new instance of Request
+ new = function(self, func_id, flags, data, auth, trans_id, seq_id)
+ local o = {
+ header = Header:new(func_id, ( data and #data ) or 0, flags, ( trans_id or -1 ), ( seq_id or -1 )),
+ data = data or ""
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- --
- -- Converts the instance to an opaque string
- -- @return str containing an opaque string
- __tostring = function(self)
- return tostring(self.header) .. tostring(self.data) ..
- ( self.auth and self.auth or "" )
- end,
+ --
+ -- Converts the instance to an opaque string
+ -- @return str containing an opaque string
+ __tostring = function(self)
+ return tostring(self.header) .. tostring(self.data) ..
+ ( self.auth and self.auth or "" )
+ end,
}
Response = {
- Error = {
- [0] = "Successful",
- [1] = "Unknown Error",
- [2] = "Message Format Error",
- [3] = "Invalid Registration",
- [4] = "RESERVED",
- [5] = "Invalid Query",
- [6] = "Source Unknown",
- [7] = "Source Absent",
- [8] = "Source Unauthorized",
- [9] = "No Such Entry",
- [10] = "Version Not Supported",
- [11] = "Internal Error",
- [12] = "Busy",
- [13] = "Option Not Understood",
- [14] = "Invalid Update",
- [15] = "Message (FUNCTION_ID) Not Supported",
- [16] = "SCN Event Rejected",
- [17] = "SCN Registration Rejected",
- [18] = "Attribute Not Implemented",
- [19] = "FC_DOMAIN_ID Not Available",
- [20] = "FC_DOMAIN_ID Not Allocated",
- [21] = "ESI Not Available",
- [22] = "Invalid Deregistration",
- [23] = "Registration Feature Not Supported",
- },
+ Error = {
+ [0] = "Successful",
+ [1] = "Unknown Error",
+ [2] = "Message Format Error",
+ [3] = "Invalid Registration",
+ [4] = "RESERVED",
+ [5] = "Invalid Query",
+ [6] = "Source Unknown",
+ [7] = "Source Absent",
+ [8] = "Source Unauthorized",
+ [9] = "No Such Entry",
+ [10] = "Version Not Supported",
+ [11] = "Internal Error",
+ [12] = "Busy",
+ [13] = "Option Not Understood",
+ [14] = "Invalid Update",
+ [15] = "Message (FUNCTION_ID) Not Supported",
+ [16] = "SCN Event Rejected",
+ [17] = "SCN Registration Rejected",
+ [18] = "Attribute Not Implemented",
+ [19] = "FC_DOMAIN_ID Not Available",
+ [20] = "FC_DOMAIN_ID Not Allocated",
+ [21] = "ESI Not Available",
+ [22] = "Invalid Deregistration",
+ [23] = "Registration Feature Not Supported",
+ },
- --
- -- Creates a new Response instance
- -- @return o new instance of Response
- new = function(self)
- local o = { attrs = Attributes:new() }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ --
+ -- Creates a new Response instance
+ -- @return o new instance of Response
+ new = function(self)
+ local o = { attrs = Attributes:new() }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- --
- -- Creates a new Response instance
- --
- -- @param data string containing an opaque string of raw data
- -- @return attr new instance of Response
- parse = function(data)
- local hdr = Header.parse(data)
- local pos = #(tostring(hdr)) + 1
- local resp = Response:new()
+ --
+ -- Creates a new Response instance
+ --
+ -- @param data string containing an opaque string of raw data
+ -- @return attr new instance of Response
+ parse = function(data)
+ local hdr = Header.parse(data)
+ local pos = #(tostring(hdr)) + 1
+ local resp = Response:new()
- pos, resp.error = bin.unpack(">I", data, pos)
- if ( resp.error ~= 0 ) then
- return resp
- end
+ pos, resp.error = bin.unpack(">I", data, pos)
+ if ( resp.error ~= 0 ) then
+ return resp
+ end
- while( pos < #data ) do
- local tag, len, val
- pos, tag, len = bin.unpack(">II", data, pos)
- pos, val = bin.unpack("A" .. len, data, pos)
- resp.attrs:add( tag, val, len )
- end
- return resp
- end,
+ while( pos < #data ) do
+ local tag, len, val
+ pos, tag, len = bin.unpack(">II", data, pos)
+ pos, val = bin.unpack("A" .. len, data, pos)
+ resp.attrs:add( tag, val, len )
+ end
+ return resp
+ end,
}
Session = {
- --
- -- Creates a new Session instance
- -- @param host table
- -- @param port table
- -- @return o instance of Session
- new = function(self, host, port)
- local o = {
- host = host,
- port = port,
- seq_id = 0,
- trans_id = 0,
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ --
+ -- Creates a new Session instance
+ -- @param host table
+ -- @param port table
+ -- @return o instance of Session
+ new = function(self, host, port)
+ local o = {
+ host = host,
+ port = port,
+ seq_id = 0,
+ trans_id = 0,
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- --
- -- Connects to the server
- -- @return status true on success, false on failure
- connect = function(self)
- self.socket = nmap.new_socket()
- self.socket:set_timeout(5000)
- return self.socket:connect(self.host, self.port)
- end,
+ --
+ -- Connects to the server
+ -- @return status true on success, false on failure
+ connect = function(self)
+ self.socket = nmap.new_socket()
+ self.socket:set_timeout(5000)
+ return self.socket:connect(self.host, self.port)
+ end,
- --
- -- Sends data to the server
- -- @return status true on success, false on failure
- -- @return err string containing the error message on failure
- send = function(self, req)
- if ( not(req.header) or not(req.header.seq_id) or not(req.header.trans_id) ) then
- return false, "Failed to send invalid request"
- end
+ --
+ -- Sends data to the server
+ -- @return status true on success, false on failure
+ -- @return err string containing the error message on failure
+ send = function(self, req)
+ if ( not(req.header) or not(req.header.seq_id) or not(req.header.trans_id) ) then
+ return false, "Failed to send invalid request"
+ end
- -- update the sequence and transaction ID's
- req.header.seq_id = self.seq_id
- req.header.trans_id = self.trans_id
+ -- update the sequence and transaction ID's
+ req.header.seq_id = self.seq_id
+ req.header.trans_id = self.trans_id
- local status, err = self.socket:send(tostring(req))
- self.trans_id = self.trans_id + 1
+ local status, err = self.socket:send(tostring(req))
+ self.trans_id = self.trans_id + 1
- return status, err
- end,
+ return status, err
+ end,
- --
- -- Receives data from the server
- -- @return status true on success, false on failure
- -- @return response instance of response
- receive = function(self)
- -- receive the 24 byte header
- local status, buf_hdr = self.socket:receive_buf(match.numbytes(12), true)
- if ( not(status) ) then
- return status, buf_hdr
- end
+ --
+ -- Receives data from the server
+ -- @return status true on success, false on failure
+ -- @return response instance of response
+ receive = function(self)
+ -- receive the 24 byte header
+ local status, buf_hdr = self.socket:receive_buf(match.numbytes(12), true)
+ if ( not(status) ) then
+ return status, buf_hdr
+ end
- local hdr = Header.parse(buf_hdr)
+ local hdr = Header.parse(buf_hdr)
- -- receive the data
- local buf_data = nil
- status, buf_data = self.socket:receive_buf(match.numbytes(hdr.pdu_len), true)
- if ( not(status) ) then
- return status, buf_data
- end
+ -- receive the data
+ local buf_data = nil
+ status, buf_data = self.socket:receive_buf(match.numbytes(hdr.pdu_len), true)
+ if ( not(status) ) then
+ return status, buf_data
+ end
- return true, Response.parse(buf_hdr .. buf_data)
- end,
+ return true, Response.parse(buf_hdr .. buf_data)
+ end,
- close = function(self)
- return self.close()
- end
+ close = function(self)
+ return self.close()
+ end
}
Helper = {
- --
- -- Creates a new Helper instance
- -- @param host param
- -- @param port param
- -- @return o new instance of Helper
- new = function(self, host, port)
- local o = { session = Session:new(host, port) }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ --
+ -- Creates a new Helper instance
+ -- @param host param
+ -- @param port param
+ -- @return o new instance of Helper
+ new = function(self, host, port)
+ local o = { session = Session:new(host, port) }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- --
- -- Connects to the server
- -- @return status true on success, false on failure
- connect = function(self)
- return self.session:connect()
- end,
+ --
+ -- Connects to the server
+ -- @return status true on success, false on failure
+ connect = function(self)
+ return self.session:connect()
+ end,
- --
- -- Lists portals
- -- @return status true on success, false on failure
- -- @return resulst list of iSCSI nodes, err string on failure
- listPortals = function(self)
- local attribs, name = Attributes:new(), "iqn.control.node\0por"
+ --
+ -- Lists portals
+ -- @return status true on success, false on failure
+ -- @return resulst list of iSCSI nodes, err string on failure
+ listPortals = function(self)
+ local attribs, name = Attributes:new(), "iqn.control.node\0por"
- attribs:add(Attribute.Tag.ISNS_TAG_ISCSI_NAME, name)
- attribs:add(Attribute.Tag.ISNS_TAG_PORTAL_IP_ADDRESS)
- attribs:add(Attribute.Tag.ISNS_TAG_DELIMITER)
- attribs:add(Attribute.Tag.ISNS_TAG_PORTAL_IP_ADDRESS)
- attribs:add(Attribute.Tag.ISNS_TAG_PORTAL_TCP_UDP_PORT)
- attribs:add(Attribute.Tag.ISNS_TAG_ENTITY_IDENTIFIER)
+ attribs:add(Attribute.Tag.ISNS_TAG_ISCSI_NAME, name)
+ attribs:add(Attribute.Tag.ISNS_TAG_PORTAL_IP_ADDRESS)
+ attribs:add(Attribute.Tag.ISNS_TAG_DELIMITER)
+ attribs:add(Attribute.Tag.ISNS_TAG_PORTAL_IP_ADDRESS)
+ attribs:add(Attribute.Tag.ISNS_TAG_PORTAL_TCP_UDP_PORT)
+ attribs:add(Attribute.Tag.ISNS_TAG_ENTITY_IDENTIFIER)
- local flags = 0x8c00 -- Sender is iSNS client, Last PDU, First PDU
+ local flags = 0x8c00 -- Sender is iSNS client, Last PDU, First PDU
- local req = Request:new(Request.FuncId.DevAttrQry, flags, tostring(attribs))
- if ( not(self.session:send(req)) ) then
- return false, "Failed to send message to server"
- end
+ local req = Request:new(Request.FuncId.DevAttrQry, flags, tostring(attribs))
+ if ( not(self.session:send(req)) ) then
+ return false, "Failed to send message to server"
+ end
- local status, resp = self.session:receive()
- if ( not(status) ) then
- return false, "Failed to receive message from server"
- end
+ local status, resp = self.session:receive()
+ if ( not(status) ) then
+ return false, "Failed to receive message from server"
+ end
- local results = {}
- local addr, proto, port
- for _, attr in ipairs(resp.attrs) do
- if ( attr.tag == Attribute.Tag.ISNS_TAG_PORTAL_IP_ADDRESS ) then
- addr = attr.val
- local pos, is_ipv4 = bin.unpack("A12", addr)
- if ( is_ipv4 == "\0\0\0\0\0\0\0\0\0\0\xFF\xFF" ) then
- local pos, bin_ip = bin.unpack("B4", addr, 13)
- addr = ipops.bin_to_ip(bin_ip)
- else
- local pos, bin_ip = bin.unpack("B16", addr)
- addr = ipops.bin_to_ip(bin_ip)
- end
- elseif ( attr.tag == Attribute.Tag.ISNS_TAG_PORTAL_TCP_UDP_PORT ) then
- local pos, s1
- pos, s1, port = bin.unpack(">SS", attr.val)
+ local results = {}
+ local addr, proto, port
+ for _, attr in ipairs(resp.attrs) do
+ if ( attr.tag == Attribute.Tag.ISNS_TAG_PORTAL_IP_ADDRESS ) then
+ addr = attr.val
+ local pos, is_ipv4 = bin.unpack("A12", addr)
+ if ( is_ipv4 == "\0\0\0\0\0\0\0\0\0\0\xFF\xFF" ) then
+ local pos, bin_ip = bin.unpack("B4", addr, 13)
+ addr = ipops.bin_to_ip(bin_ip)
+ else
+ local pos, bin_ip = bin.unpack("B16", addr)
+ addr = ipops.bin_to_ip(bin_ip)
+ end
+ elseif ( attr.tag == Attribute.Tag.ISNS_TAG_PORTAL_TCP_UDP_PORT ) then
+ local pos, s1
+ pos, s1, port = bin.unpack(">SS", attr.val)
- if ( s1 == 1 ) then
- proto = "udp"
- elseif ( s1 == 0 ) then
- proto = "tcp"
- else
- proto = "UNKNOWN"
- end
- elseif ( addr and proto and port ) then
- table.insert(results, { addr = addr, proto = proto, port = port } )
- addr, proto, port = nil, nil, nil
- end
- end
- return true, results
- end,
+ if ( s1 == 1 ) then
+ proto = "udp"
+ elseif ( s1 == 0 ) then
+ proto = "tcp"
+ else
+ proto = "UNKNOWN"
+ end
+ elseif ( addr and proto and port ) then
+ table.insert(results, { addr = addr, proto = proto, port = port } )
+ addr, proto, port = nil, nil, nil
+ end
+ end
+ return true, results
+ end,
- --
- -- Lists iSCSI nodes
- -- @return status true on success, false on failure
- -- @return resulst list of iSCSI nodes, err string on failure
- listISCINodes = function(self)
- local attribs = Attributes:new()
- local name = "iqn.control.node\0por"
- attribs:add(Attribute.Tag.ISNS_TAG_ISCSI_NAME, name)
- attribs:add(Attribute.Tag.ISNS_TAG_ISCSI_NAME)
- attribs:add(Attribute.Tag.ISNS_TAG_DELIMITER)
- attribs:add(Attribute.Tag.ISNS_TAG_ISCSI_NAME)
- attribs:add(Attribute.Tag.ISNS_TAG_ISCSI_NODE_TYPE)
+ --
+ -- Lists iSCSI nodes
+ -- @return status true on success, false on failure
+ -- @return resulst list of iSCSI nodes, err string on failure
+ listISCINodes = function(self)
+ local attribs = Attributes:new()
+ local name = "iqn.control.node\0por"
+ attribs:add(Attribute.Tag.ISNS_TAG_ISCSI_NAME, name)
+ attribs:add(Attribute.Tag.ISNS_TAG_ISCSI_NAME)
+ attribs:add(Attribute.Tag.ISNS_TAG_DELIMITER)
+ attribs:add(Attribute.Tag.ISNS_TAG_ISCSI_NAME)
+ attribs:add(Attribute.Tag.ISNS_TAG_ISCSI_NODE_TYPE)
- local flags = 0x8c00 -- Sender is iSNS client, Last PDU, First PDU
+ local flags = 0x8c00 -- Sender is iSNS client, Last PDU, First PDU
- local req = Request:new(Request.FuncId.DevAttrQry, flags, tostring(attribs))
- if ( not(self.session:send(req)) ) then
- return false, "Failed to send message to server"
- end
+ local req = Request:new(Request.FuncId.DevAttrQry, flags, tostring(attribs))
+ if ( not(self.session:send(req)) ) then
+ return false, "Failed to send message to server"
+ end
- local status, resp = self.session:receive()
- if ( not(status) ) then
- return false, "Failed to receive message from server"
- end
+ local status, resp = self.session:receive()
+ if ( not(status) ) then
+ return false, "Failed to receive message from server"
+ end
- local name, ntype
- local results = {}
- for _, attr in ipairs(resp.attrs) do
- if ( attr.tag == Attribute.Tag.ISNS_TAG_ISCSI_NAME ) then
- name = attr.val
- elseif( attr.tag == Attribute.Tag.ISNS_TAG_ISCSI_NODE_TYPE ) then
- local _, val = bin.unpack(">I", attr.val)
- if ( val == iSCSI.NodeType.CONTROL ) then
- ntype = "Control"
- elseif ( val == iSCSI.NodeType.INITIATOR ) then
- ntype = "Initiator"
- elseif ( val == iSCSI.NodeType.TARGET ) then
- ntype = "Target"
- else
- ntype = "Unknown"
- end
- end
- if ( name and ntype ) then
- table.insert(results, { name = name:match("^([^\0]*)"), type = ntype })
- name, ntype = nil, nil
- end
- end
- return true, results
- end,
+ local name, ntype
+ local results = {}
+ for _, attr in ipairs(resp.attrs) do
+ if ( attr.tag == Attribute.Tag.ISNS_TAG_ISCSI_NAME ) then
+ name = attr.val
+ elseif( attr.tag == Attribute.Tag.ISNS_TAG_ISCSI_NODE_TYPE ) then
+ local _, val = bin.unpack(">I", attr.val)
+ if ( val == iSCSI.NodeType.CONTROL ) then
+ ntype = "Control"
+ elseif ( val == iSCSI.NodeType.INITIATOR ) then
+ ntype = "Initiator"
+ elseif ( val == iSCSI.NodeType.TARGET ) then
+ ntype = "Target"
+ else
+ ntype = "Unknown"
+ end
+ end
+ if ( name and ntype ) then
+ table.insert(results, { name = name:match("^([^\0]*)"), type = ntype })
+ name, ntype = nil, nil
+ end
+ end
+ return true, results
+ end,
- close = function(self)
- return self.session:close()
- end,
+ close = function(self)
+ return self.session:close()
+ end,
}
diff --git a/nselib/json.lua b/nselib/json.lua
index 9cc0d752e..88607b163 100644
--- a/nselib/json.lua
+++ b/nselib/json.lua
@@ -32,21 +32,21 @@ _ENV = stdnse.module("json", stdnse.seeall)
--Some local shortcuts
local function dbg(str,...)
- stdnse.print_debug("Json:"..str, ...)
+ stdnse.print_debug("Json:"..str, ...)
end
local function d4(str,...)
- if nmap.debugging() > 3 then dbg(str, ...) end
+ if nmap.debugging() > 3 then dbg(str, ...) end
end
local function d3(str,...)
- if nmap.debugging() > 2 then dbg(str, ...) end
+ if nmap.debugging() > 2 then dbg(str, ...) end
end
--local dbg =stdnse.print_debug
local function dbg_err(str,...)
- stdnse.print_debug("json-ERR:"..str, ...)
+ stdnse.print_debug("json-ERR:"..str, ...)
end
- -- Javascript null representation, see explanation above
+-- Javascript null representation, see explanation above
NULL = {}
-- See section 2.5 for escapes.
@@ -56,45 +56,45 @@ NULL = {}
local ESCAPE_TABLE = {}
local REVERSE_ESCAPE_TABLE = {}
do
- local escapes = {
- [string.char(0x22)] = "\"",
- [string.char(0x5C)] = "\\",
- [string.char(0x2F)] = "/",
- [string.char(0x08)] = "b",
- [string.char(0x0C)] = "f",
- [string.char(0x0A)] = "n",
- [string.char(0x0D)] = "r",
- [string.char(0x09)] = "t",
- }
- for k, v in pairs(escapes) do
- ESCAPE_TABLE[k] = "\\" .. v
- REVERSE_ESCAPE_TABLE[v] = k
- end
+ local escapes = {
+ [string.char(0x22)] = "\"",
+ [string.char(0x5C)] = "\\",
+ [string.char(0x2F)] = "/",
+ [string.char(0x08)] = "b",
+ [string.char(0x0C)] = "f",
+ [string.char(0x0A)] = "n",
+ [string.char(0x0D)] = "r",
+ [string.char(0x09)] = "t",
+ }
+ for k, v in pairs(escapes) do
+ ESCAPE_TABLE[k] = "\\" .. v
+ REVERSE_ESCAPE_TABLE[v] = k
+ end
end
-- Escapes a string
--@param str the string
--@return a string where the special chars have been escaped
local function escape(str)
- return "\"" .. string.gsub(str, ".", ESCAPE_TABLE) .. "\""
+ return "\"" .. string.gsub(str, ".", ESCAPE_TABLE) .. "\""
end
--- Makes a table be treated as a JSON Array when generating JSON
-- A table treated as an Array has all non-number indices ignored.
-- () param t a table to be treated as an array
function make_array(t)
- local mt = getmetatable(t) or {}
- mt["json"] = "array"
- setmetatable(t, mt)
+ local mt = getmetatable(t) or {}
+ mt["json"] = "array"
+ setmetatable(t, mt)
end
--- Makes a table be treated as a JSON Object when generating JSON
-- A table treated as an Object has all non-number indices ignored.
-- () param t a table to be treated as an object
function make_object(t)
- local mt = getmetatable(t) or {}
- mt["json"] = "object"
- setmetatable(t, mt)
+ local mt = getmetatable(t) or {}
+ mt["json"] = "object"
+ setmetatable(t, mt)
end
--- Checks what JSON type a variable will be treated as when generating JSON
@@ -102,20 +102,20 @@ end
-- () return a string containing the JSON type. Valid values are "array",
-- "object", "number", "string", "boolean", and "null"
function typeof(var)
- local t = type(var)
- if var == NULL then
- return "null"
- elseif t == "table" then
- local mtval = rawget(getmetatable(var) or {}, "json")
- if mtval == "array" or (mtval ~= "object" and #var > 0) then
- return "array"
- else
- return "object"
- end
- else
- return t
- end
- error("Unknown data type in typeof")
+ local t = type(var)
+ if var == NULL then
+ return "null"
+ elseif t == "table" then
+ local mtval = rawget(getmetatable(var) or {}, "json")
+ if mtval == "array" or (mtval ~= "object" and #var > 0) then
+ return "array"
+ else
+ return "object"
+ end
+ else
+ return t
+ end
+ error("Unknown data type in typeof")
end
--- Creates json data from an object
@@ -123,22 +123,22 @@ end
--@return a string containing valid json
function generate(obj)
- -- NULL-check must be performed before
- -- checking type == table, since the NULL-object
- -- is a table
- if obj == NULL then
- return "null"
- elseif obj == false then
- return "false"
- elseif obj == true then
- return "true"
- elseif type(obj) == "number" then
- return string.format("%g", obj)
- elseif type(obj) == "string" then
- return escape(obj)
- elseif type(obj) == "table" then
- local k, v, elems, jtype
- elems = {}
+ -- NULL-check must be performed before
+ -- checking type == table, since the NULL-object
+ -- is a table
+ if obj == NULL then
+ return "null"
+ elseif obj == false then
+ return "false"
+ elseif obj == true then
+ return "true"
+ elseif type(obj) == "number" then
+ return string.format("%g", obj)
+ elseif type(obj) == "string" then
+ return escape(obj)
+ elseif type(obj) == "table" then
+ local k, v, elems, jtype
+ elems = {}
jtype = typeof(obj)
if jtype == "array" then
for _, v in ipairs(obj) do
@@ -151,54 +151,54 @@ function generate(obj)
end
return "{" .. table.concat(elems, ", ") .. "}"
end
- end
- error("Unknown data type in generate")
+ end
+ error("Unknown data type in generate")
end
-- This is the parser, implemented in OO-form to deal with state better
Json = {}
-- Constructor
function Json:new(input)
- local o = {}
- setmetatable(o, self)
- self.__index = self
- o.input = input
- o.pos = 1 -- Pos is where the NEXT letter will be read
- return o
+ local o = {}
+ setmetatable(o, self)
+ self.__index = self
+ o.input = input
+ o.pos = 1 -- Pos is where the NEXT letter will be read
+ return o
end
-- Gets next character and ups the position
--@return next character
function Json:next()
- self.pos = self.pos+1
- return self.input:sub(self.pos-1, self.pos-1)
+ self.pos = self.pos+1
+ return self.input:sub(self.pos-1, self.pos-1)
end
-- Updates the position to next non whitespace position
function Json:eatWhiteSpace()
- --Find next non-white char
- local a,b = self.input:find("%S",self.pos)
- if not a then
- self:syntaxerror("Empty data")
- return
- end
- self.pos = a
+ --Find next non-white char
+ local a,b = self.input:find("%S",self.pos)
+ if not a then
+ self:syntaxerror("Empty data")
+ return
+ end
+ self.pos = a
end
-- Jumps to a specified position
--@param position where to go
function Json:jumpTo(position)
- self.pos = position
+ self.pos = position
end
-- Returns next character, but without upping position
--@return next character
function Json:peek()
- return self.input:sub(self.pos, self.pos)
+ return self.input:sub(self.pos, self.pos)
end
--@return true if more input is in store
function Json:hasMore()
- return self.input:len() >= self.pos
+ return self.input:len() >= self.pos
end
-- Checks that the following input is equal to a string
@@ -206,270 +206,270 @@ end
-- If false, triggers a syntax error
--@param str the string to test
function Json:assertStr(str)
- local content = self.input:sub(self.pos,self.pos+str:len()-1)
- if(content == str) then-- All ok
- -- Jump forward
- self:jumpTo(self.pos+str:len())
- return
- end
- self:syntaxerror(("Expected '%s' but got '%s'"):format( str, content))
+ local content = self.input:sub(self.pos,self.pos+str:len()-1)
+ if(content == str) then-- All ok
+ -- Jump forward
+ self:jumpTo(self.pos+str:len())
+ return
+ end
+ self:syntaxerror(("Expected '%s' but got '%s'"):format( str, content))
end
-- Trigger a syntax error
function Json:syntaxerror(reason)
- self.error = ("Syntax error near pos %d: %s input: %s"):format( self.pos, reason, self.input)
- dbg(self.error)
+ self.error = ("Syntax error near pos %d: %s input: %s"):format( self.pos, reason, self.input)
+ dbg(self.error)
end
-- Check if any errors has occurred
function Json:errors()
- return self.error ~= nil
+ return self.error ~= nil
end
-- Parses a top-level JSON structure (object or array).
--@return the parsed object or puts error messages in self.error
function Json:parseStart()
- -- The top level of JSON only allows an object or an array. Only inside
- -- of the outermost container can other types appear.
- self:eatWhiteSpace()
- local c = self:peek()
- if c == '{' then
- return self:parseObject()
- elseif c == '[' then
- return self:parseArray()
- else
- self:syntaxerror(("JSON must start with object or array (started with %s)"):format(c))
- return
- end
+ -- The top level of JSON only allows an object or an array. Only inside
+ -- of the outermost container can other types appear.
+ self:eatWhiteSpace()
+ local c = self:peek()
+ if c == '{' then
+ return self:parseObject()
+ elseif c == '[' then
+ return self:parseArray()
+ else
+ self:syntaxerror(("JSON must start with object or array (started with %s)"):format(c))
+ return
+ end
end
-- Parses a value
--@return the parsed value
function Json:parseValue()
- self:eatWhiteSpace()
- local c = self:peek()
+ self:eatWhiteSpace()
+ local c = self:peek()
- local value
- if c == '{' then
- value = self:parseObject()
- elseif c == '[' then
- value = self:parseArray()
- elseif c == '"' then
- value = self:parseString()
- elseif c == 'n' then
- self:assertStr("null")
- value = NULL
- elseif c == 't' then
- self:assertStr("true")
- value = true
- elseif c == 'f' then
- self:assertStr("false")
- value = false
- else -- numeric
- -- number = [ minus ] int [ frac ] [ exp ]
- local a,b =self.input:find("-?%d+%.?%d*[eE]?[+-]?%d*", self.pos)
- if not a or not b then
- self:syntaxerror("Error 1 parsing numeric value")
- return
- end
- value = tonumber(self.input:sub(a,b))
- if(value == nil) then
- self:syntaxerror("Error 2 parsing numeric value")
- return
- end
- self:jumpTo(b+1)
- end
- return value
+ local value
+ if c == '{' then
+ value = self:parseObject()
+ elseif c == '[' then
+ value = self:parseArray()
+ elseif c == '"' then
+ value = self:parseString()
+ elseif c == 'n' then
+ self:assertStr("null")
+ value = NULL
+ elseif c == 't' then
+ self:assertStr("true")
+ value = true
+ elseif c == 'f' then
+ self:assertStr("false")
+ value = false
+ else -- numeric
+ -- number = [ minus ] int [ frac ] [ exp ]
+ local a,b =self.input:find("-?%d+%.?%d*[eE]?[+-]?%d*", self.pos)
+ if not a or not b then
+ self:syntaxerror("Error 1 parsing numeric value")
+ return
+ end
+ value = tonumber(self.input:sub(a,b))
+ if(value == nil) then
+ self:syntaxerror("Error 2 parsing numeric value")
+ return
+ end
+ self:jumpTo(b+1)
+ end
+ return value
end
-- Parses a json object {}
--@return the object (or triggers a syntax error)
function Json:parseObject()
- local object = {}
- make_object(object)
- local _= self:next() -- Eat {
+ local object = {}
+ make_object(object)
+ local _= self:next() -- Eat {
- while(self:hasMore() and not self:errors()) do
- self:eatWhiteSpace()
- local c = self:peek()
- if(c == '}') then -- Empty object, probably
- self:next() -- Eat it
- return object
- end
+ while(self:hasMore() and not self:errors()) do
+ self:eatWhiteSpace()
+ local c = self:peek()
+ if(c == '}') then -- Empty object, probably
+ self:next() -- Eat it
+ return object
+ end
- if(c ~= '"') then
- self:syntaxerror(("Expected '\"', got '%s'"):format(c))
- return
- end
+ if(c ~= '"') then
+ self:syntaxerror(("Expected '\"', got '%s'"):format(c))
+ return
+ end
- local key = self:parseString()
- if self:errors() then
- return
- end
- self:eatWhiteSpace()
- c = self:next()
- if(c ~= ':') then
- self:syntaxerror("Expected ':' got "..c)
- return
- end
- local value = self:parseValue()
+ local key = self:parseString()
+ if self:errors() then
+ return
+ end
+ self:eatWhiteSpace()
+ c = self:next()
+ if(c ~= ':') then
+ self:syntaxerror("Expected ':' got "..c)
+ return
+ end
+ local value = self:parseValue()
- if self:errors() then
- return
- end
+ if self:errors() then
+ return
+ end
- object[key] = value
+ object[key] = value
- self:eatWhiteSpace()
- c = self:next()
- -- Valid now is , or }
- if(c == '}') then
- return object
- end
- if(c ~= ',') then
- self:syntaxerror("Expected ',' or '}', got "..c)
- return
- end
- end
+ self:eatWhiteSpace()
+ c = self:next()
+ -- Valid now is , or }
+ if(c == '}') then
+ return object
+ end
+ if(c ~= ',') then
+ self:syntaxerror("Expected ',' or '}', got "..c)
+ return
+ end
+ end
end
-- Parses a json array [] or triggers a syntax error
--@return the array object
function Json:parseArray()
- local array = {}
- make_array(array)
- self:next()
- while(self:hasMore() and not self:errors()) do
- self:eatWhiteSpace()
- if(self:peek() == ']') then -- Empty array, probably
- self:next()
- break
- end
- local value = self:parseValue()
- if self:errors() then
- return
- end
- table.insert(array, value)
- self:eatWhiteSpace()
- local c = self:next()
- -- Valid now is , or ]
- if(c == ']') then return array end
- if(c ~= ',') then
- self:syntaxerror(("Expected ',' but got '%s'"):format(c))
- return
- end
- end
- return array
+ local array = {}
+ make_array(array)
+ self:next()
+ while(self:hasMore() and not self:errors()) do
+ self:eatWhiteSpace()
+ if(self:peek() == ']') then -- Empty array, probably
+ self:next()
+ break
+ end
+ local value = self:parseValue()
+ if self:errors() then
+ return
+ end
+ table.insert(array, value)
+ self:eatWhiteSpace()
+ local c = self:next()
+ -- Valid now is , or ]
+ if(c == ']') then return array end
+ if(c ~= ',') then
+ self:syntaxerror(("Expected ',' but got '%s'"):format(c))
+ return
+ end
+ end
+ return array
end
-- Decode a Unicode escape, assuming that self.pos starts just after the
-- initial \u. May consume an additional escape in the case of a UTF-16
-- surrogate pair. See RFC 2781 for UTF-16.
function Json:parseUnicodeEscape()
- local n, cp
- local hex, lowhex
- local s, e
+ local n, cp
+ local hex, lowhex
+ local s, e
- s, e, hex = self.input:find("^(....)", self.pos)
- if not hex then
- self:syntaxerror(("EOF in Unicode escape \\u%s"):format(self.input:sub(self.pos)))
- return
- end
- n = tonumber(hex, 16)
- if not n then
- self:syntaxerror(("Bad unicode escape \\u%s"):format(hex))
- return
- end
- cp = n
- self.pos = e + 1
- if n < 0xD800 or n > 0xDFFF then
- return cp
- end
- if n >= 0xDC00 and n <= 0xDFFF then
- self:syntaxerror(("Not a Unicode character: U+%04X"):format(cp))
- return
- end
+ s, e, hex = self.input:find("^(....)", self.pos)
+ if not hex then
+ self:syntaxerror(("EOF in Unicode escape \\u%s"):format(self.input:sub(self.pos)))
+ return
+ end
+ n = tonumber(hex, 16)
+ if not n then
+ self:syntaxerror(("Bad unicode escape \\u%s"):format(hex))
+ return
+ end
+ cp = n
+ self.pos = e + 1
+ if n < 0xD800 or n > 0xDFFF then
+ return cp
+ end
+ if n >= 0xDC00 and n <= 0xDFFF then
+ self:syntaxerror(("Not a Unicode character: U+%04X"):format(cp))
+ return
+ end
- -- Beginning of a UTF-16 surrogate.
- s, e, lowhex = self.input:find("^\\u(....)", self.pos)
- if not lowhex then
- self:syntaxerror(("Bad unicode escape \\u%s (missing low surrogate)"):format(hex))
- return
- end
- n = tonumber(lowhex, 16)
- if not n or not (n >= 0xDC00 and n <= 0xDFFF) then
- self:syntaxerror(("Bad unicode escape \\u%s\\u%s (bad low surrogate)"):format(hex, lowhex))
- return
- end
- self.pos = e + 1
- cp = 0x10000 + bit.band(cp, 0x3FF) * 0x400 + bit.band(n, 0x3FF)
- -- also remove last "
- return cp
+ -- Beginning of a UTF-16 surrogate.
+ s, e, lowhex = self.input:find("^\\u(....)", self.pos)
+ if not lowhex then
+ self:syntaxerror(("Bad unicode escape \\u%s (missing low surrogate)"):format(hex))
+ return
+ end
+ n = tonumber(lowhex, 16)
+ if not n or not (n >= 0xDC00 and n <= 0xDFFF) then
+ self:syntaxerror(("Bad unicode escape \\u%s\\u%s (bad low surrogate)"):format(hex, lowhex))
+ return
+ end
+ self.pos = e + 1
+ cp = 0x10000 + bit.band(cp, 0x3FF) * 0x400 + bit.band(n, 0x3FF)
+ -- also remove last "
+ return cp
end
-- Encode a Unicode code point to UTF-8. See RFC 3629.
-- Does not check that cp is a real charaacter; that is, doesn't exclude the
-- surrogate range U+D800 - U+DFFF and a handful of others.
local function utf8_enc(cp)
- local bytes = {}
- local n, mask
+ local bytes = {}
+ local n, mask
- if cp % 1.0 ~= 0.0 or cp < 0 then
- -- Only defined for nonnegative integers.
- return nil
- elseif cp <= 0x7F then
- -- Special case of one-byte encoding.
- return string.char(cp)
- elseif cp <= 0x7FF then
- n = 2
- mask = 0xC0
- elseif cp <= 0xFFFF then
- n = 3
- mask = 0xE0
- elseif cp <= 0x10FFFF then
- n = 4
- mask = 0xF0
- else
- return nil
- end
+ if cp % 1.0 ~= 0.0 or cp < 0 then
+ -- Only defined for nonnegative integers.
+ return nil
+ elseif cp <= 0x7F then
+ -- Special case of one-byte encoding.
+ return string.char(cp)
+ elseif cp <= 0x7FF then
+ n = 2
+ mask = 0xC0
+ elseif cp <= 0xFFFF then
+ n = 3
+ mask = 0xE0
+ elseif cp <= 0x10FFFF then
+ n = 4
+ mask = 0xF0
+ else
+ return nil
+ end
- while n > 1 do
- bytes[n] = string.char(0x80 + bit.band(cp, 0x3F))
- cp = bit.rshift(cp, 6)
- n = n - 1
- end
- bytes[1] = string.char(mask + cp)
+ while n > 1 do
+ bytes[n] = string.char(0x80 + bit.band(cp, 0x3F))
+ cp = bit.rshift(cp, 6)
+ n = n - 1
+ end
+ bytes[1] = string.char(mask + cp)
- return table.concat(bytes)
+ return table.concat(bytes)
end
-- Parses a json string
-- @return the string or triggers syntax error
function Json:parseString()
- local val = ''
- local c = self:next()
- assert( c == '"')
- while(self:hasMore()) do
- local c = self:next()
+ local val = ''
+ local c = self:next()
+ assert( c == '"')
+ while(self:hasMore()) do
+ local c = self:next()
- if(c == '"') then -- end of string
- break
- elseif(c == '\\') then-- Escaped char
- local d = self:next()
- if REVERSE_ESCAPE_TABLE[d] ~= nil then
- val = val .. REVERSE_ESCAPE_TABLE[d]
- elseif d == 'u' then -- Unicode chars
- local codepoint = self:parseUnicodeEscape()
- if not codepoint then
- return
- end
- val = val .. utf8_enc(codepoint)
- else
- self:syntaxerror(("Undefined escape character '%s'"):format(d))
- return false
- end
- else -- Char
- val = val .. c
- end
- end
- return val
+ if(c == '"') then -- end of string
+ break
+ elseif(c == '\\') then-- Escaped char
+ local d = self:next()
+ if REVERSE_ESCAPE_TABLE[d] ~= nil then
+ val = val .. REVERSE_ESCAPE_TABLE[d]
+ elseif d == 'u' then -- Unicode chars
+ local codepoint = self:parseUnicodeEscape()
+ if not codepoint then
+ return
+ end
+ val = val .. utf8_enc(codepoint)
+ else
+ self:syntaxerror(("Undefined escape character '%s'"):format(d))
+ return false
+ end
+ else -- Char
+ val = val .. c
+ end
+end
+return val
end
--- Parses json data into an object form
-- This is the method you probably want to use if you
@@ -478,12 +478,12 @@ end
--@return status true if ok, false if bad
--@return an object representing the json, or error message
function parse(data)
- local parser = Json:new(data)
- local result = parser:parseStart()
- if(parser.error) then
- return false, parser.error
- end
- return true, result
+ local parser = Json:new(data)
+ local result = parser:parseStart()
+ if(parser.error) then
+ return false, parser.error
+ end
+ return true, result
end
----------------------------------------------------------------------------------
@@ -491,52 +491,52 @@ end
----------------------------------------------------------------------------------
local TESTS = {
- '{"a":1}',
- '{"a":true}',
- '{"a": false}',
- '{"a": null \r\n, \t "b" \f:"ehlo"}',
- '{"a\\"a":"a\\"b\\"c\\"d"}',
- '{"foo":"gaz\\"onk", "pi":3.14159,"hello":{ "wo":"rld"}}',
- '{"a":1, "b":2}',
- '{"foo":"gazonk", "pi":3.14159,"hello":{ "wo":"rl\\td"}}',
- '[1,2,3,4,5,null,false,true,"\195\164\195\165\195\182\195\177","bar"]',
- '[]',-- This will yield {} in toJson, since in lua there is only one basic datatype - and no difference when empty
- '{}',
+ '{"a":1}',
+ '{"a":true}',
+ '{"a": false}',
+ '{"a": null \r\n, \t "b" \f:"ehlo"}',
+ '{"a\\"a":"a\\"b\\"c\\"d"}',
+ '{"foo":"gaz\\"onk", "pi":3.14159,"hello":{ "wo":"rld"}}',
+ '{"a":1, "b":2}',
+ '{"foo":"gazonk", "pi":3.14159,"hello":{ "wo":"rl\\td"}}',
+ '[1,2,3,4,5,null,false,true,"\195\164\195\165\195\182\195\177","bar"]',
+ '[]',-- This will yield {} in toJson, since in lua there is only one basic datatype - and no difference when empty
+ '{}',
- '', -- error
- 'null', -- error
- '"abc"', -- error
- '{a":1}', -- error
- '{"a" bad :1}', -- error
- '["a\\\\t"]', -- Should become Lua {"a\\t"}
- '[0.0.0]', -- error
- '[-1]',
- '[-1.123e-2]',
- '[5e3]',
- '[5e+3]',
- '[5E-3]',
- '[5.5e3]',
- '["a\\\\"]', -- Should become Lua {"a\\"}
- '{"a}": 1}', -- Should become Lua {"a}" = 1}
- '["key": "value"]', -- error
- '["\\u0041"]', -- Should become Lua {"A"}
- '["\\uD800"]', -- error
- '["\\uD834\\uDD1EX"]', -- Should become Lua {"\240\157\132\158X"}
+ '', -- error
+ 'null', -- error
+ '"abc"', -- error
+ '{a":1}', -- error
+ '{"a" bad :1}', -- error
+ '["a\\\\t"]', -- Should become Lua {"a\\t"}
+ '[0.0.0]', -- error
+ '[-1]',
+ '[-1.123e-2]',
+ '[5e3]',
+ '[5e+3]',
+ '[5E-3]',
+ '[5.5e3]',
+ '["a\\\\"]', -- Should become Lua {"a\\"}
+ '{"a}": 1}', -- Should become Lua {"a}" = 1}
+ '["key": "value"]', -- error
+ '["\\u0041"]', -- Should become Lua {"A"}
+ '["\\uD800"]', -- error
+ '["\\uD834\\uDD1EX"]', -- Should become Lua {"\240\157\132\158X"}
}
function test()
- print("Tests running")
- local i,v,res,status
- for i,v in pairs(TESTS) do
- print("----------------------------")
- print(v)
- status,res = parse(v)
- if not status then print( res) end
- if(status) then
- print(generate(res))
- else
- print("Error:".. res)
- end
- end
+ print("Tests running")
+ local i,v,res,status
+ for i,v in pairs(TESTS) do
+ print("----------------------------")
+ print(v)
+ status,res = parse(v)
+ if not status then print( res) end
+ if(status) then
+ print(generate(res))
+ else
+ print("Error:".. res)
+ end
+ end
end
return _ENV;
diff --git a/nselib/listop.lua b/nselib/listop.lua
index ca07d629d..354cd3b76 100644
--- a/nselib/listop.lua
+++ b/nselib/listop.lua
@@ -17,21 +17,21 @@ _ENV = stdnse.module("listop", stdnse.seeall)
--
Functional programming style 'list' operations
- bool is_empty(list)
- bool is_list(value)
+ bool is_empty(list)
+ bool is_list(value)
- value apply(function, list)
- list map(function, list)
- list filter(function, list)
- list flatten(list)
- list append(list1, list2)
- list cons(value1, value2)
- list reverse(list)
+ value apply(function, list)
+ list map(function, list)
+ list filter(function, list)
+ list flatten(list)
+ list append(list1, list2)
+ list cons(value1, value2)
+ list reverse(list)
- value car(list)
- value ncar(list, x)
- list cdr(list)
- list ncdr(list, x)
+ value car(list)
+ value ncar(list, x)
+ list cdr(list)
+ list ncdr(list, x)
where 'list' is an indexed table
where 'value' is an lua datatype
@@ -59,11 +59,11 @@ end
-- @param l A list.
-- @return List of function results.
function map(f, l)
- local results = {}
- for _, v in ipairs(l) do
- results[#results+1] = f(v);
- end
- return results;
+ local results = {}
+ for _, v in ipairs(l) do
+ results[#results+1] = f(v);
+ end
+ return results;
end
--- Calls the function with all the elements in the list as the parameters.
@@ -90,9 +90,9 @@ end
function filter(f, l)
local results = {}
for i, v in ipairs(l) do
- if(f(v)) then
- results[#results+1] = v;
- end
+ if(f(v)) then
+ results[#results+1] = v;
+ end
end
return results
end
@@ -134,7 +134,7 @@ end
-- @param v2 value or list.
-- @return New list.
function cons(v1, v2)
- return{ is_list(v1) and {table.unpack(v1)} or v1, is_list(v2) and {table.unpack(v2)} or v2}
+ return{ is_list(v1) and {table.unpack(v1)} or v1, is_list(v2) and {table.unpack(v2)} or v2}
end
--- Concatenate two lists and return the result.
@@ -142,23 +142,23 @@ end
-- @param l2 List.
-- @return List.
function append(l1, l2)
- local results = {table.unpack(l1)}
+ local results = {table.unpack(l1)}
- for _, v in ipairs(l2) do
- results[#results+1] = v;
- end
- return results
+ for _, v in ipairs(l2) do
+ results[#results+1] = v;
+ end
+ return results
end
--- Return a list in reverse order.
-- @param l List.
-- @return Reversed list.
function reverse(l)
- local results = {}
- for i=#l, 1, -1 do
- results[#results+1] = l[i];
- end
- return results
+ local results = {}
+ for i=#l, 1, -1 do
+ results[#results+1] = l[i];
+ end
+ return results
end
--- Return a flattened version of a list. The flattened list contains
@@ -168,17 +168,17 @@ end
-- @param l The list to flatten.
-- @return Flattened list.
function flatten(l)
- local function flat(r, t)
- for i, v in ipairs(t) do
- if(type(v) == 'table') then
- flat(r, v)
- else
- table.insert(r, v)
- end
- end
- return r
+ local function flat(r, t)
+ for i, v in ipairs(t) do
+ if(type(v) == 'table') then
+ flat(r, v)
+ else
+ table.insert(r, v)
+ end
end
- return flat({}, l)
+ return r
+ end
+ return flat({}, l)
end
return _ENV;
diff --git a/nselib/match.lua b/nselib/match.lua
index e1f69034c..fc0103296 100644
--- a/nselib/match.lua
+++ b/nselib/match.lua
@@ -28,12 +28,12 @@ _ENV = stdnse.module("match", stdnse.seeall)
-- @see nmap.receive_buf
-- @see pcre.exec
regex = function(pattern)
- local r = pcre.new(pattern, 0,"C")
+ local r = pcre.new(pattern, 0,"C")
- return function(buf)
- local s,e = r:exec(buf, 0,0);
- return s,e
- end
+ return function(buf)
+ local s,e = r:exec(buf, 0,0);
+ return s,e
+ end
end
--- Return a function that allows delimiting at a certain number of bytes.
@@ -46,13 +46,13 @@ end
-- @usage sock:receive_buf(match.numbytes(80))
-- @see nmap.receive_buf
numbytes = function(num)
- local n = num
- return function(buf)
- if(#buf >=n) then
- return n, n
- end
- return nil
- end
+ local n = num
+ return function(buf)
+ if(#buf >=n) then
+ return n, n
+ end
+ return nil
+ end
end
diff --git a/nselib/membase.lua b/nselib/membase.lua
index 88cd1bdf7..33170c47b 100644
--- a/nselib/membase.lua
+++ b/nselib/membase.lua
@@ -18,315 +18,315 @@ _ENV = stdnse.module("membase", stdnse.seeall)
-- A minimalistic implementation of the Couchbase Membase TAP protocol
TAP = {
- -- Operations
- Op = {
- LIST_SASL_MECHS = 0x20,
- AUTHENTICATE = 0x21,
- },
+ -- Operations
+ Op = {
+ LIST_SASL_MECHS = 0x20,
+ AUTHENTICATE = 0x21,
+ },
- -- Requests
- Request = {
+ -- Requests
+ Request = {
- -- Header breakdown
- -- Field (offset) (value)
- -- Magic (0): 0x80 (PROTOCOL_BINARY_REQ)
- -- Opcode (1): 0x00
- -- Key length (2-3): 0x0000 (0)
- -- Extra length (4): 0x00
- -- Data type (5): 0x00
- -- vbucket (6-7): 0x0000 (0)
- -- Total body (8-11): 0x00000000 (0)
- -- Opaque (12-15): 0x00000000 (0)
- -- CAS (16-23): 0x0000000000000000 (0)
- Header = {
+ -- Header breakdown
+ -- Field (offset) (value)
+ -- Magic (0): 0x80 (PROTOCOL_BINARY_REQ)
+ -- Opcode (1): 0x00
+ -- Key length (2-3): 0x0000 (0)
+ -- Extra length (4): 0x00
+ -- Data type (5): 0x00
+ -- vbucket (6-7): 0x0000 (0)
+ -- Total body (8-11): 0x00000000 (0)
+ -- Opaque (12-15): 0x00000000 (0)
+ -- CAS (16-23): 0x0000000000000000 (0)
+ Header = {
- -- Creates a new instance of Header
- -- @param opcode number containing the operation
- -- @return o new instance of Header
- new = function(self, opcode)
- local o = {
- magic = 0x80,
- opcode = tonumber(opcode),
- keylen = 0x0000,
- extlen = 0x00,
- data_type = 0x00,
- vbucket = 0x0000,
- total_body = 0x00000000,
- opaque = 0x00000000,
- CAS = 0x0000000000000000,
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new instance of Header
+ -- @param opcode number containing the operation
+ -- @return o new instance of Header
+ new = function(self, opcode)
+ local o = {
+ magic = 0x80,
+ opcode = tonumber(opcode),
+ keylen = 0x0000,
+ extlen = 0x00,
+ data_type = 0x00,
+ vbucket = 0x0000,
+ total_body = 0x00000000,
+ opaque = 0x00000000,
+ CAS = 0x0000000000000000,
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Converts the header to string
- -- @return string containing the Header as string
- __tostring = function(self)
- return bin.pack(">CCSCCSIIL", self.magic, self.opcode, self.keylen,
- self.extlen, self.data_type, self.vbucket, self.total_body,
- self.opaque, self.CAS)
- end,
- },
+ -- Converts the header to string
+ -- @return string containing the Header as string
+ __tostring = function(self)
+ return bin.pack(">CCSCCSIIL", self.magic, self.opcode, self.keylen,
+ self.extlen, self.data_type, self.vbucket, self.total_body,
+ self.opaque, self.CAS)
+ end,
+ },
- -- List SASL authentication mechanism
- SASLList = {
+ -- List SASL authentication mechanism
+ SASLList = {
- -- Creates a new instance of the request
- -- @return o instance of request
- new = function(self)
- local o = {
- -- 0x20 SASL List Mechs
- header = TAP.Request.Header:new(TAP.Op.LIST_SASL_MECHS)
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new instance of the request
+ -- @return o instance of request
+ new = function(self)
+ local o = {
+ -- 0x20 SASL List Mechs
+ header = TAP.Request.Header:new(TAP.Op.LIST_SASL_MECHS)
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Converts the request to string
- -- @return string containing the request as string
- __tostring = function(self)
- return tostring(self.header)
- end,
- },
+ -- Converts the request to string
+ -- @return string containing the request as string
+ __tostring = function(self)
+ return tostring(self.header)
+ end,
+ },
- -- Authenticates using SASL
- Authenticate = {
+ -- Authenticates using SASL
+ Authenticate = {
- -- Creates a new instance of the request
- -- @param username string containing the username
- -- @param password string containing the password
- -- @param mech string containing the SASL mechanism, currently suppored:
- -- PLAIN - plain-text authentication
- -- @return o instance of request
- new = function(self, username, password, mech)
- local o = {
- -- 0x20 SASL List Mechs
- header = TAP.Request.Header:new(TAP.Op.AUTHENTICATE),
- username = username,
- password = password,
- mech = mech,
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new instance of the request
+ -- @param username string containing the username
+ -- @param password string containing the password
+ -- @param mech string containing the SASL mechanism, currently suppored:
+ -- PLAIN - plain-text authentication
+ -- @return o instance of request
+ new = function(self, username, password, mech)
+ local o = {
+ -- 0x20 SASL List Mechs
+ header = TAP.Request.Header:new(TAP.Op.AUTHENTICATE),
+ username = username,
+ password = password,
+ mech = mech,
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Converts the request to string
- -- @return string containing the request as string
- __tostring = function(self)
- if ( self.mech == "PLAIN" ) then
- local mech_params = { self.username, self.password }
- local auth_data = sasl.Helper:new(self.mech):encode(table.unpack(mech_params))
+ -- Converts the request to string
+ -- @return string containing the request as string
+ __tostring = function(self)
+ if ( self.mech == "PLAIN" ) then
+ local mech_params = { self.username, self.password }
+ local auth_data = sasl.Helper:new(self.mech):encode(table.unpack(mech_params))
- self.header.keylen = #self.mech
- self.header.total_body = #auth_data + #self.mech
- return tostring(self.header) .. self.mech .. auth_data
- end
- end,
+ self.header.keylen = #self.mech
+ self.header.total_body = #auth_data + #self.mech
+ return tostring(self.header) .. self.mech .. auth_data
+ end
+ end,
- }
+ }
- },
+ },
- -- Responses
- Response = {
+ -- Responses
+ Response = {
- -- The response header
- -- Header breakdown
- -- Field (offset) (value)
- -- Magic (0): 0x81 (PROTOCOL_BINARY_RES)
- -- Opcode (1): 0x00
- -- Key length (2-3): 0x0000 (0)
- -- Extra length (4): 0x00
- -- Data type (5): 0x00
- -- Status (6-7): 0x0000 (SUCCESS)
- -- Total body (8-11): 0x00000005 (5)
- -- Opaque (12-15): 0x00000000 (0)
- -- CAS (16-23): 0x0000000000000000 (0)
- Header = {
+ -- The response header
+ -- Header breakdown
+ -- Field (offset) (value)
+ -- Magic (0): 0x81 (PROTOCOL_BINARY_RES)
+ -- Opcode (1): 0x00
+ -- Key length (2-3): 0x0000 (0)
+ -- Extra length (4): 0x00
+ -- Data type (5): 0x00
+ -- Status (6-7): 0x0000 (SUCCESS)
+ -- Total body (8-11): 0x00000005 (5)
+ -- Opaque (12-15): 0x00000000 (0)
+ -- CAS (16-23): 0x0000000000000000 (0)
+ Header = {
- -- Creates a new instance of Header
- -- @param data string containing the raw data
- -- @return o new instance of Header
- new = function(self, data)
- local o = {
- data = data
- }
- setmetatable(o, self)
- self.__index = self
- if ( o:parse() ) then
- return o
- end
- end,
+ -- Creates a new instance of Header
+ -- @param data string containing the raw data
+ -- @return o new instance of Header
+ new = function(self, data)
+ local o = {
+ data = data
+ }
+ setmetatable(o, self)
+ self.__index = self
+ if ( o:parse() ) then
+ return o
+ end
+ end,
- -- Parse the raw header and populates the class members
- -- @return status true on success, false on failure
- parse = function(self)
- if ( 24 > #self.data ) then
- stdnse.print_debug("membase: Header packet too short (%d bytes)", #self.data)
- return false, "Packet to short"
- end
- local pos
- pos, self.magic, self.opcode, self.keylen, self.extlen,
- self.data_type, self.status, self.total_body, self.opaque,
- self.CAS = bin.unpack(">CCSCCSIIL", self.data)
- return true
- end
+ -- Parse the raw header and populates the class members
+ -- @return status true on success, false on failure
+ parse = function(self)
+ if ( 24 > #self.data ) then
+ stdnse.print_debug("membase: Header packet too short (%d bytes)", #self.data)
+ return false, "Packet to short"
+ end
+ local pos
+ pos, self.magic, self.opcode, self.keylen, self.extlen,
+ self.data_type, self.status, self.total_body, self.opaque,
+ self.CAS = bin.unpack(">CCSCCSIIL", self.data)
+ return true
+ end
- },
+ },
- -- Decoders
- Decoder = {
+ -- Decoders
+ Decoder = {
- -- TAP.Op.LIST_SASL_MECHS
- [0x20] = {
- -- Creates a new instance of the decoder
- -- @param data string containing the raw response
- -- @return o instance if successfully parsed, nil on failure
- -- the member variable mechs contains the
- -- supported authentication mechanisms.
- new = function(self, data)
- local o = { data = data }
- setmetatable(o, self)
- self.__index = self
- if ( o:parse() ) then
- return o
- end
- end,
+ -- TAP.Op.LIST_SASL_MECHS
+ [0x20] = {
+ -- Creates a new instance of the decoder
+ -- @param data string containing the raw response
+ -- @return o instance if successfully parsed, nil on failure
+ -- the member variable mechs contains the
+ -- supported authentication mechanisms.
+ new = function(self, data)
+ local o = { data = data }
+ setmetatable(o, self)
+ self.__index = self
+ if ( o:parse() ) then
+ return o
+ end
+ end,
- -- Parses the raw response
- -- @return true on success
- parse = function(self)
- self.mechs = self.data
- return true
- end
- },
+ -- Parses the raw response
+ -- @return true on success
+ parse = function(self)
+ self.mechs = self.data
+ return true
+ end
+ },
- -- Login response
- [0x21] = {
- -- Creates a new instance of the decoder
- -- @param data string containing the raw response
- -- @return o instance if successfully parsed, nil on failure
- -- the member variable status contains the
- -- servers authentication response.
- new = function(self, data)
- local o = { data = data }
- setmetatable(o, self)
- self.__index = self
- if ( o:parse() ) then
- return o
- end
- end,
+ -- Login response
+ [0x21] = {
+ -- Creates a new instance of the decoder
+ -- @param data string containing the raw response
+ -- @return o instance if successfully parsed, nil on failure
+ -- the member variable status contains the
+ -- servers authentication response.
+ new = function(self, data)
+ local o = { data = data }
+ setmetatable(o, self)
+ self.__index = self
+ if ( o:parse() ) then
+ return o
+ end
+ end,
- -- Parses the raw response
- -- @return true on success
- parse = function(self)
- self.status = self.data
- return true
- end
- }
+ -- Parses the raw response
+ -- @return true on success
+ parse = function(self)
+ self.status = self.data
+ return true
+ end
+ }
- }
+ }
- },
+ },
}
-- The Helper class is the main script interface
Helper = {
- -- Creates a new instance of the helper
- -- @param host table as received by the action method
- -- @param port table as received by the action method
- -- @param options table including options to the helper, currently:
- -- timeout - socket timeout in milliseconds
- new = function(self, host, port, options)
- local o = {
- host = host,
- port = port,
- mech = stdnse.get_script_args("membase.authmech"),
- options = options or {}
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new instance of the helper
+ -- @param host table as received by the action method
+ -- @param port table as received by the action method
+ -- @param options table including options to the helper, currently:
+ -- timeout - socket timeout in milliseconds
+ new = function(self, host, port, options)
+ local o = {
+ host = host,
+ port = port,
+ mech = stdnse.get_script_args("membase.authmech"),
+ options = options or {}
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Connects the socket to the server
- -- @return true on success, false on failure
- connect = function(self)
- self.socket = nmap.new_socket()
- self.socket:set_timeout(self.options.timeout or 10000)
- return self.socket:connect(self.host, self.port)
- end,
+ -- Connects the socket to the server
+ -- @return true on success, false on failure
+ connect = function(self)
+ self.socket = nmap.new_socket()
+ self.socket:set_timeout(self.options.timeout or 10000)
+ return self.socket:connect(self.host, self.port)
+ end,
- -- Closes the socket
- close = function(self)
- return self.socket:close()
- end,
+ -- Closes the socket
+ close = function(self)
+ return self.socket:close()
+ end,
- -- Sends a request to the server, receives and parses the response
- -- @param req a Request instance
- -- @return status true on success, false on failure
- -- @return response instance of Response
- exch = function(self, req)
- local status, err = self.socket:send(tostring(req))
- if ( not(status) ) then
- return false, "Failed to send data"
- end
+ -- Sends a request to the server, receives and parses the response
+ -- @param req a Request instance
+ -- @return status true on success, false on failure
+ -- @return response instance of Response
+ exch = function(self, req)
+ local status, err = self.socket:send(tostring(req))
+ if ( not(status) ) then
+ return false, "Failed to send data"
+ end
- local data
- status, data = self.socket:receive_buf(match.numbytes(24), true)
- if ( not(status) ) then
- return false, "Failed to receive data"
- end
+ local data
+ status, data = self.socket:receive_buf(match.numbytes(24), true)
+ if ( not(status) ) then
+ return false, "Failed to receive data"
+ end
- local header = TAP.Response.Header:new(data)
+ local header = TAP.Response.Header:new(data)
- if ( header.opcode ~= req.header.opcode ) then
- stdnse.print_debug("WARNING: Received invalid op code, request contained (%d), response contained (%d)", req.header.opcode, header.opcode)
- end
+ if ( header.opcode ~= req.header.opcode ) then
+ stdnse.print_debug("WARNING: Received invalid op code, request contained (%d), response contained (%d)", req.header.opcode, header.opcode)
+ end
- if ( not(TAP.Response.Decoder[tonumber(header.opcode)]) ) then
- return false, ("No response handler for opcode: %d"):format(header.opcode)
- end
+ if ( not(TAP.Response.Decoder[tonumber(header.opcode)]) ) then
+ return false, ("No response handler for opcode: %d"):format(header.opcode)
+ end
- local status, data = self.socket:receive_buf(match.numbytes(header.total_body), true)
- if ( not(status) ) then
- return false, "Failed to receive data"
- end
+ local status, data = self.socket:receive_buf(match.numbytes(header.total_body), true)
+ if ( not(status) ) then
+ return false, "Failed to receive data"
+ end
- local response = TAP.Response.Decoder[tonumber(header.opcode)]:new(data)
- if ( not(response) ) then
- return false, "Failed to parse response from server"
- end
- return true, response
- end,
+ local response = TAP.Response.Decoder[tonumber(header.opcode)]:new(data)
+ if ( not(response) ) then
+ return false, "Failed to parse response from server"
+ end
+ return true, response
+ end,
- -- Gets list of supported SASL authentication mechanisms
- getSASLMechList = function(self)
- return self:exch(TAP.Request.SASLList:new())
- end,
+ -- Gets list of supported SASL authentication mechanisms
+ getSASLMechList = function(self)
+ return self:exch(TAP.Request.SASLList:new())
+ end,
- -- Logins to the server
- -- @param username string containing the username
- -- @param password string containing the password
- -- @param mech string containing the SASL mechanism to use
- -- @return status true on success, false on failure
- -- @return respons string containing "Auth failure" on failure
- login = function(self, username, password, mech)
- mech = mech or self.mech or "PLAIN"
- local status, response = self:exch(TAP.Request.Authenticate:new(username, password, mech))
- if ( not(status) ) then
- return false, "Auth failure"
- end
- if ( response.status == "Auth failure" ) then
- return false, response.status
- end
- return true, response.status
- end,
+ -- Logins to the server
+ -- @param username string containing the username
+ -- @param password string containing the password
+ -- @param mech string containing the SASL mechanism to use
+ -- @return status true on success, false on failure
+ -- @return respons string containing "Auth failure" on failure
+ login = function(self, username, password, mech)
+ mech = mech or self.mech or "PLAIN"
+ local status, response = self:exch(TAP.Request.Authenticate:new(username, password, mech))
+ if ( not(status) ) then
+ return false, "Auth failure"
+ end
+ if ( response.status == "Auth failure" ) then
+ return false, response.status
+ end
+ return true, response.status
+ end,
}
diff --git a/nselib/mobileme.lua b/nselib/mobileme.lua
index 6f36e95e7..944e29f14 100644
--- a/nselib/mobileme.lua
+++ b/nselib/mobileme.lua
@@ -14,214 +14,214 @@ _ENV = stdnse.module("mobileme", stdnse.seeall)
MobileMe = {
- -- headers used in all requests
- headers = {
- ["Content-Type"] = "application/json; charset=utf-8",
- ["X-Apple-Find-Api-Ver"] = "2.0",
- ["X-Apple-Authscheme"] = "UserIdGuest",
- ["X-Apple-Realm-Support"] = "1.0",
- ["User-Agent"] = "Find iPhone/1.3 MeKit (iPad: iPhone OS/4.2.1)",
- ["X-Client-Name"] = "iPad",
- ["X-Client-UUID"] = "0cf3dc501ff812adb0b202baed4f37274b210853",
- ["Accept-Language"] = "en-us",
- ["Connection"] = "keep-alive"
- },
+ -- headers used in all requests
+ headers = {
+ ["Content-Type"] = "application/json; charset=utf-8",
+ ["X-Apple-Find-Api-Ver"] = "2.0",
+ ["X-Apple-Authscheme"] = "UserIdGuest",
+ ["X-Apple-Realm-Support"] = "1.0",
+ ["User-Agent"] = "Find iPhone/1.3 MeKit (iPad: iPhone OS/4.2.1)",
+ ["X-Client-Name"] = "iPad",
+ ["X-Client-UUID"] = "0cf3dc501ff812adb0b202baed4f37274b210853",
+ ["Accept-Language"] = "en-us",
+ ["Connection"] = "keep-alive"
+ },
- -- Creates a MobileMe instance
- -- @param username string containing the Apple ID username
- -- @param password string containing the Apple ID password
- -- @return o new instance of MobileMe
- new = function(self, username, password)
- local o = {
- host = "fmipmobile.icloud.com",
- port = 443,
- username = username,
- password = password
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a MobileMe instance
+ -- @param username string containing the Apple ID username
+ -- @param password string containing the Apple ID password
+ -- @return o new instance of MobileMe
+ new = function(self, username, password)
+ local o = {
+ host = "fmipmobile.icloud.com",
+ port = 443,
+ username = username,
+ password = password
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Sends a message to an iOS device
- -- @param devid string containing the device id to which the message should
- -- be sent
- -- @param subject string containing the messsage subject
- -- @param message string containing the message body
- -- @param alarm boolean true if alarm should be sounded, false if not
- -- @return status true on success, false on failure
- -- @return err string containing the error message (if status is false)
- sendMessage = function(self, devid, subject, message, alarm)
- local data = '{"clientContext":{"appName":"FindMyiPhone","appVersion":"1.3","buildVersion":"145","deviceUDID":"0000000000000000000000000000000000000000","inactiveTime":5911,"osVersion":"3.2","productType":"iPad1,1","selectedDevice":"%s","shouldLocate":false},"device":"%s","serverContext":{"callbackIntervalInMS":3000,"clientId":"0000000000000000000000000000000000000000","deviceLoadStatus":"203","hasDevices":true,"lastSessionExtensionTime":null,"maxDeviceLoadTime":60000,"maxLocatingTime":90000,"preferredLanguage":"en","prefsUpdateTime":1276872996660,"sessionLifespan":900000,"timezone":{"currentOffset":-25200000,"previousOffset":-28800000,"previousTransition":1268560799999,"tzCurrentName":"Pacific Daylight Time","tzName":"America/Los_Angeles"},"validRegion":true},"sound":%s,"subject":"%s","text":"%s"}'
- data = data:format(devid, devid, tostring(alarm), subject, message)
+ -- Sends a message to an iOS device
+ -- @param devid string containing the device id to which the message should
+ -- be sent
+ -- @param subject string containing the messsage subject
+ -- @param message string containing the message body
+ -- @param alarm boolean true if alarm should be sounded, false if not
+ -- @return status true on success, false on failure
+ -- @return err string containing the error message (if status is false)
+ sendMessage = function(self, devid, subject, message, alarm)
+ local data = '{"clientContext":{"appName":"FindMyiPhone","appVersion":"1.3","buildVersion":"145","deviceUDID":"0000000000000000000000000000000000000000","inactiveTime":5911,"osVersion":"3.2","productType":"iPad1,1","selectedDevice":"%s","shouldLocate":false},"device":"%s","serverContext":{"callbackIntervalInMS":3000,"clientId":"0000000000000000000000000000000000000000","deviceLoadStatus":"203","hasDevices":true,"lastSessionExtensionTime":null,"maxDeviceLoadTime":60000,"maxLocatingTime":90000,"preferredLanguage":"en","prefsUpdateTime":1276872996660,"sessionLifespan":900000,"timezone":{"currentOffset":-25200000,"previousOffset":-28800000,"previousTransition":1268560799999,"tzCurrentName":"Pacific Daylight Time","tzName":"America/Los_Angeles"},"validRegion":true},"sound":%s,"subject":"%s","text":"%s"}'
+ data = data:format(devid, devid, tostring(alarm), subject, message)
- local url = ("/fmipservice/device/%s/sendMessage"):format(self.username)
- local auth = { username = self.username, password = self.password }
+ local url = ("/fmipservice/device/%s/sendMessage"):format(self.username)
+ local auth = { username = self.username, password = self.password }
- local response = http.post(self.host, self.port, url, { header = self.headers, auth = auth, timeout = 10000 }, nil, data)
+ local response = http.post(self.host, self.port, url, { header = self.headers, auth = auth, timeout = 10000 }, nil, data)
- if ( response.status == 200 ) then
- local status, resp = json.parse(response.body)
- if ( not(status) ) then
- stdnse.print_debug(2, "Failed to parse JSON response from server")
- return false, "Failed to parse JSON response from server"
- end
+ if ( response.status == 200 ) then
+ local status, resp = json.parse(response.body)
+ if ( not(status) ) then
+ stdnse.print_debug(2, "Failed to parse JSON response from server")
+ return false, "Failed to parse JSON response from server"
+ end
- if ( resp.statusCode ~= "200" ) then
- stdnse.print_debug(2, "Failed to send message to server")
- return false, "Failed to send message to server"
- end
- end
- return true
- end,
+ if ( resp.statusCode ~= "200" ) then
+ stdnse.print_debug(2, "Failed to send message to server")
+ return false, "Failed to send message to server"
+ end
+ end
+ return true
+ end,
- -- Updates location information for all devices controlled by the Apple ID
- -- @return status true on success, false on failure
- -- @return json parsed json table or string containing an error message on
- -- failure
- update = function(self)
+ -- Updates location information for all devices controlled by the Apple ID
+ -- @return status true on success, false on failure
+ -- @return json parsed json table or string containing an error message on
+ -- failure
+ update = function(self)
- local auth = {
- username = self.username,
- password = self.password
- }
+ local auth = {
+ username = self.username,
+ password = self.password
+ }
- local url = ("/fmipservice/device/%s/initClient"):format(self.username)
- local data= '{"clientContext":{"appName":"FindMyiPhone","appVersion":"1.3","buildVersion":"145","deviceUDID":"0000000000000000000000000000000000000000","inactiveTime":2147483647,"osVersion":"4.2.1","personID":0,"productType":"iPad1,1"}}'
+ local url = ("/fmipservice/device/%s/initClient"):format(self.username)
+ local data= '{"clientContext":{"appName":"FindMyiPhone","appVersion":"1.3","buildVersion":"145","deviceUDID":"0000000000000000000000000000000000000000","inactiveTime":2147483647,"osVersion":"4.2.1","personID":0,"productType":"iPad1,1"}}'
- local retries = 2
+ local retries = 2
- local response
- repeat
- response = http.post(self.host, self.port, url, { header = self.headers, auth = auth }, nil, data)
- if ( response.header["x-apple-mme-host"] ) then
- self.host = response.header["x-apple-mme-host"]
- end
+ local response
+ repeat
+ response = http.post(self.host, self.port, url, { header = self.headers, auth = auth }, nil, data)
+ if ( response.header["x-apple-mme-host"] ) then
+ self.host = response.header["x-apple-mme-host"]
+ end
- if ( response.status == 401 ) then
- return false, "Authentication failed"
- elseif ( response.status ~= 200 and response.status ~= 330 ) then
- return false, "An unexpected error occured"
- end
+ if ( response.status == 401 ) then
+ return false, "Authentication failed"
+ elseif ( response.status ~= 200 and response.status ~= 330 ) then
+ return false, "An unexpected error occured"
+ end
- retries = retries - 1
- until ( 200 == response.status or 0 == retries)
+ retries = retries - 1
+ until ( 200 == response.status or 0 == retries)
- if ( response.status ~= 200 ) then
- return false, "Received unexpected response from server"
- end
+ if ( response.status ~= 200 ) then
+ return false, "Received unexpected response from server"
+ end
- local status, parsed_json = json.parse(response.body)
+ local status, parsed_json = json.parse(response.body)
- if ( not(status) or parsed_json.statusCode ~= "200" ) then
- return false, "Failed to parse JSON response from server"
- end
+ if ( not(status) or parsed_json.statusCode ~= "200" ) then
+ return false, "Failed to parse JSON response from server"
+ end
- -- cache the parsed_json.content as devices
- self.devices = parsed_json.content
+ -- cache the parsed_json.content as devices
+ self.devices = parsed_json.content
- return true, parsed_json
- end,
+ return true, parsed_json
+ end,
- -- Get's a list of devices
- -- @return devices table containing a list of devices
- getDevices = function(self)
- if ( not(self.devices) ) then
- self:update()
- end
- return self.devices
- end
+ -- Get's a list of devices
+ -- @return devices table containing a list of devices
+ getDevices = function(self)
+ if ( not(self.devices) ) then
+ self:update()
+ end
+ return self.devices
+ end
}
Helper = {
- -- Creates a Helper instance
- -- @param username string containing the Apple ID username
- -- @param password string containing the Apple ID password
- -- @return o new instance of Helper
- new = function(self, username, password)
- local o = {
- mm = MobileMe:new(username, password)
- }
- setmetatable(o, self)
- self.__index = self
- o.mm:update()
- return o
- end,
+ -- Creates a Helper instance
+ -- @param username string containing the Apple ID username
+ -- @param password string containing the Apple ID password
+ -- @return o new instance of Helper
+ new = function(self, username, password)
+ local o = {
+ mm = MobileMe:new(username, password)
+ }
+ setmetatable(o, self)
+ self.__index = self
+ o.mm:update()
+ return o
+ end,
- -- Get's the geolocation from each device
- --
- -- @return status true on success, false on failure
- -- @return result table containing a table of device locations
- -- the table is indexed based on the name of the device and
- -- contains a location table with the following fields:
- -- * longitude - the GPS longitude
- -- * latitude - the GPS latitude
- -- * accuracy - the location accuracy
- -- * timestamp - the time the location was acquired
- -- * postype - the position type (GPS or WiFi)
- -- * finished -
- -- or string containing an error message on failure
- getLocation = function(self)
- -- do 3 tries, with a 5 second timeout to allow the location to update
- -- there are two attributes, locationFinished and isLocating that seem
- -- to be good candidates to monitor, but so far, I haven't had any
- -- success with that.
- local tries, timeout = 3, 5
- local result = {}
+ -- Get's the geolocation from each device
+ --
+ -- @return status true on success, false on failure
+ -- @return result table containing a table of device locations
+ -- the table is indexed based on the name of the device and
+ -- contains a location table with the following fields:
+ -- * longitude - the GPS longitude
+ -- * latitude - the GPS latitude
+ -- * accuracy - the location accuracy
+ -- * timestamp - the time the location was acquired
+ -- * postype - the position type (GPS or WiFi)
+ -- * finished -
+ -- or string containing an error message on failure
+ getLocation = function(self)
+ -- do 3 tries, with a 5 second timeout to allow the location to update
+ -- there are two attributes, locationFinished and isLocating that seem
+ -- to be good candidates to monitor, but so far, I haven't had any
+ -- success with that.
+ local tries, timeout = 3, 5
+ local result = {}
- repeat
- local status, response = self.mm:update()
+ repeat
+ local status, response = self.mm:update()
- if ( not(status) or not(response) ) then
- return false, "Failed to retrieve response from server"
- end
- for _, device in ipairs(response.content) do
- if ( device.location ) then
- result[device.name] = {
- longitude = device.location.longitude,
- latitude = device.location.latitude,
- accuracy = device.location.horizontalAccuracy,
- timestamp = device.location.timeStamp,
- postype = device.location.positionType,
- finished = device.location.locationFinished,
- }
- end
- end
- tries = tries - 1
- if ( tries > 0 ) then
- stdnse.sleep(timeout)
- end
- until( tries == 0 )
- return true, result
- end,
+ if ( not(status) or not(response) ) then
+ return false, "Failed to retrieve response from server"
+ end
+ for _, device in ipairs(response.content) do
+ if ( device.location ) then
+ result[device.name] = {
+ longitude = device.location.longitude,
+ latitude = device.location.latitude,
+ accuracy = device.location.horizontalAccuracy,
+ timestamp = device.location.timeStamp,
+ postype = device.location.positionType,
+ finished = device.location.locationFinished,
+ }
+ end
+ end
+ tries = tries - 1
+ if ( tries > 0 ) then
+ stdnse.sleep(timeout)
+ end
+ until( tries == 0 )
+ return true, result
+ end,
- -- Gets a list of names and ids of devices associated with the Apple ID
- -- @return status true on success, false on failure
- -- @return table of devices containing the following fields:
- -- name and id
- getDevices = function(self)
- local devices = {}
- for _, dev in ipairs(self.mm:getDevices()) do
- table.insert(devices, { name = dev.name, id = dev.id })
- end
- return true, devices
- end,
+ -- Gets a list of names and ids of devices associated with the Apple ID
+ -- @return status true on success, false on failure
+ -- @return table of devices containing the following fields:
+ -- name and id
+ getDevices = function(self)
+ local devices = {}
+ for _, dev in ipairs(self.mm:getDevices()) do
+ table.insert(devices, { name = dev.name, id = dev.id })
+ end
+ return true, devices
+ end,
- -- Send a message to an iOS Device
- --
- -- @param devid string containing the device id to which the message should
- -- be sent
- -- @param subject string containing the messsage subject
- -- @param message string containing the message body
- -- @param alarm boolean true if alarm should be sounded, false if not
- -- @return status true on success, false on failure
- -- @return err string containing the error message (if status is false)
- sendMessage = function(self, ...)
- return self.mm:sendMessage(...)
- end
+ -- Send a message to an iOS Device
+ --
+ -- @param devid string containing the device id to which the message should
+ -- be sent
+ -- @param subject string containing the messsage subject
+ -- @param message string containing the message body
+ -- @param alarm boolean true if alarm should be sounded, false if not
+ -- @return status true on success, false on failure
+ -- @return err string containing the error message (if status is false)
+ sendMessage = function(self, ...)
+ return self.mm:sendMessage(...)
+ end
}
diff --git a/nselib/natpmp.lua b/nselib/natpmp.lua
index 74540d902..088dbde94 100644
--- a/nselib/natpmp.lua
+++ b/nselib/natpmp.lua
@@ -13,129 +13,129 @@ local stdnse = require "stdnse"
_ENV = stdnse.module("natpmp", stdnse.seeall)
local ResultCode = {
- SUCCESS = 0,
- UNSUPPORTED_VERSION = 1,
- NOT_AUTHORIZED = 2,
- NETWORK_FAILURE = 3,
- OUT_OF_RESOURCES = 4,
- UNSUPPORTED_OPCODE = 5,
+ SUCCESS = 0,
+ UNSUPPORTED_VERSION = 1,
+ NOT_AUTHORIZED = 2,
+ NETWORK_FAILURE = 3,
+ OUT_OF_RESOURCES = 4,
+ UNSUPPORTED_OPCODE = 5,
}
local ErrorMessage = {
- [ResultCode.UNSUPPORTED_VERSION] = "The device did not support the protocol version",
- [ResultCode.NOT_AUTHORIZED] = "The operation was not authorized",
- [ResultCode.NETWORK_FAILURE] = "Network failure",
- [ResultCode.OUT_OF_RESOURCES] = "The device is out of resources",
- [ResultCode.UNSUPPORTED_OPCODE] = "The requested operation was not supported",
+ [ResultCode.UNSUPPORTED_VERSION] = "The device did not support the protocol version",
+ [ResultCode.NOT_AUTHORIZED] = "The operation was not authorized",
+ [ResultCode.NETWORK_FAILURE] = "Network failure",
+ [ResultCode.OUT_OF_RESOURCES] = "The device is out of resources",
+ [ResultCode.UNSUPPORTED_OPCODE] = "The requested operation was not supported",
}
Request = {
- GetWANIP = {
+ GetWANIP = {
- new = function(self)
- local o = { version = 0, op = 0 }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ new = function(self)
+ local o = { version = 0, op = 0 }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- __tostring = function(self)
- return bin.pack(">CC", self.version, self.op)
- end,
+ __tostring = function(self)
+ return bin.pack(">CC", self.version, self.op)
+ end,
- },
+ },
- MapPort = {
+ MapPort = {
- new = function(self, pubport, privport, proto, lifetime)
- assert(proto == "udp" or proto == "tcp", "Unsupported protocol")
- local o = {
- version = 0,
- pubport = pubport,
- privport = privport,
- proto = proto,
- lifetime = lifetime or 3600
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ new = function(self, pubport, privport, proto, lifetime)
+ assert(proto == "udp" or proto == "tcp", "Unsupported protocol")
+ local o = {
+ version = 0,
+ pubport = pubport,
+ privport = privport,
+ proto = proto,
+ lifetime = lifetime or 3600
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- __tostring = function(self)
- return bin.pack(">CCSSSI",
- self.version,
- (self.proto=="udp" and 1 or 2),
- 0, -- reserved
- self.privport, self.pubport,
- self.lifetime)
- end,
+ __tostring = function(self)
+ return bin.pack(">CCSSSI",
+ self.version,
+ (self.proto=="udp" and 1 or 2),
+ 0, -- reserved
+ self.privport, self.pubport,
+ self.lifetime)
+ end,
- }
+ }
}
Response = {
- GetWANIP = {
+ GetWANIP = {
- new = function(self, data)
- local o = { data = data }
- setmetatable(o, self)
- self.__index = self
- if ( o:parse() ) then
- return o
- end
- end,
+ new = function(self, data)
+ local o = { data = data }
+ setmetatable(o, self)
+ self.__index = self
+ if ( o:parse() ) then
+ return o
+ end
+ end,
- parse = function(self)
- if ( #self.data ~= 12 ) then
- return
- end
+ parse = function(self)
+ if ( #self.data ~= 12 ) then
+ return
+ end
- local pos
- pos, self.version, self.op, self.rescode = bin.unpack("ISSI", self.data, pos)
- return true
- end,
- }
+ pos, self.time, self.privport, self.pubport, self.lifetime = bin.unpack(">ISSI", self.data, pos)
+ return true
+ end,
+ }
}
@@ -146,75 +146,75 @@ Response = {
Helper = {
- new = function(self, host, port)
- local o = { host = host, port = port }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ new = function(self, host, port)
+ local o = { host = host, port = port }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- exchPacket = function(self, data)
- local socket = nmap.new_socket("udp")
- socket:set_timeout(5000)
+ exchPacket = function(self, data)
+ local socket = nmap.new_socket("udp")
+ socket:set_timeout(5000)
- local status = socket:sendto(self.host, self.port, data)
- if ( not(status) ) then
- socket:close()
- return false, "Failed to send request to device"
- end
+ local status = socket:sendto(self.host, self.port, data)
+ if ( not(status) ) then
+ socket:close()
+ return false, "Failed to send request to device"
+ end
- local response
- status, response = socket:receive()
- socket:close()
- if ( not(status) ) then
- return false, "Failed to receive response from router"
- end
- return true, response
- end,
+ local response
+ status, response = socket:receive()
+ socket:close()
+ if ( not(status) ) then
+ return false, "Failed to receive response from router"
+ end
+ return true, response
+ end,
- --- Gets the WAN ip of the router
- getWANIP = function(self)
- local packet = Request.GetWANIP:new()
- local status, response = self:exchPacket(tostring(packet))
- if ( not(status) ) then
- return status, response
- end
+ --- Gets the WAN ip of the router
+ getWANIP = function(self)
+ local packet = Request.GetWANIP:new()
+ local status, response = self:exchPacket(tostring(packet))
+ if ( not(status) ) then
+ return status, response
+ end
- response = Response.GetWANIP:new(response)
- if ( not(response) ) then
- return false, "Failed to parse response from router"
- end
+ response = Response.GetWANIP:new(response)
+ if ( not(response) ) then
+ return false, "Failed to parse response from router"
+ end
- return true, response
- end,
+ return true, response
+ end,
- --- Maps a public port to a private port
- -- @param pubport number containing the public external port to map
- -- @param privport number containing the private internal port to map
- -- @param protocol string containing the protocol to map (udp|tcp)
- -- @param lifetime [optional] number containing the lifetime in seconds
- mapPort = function(self, pubport, privport, protocol, lifetime)
- local packet = Request.MapPort:new(pubport, privport, protocol, lifetime)
- local status, response = self:exchPacket(tostring(packet))
- if ( not(status) ) then
- return status, response
- end
+ --- Maps a public port to a private port
+ -- @param pubport number containing the public external port to map
+ -- @param privport number containing the private internal port to map
+ -- @param protocol string containing the protocol to map (udp|tcp)
+ -- @param lifetime [optional] number containing the lifetime in seconds
+ mapPort = function(self, pubport, privport, protocol, lifetime)
+ local packet = Request.MapPort:new(pubport, privport, protocol, lifetime)
+ local status, response = self:exchPacket(tostring(packet))
+ if ( not(status) ) then
+ return status, response
+ end
- response = Response.MapPort:new(response)
- if ( not(response) ) then
- return false, "Failed to parse response from router"
- end
+ response = Response.MapPort:new(response)
+ if ( not(response) ) then
+ return false, "Failed to parse response from router"
+ end
- return true, response
- end,
+ return true, response
+ end,
- unmapPort = function(self, pubport, privport)
- return self:mapPort(pubport, privport, 0)
- end,
+ unmapPort = function(self, pubport, privport)
+ return self:mapPort(pubport, privport, 0)
+ end,
- unmapAllPorts = function(self)
- return self.mapPort(0, 0, 0)
- end,
+ unmapAllPorts = function(self)
+ return self.mapPort(0, 0, 0)
+ end,
}
diff --git a/nselib/ndmp.lua b/nselib/ndmp.lua
index be9a95161..c7911cd58 100644
--- a/nselib/ndmp.lua
+++ b/nselib/ndmp.lua
@@ -15,397 +15,397 @@ _ENV = stdnse.module("ndmp", stdnse.seeall)
NDMP = {
- -- Message types
- MessageType = {
- CONFIG_GET_HOST_INFO = 0x00000100,
- CONFIG_GET_FS_INFO = 0x00000105,
- CONFIG_GET_AUTH_ATTR = 0x00000103,
- CONFIG_GET_SERVER_INFO = 0x00000108,
- CONNECT_CLIENT_AUTH = 0x00000901,
- },
+ -- Message types
+ MessageType = {
+ CONFIG_GET_HOST_INFO = 0x00000100,
+ CONFIG_GET_FS_INFO = 0x00000105,
+ CONFIG_GET_AUTH_ATTR = 0x00000103,
+ CONFIG_GET_SERVER_INFO = 0x00000108,
+ CONNECT_CLIENT_AUTH = 0x00000901,
+ },
- -- The fragment header, 4 bytes where the highest bit is used to determine
- -- whether the fragment is the last or not.
- FragmentHeader = {
- size = 4,
+ -- The fragment header, 4 bytes where the highest bit is used to determine
+ -- whether the fragment is the last or not.
+ FragmentHeader = {
+ size = 4,
- -- Creates a new instance of fragment header
- -- @return o instance of Class
- new = function(self)
- local o = {
- last = true,
- length = 24,
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new instance of fragment header
+ -- @return o instance of Class
+ new = function(self)
+ local o = {
+ last = true,
+ length = 24,
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Parse data stream and create a new instance of this class
- -- @param data opaque string
- -- @return fh new instance of FragmentHeader class
- parse = function(data)
- local fh = NDMP.FragmentHeader:new()
- local _, tmp = bin.unpack(">I", data)
- fh.length = bit.band(tmp, 0x7fffffff)
- fh.last= bit.rshift(tmp, 31)
- return fh
- end,
+ -- Parse data stream and create a new instance of this class
+ -- @param data opaque string
+ -- @return fh new instance of FragmentHeader class
+ parse = function(data)
+ local fh = NDMP.FragmentHeader:new()
+ local _, tmp = bin.unpack(">I", data)
+ fh.length = bit.band(tmp, 0x7fffffff)
+ fh.last= bit.rshift(tmp, 31)
+ return fh
+ end,
- -- Serializes the instance to an opaque string
- -- @return str string containing the serialized class
- __tostring = function(self)
- local tmp = 0
- if ( self.last ) then
- tmp = 0x80000000
- end
- tmp = tmp + self.length
- return bin.pack(">I", tmp)
- end,
+ -- Serializes the instance to an opaque string
+ -- @return str string containing the serialized class
+ __tostring = function(self)
+ local tmp = 0
+ if ( self.last ) then
+ tmp = 0x80000000
+ end
+ tmp = tmp + self.length
+ return bin.pack(">I", tmp)
+ end,
- },
+ },
- -- The ndmp 24 byte header
- Header = {
- size = 24,
+ -- The ndmp 24 byte header
+ Header = {
+ size = 24,
- -- creates a new instance of Header
- -- @return o instance of Header
- new = function(self)
- local o = {
- seq = 0,
- time = os.time(),
- type = 0,
- msg = 0x00000108,
- reply_seq = 0,
- error = 0,
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- creates a new instance of Header
+ -- @return o instance of Header
+ new = function(self)
+ local o = {
+ seq = 0,
+ time = os.time(),
+ type = 0,
+ msg = 0x00000108,
+ reply_seq = 0,
+ error = 0,
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Create a Header instance from opaque data string
- -- @param data opaque string
- -- @return hdr new instance of Header
- parse = function(data)
- local hdr = NDMP.Header:new()
- local pos
- pos, hdr.seq, hdr.time, hdr.type, hdr.msg, hdr.reply_seq, hdr.error = bin.unpack(">IIIIII", data)
- return hdr
- end,
+ -- Create a Header instance from opaque data string
+ -- @param data opaque string
+ -- @return hdr new instance of Header
+ parse = function(data)
+ local hdr = NDMP.Header:new()
+ local pos
+ pos, hdr.seq, hdr.time, hdr.type, hdr.msg, hdr.reply_seq, hdr.error = bin.unpack(">IIIIII", data)
+ return hdr
+ end,
- -- Serializes the instance to an opaque string
- -- @return str string containing the serialized class instance
- __tostring = function(self)
- return bin.pack(">IIIIII", self.seq, self.time, self.type, self.msg, self.reply_seq, self.error)
- end,
+ -- Serializes the instance to an opaque string
+ -- @return str string containing the serialized class instance
+ __tostring = function(self)
+ return bin.pack(">IIIIII", self.seq, self.time, self.type, self.msg, self.reply_seq, self.error)
+ end,
- },
+ },
}
NDMP.Message = {}
NDMP.Message.ConfigGetServerInfo = {
- -- Creates a Config Server Info instance
- -- @return o new instance of Class
- new = function(self)
- local o = {
- frag_header = NDMP.FragmentHeader:new(),
- header = NDMP.Header:new(),
- data = nil,
- }
- o.header.msg = NDMP.MessageType.CONFIG_GET_SERVER_INFO
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a Config Server Info instance
+ -- @return o new instance of Class
+ new = function(self)
+ local o = {
+ frag_header = NDMP.FragmentHeader:new(),
+ header = NDMP.Header:new(),
+ data = nil,
+ }
+ o.header.msg = NDMP.MessageType.CONFIG_GET_SERVER_INFO
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Create a ConfigGetServerInfo instance from opaque data string
- -- @param data opaque string
- -- @return msg new instance of ConfigGetServerInfo
- parse = function(data)
- local msg = NDMP.Message.ConfigGetServerInfo:new()
- msg.frag_header = NDMP.FragmentHeader.parse(data)
- data = data:sub(NDMP.FragmentHeader.size + 1)
- msg.header = NDMP.Header.parse(data)
- msg.data = data:sub(NDMP.Header.size + 1)
+ -- Create a ConfigGetServerInfo instance from opaque data string
+ -- @param data opaque string
+ -- @return msg new instance of ConfigGetServerInfo
+ parse = function(data)
+ local msg = NDMP.Message.ConfigGetServerInfo:new()
+ msg.frag_header = NDMP.FragmentHeader.parse(data)
+ data = data:sub(NDMP.FragmentHeader.size + 1)
+ msg.header = NDMP.Header.parse(data)
+ msg.data = data:sub(NDMP.Header.size + 1)
- msg.serverinfo = {}
- local pos, err = bin.unpack(">I", msg.data)
- pos, msg.serverinfo.vendor = Util.parseString(msg.data, pos)
- pos, msg.serverinfo.product = Util.parseString(msg.data, pos)
- pos, msg.serverinfo.version = Util.parseString(msg.data, pos)
- return msg
- end,
+ msg.serverinfo = {}
+ local pos, err = bin.unpack(">I", msg.data)
+ pos, msg.serverinfo.vendor = Util.parseString(msg.data, pos)
+ pos, msg.serverinfo.product = Util.parseString(msg.data, pos)
+ pos, msg.serverinfo.version = Util.parseString(msg.data, pos)
+ return msg
+ end,
- -- Serializes the instance to an opaque string
- -- @return str string containing the serialized class instance
- __tostring = function(self)
- return tostring(self.frag_header) .. tostring(self.header) .. tostring(self.data or "")
- end,
+ -- Serializes the instance to an opaque string
+ -- @return str string containing the serialized class instance
+ __tostring = function(self)
+ return tostring(self.frag_header) .. tostring(self.header) .. tostring(self.data or "")
+ end,
}
NDMP.Message.ConfigGetHostInfo = {
- new = function(self)
- local o = {
- frag_header = NDMP.FragmentHeader:new(),
- header = NDMP.Header:new(),
- data = nil,
- }
- o.header.msg = NDMP.MessageType.CONFIG_GET_HOST_INFO
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ new = function(self)
+ local o = {
+ frag_header = NDMP.FragmentHeader:new(),
+ header = NDMP.Header:new(),
+ data = nil,
+ }
+ o.header.msg = NDMP.MessageType.CONFIG_GET_HOST_INFO
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- parse = function(data)
- local msg = NDMP.Message.ConfigGetServerInfo:new()
- msg.frag_header = NDMP.FragmentHeader.parse(data)
- data = data:sub(NDMP.FragmentHeader.size + 1)
- msg.header = NDMP.Header.parse(data)
- msg.data = data:sub(NDMP.Header.size + 1)
+ parse = function(data)
+ local msg = NDMP.Message.ConfigGetServerInfo:new()
+ msg.frag_header = NDMP.FragmentHeader.parse(data)
+ data = data:sub(NDMP.FragmentHeader.size + 1)
+ msg.header = NDMP.Header.parse(data)
+ msg.data = data:sub(NDMP.Header.size + 1)
- msg.hostinfo = {}
- local pos, err = bin.unpack(">I", msg.data)
- pos, msg.hostinfo.hostname = Util.parseString(msg.data, pos)
- pos, msg.hostinfo.ostype = Util.parseString(msg.data, pos)
- pos, msg.hostinfo.osver = Util.parseString(msg.data, pos)
- pos, msg.hostinfo.hostid = Util.parseString(msg.data, pos)
- return msg
- end,
+ msg.hostinfo = {}
+ local pos, err = bin.unpack(">I", msg.data)
+ pos, msg.hostinfo.hostname = Util.parseString(msg.data, pos)
+ pos, msg.hostinfo.ostype = Util.parseString(msg.data, pos)
+ pos, msg.hostinfo.osver = Util.parseString(msg.data, pos)
+ pos, msg.hostinfo.hostid = Util.parseString(msg.data, pos)
+ return msg
+ end,
- __tostring = function(self)
- return tostring(self.frag_header) .. tostring(self.header) .. tostring(self.data or "")
- end,
+ __tostring = function(self)
+ return tostring(self.frag_header) .. tostring(self.header) .. tostring(self.data or "")
+ end,
}
NDMP.Message.ConfigGetFsInfo = {
- new = function(self)
- local o = {
- frag_header = NDMP.FragmentHeader:new(),
- header = NDMP.Header:new(),
- data = nil,
- fsinfo = {},
- }
- o.header.msg = NDMP.MessageType.CONFIG_GET_FS_INFO
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ new = function(self)
+ local o = {
+ frag_header = NDMP.FragmentHeader:new(),
+ header = NDMP.Header:new(),
+ data = nil,
+ fsinfo = {},
+ }
+ o.header.msg = NDMP.MessageType.CONFIG_GET_FS_INFO
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- parse = function(data)
- local msg = NDMP.Message.ConfigGetFsInfo:new()
- msg.frag_header = NDMP.FragmentHeader.parse(data)
- data = data:sub(NDMP.FragmentHeader.size + 1)
- msg.header = NDMP.Header.parse(data)
- msg.data = data:sub(NDMP.Header.size + 1)
+ parse = function(data)
+ local msg = NDMP.Message.ConfigGetFsInfo:new()
+ msg.frag_header = NDMP.FragmentHeader.parse(data)
+ data = data:sub(NDMP.FragmentHeader.size + 1)
+ msg.header = NDMP.Header.parse(data)
+ msg.data = data:sub(NDMP.Header.size + 1)
- local pos, err, count = bin.unpack(">II", msg.data)
- for i=1, count do
- local item = {}
- pos, item.invalid = bin.unpack(">I", msg.data, pos)
- pos, item.fs_type = Util.parseString(msg.data, pos)
- pos, item.fs_logical_device = Util.parseString(msg.data, pos)
- pos, item.fs_physical_device = Util.parseString(msg.data, pos)
- pos, item.total_size = bin.unpack(">L", msg.data, pos)
- pos, item.used_size = bin.unpack(">L", msg.data, pos)
- pos, item.avail_size = bin.unpack(">L", msg.data, pos)
- pos, item.total_inodes = bin.unpack(">L", msg.data, pos)
- pos, item.used_inodes = bin.unpack(">L", msg.data, pos)
- pos, item.fs_env = Util.parseString(msg.data, pos)
- pos, item.fs_status = Util.parseString(msg.data, pos)
- table.insert(msg.fsinfo, item)
- end
- return msg
- end,
+ local pos, err, count = bin.unpack(">II", msg.data)
+ for i=1, count do
+ local item = {}
+ pos, item.invalid = bin.unpack(">I", msg.data, pos)
+ pos, item.fs_type = Util.parseString(msg.data, pos)
+ pos, item.fs_logical_device = Util.parseString(msg.data, pos)
+ pos, item.fs_physical_device = Util.parseString(msg.data, pos)
+ pos, item.total_size = bin.unpack(">L", msg.data, pos)
+ pos, item.used_size = bin.unpack(">L", msg.data, pos)
+ pos, item.avail_size = bin.unpack(">L", msg.data, pos)
+ pos, item.total_inodes = bin.unpack(">L", msg.data, pos)
+ pos, item.used_inodes = bin.unpack(">L", msg.data, pos)
+ pos, item.fs_env = Util.parseString(msg.data, pos)
+ pos, item.fs_status = Util.parseString(msg.data, pos)
+ table.insert(msg.fsinfo, item)
+ end
+ return msg
+ end,
- __tostring = function(self)
- return tostring(self.frag_header) .. tostring(self.header) .. tostring(self.data or "")
- end,
+ __tostring = function(self)
+ return tostring(self.frag_header) .. tostring(self.header) .. tostring(self.data or "")
+ end,
}
NDMP.Message.UnhandledMessage = {
- new = function(self)
- local o = {
- frag_header = NDMP.FragmentHeader:new(),
- header = NDMP.Header:new(),
- data = nil,
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ new = function(self)
+ local o = {
+ frag_header = NDMP.FragmentHeader:new(),
+ header = NDMP.Header:new(),
+ data = nil,
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- parse = function(data)
- local msg = NDMP.Message.ConfigGetFsInfo:new()
- msg.frag_header = NDMP.FragmentHeader.parse(data)
- data = data:sub(NDMP.FragmentHeader.size + 1)
- msg.header = NDMP.Header.parse(data)
- msg.data = data:sub(NDMP.Header.size + 1)
- return msg
- end,
+ parse = function(data)
+ local msg = NDMP.Message.ConfigGetFsInfo:new()
+ msg.frag_header = NDMP.FragmentHeader.parse(data)
+ data = data:sub(NDMP.FragmentHeader.size + 1)
+ msg.header = NDMP.Header.parse(data)
+ msg.data = data:sub(NDMP.Header.size + 1)
+ return msg
+ end,
- __tostring = function(self)
- return tostring(self.frag_header) .. tostring(self.header) .. tostring(self.data or "")
- end
+ __tostring = function(self)
+ return tostring(self.frag_header) .. tostring(self.header) .. tostring(self.data or "")
+ end
}
Util = {
- parseString = function(data, pos)
- local pos, str = bin.unpack(">a", data, pos)
- local pad = ( 4 - ( #str % 4 ) ~= 4 ) and 4 - ( #str % 4 ) or 0
- return pos + pad, str
+ parseString = function(data, pos)
+ local pos, str = bin.unpack(">a", data, pos)
+ local pad = ( 4 - ( #str % 4 ) ~= 4 ) and 4 - ( #str % 4 ) or 0
+ return pos + pad, str
- end,
+ end,
}
NDMP.TypeToMessage = {
- [NDMP.MessageType.CONFIG_GET_SERVER_INFO] = NDMP.Message.ConfigGetServerInfo,
- [NDMP.MessageType.CONFIG_GET_HOST_INFO] = NDMP.Message.ConfigGetHostInfo,
- [NDMP.MessageType.CONFIG_GET_FS_INFO] = NDMP.Message.ConfigGetFsInfo,
+ [NDMP.MessageType.CONFIG_GET_SERVER_INFO] = NDMP.Message.ConfigGetServerInfo,
+ [NDMP.MessageType.CONFIG_GET_HOST_INFO] = NDMP.Message.ConfigGetHostInfo,
+ [NDMP.MessageType.CONFIG_GET_FS_INFO] = NDMP.Message.ConfigGetFsInfo,
}
-- Handles the communication with the NDMP service
Comm = {
- -- Creates new Comm instance
- -- @param host table as received by the action method
- -- @param port table as receuved by the action method
- -- @return o new instance of Comm
- new = function(self, host, port)
- local o = {
- host = host,
- port = port,
- socket = nmap.new_socket(),
- seq = 0,
- in_queue = {},
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates new Comm instance
+ -- @param host table as received by the action method
+ -- @param port table as receuved by the action method
+ -- @return o new instance of Comm
+ new = function(self, host, port)
+ local o = {
+ host = host,
+ port = port,
+ socket = nmap.new_socket(),
+ seq = 0,
+ in_queue = {},
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Connects to the NDMP server
- -- @return status true on success, false on failure
- connect = function(self)
- -- some servers seem to take their time, so leave this as 10s for now
- self.socket:set_timeout(10000)
- return self.socket:connect(self.host, self.port)
- end,
+ -- Connects to the NDMP server
+ -- @return status true on success, false on failure
+ connect = function(self)
+ -- some servers seem to take their time, so leave this as 10s for now
+ self.socket:set_timeout(10000)
+ return self.socket:connect(self.host, self.port)
+ end,
- -- Receives a message from the server
- -- @return status true on success, false on failure
- -- @return msg NDMP message when a parser exists, otherwise nil
- sock_recv = function(self)
- local status, frag_data = self.socket:receive_buf(match.numbytes(4), true)
- if ( not(status) ) then
- return false, "Failed to read NDMP 4-byte fragment header"
- end
- local frag_header = NDMP.FragmentHeader.parse(frag_data)
+ -- Receives a message from the server
+ -- @return status true on success, false on failure
+ -- @return msg NDMP message when a parser exists, otherwise nil
+ sock_recv = function(self)
+ local status, frag_data = self.socket:receive_buf(match.numbytes(4), true)
+ if ( not(status) ) then
+ return false, "Failed to read NDMP 4-byte fragment header"
+ end
+ local frag_header = NDMP.FragmentHeader.parse(frag_data)
- local status, header_data = self.socket:receive_buf(match.numbytes(24), true)
- if ( not(status) ) then
- return false, "Failed to read NDMP 24-byte header"
- end
- local header = NDMP.Header.parse(header_data)
+ local status, header_data = self.socket:receive_buf(match.numbytes(24), true)
+ if ( not(status) ) then
+ return false, "Failed to read NDMP 24-byte header"
+ end
+ local header = NDMP.Header.parse(header_data)
- local status, data = self.socket:receive_buf(match.numbytes(frag_header.length - 24), true)
- if ( not(status) ) then
- return false, "Failed to read NDMP data"
- end
+ local status, data = self.socket:receive_buf(match.numbytes(frag_header.length - 24), true)
+ if ( not(status) ) then
+ return false, "Failed to read NDMP data"
+ end
- if ( NDMP.TypeToMessage[header.msg] ) then
- return true, NDMP.TypeToMessage[header.msg].parse(frag_data .. header_data .. data)
- end
- return true, NDMP.Message.UnhandledMessage.parse(frag_data .. header_data .. data)
- end,
+ if ( NDMP.TypeToMessage[header.msg] ) then
+ return true, NDMP.TypeToMessage[header.msg].parse(frag_data .. header_data .. data)
+ end
+ return true, NDMP.Message.UnhandledMessage.parse(frag_data .. header_data .. data)
+ end,
- recv = function(self)
- if ( #self.in_queue > 0 ) then
- return true, table.remove(self.in_queue, 1)
- end
- return self:sock_recv()
- end,
+ recv = function(self)
+ if ( #self.in_queue > 0 ) then
+ return true, table.remove(self.in_queue, 1)
+ end
+ return self:sock_recv()
+ end,
- -- Sends a message to the server
- -- @param msg NDMP message
- -- @return status true on success, false on failure
- -- @return err string containing the error message when status is false
- send = function(self, msg)
- self.seq = self.seq + 1
- msg.header.seq = self.seq
- return self.socket:send(tostring(msg))
- end,
+ -- Sends a message to the server
+ -- @param msg NDMP message
+ -- @return status true on success, false on failure
+ -- @return err string containing the error message when status is false
+ send = function(self, msg)
+ self.seq = self.seq + 1
+ msg.header.seq = self.seq
+ return self.socket:send(tostring(msg))
+ end,
- exch = function(self, msg)
- local status, err = self:send(msg)
- if ( not(status) ) then
- return false, "Failed to send ndmp Message to server"
- end
- local s_seq = msg.header.seq
+ exch = function(self, msg)
+ local status, err = self:send(msg)
+ if ( not(status) ) then
+ return false, "Failed to send ndmp Message to server"
+ end
+ local s_seq = msg.header.seq
- for k, v in ipairs(self.in_queue) do
- if ( v.reply_seq == s_seq ) then
- return true, table.remove(self.in_queue, k)
- end
- end
+ for k, v in ipairs(self.in_queue) do
+ if ( v.reply_seq == s_seq ) then
+ return true, table.remove(self.in_queue, k)
+ end
+ end
- while(true) do
- local reply
- status, reply = self:sock_recv()
- if ( not(status) ) then
- return false, "Failed to receive msg from server"
- elseif ( reply and reply.header and reply.header.reply_seq == s_seq ) then
- return true, reply
- else
- table.insert(self.in_queue, reply)
- end
- end
- end,
+ while(true) do
+ local reply
+ status, reply = self:sock_recv()
+ if ( not(status) ) then
+ return false, "Failed to receive msg from server"
+ elseif ( reply and reply.header and reply.header.reply_seq == s_seq ) then
+ return true, reply
+ else
+ table.insert(self.in_queue, reply)
+ end
+ end
+ end,
- close = function(self) return self.socket:close() end,
+ close = function(self) return self.socket:close() end,
}
Helper = {
- new = function(self, host, port)
- local o = { comm = Comm:new(host, port) }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ new = function(self, host, port)
+ local o = { comm = Comm:new(host, port) }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- connect = function(self)
- return self.comm:connect()
- end,
+ connect = function(self)
+ return self.comm:connect()
+ end,
- getFsInfo = function(self)
- return self.comm:exch(NDMP.Message.ConfigGetFsInfo:new())
- end,
+ getFsInfo = function(self)
+ return self.comm:exch(NDMP.Message.ConfigGetFsInfo:new())
+ end,
- getHostInfo = function(self)
- return self.comm:exch(NDMP.Message.ConfigGetHostInfo:new())
- end,
+ getHostInfo = function(self)
+ return self.comm:exch(NDMP.Message.ConfigGetHostInfo:new())
+ end,
- getServerInfo = function(self)
- return self.comm:exch(NDMP.Message.ConfigGetServerInfo:new())
- end,
+ getServerInfo = function(self)
+ return self.comm:exch(NDMP.Message.ConfigGetServerInfo:new())
+ end,
- close = function(self)
- return self.comm:close()
+ close = function(self)
+ return self.comm:close()
- end
+ end
}
diff --git a/nselib/netbios.lua b/nselib/netbios.lua
index 0412d58a2..40c4f9886 100644
--- a/nselib/netbios.lua
+++ b/nselib/netbios.lua
@@ -17,8 +17,8 @@ _ENV = stdnse.module("netbios", stdnse.seeall)
types = {
- NB = 32,
- NBSTAT = 33,
+ NB = 32,
+ NBSTAT = 33,
}
--- Encode a NetBIOS name for transport. Most packets that use the NetBIOS name
@@ -39,45 +39,45 @@ types = {
-- (eg. "\x20FEEFFDFEDBCACACACACACACACACAAA\x08insecure\x03org")
function name_encode(name, scope)
- stdnse.print_debug(3, "Encoding name '%s'", name)
- -- Truncate or pad the string to 16 bytes
- if(#name >= 16) then
- name = string.sub(name, 1, 16)
- else
- local padding = " "
- if name == "*" then
- padding = "\0"
- end
+ stdnse.print_debug(3, "Encoding name '%s'", name)
+ -- Truncate or pad the string to 16 bytes
+ if(#name >= 16) then
+ name = string.sub(name, 1, 16)
+ else
+ local padding = " "
+ if name == "*" then
+ padding = "\0"
+ end
- repeat
- name = name .. padding
- until #name == 16
- end
+ repeat
+ name = name .. padding
+ until #name == 16
+ end
- -- Convert to uppercase
- name = string.upper(name)
+ -- Convert to uppercase
+ name = string.upper(name)
- -- Do the L1 encoding
- local L1_encoded = ""
- for i=1, #name, 1 do
- local b = string.byte(name, i)
- L1_encoded = L1_encoded .. string.char(bit.rshift(bit.band(b, 0xF0), 4) + 0x41)
- L1_encoded = L1_encoded .. string.char(bit.rshift(bit.band(b, 0x0F), 0) + 0x41)
- end
+ -- Do the L1 encoding
+ local L1_encoded = ""
+ for i=1, #name, 1 do
+ local b = string.byte(name, i)
+ L1_encoded = L1_encoded .. string.char(bit.rshift(bit.band(b, 0xF0), 4) + 0x41)
+ L1_encoded = L1_encoded .. string.char(bit.rshift(bit.band(b, 0x0F), 0) + 0x41)
+ end
- -- Do the L2 encoding
- local L2_encoded = string.char(32) .. L1_encoded
+ -- Do the L2 encoding
+ local L2_encoded = string.char(32) .. L1_encoded
- if scope ~= nil then
- -- Split the scope at its periods
- local piece
- for piece in string.gmatch(scope, "[^.]+") do
- L2_encoded = L2_encoded .. string.char(#piece) .. piece
- end
- end
+ if scope ~= nil then
+ -- Split the scope at its periods
+ local piece
+ for piece in string.gmatch(scope, "[^.]+") do
+ L2_encoded = L2_encoded .. string.char(#piece) .. piece
+ end
+ end
- stdnse.print_debug(3, "=> '%s'", L2_encoded)
- return L2_encoded
+ stdnse.print_debug(3, "=> '%s'", L2_encoded)
+ return L2_encoded
end
@@ -89,38 +89,38 @@ end
--@return the decoded name and the scope. The name will still be padded, and the
-- scope will never be nil (empty string is returned if no scope is present)
function name_decode(encoded_name)
- local name = ""
- local scope = ""
+ local name = ""
+ local scope = ""
- local len = string.byte(encoded_name, 1)
- local i
+ local len = string.byte(encoded_name, 1)
+ local i
- stdnse.print_debug(3, "Decoding name '%s'", encoded_name)
+ stdnse.print_debug(3, "Decoding name '%s'", encoded_name)
- for i = 2, len + 1, 2 do
- local ch = 0
- ch = bit.bor(ch, bit.lshift(string.byte(encoded_name, i) - 0x41, 4))
- ch = bit.bor(ch, bit.lshift(string.byte(encoded_name, i + 1) - 0x41, 0))
+ for i = 2, len + 1, 2 do
+ local ch = 0
+ ch = bit.bor(ch, bit.lshift(string.byte(encoded_name, i) - 0x41, 4))
+ ch = bit.bor(ch, bit.lshift(string.byte(encoded_name, i + 1) - 0x41, 0))
- name = name .. string.char(ch)
- end
+ name = name .. string.char(ch)
+ end
- -- Decode the scope
- local pos = 34
- while #encoded_name > pos do
- local len = string.byte(encoded_name, pos)
- scope = scope .. string.sub(encoded_name, pos + 1, pos + len) .. "."
- pos = pos + 1 + len
- end
+ -- Decode the scope
+ local pos = 34
+ while #encoded_name > pos do
+ local len = string.byte(encoded_name, pos)
+ scope = scope .. string.sub(encoded_name, pos + 1, pos + len) .. "."
+ pos = pos + 1 + len
+ end
- -- If there was a scope, remove the trailing period
- if(#scope > 0) then
- scope = string.sub(scope, 1, #scope - 1)
- end
+ -- If there was a scope, remove the trailing period
+ if(#scope > 0) then
+ scope = string.sub(scope, 1, #scope - 1)
+ end
- stdnse.print_debug(3, "=> '%s'", name)
+ stdnse.print_debug(3, "=> '%s'", name)
- return name, scope
+ return name, scope
end
--- Sends out a UDP probe on port 137 to get a human-readable list of names the
@@ -131,23 +131,23 @@ end
-- list of names. Otherwise, result is an error message.
function get_names(host, prefix)
- local status, names, statistics = do_nbstat(host)
+ local status, names, statistics = do_nbstat(host)
- if(prefix == nil) then
- prefix = ""
- end
+ if(prefix == nil) then
+ prefix = ""
+ end
- if(status) then
- local result = ""
- for i = 1, #names, 1 do
- result = result .. string.format("%s%s<%02x>\n", prefix, names[i]['name'], names[i]['prefix'])
- end
+ if(status) then
+ local result = ""
+ for i = 1, #names, 1 do
+ result = result .. string.format("%s%s<%02x>\n", prefix, names[i]['name'], names[i]['prefix'])
+ end
- return true, result
- else
- return false, names
- end
+ return true, result
+ else
+ return false, names
+ end
end
--- Sends out a UDP probe on port 137 to get the server's name (that is, the
@@ -158,24 +158,24 @@ end
-- otherwise, result is an error message.
function get_server_name(host, names)
- local status
- local i
+ local status
+ local i
- if names == nil then
- status, names = do_nbstat(host)
+ if names == nil then
+ status, names = do_nbstat(host)
- if(status == false) then
- return false, names
- end
- end
+ if(status == false) then
+ return false, names
+ end
+ end
- for i = 1, #names, 1 do
- if names[i]['suffix'] == 0x20 then
- return true, names[i]['name']
- end
- end
+ for i = 1, #names, 1 do
+ if names[i]['suffix'] == 0x20 then
+ return true, names[i]['name']
+ end
+ end
- return false, "Couldn't find NetBIOS server name"
+ return false, "Couldn't find NetBIOS server name"
end
--- Sends out a UDP probe on port 137 to get the user's name (that is, the
@@ -188,27 +188,27 @@ end
-- otherwise, result is an error message.
function get_user_name(host, names)
- local status, server_name = get_server_name(host, names)
+ local status, server_name = get_server_name(host, names)
- if(status == false) then
- return false, server_name
- end
+ if(status == false) then
+ return false, server_name
+ end
- if(names == nil) then
- status, names = do_nbstat(host)
+ if(names == nil) then
+ status, names = do_nbstat(host)
- if(status == false) then
- return false, names
- end
- end
+ if(status == false) then
+ return false, names
+ end
+ end
- for i = 1, #names, 1 do
- if names[i]['suffix'] == 0x03 and names[i]['name'] ~= server_name then
- return true, names[i]['name']
- end
- end
+ for i = 1, #names, 1 do
+ if names[i]['suffix'] == 0x03 and names[i]['name'] ~= server_name then
+ return true, names[i]['name']
+ end
+ end
- return true, nil
+ return true, nil
end
@@ -260,204 +260,204 @@ end
-- Otherwise, names is an error message and statistics is undefined.
function do_nbstat(host)
- local status, err
- local socket = nmap.new_socket()
- local encoded_name = name_encode("*")
- local statistics
- local reg
- if type(host) == "string" then --ip
- stdnse.print_debug(3, "Performing nbstat on host '%s'", host)
- nmap.registry.netbios = nmap.registry.netbios or {}
- nmap.registry.netbios[host] = nmap.registry.netbios[host] or {}
- reg = nmap.registry.netbios[host]
- else
- stdnse.print_debug(3, "Performing nbstat on host '%s'", host.ip)
- if host.registry.netbios == nil and
- nmap.registry.netbios ~= nil and
- nmap.registry.netbios[host.ip] ~= nil then
- host.registry.netbios = nmap.registry.netbios[host.ip]
- end
- host.registry.netbios = host.registry.netbios or {}
- reg = host.registry.netbios
- end
+ local status, err
+ local socket = nmap.new_socket()
+ local encoded_name = name_encode("*")
+ local statistics
+ local reg
+ if type(host) == "string" then --ip
+ stdnse.print_debug(3, "Performing nbstat on host '%s'", host)
+ nmap.registry.netbios = nmap.registry.netbios or {}
+ nmap.registry.netbios[host] = nmap.registry.netbios[host] or {}
+ reg = nmap.registry.netbios[host]
+ else
+ stdnse.print_debug(3, "Performing nbstat on host '%s'", host.ip)
+ if host.registry.netbios == nil and
+ nmap.registry.netbios ~= nil and
+ nmap.registry.netbios[host.ip] ~= nil then
+ host.registry.netbios = nmap.registry.netbios[host.ip]
+ end
+ host.registry.netbios = host.registry.netbios or {}
+ reg = host.registry.netbios
+ end
- -- Check if it's cached in the registry for this host
- if(reg["nbstat_names"] ~= nil) then
- stdnse.print_debug(3, " |_ [using cached value]")
- return true, reg["nbstat_names"], reg["nbstat_statistics"]
- end
+ -- Check if it's cached in the registry for this host
+ if(reg["nbstat_names"] ~= nil) then
+ stdnse.print_debug(3, " |_ [using cached value]")
+ return true, reg["nbstat_names"], reg["nbstat_statistics"]
+ end
- -- Create the query header
- local query = bin.pack(">SSSSSS",
- 0x1337, -- Transaction id
- 0x0000, -- Flags
- 1, -- Questions
- 0, -- Answers
- 0, -- Authority
- 0 -- Extra
- )
+ -- Create the query header
+ local query = bin.pack(">SSSSSS",
+ 0x1337, -- Transaction id
+ 0x0000, -- Flags
+ 1, -- Questions
+ 0, -- Answers
+ 0, -- Authority
+ 0 -- Extra
+ )
- query = query .. bin.pack(">zSS",
- encoded_name, -- Encoded name
- 0x0021, -- Query type (0x21 = NBSTAT)
- 0x0001 -- Class = IN
- )
- status, err = socket:connect(host, 137, "udp")
- if(status == false) then
- return false, err
- end
+ query = query .. bin.pack(">zSS",
+ encoded_name, -- Encoded name
+ 0x0021, -- Query type (0x21 = NBSTAT)
+ 0x0001 -- Class = IN
+ )
+ status, err = socket:connect(host, 137, "udp")
+ if(status == false) then
+ return false, err
+ end
- status, err = socket:send(query)
- if(status == false) then
- return false, err
- end
+ status, err = socket:send(query)
+ if(status == false) then
+ return false, err
+ end
- socket:set_timeout(1000)
+ socket:set_timeout(1000)
- local status, result = socket:receive_bytes(1)
- if(status == false) then
- return false, result
- end
+ local status, result = socket:receive_bytes(1)
+ if(status == false) then
+ return false, result
+ end
- local close_status, err = socket:close()
- if(close_status == false) then
- return false, err
- end
+ local close_status, err = socket:close()
+ if(close_status == false) then
+ return false, err
+ end
- if(status) then
- local pos, TRN_ID, FLAGS, QDCOUNT, ANCOUNT, NSCOUNT, ARCOUNT, rr_name, rr_type, rr_class, rr_ttl
- local rrlength, name_count
+ if(status) then
+ local pos, TRN_ID, FLAGS, QDCOUNT, ANCOUNT, NSCOUNT, ARCOUNT, rr_name, rr_type, rr_class, rr_ttl
+ local rrlength, name_count
- pos, TRN_ID, FLAGS, QDCOUNT, ANCOUNT, NSCOUNT, ARCOUNT = bin.unpack(">SSSSSS", result)
+ pos, TRN_ID, FLAGS, QDCOUNT, ANCOUNT, NSCOUNT, ARCOUNT = bin.unpack(">SSSSSS", result)
- -- Sanity check the result (has to have the same TRN_ID, 1 answer, and proper flags)
- if(TRN_ID ~= 0x1337) then
- return false, string.format("Invalid transaction ID returned: 0x%04x", TRN_ID)
- end
- if(ANCOUNT ~= 1) then
- return false, "Server returned an invalid number of answers"
- end
- if(bit.band(FLAGS, 0x8000) == 0) then
- return false, "Server's flags didn't indicate a response"
- end
- if(bit.band(FLAGS, 0x0007) ~= 0) then
- return false, string.format("Server returned a NetBIOS error: 0x%02x", bit.band(FLAGS, 0x0007))
- end
+ -- Sanity check the result (has to have the same TRN_ID, 1 answer, and proper flags)
+ if(TRN_ID ~= 0x1337) then
+ return false, string.format("Invalid transaction ID returned: 0x%04x", TRN_ID)
+ end
+ if(ANCOUNT ~= 1) then
+ return false, "Server returned an invalid number of answers"
+ end
+ if(bit.band(FLAGS, 0x8000) == 0) then
+ return false, "Server's flags didn't indicate a response"
+ end
+ if(bit.band(FLAGS, 0x0007) ~= 0) then
+ return false, string.format("Server returned a NetBIOS error: 0x%02x", bit.band(FLAGS, 0x0007))
+ end
- -- Start parsing the answer field
- pos, rr_name, rr_type, rr_class, rr_ttl = bin.unpack(">zSSI", result, pos)
+ -- Start parsing the answer field
+ pos, rr_name, rr_type, rr_class, rr_ttl = bin.unpack(">zSSI", result, pos)
- -- More sanity checks
- if(rr_name ~= encoded_name) then
- return false, "Server returned incorrect name"
- end
- if(rr_class ~= 0x0001) then
- return false, "Server returned incorrect class"
- end
- if(rr_type ~= 0x0021) then
- return false, "Server returned incorrect query type"
- end
+ -- More sanity checks
+ if(rr_name ~= encoded_name) then
+ return false, "Server returned incorrect name"
+ end
+ if(rr_class ~= 0x0001) then
+ return false, "Server returned incorrect class"
+ end
+ if(rr_type ~= 0x0021) then
+ return false, "Server returned incorrect query type"
+ end
- pos, rrlength, name_count = bin.unpack(">SC", result, pos)
+ pos, rrlength, name_count = bin.unpack(">SC", result, pos)
- local names = {}
- for i = 1, name_count do
- local name, suffix, flags
+ local names = {}
+ for i = 1, name_count do
+ local name, suffix, flags
- -- Instead of reading the 16-byte name and pulling off the suffix,
- -- we read the first 15 bytes and then the 1-byte suffix.
- pos, name, suffix, flags = bin.unpack(">A15CS", result, pos)
- name = string.gsub(name, "[ ]*$", "")
+ -- Instead of reading the 16-byte name and pulling off the suffix,
+ -- we read the first 15 bytes and then the 1-byte suffix.
+ pos, name, suffix, flags = bin.unpack(">A15CS", result, pos)
+ name = string.gsub(name, "[ ]*$", "")
- names[i] = {}
- names[i]['name'] = name
- names[i]['suffix'] = suffix
- names[i]['flags'] = flags
+ names[i] = {}
+ names[i]['name'] = name
+ names[i]['suffix'] = suffix
+ names[i]['flags'] = flags
- -- Decrement the length
- rrlength = rrlength - 18
- end
+ -- Decrement the length
+ rrlength = rrlength - 18
+ end
- if(rrlength > 0) then
- rrlength = rrlength - 1
- end
- pos, statistics = bin.unpack(string.format(">A%d", rrlength), result, pos)
+ if(rrlength > 0) then
+ rrlength = rrlength - 1
+ end
+ pos, statistics = bin.unpack(string.format(">A%d", rrlength), result, pos)
- -- Put it in the registry, in case anybody else needs it
- reg["nbstat_names"] = names
- reg["nbstat_statistics"] = statistics
+ -- Put it in the registry, in case anybody else needs it
+ reg["nbstat_names"] = names
+ reg["nbstat_statistics"] = statistics
- return true, names, statistics
+ return true, names, statistics
- else
- return false, "Name query failed: " .. result
- end
+ else
+ return false, "Name query failed: " .. result
+ end
end
function nbquery(host, nbname, options)
- -- override any options or set the default values
- local options = options or {}
- options.port = options.port or 137
- options.retPkt = options.retPkt or true
- options.dtype = options.dtype or types.NB
- options.host = host.ip
- options.flags = options.flags or ( options.multiple and 0x0110 )
- options.id = math.random(0xFFFF)
+ -- override any options or set the default values
+ local options = options or {}
+ options.port = options.port or 137
+ options.retPkt = options.retPkt or true
+ options.dtype = options.dtype or types.NB
+ options.host = host.ip
+ options.flags = options.flags or ( options.multiple and 0x0110 )
+ options.id = math.random(0xFFFF)
- -- encode and chop off the leading byte, as the dns library takes care of
- -- specifying the length
- local encoded_name = name_encode(nbname):sub(2)
+ -- encode and chop off the leading byte, as the dns library takes care of
+ -- specifying the length
+ local encoded_name = name_encode(nbname):sub(2)
- local status, response = dns.query( encoded_name, options )
- if ( not(status) ) then return false, "ERROR: nbquery failed" end
+ local status, response = dns.query( encoded_name, options )
+ if ( not(status) ) then return false, "ERROR: nbquery failed" end
- local results = {}
- -- discard any additional responses
- if ( options.multiple and #response > 0 ) then
- for _, resp in ipairs(response) do
- assert( options.id == resp.output.id, "Received packet with invalid transaction ID" )
- if ( not(resp.output.answers) or #resp.output.answers < 1 ) then
- return false, "ERROR: Response contained no answers"
- end
- local dname = string.char(#resp.output.answers[1].dname) .. resp.output.answers[1].dname
- table.insert( results, { peer = resp.peer, name = name_decode(dname) } )
- end
- return true, results
- else
- local dname = string.char(#response.answers[1].dname) .. response.answers[1].dname
- return true, { { peer = host.ip, name = name_decode(dname) } }
- end
+ local results = {}
+ -- discard any additional responses
+ if ( options.multiple and #response > 0 ) then
+ for _, resp in ipairs(response) do
+ assert( options.id == resp.output.id, "Received packet with invalid transaction ID" )
+ if ( not(resp.output.answers) or #resp.output.answers < 1 ) then
+ return false, "ERROR: Response contained no answers"
+ end
+ local dname = string.char(#resp.output.answers[1].dname) .. resp.output.answers[1].dname
+ table.insert( results, { peer = resp.peer, name = name_decode(dname) } )
+ end
+ return true, results
+ else
+ local dname = string.char(#response.answers[1].dname) .. response.answers[1].dname
+ return true, { { peer = host.ip, name = name_decode(dname) } }
+ end
end
---Convert the 16-bit flags field to a string.
--@param flags The 16-bit flags field
--@return A string representing the flags
function flags_to_string(flags)
- local result = ""
+ local result = ""
- if(bit.band(flags, 0x8000) ~= 0) then
- result = result .. ""
- else
- result = result .. ""
- end
+ if(bit.band(flags, 0x8000) ~= 0) then
+ result = result .. ""
+ else
+ result = result .. ""
+ end
- if(bit.band(flags, 0x1000) ~= 0) then
- result = result .. ""
- end
+ if(bit.band(flags, 0x1000) ~= 0) then
+ result = result .. ""
+ end
- if(bit.band(flags, 0x0800) ~= 0) then
- result = result .. ""
- end
+ if(bit.band(flags, 0x0800) ~= 0) then
+ result = result .. ""
+ end
- if(bit.band(flags, 0x0400) ~= 0) then
- result = result .. ""
- end
+ if(bit.band(flags, 0x0400) ~= 0) then
+ result = result .. ""
+ end
- if(bit.band(flags, 0x0200) ~= 0) then
- result = result .. ""
- end
+ if(bit.band(flags, 0x0200) ~= 0) then
+ result = result .. ""
+ end
- return result
+ return result
end
diff --git a/nselib/nrpc.lua b/nselib/nrpc.lua
index fb519cee6..badb5d0ec 100644
--- a/nselib/nrpc.lua
+++ b/nselib/nrpc.lua
@@ -9,12 +9,12 @@
-- --------
-- The library contains the following classes:
--
--- o DominoPacket
--- - The packet class holding the packets sent between the client and the
+-- o DominoPacket
+-- - The packet class holding the packets sent between the client and the
-- IBM Lotus Domino server
--
-- o Helper
--- - A helper class that provides easy access to the rest of the library
+-- - A helper class that provides easy access to the rest of the library
--
-- o DominoSocket
-- - This is a copy of the DB2Socket class which provides fundamental
@@ -27,10 +27,10 @@
-- to interface the library:
--
--
--- helper = nrpc.Helper:new(host, port)
--- status, err = nrpc:Connect()
--- status, res = nrpc:isValidUser("Patrik Karlsson")
--- status, err = nrpc:Close()
+-- helper = nrpc.Helper:new(host, port)
+-- status, err = nrpc:Connect()
+-- status, res = nrpc:isValidUser("Patrik Karlsson")
+-- status, err = nrpc:Close()
--
--
-- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html
@@ -51,180 +51,180 @@ _ENV = stdnse.module("nrpc", stdnse.seeall)
-- The Domino Packet
DominoPacket = {
- --- Creates a new DominoPacket instance
- --
- -- @param data string containing the packet data
- -- @return a new DominoPacket instance
- new = function( self, data )
- local o = {}
- setmetatable(o, self)
- self.__index = self
- o.data = data
- return o
- end,
+ --- Creates a new DominoPacket instance
+ --
+ -- @param data string containing the packet data
+ -- @return a new DominoPacket instance
+ new = function( self, data )
+ local o = {}
+ setmetatable(o, self)
+ self.__index = self
+ o.data = data
+ return o
+ end,
- --- Reads a packet from the DominoSocket
- --
- -- @param domsock DominoSocket connected to the server
- -- @return Status (true or false).
- -- @return Error code (if status is false).
- read = function( self, domsock )
- local status, data = domsock:recv(2)
- local pos, len = bin.unpack( ""tcp", "udp", or
- -- @return Status (true or false).
- -- @return Error code (if status is false).
- connect = function( self, hostid, port, protocol )
- self.Socket:set_timeout(5000)
- return self.Socket:connect( hostid, port, protocol )
- end,
+ --- Establishes a connection.
+ --
+ -- @param hostid Hostname or IP address.
+ -- @param port Port number.
+ -- @param protocol "tcp", "udp", or
+ -- @return Status (true or false).
+ -- @return Error code (if status is false).
+ connect = function( self, hostid, port, protocol )
+ self.Socket:set_timeout(5000)
+ 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,
+ --- 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
+ --- 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 ""
+ 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
+ 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)
+ data = self.Buffer:sub( 1, count )
+ self.Buffer = self.Buffer:sub( count + 1)
- return true, data
- end,
+ 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 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,
}
Helper = {
- --- Creates a new Helper instance
- --
- -- @param host table as recieved by the script action method
- -- @param port table as recieved by the script action method
- new = function(self, host, port)
- local o = {}
- setmetatable(o, self)
- self.__index = self
- o.host = host
- o.port = port
- o.domsock = DominoSocket:new()
- return o
- end,
+ --- Creates a new Helper instance
+ --
+ -- @param host table as recieved by the script action method
+ -- @param port table as recieved by the script action method
+ new = function(self, host, port)
+ local o = {}
+ setmetatable(o, self)
+ self.__index = self
+ o.host = host
+ o.port = port
+ o.domsock = DominoSocket:new()
+ return o
+ end,
- --- Connects the socket to the Domino server
- --
- -- @return status true on success, false on failure
- -- @return err error message if status is false
- connect = function( self )
- if( not( self.domsock:connect( self.host.ip, self.port.number, "tcp" ) ) ) then
- return false, ("ERROR: Failed to connect to Domino server %s:%d\n"):format(self.host, self.port)
- end
- return true
- end,
+ --- Connects the socket to the Domino server
+ --
+ -- @return status true on success, false on failure
+ -- @return err error message if status is false
+ connect = function( self )
+ if( not( self.domsock:connect( self.host.ip, self.port.number, "tcp" ) ) ) then
+ return false, ("ERROR: Failed to connect to Domino server %s:%d\n"):format(self.host, self.port)
+ end
+ return true
+ end,
- --- Disconnects from the Lotus Domino Server
- --
- -- @return status true on success, false on failure
- -- @return err error message if status is false
- disconnect = function( self )
- return self.domsock:close()
- end,
+ --- Disconnects from the Lotus Domino Server
+ --
+ -- @return status true on success, false on failure
+ -- @return err error message if status is false
+ disconnect = function( self )
+ return self.domsock:close()
+ end,
- --- Attempt to check whether the user exists in Domino or not
- --
- -- @param username string containing the user name to guess
- -- @return status true on success false on failure
- -- @return domino_id if it exists and status is true
- -- err if status is false
- isValidUser = function( self, username )
- local data = bin.pack("H", "00001e00000001000080000007320000700104020000fb2b2d00281f1e000000124c010000000000")
- local status, id_data
- local data_len, pos, total_len, pkt_type, valid_user
+ --- Attempt to check whether the user exists in Domino or not
+ --
+ -- @param username string containing the user name to guess
+ -- @return status true on success false on failure
+ -- @return domino_id if it exists and status is true
+ -- err if status is false
+ isValidUser = function( self, username )
+ local data = bin.pack("H", "00001e00000001000080000007320000700104020000fb2b2d00281f1e000000124c010000000000")
+ local status, id_data
+ local data_len, pos, total_len, pkt_type, valid_user
- self.domsock:send( tostring(DominoPacket:new( data )) )
- data = DominoPacket:new():read( self.domsock )
+ self.domsock:send( tostring(DominoPacket:new( data )) )
+ data = DominoPacket:new():read( self.domsock )
- data = bin.pack("HCHAH", "0100320002004f000100000500000900", #username + 1, "000000000000000000000000000000000028245573657273290000", username, "00")
- self.domsock:send( tostring(DominoPacket:new( data ) ) )
- status, id_data = DominoPacket:new():read( self.domsock )
+ data = bin.pack("HCHAH", "0100320002004f000100000500000900", #username + 1, "000000000000000000000000000000000028245573657273290000", username, "00")
+ self.domsock:send( tostring(DominoPacket:new( data ) ) )
+ status, id_data = DominoPacket:new():read( self.domsock )
- pos, pkt_type = bin.unpack("C", id_data, 3)
- pos, valid_user = bin.unpack("C", id_data, 11)
- pos, total_len = bin.unpack(" 0x7f then
- ch = string.byte(".", 1)
- end
- io.write(string.format("%c", ch))
- end
+ -- Loop through the string again, this time the ascii
+ for char=1, 16, 1 do
+ local ch = string.byte(str, ((line - 1) * 16) + char)
+ if ch < 0x20 or ch > 0x7f then
+ ch = string.byte(".", 1)
+ end
+ io.write(string.format("%c", ch))
+ end
- io.write("\n")
- end
+ io.write("\n")
+ end
- -- Prints out the final, partial line
- if (#str % 16 ~= 0) then
- local line = math.floor((#str/16)) + 1
- io.write(string.format("%08x ", (line - 1) * 16))
+ -- Prints out the final, partial line
+ if (#str % 16 ~= 0) then
+ local line = math.floor((#str/16)) + 1
+ io.write(string.format("%08x ", (line - 1) * 16))
- for char=1, #str % 16, 1 do
- local ch = string.byte(str, ((line - 1) * 16) + char)
- io.write(string.format("%02x ", ch))
- end
- io.write(string.rep(" ", 16 - (#str % 16)));
- io.write(" ")
+ for char=1, #str % 16, 1 do
+ local ch = string.byte(str, ((line - 1) * 16) + char)
+ io.write(string.format("%02x ", ch))
+ end
+ io.write(string.rep(" ", 16 - (#str % 16)));
+ io.write(" ")
- for char=1, #str % 16, 1 do
- local ch = string.byte(str, ((line - 1) * 16) + char)
- if ch < 0x20 or ch > 0x7f then
- ch = string.byte(".", 1)
- end
- io.write(string.format("%c", ch))
- end
+ for char=1, #str % 16, 1 do
+ local ch = string.byte(str, ((line - 1) * 16) + char)
+ if ch < 0x20 or ch > 0x7f then
+ ch = string.byte(".", 1)
+ end
+ io.write(string.format("%c", ch))
+ end
- io.write("\n")
- end
+ io.write("\n")
+ end
- -- Print out the length
- io.write(string.format(" Length: %d [0x%x]\n", #str, #str))
+ -- Print out the length
+ io.write(string.format(" Length: %d [0x%x]\n", #str, #str))
end
---Print out a stacktrace. The stacktrace will naturally include this function call.
function print_stack()
- local thread = coroutine.running()
- local trace = debug.traceback(thread);
- if trace ~= "stack traceback:" then
- print(thread, "\n", trace, "\n");
- end
+ local thread = coroutine.running()
+ local trace = debug.traceback(thread);
+ if trace ~= "stack traceback:" then
+ print(thread, "\n", trace, "\n");
+ end
end
diff --git a/nselib/ospf.lua b/nselib/ospf.lua
index 0938fedce..b93f7a937 100644
--- a/nselib/ospf.lua
+++ b/nselib/ospf.lua
@@ -19,281 +19,281 @@ _ENV = stdnse.module("ospf", stdnse.seeall)
-- The OSPF class.
OSPF = {
- -- Message Type constants
- Message = {
- HELLO = 1,
- DB_DESCRIPTION = 2,
- LS_UPDATE = 4,
- },
+ -- Message Type constants
+ Message = {
+ HELLO = 1,
+ DB_DESCRIPTION = 2,
+ LS_UPDATE = 4,
+ },
- LSUpdate = {
+ LSUpdate = {
+
+ },
+
+ Header = {
+ size = 24,
+ new = function(self, type, area_id, router_id, auth_type, auth_data)
+ local o = {
+ ver = 2,
+ type = type,
+ length = 0,
+ router_id = router_id or 0,
+ area_id = area_id or 0,
+ chksum = 0,
+ auth_type = auth_type or 0,
+ auth_data = auth_data or {},
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
+
+ parse = function(data)
+ local header = OSPF.Header:new()
+ local pos
+ pos, header.ver, header.type, header.length = bin.unpack(">CCS", data)
+ assert( header.ver == 2, "Invalid OSPF version detected")
+
+ pos, header.router_id, header.area_id, header.chksum, header.auth_type
+ = bin.unpack("ISS", data, pos)
+
+ -- No authentication
+ if header.auth_type == 0x00 then
+ header.auth_data.password = nil
+ -- Clear text password
+ elseif header.auth_type == 0x01 then
+ pos, header.auth_data.password = bin.unpack(">A8", data, pos)
+ -- MD5 hash authentication
+ elseif header.auth_type == 0x02 then
+ local _
+ _, header.auth_data.keyid = bin.unpack(">C", data, pos+2)
+ _, header.auth_data.length = bin.unpack(">C", data, pos+3)
+ _, header.auth_data.seq = bin.unpack(">C", data, pos+4)
+ _, header.auth_data.hash = bin.unpack(">H"..header.auth_data.length, data, header.length+1)
+ else
+ -- Shouldn't happen
+ stdnse.print_debug("Unknown authentication type " .. header.auth_type)
+ return nil
+ end
+ header.router_id = ipOps.fromdword(header.router_id)
+ return header
+ end,
+
+ --- Sets the OSPF Area ID
+ -- @param areaid Area ID.
+ setAreaID = function(self, areaid)
+ self.area_id = (type(areaid) == "number") and areaid or ipOps.todword(areaid)
+ end,
+
+ --- Sets the OSPF Router ID
+ -- @param router_id Router ID.
+ setRouterId = function(self, router_id)
+ self.router_id = router_id
+ end,
+
+ --- Sets the OSPF Packet length
+ -- @param length Packet length.
+ setLength = function(self, length)
+ self.length = self.size + length
+ end,
+
+ __tostring = function(self)
+ local hdr = bin.pack(">CCS", self.ver, self.type, self.length )
+ hdr = hdr .. bin.pack(">IISS", ipOps.todword(self.router_id), self.area_id, self.chksum, self.auth_type)
+ if self.auth_type == 0x00 then
+ hdr = hdr .. bin.pack(">L", 0x00)
+ elseif self.auth_type == 0x01 then
+ hdr = hdr .. bin.pack(">A8", self.auth_data.password)
+ elseif self.auth_type == 0x02 then
+ hdr = hdr .. bin.pack(">A".. self.auth_data.length, self.auth_data.hash)
+ end
+ return hdr
+ end,
+
+ },
+
+ Hello = {
+ new = function(self)
+ local o = {
+ header = OSPF.Header:new(OSPF.Message.HELLO),
+ options = 0x02,
+ prio = 0,
+ interval = 10,
+ router_dead_interval = 40,
+ neighbors = {},
+ DR = "0.0.0.0",
+ BDR = "0.0.0.0",
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
+
+ --- Adds a neighbor to the list of neighbors.
+ -- @param neighbor IP Address of the neighbor.
+ addNeighbor = function(self, neighbor)
+ table.insert(self.neighbors, neighbor)
+ end,
+
+ --- Sets the OSPF netmask.
+ -- @param netmask Netmask in A.B.C.D
+ setNetmask = function(self, netmask)
+ if netmask then
+ self.netmask = netmask
+ end
+ end,
+
+ --- Sets the OSPF designated Router.
+ -- @param router IP address of the designated router.
+ setDesignatedRouter = function(self, router)
+ if router then
+ self.DR = router
+ end
+ end,
+
+ --- Sets the OSPF backup Router.
+ -- @param router IP Address of the backup router.
+ setBackupRouter = function(self, router)
+ if router then
+ self.BDR = router
+ end
+ end,
+
+ __tostring = function(self)
+ self.neighbors = self.neighbors or {}
+ local function tostr()
+ local data = bin.pack(">ISCCIII", ipOps.todword(self.netmask), self.interval, self.options, self.prio, self.router_dead_interval, ipOps.todword(self.DR), ipOps.todword(self.BDR))
+ for _, n in ipairs(self.neighbors) do
+ data = data .. bin.pack(">I", ipOps.todword(n))
+ end
+ self.header:setLength(#data)
+ return tostring(self.header) .. data
+ end
+ local data = tostr()
+ self.header.chksum = packet.in_cksum(data:sub(1,12) .. data:sub(25))
+ return tostr()
+ end,
+
+ parse = function(data)
+ local hello = OSPF.Hello:new()
+ local pos = OSPF.Header.size + 1
+ hello.header = OSPF.Header.parse(data)
+ assert( #data >= hello.header.length, "OSPF packet too short")
+ pos, hello.netmask, hello.interval, hello.options, hello.prio,
+ hello.router_dead_interval, hello.DR,
+ hello.BDR = bin.unpack("CCS", data)
- assert( header.ver == 2, "Invalid OSPF version detected")
+ __tostring = function(self)
+ local function tostr()
+ local flags = 0
+ if ( self.init ) then flags = flags + 4 end
+ if ( self.more ) then flags = flags + 2 end
+ if ( self.master) then flags= flags + 1 end
- pos, header.router_id, header.area_id, header.chksum, header.auth_type
- = bin.unpack("ISS", data, pos)
+ local data = bin.pack(">SCCI", self.mtu, self.options, flags, self.sequence)
+ self.header:setLength(#data)
+ return tostring(self.header) .. data
+ end
+ local data = tostr()
+ self.header.chksum = packet.in_cksum(data:sub(1,12) .. data:sub(25))
+ return tostr()
+ end,
- -- No authentication
- if header.auth_type == 0x00 then
- header.auth_data.password = nil
- -- Clear text password
- elseif header.auth_type == 0x01 then
- pos, header.auth_data.password = bin.unpack(">A8", data, pos)
- -- MD5 hash authentication
- elseif header.auth_type == 0x02 then
- local _
- _, header.auth_data.keyid = bin.unpack(">C", data, pos+2)
- _, header.auth_data.length = bin.unpack(">C", data, pos+3)
- _, header.auth_data.seq = bin.unpack(">C", data, pos+4)
- _, header.auth_data.hash = bin.unpack(">H"..header.auth_data.length, data, header.length+1)
- else
- -- Shouldn't happen
- stdnse.print_debug("Unknown authentication type " .. header.auth_type)
- return nil
- end
- header.router_id = ipOps.fromdword(header.router_id)
- return header
- end,
+ parse = function(data)
+ local desc = OSPF.DBDescription:new()
+ local pos = OSPF.Header.size + 1
+ desc.header = OSPF.Header.parse(data)
+ assert( #data == desc.header.length, "OSPF packet too short")
- --- Sets the OSPF Area ID
- -- @param areaid Area ID.
- setAreaID = function(self, areaid)
- self.area_id = (type(areaid) == "number") and areaid or ipOps.todword(areaid)
- end,
+ local flags = 0
+ pos, desc.mtu, desc.options, flags, desc.sequence = bin.unpack(">SCCI", data, pos)
- --- Sets the OSPF Router ID
- -- @param router_id Router ID.
- setRouterId = function(self, router_id)
- self.router_id = router_id
- end,
+ desc.init = ( bit.band(flags, 4) == 4 )
+ desc.more = ( bit.band(flags, 2) == 2 )
+ desc.master = ( bit.band(flags, 1) == 1 )
- --- Sets the OSPF Packet length
- -- @param length Packet length.
- setLength = function(self, length)
- self.length = self.size + length
- end,
+ if ( desc.init or not(desc.more) ) then
+ return desc
+ end
- __tostring = function(self)
- local hdr = bin.pack(">CCS", self.ver, self.type, self.length )
- hdr = hdr .. bin.pack(">IISS", ipOps.todword(self.router_id), self.area_id, self.chksum, self.auth_type)
- if self.auth_type == 0x00 then
- hdr = hdr .. bin.pack(">L", 0x00)
- elseif self.auth_type == 0x01 then
- hdr = hdr .. bin.pack(">A8", self.auth_data.password)
- elseif self.auth_type == 0x02 then
- hdr = hdr .. bin.pack(">A".. self.auth_data.length, self.auth_data.hash)
- end
- return hdr
- end,
+ return desc
+ end,
- },
+ },
- Hello = {
- new = function(self)
- local o = {
- header = OSPF.Header:new(OSPF.Message.HELLO),
- options = 0x02,
- prio = 0,
- interval = 10,
- router_dead_interval = 40,
- neighbors = {},
- DR = "0.0.0.0",
- BDR = "0.0.0.0",
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ Response = {
- --- Adds a neighbor to the list of neighbors.
- -- @param neighbor IP Address of the neighbor.
- addNeighbor = function(self, neighbor)
- table.insert(self.neighbors, neighbor)
- end,
+ parse = function(data)
+ local pos, ver, ospf_type = bin.unpack("CC", data)
+ if ( ospf_type == OSPF.Message.HELLO ) then
+ return OSPF.Hello.parse( data )
+ elseif( ospf_type == OSPF.Message.DB_DESCRIPTION ) then
+ return OSPF.DBDescription.parse(data)
+ end
+ return
+ end,
- --- Sets the OSPF netmask.
- -- @param netmask Netmask in A.B.C.D
- setNetmask = function(self, netmask)
- if netmask then
- self.netmask = netmask
- end
- end,
-
- --- Sets the OSPF designated Router.
- -- @param router IP address of the designated router.
- setDesignatedRouter = function(self, router)
- if router then
- self.DR = router
- end
- end,
-
- --- Sets the OSPF backup Router.
- -- @param router IP Address of the backup router.
- setBackupRouter = function(self, router)
- if router then
- self.BDR = router
- end
- end,
-
- __tostring = function(self)
- self.neighbors = self.neighbors or {}
- local function tostr()
- local data = bin.pack(">ISCCIII", ipOps.todword(self.netmask), self.interval, self.options, self.prio, self.router_dead_interval, ipOps.todword(self.DR), ipOps.todword(self.BDR))
- for _, n in ipairs(self.neighbors) do
- data = data .. bin.pack(">I", ipOps.todword(n))
- end
- self.header:setLength(#data)
- return tostring(self.header) .. data
- end
- local data = tostr()
- self.header.chksum = packet.in_cksum(data:sub(1,12) .. data:sub(25))
- return tostr()
- end,
-
- parse = function(data)
- local hello = OSPF.Hello:new()
- local pos = OSPF.Header.size + 1
- hello.header = OSPF.Header.parse(data)
- assert( #data >= hello.header.length, "OSPF packet too short")
- pos, hello.netmask, hello.interval, hello.options, hello.prio,
- hello.router_dead_interval, hello.DR,
- hello.BDR = bin.unpack("SCCI", self.mtu, self.options, flags, self.sequence)
- self.header:setLength(#data)
- return tostring(self.header) .. data
- end
- local data = tostr()
- self.header.chksum = packet.in_cksum(data:sub(1,12) .. data:sub(25))
- return tostr()
- end,
-
- parse = function(data)
- local desc = OSPF.DBDescription:new()
- local pos = OSPF.Header.size + 1
- desc.header = OSPF.Header.parse(data)
- assert( #data == desc.header.length, "OSPF packet too short")
-
- local flags = 0
- pos, desc.mtu, desc.options, flags, desc.sequence = bin.unpack(">SCCI", data, pos)
-
- desc.init = ( bit.band(flags, 4) == 4 )
- desc.more = ( bit.band(flags, 2) == 2 )
- desc.master = ( bit.band(flags, 1) == 1 )
-
- if ( desc.init or not(desc.more) ) then
- return desc
- end
-
- return desc
- end,
-
- },
-
- Response = {
-
- parse = function(data)
- local pos, ver, ospf_type = bin.unpack("CC", data)
- if ( ospf_type == OSPF.Message.HELLO ) then
- return OSPF.Hello.parse( data )
- elseif( ospf_type == OSPF.Message.DB_DESCRIPTION ) then
- return OSPF.DBDescription.parse(data)
- end
- return
- end,
-
- }
+ }
}
return _ENV;
diff --git a/nselib/pop3.lua b/nselib/pop3.lua
index 982272641..e217a5a41 100644
--- a/nselib/pop3.lua
+++ b/nselib/pop3.lua
@@ -15,11 +15,11 @@ local HAVE_SSL, openssl = pcall(require,'openssl')
err = {
- none = 0,
- userError = 1,
- pwError = 2,
- informationMissing = 3,
- OpenSSLMissing = 4,
+ none = 0,
+ userError = 1,
+ pwError = 2,
+ informationMissing = 3,
+ OpenSSLMissing = 4,
}
---
@@ -27,7 +27,7 @@ err = {
-- @param line First line returned from an POP3 request.
-- @return The string "+OK" if found or nil otherwise.
function stat(line)
- return string.match(line, "+OK")
+ return string.match(line, "+OK")
end
@@ -40,16 +40,16 @@ end
-- @return Status (true or false).
-- @return Error code if status is false.
function login_user(socket, user, pw)
- socket:send("USER " .. user .. "\r\n")
- local status, line = socket:receive_lines(1)
- if not stat(line) then return false, err.user_error end
- socket:send("PASS " .. pw .. "\r\n")
+ socket:send("USER " .. user .. "\r\n")
+ local status, line = socket:receive_lines(1)
+ if not stat(line) then return false, err.user_error end
+ socket:send("PASS " .. pw .. "\r\n")
- status, line = socket:receive_lines(1)
+ status, line = socket:receive_lines(1)
- if stat(line) then return true, err.none
- else return false, err.pwError
- end
+ if stat(line) then return true, err.none
+ else return false, err.pwError
+ end
end
@@ -62,16 +62,16 @@ end
-- @return Error code if status is false.
function login_sasl_plain(socket, user, pw)
- local auth64 = base64.enc(user .. "\0" .. user .. "\0" .. pw)
- socket:send("AUTH PLAIN " .. auth64 .. "\r\n")
+ local auth64 = base64.enc(user .. "\0" .. user .. "\0" .. pw)
+ socket:send("AUTH PLAIN " .. auth64 .. "\r\n")
- local status, line = socket:receive_lines(1)
+ local status, line = socket:receive_lines(1)
- if stat(line) then
- return true, err.none
- else
- return false, err.pwError
- end
+ if stat(line) then
+ return true, err.none
+ else
+ return false, err.pwError
+ end
end
---
@@ -83,34 +83,34 @@ end
-- @return Error code if status is false.
function login_sasl_login(socket, user, pw)
- local user64 = base64.enc(user)
+ local user64 = base64.enc(user)
- local pw64 = base64.enc(pw)
+ local pw64 = base64.enc(pw)
- socket:send("AUTH LOGIN\r\n")
+ socket:send("AUTH LOGIN\r\n")
- local status, line = socket:receive_lines(1)
- if not base64.dec(string.sub(line, 3)) == "User Name:" then
- return false, err.userError
- end
+ local status, line = socket:receive_lines(1)
+ if not base64.dec(string.sub(line, 3)) == "User Name:" then
+ return false, err.userError
+ end
- socket:send(user64)
+ socket:send(user64)
- local status, line = socket:receive_lines(1)
+ local status, line = socket:receive_lines(1)
- if not base64.dec(string.sub(line, 3)) == "Password:" then
- return false, err.userError
- end
+ if not base64.dec(string.sub(line, 3)) == "Password:" then
+ return false, err.userError
+ end
- socket:send(pw64)
+ socket:send(pw64)
- local status, line = socket:receive_lines(1)
+ local status, line = socket:receive_lines(1)
- if stat(line) then
- return true, err.none
- else
- return false, err.pwError
- end
+ if stat(line) then
+ return true, err.none
+ else
+ return false, err.pwError
+ end
end
---
@@ -122,18 +122,18 @@ end
-- @return Status (true or false).
-- @return Error code if status is false.
function login_apop(socket, user, pw, challenge)
- if type(challenge) ~= "string" then return false, err.informationMissing end
+ if type(challenge) ~= "string" then return false, err.informationMissing end
- local apStr = stdnse.tohex(openssl.md5(challenge .. pw))
- socket:send(("APOP %s %s\r\n"):format(user, apStr))
+ local apStr = stdnse.tohex(openssl.md5(challenge .. pw))
+ socket:send(("APOP %s %s\r\n"):format(user, apStr))
- local status, line = socket:receive_lines(1)
+ local status, line = socket:receive_lines(1)
- if (stat(line)) then
- return true, err.none
- else
- return false, err.pwError
- end
+ if (stat(line)) then
+ return true, err.none
+ else
+ return false, err.pwError
+ end
end
---
@@ -146,49 +146,49 @@ end
-- @return nil or String error message.
function capabilities(host, port)
- local socket, line, bopt, first_line = comm.tryssl(host, port, "" , {timeout=10000, recv_before=true})
- if not socket then
- return nil, "Could Not Connect"
- end
- if not stat(first_line) then
- return nil, "No Response"
- end
+ local socket, line, bopt, first_line = comm.tryssl(host, port, "" , {timeout=10000, recv_before=true})
+ if not socket then
+ return nil, "Could Not Connect"
+ end
+ if not stat(first_line) then
+ return nil, "No Response"
+ end
- local capas = {}
- if string.find(first_line, "<[%p%w]+>") then
- capas.APOP = {}
- end
+ local capas = {}
+ if string.find(first_line, "<[%p%w]+>") then
+ capas.APOP = {}
+ end
- local status = socket:send("CAPA\r\n")
- if( not(status) ) then
- return nil, "Failed to send"
- end
+ local status = socket:send("CAPA\r\n")
+ if( not(status) ) then
+ return nil, "Failed to send"
+ end
- status, line = socket:receive_buf("%.", false)
- if( not(status) ) then
- return nil, "Failed to receive"
- end
- socket:close()
+ status, line = socket:receive_buf("%.", false)
+ if( not(status) ) then
+ return nil, "Failed to receive"
+ end
+ socket:close()
- local lines = stdnse.strsplit("\r\n",line)
- if not stat(table.remove(lines,1)) then
- capas.capa = false
- return capas
- end
+ local lines = stdnse.strsplit("\r\n",line)
+ if not stat(table.remove(lines,1)) then
+ capas.capa = false
+ return capas
+ end
- for _, line in ipairs(lines) do
- if ( line and #line>0 ) then
- local capability = line:sub(line:find("[%w-]+"))
- line = line:sub(#capability + 2)
- if ( line ~= "" ) then
- capas[capability] = stdnse.strsplit(" ", line)
- else
- capas[capability] = {}
- end
- end
- end
+ for _, line in ipairs(lines) do
+ if ( line and #line>0 ) then
+ local capability = line:sub(line:find("[%w-]+"))
+ line = line:sub(#capability + 2)
+ if ( line ~= "" ) then
+ capas[capability] = stdnse.strsplit(" ", line)
+ else
+ capas[capability] = {}
+ end
+ end
+ end
- return capas
+ return capas
end
---
@@ -200,23 +200,23 @@ end
-- @return Error code if status is false.
function login_sasl_crammd5(socket, user, pw)
- socket:send("AUTH CRAM-MD5\r\n")
+ socket:send("AUTH CRAM-MD5\r\n")
- local status, line = socket:receive_lines(1)
+ local status, line = socket:receive_lines(1)
- local challenge = base64.dec(string.sub(line, 3))
+ local challenge = base64.dec(string.sub(line, 3))
- local digest = stdnse.tohex(openssl.hmac('md5', pw, challenge))
- local authStr = base64.enc(user .. " " .. digest)
- socket:send(authStr .. "\r\n")
+ local digest = stdnse.tohex(openssl.hmac('md5', pw, challenge))
+ local authStr = base64.enc(user .. " " .. digest)
+ socket:send(authStr .. "\r\n")
- local status, line = socket:receive_lines(1)
+ local status, line = socket:receive_lines(1)
- if stat(line) then
- return true, err.none
- else
- return false, err.pwError
- end
+ if stat(line) then
+ return true, err.none
+ else
+ return false, err.pwError
+ end
end
-- Overwrite functions requiring OpenSSL if we got no OpenSSL.
diff --git a/nselib/proxy.lua b/nselib/proxy.lua
index c937a822f..59714d283 100644
--- a/nselib/proxy.lua
+++ b/nselib/proxy.lua
@@ -211,7 +211,7 @@ function socksHandshake(socket, version, hostname)
stdnse.print_debug("Socks4: Received \"request failed because client is not running identd\" from proxy server")
elseif (request_status == 0x5d) then
stdnse.print_debug("Socks4: Received \"request failed because client's identd could not confirm" ..
- "\nthe user ID string in the request from proxy server")
+ "\nthe user ID string in the request from proxy server")
end
return false
end
@@ -234,24 +234,24 @@ function socksHandshake(socket, version, hostname)
local z = try(socket:receive())
local request_status = string.byte(z, 2)
if (request_status == 0x00) then
- stdnse.print_debug("Socks5: Received \"Request Granted\" from proxy server\n")
- return socket
+ stdnse.print_debug("Socks5: Received \"Request Granted\" from proxy server\n")
+ return socket
elseif(request_status == 0x01) then
- stdnse.print_debug("Socks5: Received \"General failure\" from proxy server")
+ stdnse.print_debug("Socks5: Received \"General failure\" from proxy server")
elseif (request_status == 0x02) then
- stdnse.print_debug("Socks5: Received \"Connection not allowed by ruleset\" from proxy server")
+ stdnse.print_debug("Socks5: Received \"Connection not allowed by ruleset\" from proxy server")
elseif (request_status == 0x03) then
- stdnse.print_debug("Socks5: Received \"Network unreachable\" from proxy server")
+ stdnse.print_debug("Socks5: Received \"Network unreachable\" from proxy server")
elseif (request_status == 0x04) then
- stdnse.print_debug("Socks5: Received \"Host unreachable\" from proxy server")
+ stdnse.print_debug("Socks5: Received \"Host unreachable\" from proxy server")
elseif (request_status == 0x05) then
- stdnse.print_debug("Socks5: Received \"Connection refused by destination host\" from proxy server")
+ stdnse.print_debug("Socks5: Received \"Connection refused by destination host\" from proxy server")
elseif (request_status == 0x06) then
- stdnse.print_debug("Socks5: Received \"TTL Expired\" from proxy server")
+ stdnse.print_debug("Socks5: Received \"TTL Expired\" from proxy server")
elseif (request_status == 0x07) then
- stdnse.print_debug("Socks5: Received \"command not supported / protocol error\" from proxy server")
+ stdnse.print_debug("Socks5: Received \"command not supported / protocol error\" from proxy server")
elseif (request_status == 0x08) then
- stdnse.print_debug("Socks5: Received \"Address type not supported\" from proxy server")
+ stdnse.print_debug("Socks5: Received \"Address type not supported\" from proxy server")
end
end
return false
diff --git a/nselib/rdp.lua b/nselib/rdp.lua
index 2b093a607..5aafbde78 100644
--- a/nselib/rdp.lua
+++ b/nselib/rdp.lua
@@ -14,325 +14,325 @@ _ENV = stdnse.module("rdp", stdnse.seeall)
Packet = {
- TPKT = {
+ TPKT = {
- new = function(self, data)
- local o = { data = tostring(data), version = 3 }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ new = function(self, data)
+ local o = { data = tostring(data), version = 3 }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- __tostring = function(self)
- return bin.pack(">CCSA",
- self.version,
- self.reserved or 0,
- (self.data and #self.data + 4 or 4),
- self.data
- )
- end,
+ __tostring = function(self)
+ return bin.pack(">CCSA",
+ self.version,
+ self.reserved or 0,
+ (self.data and #self.data + 4 or 4),
+ self.data
+ )
+ end,
- parse = function(data)
- local tpkt = Packet.TPKT:new()
- local pos
+ parse = function(data)
+ local tpkt = Packet.TPKT:new()
+ local pos
- pos, tpkt.version, tpkt.reserved, tpkt.length = bin.unpack(">CCS", data)
- pos, tpkt.data = bin.unpack("A" .. (#data - pos), data, pos)
- return tpkt
- end
- },
+ pos, tpkt.version, tpkt.reserved, tpkt.length = bin.unpack(">CCS", data)
+ pos, tpkt.data = bin.unpack("A" .. (#data - pos), data, pos)
+ return tpkt
+ end
+ },
- ITUT = {
+ ITUT = {
- new = function(self, code, data)
- local o = { data = tostring(data), code = code }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ new = function(self, code, data)
+ local o = { data = tostring(data), code = code }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- parse = function(data)
- local itut = Packet.ITUT:new()
- local pos
+ parse = function(data)
+ local itut = Packet.ITUT:new()
+ local pos
- pos, itut.length, itut.code = bin.unpack("CC", data)
+ pos, itut.length, itut.code = bin.unpack("CC", data)
- if ( itut.code == 0xF0 ) then
- pos, itut.eot = bin.unpack("C", data, pos)
- elseif ( itut.code == 0xD0 ) then
- pos, itut.dstref, itut.srcref, itut.class = bin.unpack(">SSC", data, pos)
- end
+ if ( itut.code == 0xF0 ) then
+ pos, itut.eot = bin.unpack("C", data, pos)
+ elseif ( itut.code == 0xD0 ) then
+ pos, itut.dstref, itut.srcref, itut.class = bin.unpack(">SSC", data, pos)
+ end
- pos, itut.data = bin.unpack("A" .. (#data - pos), data, pos)
- return itut
- end,
+ pos, itut.data = bin.unpack("A" .. (#data - pos), data, pos)
+ return itut
+ end,
- __tostring = function(self)
- local len = (self.code ~= 0xF0 and #self.data + 1 or 2)
- local data = bin.pack("CC",
- len,
- self.code or 0
- )
+ __tostring = function(self)
+ local len = (self.code ~= 0xF0 and #self.data + 1 or 2)
+ local data = bin.pack("CC",
+ len,
+ self.code or 0
+ )
- if ( self.code == 0xF0 ) then
- data = data .. bin.pack("C", 0x80) -- EOT
- end
+ if ( self.code == 0xF0 ) then
+ data = data .. bin.pack("C", 0x80) -- EOT
+ end
- return data .. self.data
- end,
+ return data .. self.data
+ end,
- },
+ },
}
Request = {
- ConnectionRequest = {
+ ConnectionRequest = {
- new = function(self, proto)
- local o = { proto = proto }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ new = function(self, proto)
+ local o = { proto = proto }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- __tostring = function(self)
- local cookie = "mstshash=nmap"
- local itpkt_len = 21 + #cookie
- local itut_len = 16 + #cookie
+ __tostring = function(self)
+ local cookie = "mstshash=nmap"
+ local itpkt_len = 21 + #cookie
+ local itut_len = 16 + #cookie
- local data = bin.pack(">SSCA",
- 0x0000, -- dst reference
- 0x0000, -- src reference
- 0x00, -- class and options
- ("Cookie: %s\r\n"):format(cookie))
+ local data = bin.pack(">SSCA",
+ 0x0000, -- dst reference
+ 0x0000, -- src reference
+ 0x00, -- class and options
+ ("Cookie: %s\r\n"):format(cookie))
- if ( self.proto ) then
- data = data .. bin.pack("SSSSAA", self.type, DUMMY, #self.username, #self.password, self.username, self.password)
- end,
+ __tostring = function(self)
+ local DUMMY = 0
+ return bin.pack(">SSSSAA", self.type, DUMMY, #self.username, #self.password, self.username, self.password)
+ end,
- },
+ },
- NULL = {
+ NULL = {
- new = function(self)
- local o = {
- type = 0,
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ new = function(self)
+ local o = {
+ type = 0,
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- __tostring = function(self)
- local DUMMY = 0
- return bin.pack(">SSSS", self.type, DUMMY, 0, 0)
- end,
+ __tostring = function(self)
+ local DUMMY = 0
+ return bin.pack(">SSSS", self.type, DUMMY, 0, 0)
+ end,
- }
+ }
- },
+ },
- -- The common request and response header
- Header = {
- size = 8,
- new = function(self, type, value, length)
- local o = {
- version = 0,
- type = type,
- value= value or 0,
- length = length or 0
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- The common request and response header
+ Header = {
+ size = 8,
+ new = function(self, type, value, length)
+ local o = {
+ version = 0,
+ type = type,
+ value= value or 0,
+ length = length or 0
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- parse = function(data)
- local header = RPCAP.Header:new()
- local pos
- pos, header.version, header.type, header.value, header.length = bin.unpack(">CCSI", data)
- return header
- end,
+ parse = function(data)
+ local header = RPCAP.Header:new()
+ local pos
+ pos, header.version, header.type, header.value, header.length = bin.unpack(">CCSI", data)
+ return header
+ end,
- __tostring = function(self)
- return bin.pack(">CCSI", self.version, self.type, self.value, self.length)
- end,
+ __tostring = function(self)
+ return bin.pack(">CCSI", self.version, self.type, self.value, self.length)
+ end,
- },
+ },
- -- The implemented request types are kept here
- Request = {
+ -- The implemented request types are kept here
+ Request = {
- Authentication = {
+ Authentication = {
- new = function(self, data)
- local o = {
- header = RPCAP.Header:new(RPCAP.MessageType.AUTH_REQUEST, nil, #data),
- data = data,
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ new = function(self, data)
+ local o = {
+ header = RPCAP.Header:new(RPCAP.MessageType.AUTH_REQUEST, nil, #data),
+ data = data,
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- __tostring = function(self)
- return tostring(self.header) .. tostring(self.data)
- end,
+ __tostring = function(self)
+ return tostring(self.header) .. tostring(self.data)
+ end,
- },
+ },
- FindAllInterfaces = {
+ FindAllInterfaces = {
- new = function(self)
- local o = {
- header = RPCAP.Header:new(RPCAP.MessageType.FIND_ALL_INTERFACES)
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ new = function(self)
+ local o = {
+ header = RPCAP.Header:new(RPCAP.MessageType.FIND_ALL_INTERFACES)
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- __tostring = function(self)
- return tostring(self.header)
- end,
+ __tostring = function(self)
+ return tostring(self.header)
+ end,
- }
+ }
- },
+ },
- -- Parsers for responses are kept here
- Response = {
+ -- Parsers for responses are kept here
+ Response = {
- Authentication = {
- new = function(self)
- local o = { }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ Authentication = {
+ new = function(self)
+ local o = { }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- parse = function(data)
- local resp = RPCAP.Response.Authentication:new()
- local pos = RPCAP.Header.size + 1
- resp.header = RPCAP.Header.parse(data)
- return resp
- end
- },
+ parse = function(data)
+ local resp = RPCAP.Response.Authentication:new()
+ local pos = RPCAP.Header.size + 1
+ resp.header = RPCAP.Header.parse(data)
+ return resp
+ end
+ },
- Error = {
- new = function(self)
- local o = { }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ Error = {
+ new = function(self)
+ local o = { }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- parse = function(data)
- local err = RPCAP.Response.Error:new()
- local pos = RPCAP.Header.size + 1
- err.header = RPCAP.Header.parse(data)
- pos, err.error = bin.unpack("A" .. err.header.length, data, pos)
- return err
- end
+ parse = function(data)
+ local err = RPCAP.Response.Error:new()
+ local pos = RPCAP.Header.size + 1
+ err.header = RPCAP.Header.parse(data)
+ pos, err.error = bin.unpack("A" .. err.header.length, data, pos)
+ return err
+ end
- },
+ },
- FindAllInterfaces = {
- new = function(self)
- local o = { }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ FindAllInterfaces = {
+ new = function(self)
+ local o = { }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- parse = function(data)
+ parse = function(data)
- -- Each address is made up of 4 128 byte fields, this function
- -- parses these fields and return the response, if it
- -- understands it. Otherwise it simply increases the pos by the
- -- correct offset, to get us to the next field.
- local function parseField(data, pos)
- local offset = pos
- local family, port
- pos, family, port = bin.unpack(">SS", data, pos)
+ -- Each address is made up of 4 128 byte fields, this function
+ -- parses these fields and return the response, if it
+ -- understands it. Otherwise it simply increases the pos by the
+ -- correct offset, to get us to the next field.
+ local function parseField(data, pos)
+ local offset = pos
+ local family, port
+ pos, family, port = bin.unpack(">SS", data, pos)
- if ( family == 0x0017 ) then
- -- not sure why...
- pos = pos + 4
+ if ( family == 0x0017 ) then
+ -- not sure why...
+ pos = pos + 4
- local ipv6
- pos, ipv6 = bin.unpack("B16", data, pos)
- return offset + 128, ipOps.bin_to_ip(ipv6)
- elseif ( family == 0x0002 ) then
- local ipv4
- pos, ipv4 = bin.unpack("B4", data, pos)
- return offset + 128, ipOps.bin_to_ip(ipv4)
- end
+ local ipv6
+ pos, ipv6 = bin.unpack("B16", data, pos)
+ return offset + 128, ipOps.bin_to_ip(ipv6)
+ elseif ( family == 0x0002 ) then
+ local ipv4
+ pos, ipv4 = bin.unpack("B4", data, pos)
+ return offset + 128, ipOps.bin_to_ip(ipv4)
+ end
- return offset + 128, nil
- end
+ return offset + 128, nil
+ end
- -- Parses one of X addresses returned for an interface
- local function parseAddress(data, pos)
- local fields = {"ip", "netmask", "bcast", "p2p"}
- local addr = {}
+ -- Parses one of X addresses returned for an interface
+ local function parseAddress(data, pos)
+ local fields = {"ip", "netmask", "bcast", "p2p"}
+ local addr = {}
- for _, f in ipairs(fields) do
- pos, addr[f] = parseField(data, pos)
- end
+ for _, f in ipairs(fields) do
+ pos, addr[f] = parseField(data, pos)
+ end
- return pos, addr
- end
+ return pos, addr
+ end
- local resp = RPCAP.Response.FindAllInterfaces:new()
- local pos = RPCAP.Header.size + 1
- resp.header = RPCAP.Header.parse(data)
- resp.ifaces = {}
+ local resp = RPCAP.Response.FindAllInterfaces:new()
+ local pos = RPCAP.Header.size + 1
+ resp.header = RPCAP.Header.parse(data)
+ resp.ifaces = {}
- for i=1, resp.header.value do
- local name_len, desc_len, iface_flags, addr_count, dummy
- pos, name_len, desc_len, iface_flags, addr_count, dummy = bin.unpack(">SSISS", data, pos)
+ for i=1, resp.header.value do
+ local name_len, desc_len, iface_flags, addr_count, dummy
+ pos, name_len, desc_len, iface_flags, addr_count, dummy = bin.unpack(">SSISS", data, pos)
- local name, desc
- pos, name, desc = bin.unpack("A" .. name_len .. "A" .. desc_len, data, pos)
+ local name, desc
+ pos, name, desc = bin.unpack("A" .. name_len .. "A" .. desc_len, data, pos)
- local addrs = {}
- for j=1, addr_count do
- local addr
- pos, addr = parseAddress(data, pos)
- local cidr
- if ( addr.netmask ) then
- local bits = ipOps.ip_to_bin(addr.netmask)
- local ones = bits:match("^(1*)")
- cidr = #ones
- table.insert(addrs, ("%s/%d"):format(addr.ip,cidr))
- else
- table.insert(addrs, addr.ip)
- end
- end
- table.insert(resp.ifaces, { name = name, desc = desc, addrs = addrs })
- end
- return resp
- end,
- }
+ local addrs = {}
+ for j=1, addr_count do
+ local addr
+ pos, addr = parseAddress(data, pos)
+ local cidr
+ if ( addr.netmask ) then
+ local bits = ipOps.ip_to_bin(addr.netmask)
+ local ones = bits:match("^(1*)")
+ cidr = #ones
+ table.insert(addrs, ("%s/%d"):format(addr.ip,cidr))
+ else
+ table.insert(addrs, addr.ip)
+ end
+ end
+ table.insert(resp.ifaces, { name = name, desc = desc, addrs = addrs })
+ end
+ return resp
+ end,
+ }
- }
+ }
}
-- Maps packet types to classes
RPCAP.TypeToClass = {
- [1] = RPCAP.Response.Error,
- [130] = RPCAP.Response.FindAllInterfaces,
- [136] = RPCAP.Response.Authentication,
+ [1] = RPCAP.Response.Error,
+ [130] = RPCAP.Response.FindAllInterfaces,
+ [136] = RPCAP.Response.Authentication,
}
-- The communication class
Comm = {
- -- Creates a new instance of the Comm class
- -- @param host table
- -- @param port table
- -- @return o instance of Comm
- new = function(self, host, port)
- local o = { host = host, port = port, socket = nmap.new_socket() }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new instance of the Comm class
+ -- @param host table
+ -- @param port table
+ -- @return o instance of Comm
+ new = function(self, host, port)
+ local o = { host = host, port = port, socket = nmap.new_socket() }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Connects the socket to the server
- connect = function(self)
- return self.socket:connect(self.host, self.port)
- end,
+ -- Connects the socket to the server
+ connect = function(self)
+ return self.socket:connect(self.host, self.port)
+ end,
- -- Sends an instance of the request class to the server
- -- @param req class instance
- -- @return status true on success, false on failure
- -- @return err string containing error message if status is false
- send = function(self, req)
- return self.socket:send(req)
- end,
+ -- Sends an instance of the request class to the server
+ -- @param req class instance
+ -- @return status true on success, false on failure
+ -- @return err string containing error message if status is false
+ send = function(self, req)
+ return self.socket:send(req)
+ end,
- -- receives a packet and attempts to parse it if it has a supported parser
- -- in RPCAP.TypeToClass
- -- @return status true on success, false on failure
- -- @return resp instance of a Response class or
- -- err string containing the error message
- recv = function(self)
- local status, hdr_data = self.socket:receive_buf(match.numbytes(RPCAP.Header.size), true)
- if ( not(status) ) then
- return status, hdr_data
- end
+ -- receives a packet and attempts to parse it if it has a supported parser
+ -- in RPCAP.TypeToClass
+ -- @return status true on success, false on failure
+ -- @return resp instance of a Response class or
+ -- err string containing the error message
+ recv = function(self)
+ local status, hdr_data = self.socket:receive_buf(match.numbytes(RPCAP.Header.size), true)
+ if ( not(status) ) then
+ return status, hdr_data
+ end
- local header = RPCAP.Header.parse(hdr_data)
- if ( not(header) ) then
- return false, "rpcap: Failed to parse header"
- end
+ local header = RPCAP.Header.parse(hdr_data)
+ if ( not(header) ) then
+ return false, "rpcap: Failed to parse header"
+ end
- local status, data = self.socket:receive_buf(match.numbytes(header.length), true)
- if ( not(status) ) then
- return false, "rpcap: Failed to read packet data"
- end
+ local status, data = self.socket:receive_buf(match.numbytes(header.length), true)
+ if ( not(status) ) then
+ return false, "rpcap: Failed to read packet data"
+ end
- if ( RPCAP.TypeToClass[header.type] ) then
- local resp = RPCAP.TypeToClass[header.type].parse(hdr_data .. data)
- if ( resp ) then
- return true, resp
- end
- end
+ if ( RPCAP.TypeToClass[header.type] ) then
+ local resp = RPCAP.TypeToClass[header.type].parse(hdr_data .. data)
+ if ( resp ) then
+ return true, resp
+ end
+ end
- return false, "Failed to receive response from server"
- end,
+ return false, "Failed to receive response from server"
+ end,
- -- Sends and request and receives the response
- -- @param req the instance of the Request class to send
- -- @return status true on success, false on failure
- -- @return resp instance of a Response class or
- -- err string containing the error message
- exch = function(self, req)
- local status, data = self:send(tostring(req))
- if ( not(status) ) then
- return status, data
- end
- return self:recv()
- end,
+ -- Sends and request and receives the response
+ -- @param req the instance of the Request class to send
+ -- @return status true on success, false on failure
+ -- @return resp instance of a Response class or
+ -- err string containing the error message
+ exch = function(self, req)
+ local status, data = self:send(tostring(req))
+ if ( not(status) ) then
+ return status, data
+ end
+ return self:recv()
+ end,
- -- closes the socket
- close = function(self)
- return self.socket:close()
- end,
+ -- closes the socket
+ close = function(self)
+ return self.socket:close()
+ end,
}
Helper = {
- -- Creates a new instance of the Helper class
- -- @param host table
- -- @param port table
- -- @return o instance of Helper
- new = function(self, host, port)
- local o = {
- host = host,
- port = port,
- comm = Comm:new(host, port)
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new instance of the Helper class
+ -- @param host table
+ -- @param port table
+ -- @return o instance of Helper
+ new = function(self, host, port)
+ local o = {
+ host = host,
+ port = port,
+ comm = Comm:new(host, port)
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Connects to the server
- connect = function(self)
- return self.comm:connect(self.host, self.port)
- end,
+ -- Connects to the server
+ connect = function(self)
+ return self.comm:connect(self.host, self.port)
+ end,
- -- Authenticates to the service, in case no username or password is given
- -- NULL authentication is assumed.
- -- @param username [optional]
- -- @param password [optional]
- -- @return status true on success, false on failure
- -- @return err string containing error mesage on failure
- login = function(self, username, password)
- local auth
+ -- Authenticates to the service, in case no username or password is given
+ -- NULL authentication is assumed.
+ -- @param username [optional]
+ -- @param password [optional]
+ -- @return status true on success, false on failure
+ -- @return err string containing error mesage on failure
+ login = function(self, username, password)
+ local auth
- if ( username and password ) then
- auth = RPCAP.Authentication.PWD:new(username, password)
- else
- auth = RPCAP.Authentication.NULL:new()
- end
+ if ( username and password ) then
+ auth = RPCAP.Authentication.PWD:new(username, password)
+ else
+ auth = RPCAP.Authentication.NULL:new()
+ end
- local req = RPCAP.Request.Authentication:new(tostring(auth))
- local status, resp = self.comm:exch(req)
+ local req = RPCAP.Request.Authentication:new(tostring(auth))
+ local status, resp = self.comm:exch(req)
- if ( not(status) ) then
- return false, resp
- end
+ if ( not(status) ) then
+ return false, resp
+ end
- if ( status and resp.error ) then
- return false, resp.error
- end
- return true
- end,
+ if ( status and resp.error ) then
+ return false, resp.error
+ end
+ return true
+ end,
- -- Requests a list of all interfaces
- -- @return table containing interfaces and addresses
- findAllInterfaces = function(self)
- local req = RPCAP.Request.FindAllInterfaces:new()
- local status, resp = self.comm:exch(req)
+ -- Requests a list of all interfaces
+ -- @return table containing interfaces and addresses
+ findAllInterfaces = function(self)
+ local req = RPCAP.Request.FindAllInterfaces:new()
+ local status, resp = self.comm:exch(req)
- if ( not(status) ) then
- return false, resp
- end
+ if ( not(status) ) then
+ return false, resp
+ end
- local results = {}
- for _, iface in ipairs(resp.ifaces) do
- local entry = {}
- entry.name = iface.name
- table.insert(entry, iface.desc)
- table.insert(entry, { name = "Addresses", iface.addrs })
- table.insert(results, entry)
- end
- return true, results
- end,
+ local results = {}
+ for _, iface in ipairs(resp.ifaces) do
+ local entry = {}
+ entry.name = iface.name
+ table.insert(entry, iface.desc)
+ table.insert(entry, { name = "Addresses", iface.addrs })
+ table.insert(results, entry)
+ end
+ return true, results
+ end,
- -- Closes the connection to the server
- close = function(self)
- return self.comm:close()
- end,
+ -- Closes the connection to the server
+ close = function(self)
+ return self.comm:close()
+ end,
}
return _ENV;
diff --git a/nselib/rsync.lua b/nselib/rsync.lua
index c3141893c..4ef87a93d 100644
--- a/nselib/rsync.lua
+++ b/nselib/rsync.lua
@@ -16,159 +16,159 @@ _ENV = stdnse.module("rsync", stdnse.seeall)
-- The Helper class serves as the main interface for script writers
Helper = {
- -- Creates a new instance of the Helper class
- -- @param host table as received by the action function
- -- @param port table as received by the action function
- -- @param options table containing any additional options
- -- @return o instance of Helper
- new = function(self, host, port, options)
- local o = { host = host, port = port, options = options or {} }
- assert(o.options.module, "No rsync module was specified, aborting ...")
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new instance of the Helper class
+ -- @param host table as received by the action function
+ -- @param port table as received by the action function
+ -- @param options table containing any additional options
+ -- @return o instance of Helper
+ new = function(self, host, port, options)
+ local o = { host = host, port = port, options = options or {} }
+ assert(o.options.module, "No rsync module was specified, aborting ...")
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Handles send and receive of control messages
- -- @param data string containing the command to send
- -- @return status true on succes, false on failure
- -- @return data containing the response from the server
- -- err string, if status is false
- ctrl_exch = function(self, data)
- local status, err = self.socket:send(data.."\n")
- if ( not(status) ) then
- return false, err
- end
- local status, data = self.socket:receive_buf("\n", false)
- if( not(status) ) then
- return false, err
- end
- return true, data
- end,
+ -- Handles send and receive of control messages
+ -- @param data string containing the command to send
+ -- @return status true on succes, false on failure
+ -- @return data containing the response from the server
+ -- err string, if status is false
+ ctrl_exch = function(self, data)
+ local status, err = self.socket:send(data.."\n")
+ if ( not(status) ) then
+ return false, err
+ end
+ local status, data = self.socket:receive_buf("\n", false)
+ if( not(status) ) then
+ return false, err
+ end
+ return true, data
+ end,
- -- Connects to the rsync server
- -- @return status, true on success, false on failure
- -- @return err string containing an error message if status is false
- connect = function(self)
- self.socket = nmap.new_socket()
- self.socket:set_timeout(self.options.timeout or 5000)
- local status, err = self.socket:connect(self.host, self.port)
- if ( not(status) ) then
- return false, err
- end
+ -- Connects to the rsync server
+ -- @return status, true on success, false on failure
+ -- @return err string containing an error message if status is false
+ connect = function(self)
+ self.socket = nmap.new_socket()
+ self.socket:set_timeout(self.options.timeout or 5000)
+ local status, err = self.socket:connect(self.host, self.port)
+ if ( not(status) ) then
+ return false, err
+ end
- local data
- status, data = self:ctrl_exch("@RSYNCD: 29")
- if ( not(status) ) then
- return false, data
- end
- if ( not(data:match("^@RSYNCD: [%.%d]+$")) ) then
- return false, "Protocol error"
- end
- return true
- end,
+ local data
+ status, data = self:ctrl_exch("@RSYNCD: 29")
+ if ( not(status) ) then
+ return false, data
+ end
+ if ( not(data:match("^@RSYNCD: [%.%d]+$")) ) then
+ return false, "Protocol error"
+ end
+ return true
+ end,
- -- Authenticates against the rsync module. If no username is given, assume
- -- no authentication is required.
- -- @param username [optional] string containing the username
- -- @param password [optional] string containing the password
- login = function(self, username, password)
- password = password or ""
- local status, data = self:ctrl_exch(self.options.module)
- if (not(status)) then
- return false, data
- end
+ -- Authenticates against the rsync module. If no username is given, assume
+ -- no authentication is required.
+ -- @param username [optional] string containing the username
+ -- @param password [optional] string containing the password
+ login = function(self, username, password)
+ password = password or ""
+ local status, data = self:ctrl_exch(self.options.module)
+ if (not(status)) then
+ return false, data
+ end
- local chall
- if ( data:match("@RSYNCD: OK") ) then
- return true, "No authentication was required"
- else
- chall = data:match("^@RSYNCD: AUTHREQD (.*)$")
- if ( not(chall) and data:match("^@ERROR: Unknown module") ) then
- return false, data:match("^@ERROR: (.*)$")
- elseif ( not(chall) ) then
- return false, "Failed to retrieve challenge"
- end
- end
+ local chall
+ if ( data:match("@RSYNCD: OK") ) then
+ return true, "No authentication was required"
+ else
+ chall = data:match("^@RSYNCD: AUTHREQD (.*)$")
+ if ( not(chall) and data:match("^@ERROR: Unknown module") ) then
+ return false, data:match("^@ERROR: (.*)$")
+ elseif ( not(chall) ) then
+ return false, "Failed to retrieve challenge"
+ end
+ end
- if ( chall and not(username) ) then
- return false, "Authentication required"
- end
+ if ( chall and not(username) ) then
+ return false, "Authentication required"
+ end
- local md4 = openssl.md4("\0\0\0\0" .. password .. chall)
- local resp = base64.enc(md4):sub(1,-3)
- status, data = self:ctrl_exch(username .. " " .. resp)
- if (not(status)) then
- return false, data
- end
+ local md4 = openssl.md4("\0\0\0\0" .. password .. chall)
+ local resp = base64.enc(md4):sub(1,-3)
+ status, data = self:ctrl_exch(username .. " " .. resp)
+ if (not(status)) then
+ return false, data
+ end
- if ( data == "@RSYNCD: OK" ) then
- return true, "Authentication successfull"
- end
- return false, "Authentication failed"
- end,
+ if ( data == "@RSYNCD: OK" ) then
+ return true, "Authentication successfull"
+ end
+ return false, "Authentication failed"
+ end,
- -- Lists accessible modules from the rsync server
- -- @return status true on success, false on failure
- -- @return modules table containing a list of modules
- listModules = function(self)
- local status, data = self.socket:send("\n")
- if (not(status)) then
- return false, data
- end
+ -- Lists accessible modules from the rsync server
+ -- @return status true on success, false on failure
+ -- @return modules table containing a list of modules
+ listModules = function(self)
+ local status, data = self.socket:send("\n")
+ if (not(status)) then
+ return false, data
+ end
- local modules = {}
- while(true) do
- status, data = self.socket:receive_buf("\n", false)
- if (not(status)) then
- return false, data
- end
- if ( data == "@RSYNCD: EXIT" ) then
- break
- else
- table.insert(modules, data)
- end
- end
- return true, modules
- end,
+ local modules = {}
+ while(true) do
+ status, data = self.socket:receive_buf("\n", false)
+ if (not(status)) then
+ return false, data
+ end
+ if ( data == "@RSYNCD: EXIT" ) then
+ break
+ else
+ table.insert(modules, data)
+ end
+ end
+ return true, modules
+ end,
- -- Lists the files available for the directory/module
- -- TODO: Add support for parsing results, seemed straight forward at
- -- first, but wasn't.
- listFiles = function(self)
- -- list recursively and enable MD4 checksums
- local data = ("--server\n--sender\n-rc\n.\n%s\n\n"):format(self.options.module)
- local status, data = self.socket:send(data)
- if ( not(status) ) then
- return false, data
- end
- status, data = self.socket:receive_bytes(4)
- if ( not(status) ) then
- return false, data
- end
+ -- Lists the files available for the directory/module
+ -- TODO: Add support for parsing results, seemed straight forward at
+ -- first, but wasn't.
+ listFiles = function(self)
+ -- list recursively and enable MD4 checksums
+ local data = ("--server\n--sender\n-rc\n.\n%s\n\n"):format(self.options.module)
+ local status, data = self.socket:send(data)
+ if ( not(status) ) then
+ return false, data
+ end
+ status, data = self.socket:receive_bytes(4)
+ if ( not(status) ) then
+ return false, data
+ end
- status, data = self.socket:send("\0\0\0\0")
- if ( not(status) ) then
- return false, data
- end
+ status, data = self.socket:send("\0\0\0\0")
+ if ( not(status) ) then
+ return false, data
+ end
- status, data = self.socket:receive_buf(match.numbytes(4), false)
- if ( not(status) ) then
- return false, data
- end
+ status, data = self.socket:receive_buf(match.numbytes(4), false)
+ if ( not(status) ) then
+ return false, data
+ end
- local pos, len = bin.unpack(" 0 ) then
- req = req .. stdnse.strjoin("\r\n", self.headers) .. "\r\n"
- end
+ local req = stdnse.strjoin("\r\n", {
+ ("%s %s RTSP/1.0"):format(self.method, self.url),
+ ("CSeq: %d"):format(self.cseq)
+ } ) .. "\r\n"
+ if ( #self.headers > 0 ) then
+ req = req .. stdnse.strjoin("\r\n", self.headers) .. "\r\n"
+ end
- return req .. "\r\n"
- end,
+ return req .. "\r\n"
+ end,
}
-- The RTSP response instance
Response = {
- --- Creates a new Response instance
- -- @param data string containing the unparsed data
- new = function(self, data)
- assert(data, "No data was supplied")
- local o = {
- raw = data,
- status = tonumber(data:match("^RTSP%/1%.0 (%d*) "))
- }
+ --- Creates a new Response instance
+ -- @param data string containing the unparsed data
+ new = function(self, data)
+ assert(data, "No data was supplied")
+ local o = {
+ raw = data,
+ status = tonumber(data:match("^RTSP%/1%.0 (%d*) "))
+ }
- -- Split the response into a temporary array
- local tmp = stdnse.strsplit("\r\n", data)
- if ( not(tmp) ) then return nil end
+ -- Split the response into a temporary array
+ local tmp = stdnse.strsplit("\r\n", data)
+ if ( not(tmp) ) then return nil end
- -- we should have atleas one entry
- if ( #tmp > 1 ) then
- o.headers = {}
- for i=2, #tmp do
- -- if we have an empty line, this should be the end of headers
- if ( #tmp[i] == 0 ) then break end
- local key, val = tmp[i]:match("^(.-): (.*)$")
- -- create a key per header name
- o.headers[key] = val
- end
- end
+ -- we should have atleas one entry
+ if ( #tmp > 1 ) then
+ o.headers = {}
+ for i=2, #tmp do
+ -- if we have an empty line, this should be the end of headers
+ if ( #tmp[i] == 0 ) then break end
+ local key, val = tmp[i]:match("^(.-): (.*)$")
+ -- create a key per header name
+ o.headers[key] = val
+ end
+ end
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
}
@@ -128,163 +128,163 @@ Response = {
-- RTSP Client class
Client = {
- -- Creates a new Client instance
- -- @param host table as received by the action method
- -- @param port table as received by the action method
- -- @return o instance of Client
- new = function(self, host, port)
- local o = {
- host = host,
- port = port,
- cseq = 0,
- headers = { },
- retries = 3,
- timeout = 10 * 1000,
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new Client instance
+ -- @param host table as received by the action method
+ -- @param port table as received by the action method
+ -- @return o instance of Client
+ new = function(self, host, port)
+ local o = {
+ host = host,
+ port = port,
+ cseq = 0,
+ headers = { },
+ retries = 3,
+ timeout = 10 * 1000,
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- --- Sets the number of retries for socket reads
- -- @param retries number containing the number of retries
- setRetries = function(self, retries) self.retries = retries end,
+ --- Sets the number of retries for socket reads
+ -- @param retries number containing the number of retries
+ setRetries = function(self, retries) self.retries = retries end,
- --- Sets the socket connection timeout in ms
- -- @param timeout number containing the timeout in ms
- setTimeout = function(self, timeout) self.timeout = timeout end,
+ --- Sets the socket connection timeout in ms
+ -- @param timeout number containing the timeout in ms
+ setTimeout = function(self, timeout) self.timeout = timeout end,
- --- Adds a RTSP header to the request
- -- @param header string containing the header name
- -- @param value string containing the header value
- addHeader = function(self, header, value)
- table.insert(self.headers, { ("%s: %s"):format(header,value) } )
- end,
+ --- Adds a RTSP header to the request
+ -- @param header string containing the header name
+ -- @param value string containing the header value
+ addHeader = function(self, header, value)
+ table.insert(self.headers, { ("%s: %s"):format(header,value) } )
+ end,
- --- Connects to the RTSP server
- -- @return status true on success, false on failure
- -- @return err string containing the error message on failure
- connect = function(self)
- self.socket = nmap.new_socket()
- self.socket:set_timeout(self.timeout)
- local status = self.socket:connect(self.host, self.port)
- if ( not(status) ) then
- stdnse.print_debug(2, "Failed to connect to the server: %s", self.host.ip)
- return false, ("Failed to connect to the server: %s"):format(self.host.ip)
- end
- return true
- end,
+ --- Connects to the RTSP server
+ -- @return status true on success, false on failure
+ -- @return err string containing the error message on failure
+ connect = function(self)
+ self.socket = nmap.new_socket()
+ self.socket:set_timeout(self.timeout)
+ local status = self.socket:connect(self.host, self.port)
+ if ( not(status) ) then
+ stdnse.print_debug(2, "Failed to connect to the server: %s", self.host.ip)
+ return false, ("Failed to connect to the server: %s"):format(self.host.ip)
+ end
+ return true
+ end,
- --- Sends a DESCRIBE request to the server and receives the response
- -- @param url string containing the RTSP URL
- -- @return status true on success, false on failure
- -- @return response Response instance on success
- -- err string containing the error message on failure
- describe = function(self, url)
- local req = Request:new(url, self.headers)
- req:setMethod("DESCRIBE")
- return self:exch(req)
- end,
+ --- Sends a DESCRIBE request to the server and receives the response
+ -- @param url string containing the RTSP URL
+ -- @return status true on success, false on failure
+ -- @return response Response instance on success
+ -- err string containing the error message on failure
+ describe = function(self, url)
+ local req = Request:new(url, self.headers)
+ req:setMethod("DESCRIBE")
+ return self:exch(req)
+ end,
- options = function(self, url)
- local req = Request:new(url, self.headers)
- req:setMethod("OPTIONS")
- return self:exch(req)
- end,
+ options = function(self, url)
+ local req = Request:new(url, self.headers)
+ req:setMethod("OPTIONS")
+ return self:exch(req)
+ end,
- --- Sends a request to the server and receives the response and attempts
- -- to retry if either send or receive fails.
- -- @param request instance of Request
- -- @return status true on success, false on failure
- -- @return response Response instance on success
- -- err string containing the error message on failure
- exch = function(self, req)
- local retries = self.retries
- local status, data
- self.cseq = self.cseq + 1
- req:setCSeq( self.cseq )
+ --- Sends a request to the server and receives the response and attempts
+ -- to retry if either send or receive fails.
+ -- @param request instance of Request
+ -- @return status true on success, false on failure
+ -- @return response Response instance on success
+ -- err string containing the error message on failure
+ exch = function(self, req)
+ local retries = self.retries
+ local status, data
+ self.cseq = self.cseq + 1
+ req:setCSeq( self.cseq )
- repeat
- local err
- status, err = self.socket:send( tostring(req) )
- -- check if send was successfull, in case it wasn't AND
- -- this is our last retry, ABORT
- if ( not(status) and 0 == retries - 1 ) then
- stdnse.print_debug(2, "Failed to send request to server (%s)", err)
- return false, ("Failed to send request to server (%s)"):format(err)
- -- if send was successfull, attempt to receive the response
- elseif ( status ) then
- status, data = self.socket:receive()
- -- if we got the response allright, break out of retry loop
- if ( status ) then break end
- end
- -- if either send or receive fails, re-connect the socket
- if ( not(status) ) then
- self:close()
- local status, err = self:connect()
- -- if re-connect fails, BAIL out of here
- if ( not(status) ) then
- stdnse.print_debug(2, "Failed to reconnect socket to server (%s)", err)
- return false, ("Failed to reconnect socket to server (%s)"):format(err)
- end
- end
- retries = retries - 1
- until( status or retries == 0 )
+ repeat
+ local err
+ status, err = self.socket:send( tostring(req) )
+ -- check if send was successfull, in case it wasn't AND
+ -- this is our last retry, ABORT
+ if ( not(status) and 0 == retries - 1 ) then
+ stdnse.print_debug(2, "Failed to send request to server (%s)", err)
+ return false, ("Failed to send request to server (%s)"):format(err)
+ -- if send was successfull, attempt to receive the response
+ elseif ( status ) then
+ status, data = self.socket:receive()
+ -- if we got the response allright, break out of retry loop
+ if ( status ) then break end
+ end
+ -- if either send or receive fails, re-connect the socket
+ if ( not(status) ) then
+ self:close()
+ local status, err = self:connect()
+ -- if re-connect fails, BAIL out of here
+ if ( not(status) ) then
+ stdnse.print_debug(2, "Failed to reconnect socket to server (%s)", err)
+ return false, ("Failed to reconnect socket to server (%s)"):format(err)
+ end
+ end
+ retries = retries - 1
+ until( status or retries == 0 )
- if( not(status) ) then
- stdnse.print_debug(2, "Failed to receive response from server (%s)", data)
- return false, ("Failed to receive response from server (%s)"):format(data)
- end
+ if( not(status) ) then
+ stdnse.print_debug(2, "Failed to receive response from server (%s)", data)
+ return false, ("Failed to receive response from server (%s)"):format(data)
+ end
- return true, Response:new(data)
- end,
+ return true, Response:new(data)
+ end,
- --- Closes the RTSP socket with the server
- close = function(self)
- return self.socket:close()
- end,
+ --- Closes the RTSP socket with the server
+ close = function(self)
+ return self.socket:close()
+ end,
}
-- The Helper class is the main script interface
Helper = {
- -- Creates a new Helper instance
- -- @param host table as received by the action method
- -- @param port table as received by the action method
- -- @return o instance of Client
- new = function(self, host, port)
- local o = { host = host, port = port, client = Client:new(host, port) }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new Helper instance
+ -- @param host table as received by the action method
+ -- @param port table as received by the action method
+ -- @return o instance of Client
+ new = function(self, host, port)
+ local o = { host = host, port = port, client = Client:new(host, port) }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Connects to the RTSP server
- -- @return status true on success, false on failure
- -- @return err string containing the error message on failure
- connect = function(self)
- return self.client:connect()
- end,
+ -- Connects to the RTSP server
+ -- @return status true on success, false on failure
+ -- @return err string containing the error message on failure
+ connect = function(self)
+ return self.client:connect()
+ end,
- -- Closes the RTSP socket with the server
- close = function(self)
- return self.client:close()
- end,
+ -- Closes the RTSP socket with the server
+ close = function(self)
+ return self.client:close()
+ end,
- -- Sends a DESCRIBE request to the server and receives the response
- --
- -- @param url string containing the RTSP URL
- -- @return status true on success, false on failure
- -- @return response string containing the unparsed RTSP response on success
- -- err string containing the error message on failure
- describe = function(self, url)
- return self.client:describe(url)
- end,
+ -- Sends a DESCRIBE request to the server and receives the response
+ --
+ -- @param url string containing the RTSP URL
+ -- @return status true on success, false on failure
+ -- @return response string containing the unparsed RTSP response on success
+ -- err string containing the error message on failure
+ describe = function(self, url)
+ return self.client:describe(url)
+ end,
- options = function(self, url)
- return self.client:options(url)
- end,
+ options = function(self, url)
+ return self.client:options(url)
+ end,
}
diff --git a/nselib/sasl.lua b/nselib/sasl.lua
index e81783a02..7c94aafb5 100644
--- a/nselib/sasl.lua
+++ b/nselib/sasl.lua
@@ -8,8 +8,8 @@
-- necessary arguments (@see DigestMD5.new).
-- It can be called throught the SASL helper or directly like this:
--
--- local dmd5 = DigestMD5:new(chall, user, pass, "AUTHENTICATE", nil, "imap")
--- local digest = dmd5:calcDigest()
+-- local dmd5 = DigestMD5:new(chall, user, pass, "AUTHENTICATE", nil, "imap")
+-- local digest = dmd5:calcDigest()
--
--
-- The NTLM class contains all code necessary to calculate a
@@ -17,8 +17,8 @@
-- arguments (@see NTLM.new). It can be called through the SASL helper or
-- directly like this:
--
--- local ntlm = NTLM:new(chall, user, pass)
--- local response = ntlm:calcResponse()
+-- local ntlm = NTLM:new(chall, user, pass)
+-- local response = ntlm:calcResponse()
--
--
-- The Helper class contains the high level methodes:
@@ -37,8 +37,8 @@
-- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html
-- Version 0.2
--- Created 07/17/2011 - v0.1 - Created by Djalal Harouini
--- Revised 07/18/2011 - v0.2 - Added NTLM, DIGEST-MD5 classes
+-- Created 07/17/2011 - v0.1 - Created by Djalal Harouini
+-- Revised 07/18/2011 - v0.2 - Added NTLM, DIGEST-MD5 classes
local bin = require "bin"
@@ -50,8 +50,8 @@ _ENV = stdnse.module("sasl", stdnse.seeall)
local HAVE_SSL, openssl = pcall(require, 'openssl')
if ( not(HAVE_SSL) ) then
- stdnse.print_debug(1,
- "sasl.lua: OpenSSL not present, SASL support limited.")
+ stdnse.print_debug(1,
+ "sasl.lua: OpenSSL not present, SASL support limited.")
end
local MECHANISMS = { }
@@ -59,22 +59,22 @@ if HAVE_SSL then
-- Calculates a DIGEST MD5 response
DigestMD5 = {
- --- Instantiates DigestMD5
- --
- -- @param chall string containing the base64 decoded challenge
- -- @return a new instance of DigestMD5
+ --- Instantiates DigestMD5
+ --
+ -- @param chall string containing the base64 decoded challenge
+ -- @return a new instance of DigestMD5
new = function(self, chall, username, password, method, uri, service, realm)
local o = { nc = 0,
- chall = chall,
- challnvs = {},
- username = username,
- password = password,
- method = method,
- uri = uri,
- service = service,
- realm = realm }
- setmetatable(o, self)
- self.__index = self
+ chall = chall,
+ challnvs = {},
+ username = username,
+ password = password,
+ method = method,
+ uri = uri,
+ service = service,
+ realm = realm }
+ setmetatable(o, self)
+ self.__index = self
o:parseChallenge()
return o
end,
@@ -121,8 +121,8 @@ if HAVE_SSL then
local A1 = stdnse.tohex(openssl.md5(A1_part1 .. ":" .. self.challnvs.nonce .. ':' .. cnonce))
local A2 = stdnse.tohex(openssl.md5(("%s:%s"):format(self.method, uri)))
local digest = stdnse.tohex(openssl.md5(A1 .. ":" .. self.challnvs.nonce .. ":" ..
- ("%08d"):format(self.nc) .. ":" .. cnonce .. ":" ..
- qop .. ":" .. A2))
+ ("%08d"):format(self.nc) .. ":" .. cnonce .. ":" ..
+ qop .. ":" .. A2))
local b1
if not self.challnvs.algorithm or self.challnvs.algorithm == "MD5" then
@@ -136,7 +136,7 @@ if HAVE_SSL then
local digest_http
if not qop_not_specified then
digest_http = stdnse.tohex(openssl.md5(b1 .. ":" .. self.challnvs.nonce .. ":" ..
- ("%08d"):format(self.nc) .. ":" .. cnonce .. ":" .. qop .. ":" .. A2))
+ ("%08d"):format(self.nc) .. ":" .. cnonce .. ":" .. qop .. ":" .. A2))
else
digest_http = stdnse.tohex(openssl.md5(b1 .. ":" .. self.challnvs.nonce .. ":" .. A2))
end
@@ -170,113 +170,113 @@ if HAVE_SSL then
}
- -- The NTLM class handling NTLM challenge response authentication
- NTLM = {
+ -- The NTLM class handling NTLM challenge response authentication
+ NTLM = {
- --- Creates a new instance of the NTLM class
- --
- -- @param chall string containing the challenge received from the server
- -- @param username string containing the username
- -- @param password string containing the password
- -- @return new instance of NTML
- new = function(self, chall, username, password)
- local o = { nc = 0,
- chall = chall,
- username = username,
- password = password}
- setmetatable(o, self)
- self.__index = self
- o:parseChallenge()
- return o
- end,
+ --- Creates a new instance of the NTLM class
+ --
+ -- @param chall string containing the challenge received from the server
+ -- @param username string containing the username
+ -- @param password string containing the password
+ -- @return new instance of NTML
+ new = function(self, chall, username, password)
+ local o = { nc = 0,
+ chall = chall,
+ username = username,
+ password = password}
+ setmetatable(o, self)
+ self.__index = self
+ o:parseChallenge()
+ return o
+ end,
- --- Converst str to "unicode" (adds null bytes for every other byte)
- -- @param str containing string to convert
- -- @return unicode string containing the unicoded str
- to_unicode = function(str)
- local unicode = ""
- for i = 1, #str, 1 do
- unicode = unicode .. bin.pack("CRAM-MD5 mechanism.
--
@@ -287,8 +287,8 @@ if HAVE_SSL then
-- compiled without OpenSSL.
function cram_md5_enc(username, password, challenge)
local encode = stdnse.tohex(openssl.hmac('md5',
- password,
- challenge))
+ password,
+ challenge))
return username.." "..encode
end
@@ -303,16 +303,16 @@ if HAVE_SSL then
-- @return string The encoded string on success, or nil if Nmap was
-- compiled without OpenSSL.
function digest_md5_enc(username, password, challenge, service, uri)
- return DigestMD5:new(challenge,
- username,
- password,
- "AUTHENTICATE",
- uri,
- service):calcDigest()
+ return DigestMD5:new(challenge,
+ username,
+ password,
+ "AUTHENTICATE",
+ uri,
+ service):calcDigest()
end
function ntlm_enc(username, password, challenge)
- return NTLM:new(challenge, username, password):calcResponse()
+ return NTLM:new(challenge, username, password):calcResponse()
end
else
diff --git a/nselib/shortport.lua b/nselib/shortport.lua
index a7b74ca1b..f6a23f7f7 100644
--- a/nselib/shortport.lua
+++ b/nselib/shortport.lua
@@ -16,12 +16,12 @@ _ENV = stdnse.module("shortport", stdnse.seeall)
-- @param value The value to check for.
-- @return True if t contains value, false otherwise.
local function includes(t, value)
- for _, elem in ipairs(t) do
- if elem == value then
- return true
- end
- end
- return false
+ for _, elem in ipairs(t) do
+ if elem == value then
+ return true
+ end
+ end
+ return false
end
--- Check if the port and it's protocol are in the exclude directive.
@@ -31,8 +31,8 @@ end
-- @return True if the port and protocol are
-- in the exclude directive.
port_is_excluded = function(port, proto)
- proto = proto or "tcp"
- return nmap.port_is_excluded(port, proto)
+ proto = proto or "tcp"
+ return nmap.port_is_excluded(port, proto)
end
--- Return a portrule that returns true when given an open port matching a
@@ -45,24 +45,24 @@ end
-- @return Function for the portrule.
-- @usage portrule = shortport.portnumber({80, 443})
portnumber = function(ports, protos, states)
- protos = protos or "tcp"
- states = states or {"open", "open|filtered"}
+ protos = protos or "tcp"
+ states = states or {"open", "open|filtered"}
- if type(ports) ~= "table" then
- ports = {ports}
- end
- if type(protos) ~= "table" then
- protos = {protos}
- end
- if type(states) ~= "table" then
- states = {states}
- end
+ if type(ports) ~= "table" then
+ ports = {ports}
+ end
+ if type(protos) ~= "table" then
+ protos = {protos}
+ end
+ if type(states) ~= "table" then
+ states = {states}
+ end
- return function(host, port)
- return includes(ports, port.number)
- and includes(protos, port.protocol)
- and includes(states, port.state)
- end
+ return function(host, port)
+ return includes(ports, port.number)
+ and includes(protos, port.protocol)
+ and includes(states, port.state)
+ end
end
--- Return a portrule that returns true when given an open port with a
@@ -82,24 +82,24 @@ end
-- @return Function for the portrule.
-- @usage portrule = shortport.service("ftp")
service = function(services, protos, states)
- protos = protos or "tcp"
- states = states or {"open", "open|filtered"}
+ protos = protos or "tcp"
+ states = states or {"open", "open|filtered"}
- if type(services) ~= "table" then
- services = {services}
- end
- if type(protos) ~= "table" then
- protos = {protos}
- end
- if type(states) ~= "table" then
- states = {states}
- end
+ if type(services) ~= "table" then
+ services = {services}
+ end
+ if type(protos) ~= "table" then
+ protos = {protos}
+ end
+ if type(states) ~= "table" then
+ states = {states}
+ end
- return function(host, port)
- return includes(services, port.service)
- and includes(protos, port.protocol)
- and includes(states, port.state)
- end
+ return function(host, port)
+ return includes(services, port.service)
+ and includes(protos, port.protocol)
+ and includes(states, port.state)
+ end
end
--- Return a portrule that returns true when given an open port matching
@@ -119,11 +119,11 @@ end
-- {"open", "open|filtered"}.
-- @return Function for the portrule.
port_or_service = function(ports, services, protos, states)
- return function(host, port)
- local port_checker = portnumber(ports, protos, states)
- local service_checker = service(services, protos, states)
- return port_checker(host, port) or service_checker(host, port)
- end
+ return function(host, port)
+ local port_checker = portnumber(ports, protos, states)
+ local service_checker = service(services, protos, states)
+ return port_checker(host, port) or service_checker(host, port)
+ end
end
--- Return a portrule that returns true when given an open port matching
@@ -144,24 +144,24 @@ end
-- {"open", "open|filtered"}.
-- @return Function for the portrule.
version_port_or_service = function(ports, services, protos, states)
- return function(host, port)
- local p_s_check = port_or_service(ports, services, protos, states)
- return p_s_check(host, port)
- and not(port_is_excluded(port.number, port.protocol))
- end
+ return function(host, port)
+ local p_s_check = port_or_service(ports, services, protos, states)
+ return p_s_check(host, port)
+ and not(port_is_excluded(port.number, port.protocol))
+ end
end
--[[
- Apache Tomcat HTTP server default ports: 8180 and 8000
- Litespeed webserver default ports: 8088 and 7080
+Apache Tomcat HTTP server default ports: 8180 and 8000
+Litespeed webserver default ports: 8088 and 7080
--]]
LIKELY_HTTP_PORTS = {
- 80, 443, 631, 7080, 8080, 8088, 5800, 3872, 8180, 8000
+ 80, 443, 631, 7080, 8080, 8088, 5800, 3872, 8180, 8000
}
LIKELY_HTTP_SERVICES = {
- "http", "https", "ipp", "http-alt", "vnc-http", "oem-agent", "soap",
- "http-proxy",
+ "http", "https", "ipp", "http-alt", "vnc-http", "oem-agent", "soap",
+ "http-proxy",
}
---
@@ -179,12 +179,12 @@ LIKELY_HTTP_SERVICES = {
http = port_or_service(LIKELY_HTTP_PORTS, LIKELY_HTTP_SERVICES)
local LIKELY_SSL_PORTS = {
- 443, 465, 587, 636, 989, 990, 992, 993, 994, 995, 5061, 6679, 6697, 8443,
- 9001,
+ 443, 465, 587, 636, 989, 990, 992, 993, 994, 995, 5061, 6679, 6697, 8443,
+ 9001,
}
local LIKELY_SSL_SERVICES = {
- "ftps", "ftps-data", "https", "https-alt", "imaps", "ircs",
- "ldapssl", "pop3s", "sip-tls", "smtps", "telnets", "tor-orport",
+ "ftps", "ftps-data", "https", "https-alt", "imaps", "ircs",
+ "ldapssl", "pop3s", "sip-tls", "smtps", "telnets", "tor-orport",
}
---
@@ -197,8 +197,8 @@ local LIKELY_SSL_SERVICES = {
-- @usage
-- portrule = shortport.ssl
function ssl(host, port)
- return port.version.service_tunnel == "ssl" or
- port_or_service(LIKELY_SSL_PORTS, LIKELY_SSL_SERVICES, {"tcp", "sctp"})(host, port)
+ return port.version.service_tunnel == "ssl" or
+ port_or_service(LIKELY_SSL_PORTS, LIKELY_SSL_SERVICES, {"tcp", "sctp"})(host, port)
end
return _ENV;
diff --git a/nselib/snmp.lua b/nselib/snmp.lua
index 1798c0b81..6a69aa9a4 100644
--- a/nselib/snmp.lua
+++ b/nselib/snmp.lua
@@ -20,37 +20,37 @@ local tagEncoder = {}
-- Override the boolean encoder
tagEncoder['boolean'] = function(self, val)
- return bin.pack('H', '05 00')
+ return bin.pack('H', '05 00')
end
-- Complex tag encoders
tagEncoder['table'] = function(self, val)
- if val._snmp == '06' then -- OID
- local oidStr = string.char(val[1]*40 + val[2])
- for i = 3, #val do
- oidStr = oidStr .. self.encode_oid_component(val[i])
- end
- return bin.pack("HAA", '06', self.encodeLength(#oidStr), oidStr)
+ if val._snmp == '06' then -- OID
+ local oidStr = string.char(val[1]*40 + val[2])
+ for i = 3, #val do
+ oidStr = oidStr .. self.encode_oid_component(val[i])
+ end
+ return bin.pack("HAA", '06', self.encodeLength(#oidStr), oidStr)
- elseif (val._snmp == '40') then -- ipAddress
- return bin.pack("HC4", '40 04', table.unpack(val))
+ elseif (val._snmp == '40') then -- ipAddress
+ return bin.pack("HC4", '40 04', table.unpack(val))
-- counter or gauge or timeticks or opaque
- elseif (val._snmp == '41' or val._snmp == '42' or val._snmp == '43' or val._snmp == '44') then
- local val = self:encodeInt(val[1])
- return bin.pack("HAA", val._snmp, self.encodeLength(#val), val)
- end
+ elseif (val._snmp == '41' or val._snmp == '42' or val._snmp == '43' or val._snmp == '44') then
+ local val = self:encodeInt(val[1])
+ return bin.pack("HAA", val._snmp, self.encodeLength(#val), val)
+ end
- local encVal = ""
- for _, v in ipairs(val) do
- encVal = encVal .. self:encode(v) -- todo: buffer?
- end
+ local encVal = ""
+ for _, v in ipairs(val) do
+ encVal = encVal .. self:encode(v) -- todo: buffer?
+ end
- local tableType = bin.pack("H", "30")
- if (val["_snmp"]) then
- tableType = bin.pack("H", val["_snmp"])
- end
- return bin.pack('AAA', tableType, self.encodeLength(#encVal), encVal)
+ local tableType = bin.pack("H", "30")
+ if (val["_snmp"]) then
+ tableType = bin.pack("H", val["_snmp"])
+ end
+ return bin.pack('AAA', tableType, self.encodeLength(#encVal), encVal)
end
---
@@ -59,18 +59,18 @@ end
-- @param val Value to be encoded.
-- @return Encoded value.
function encode(val)
- local vtype = type(val)
- local encoder = asn1.ASN1Encoder:new()
- encoder:registerTagEncoders( tagEncoder )
+ local vtype = type(val)
+ local encoder = asn1.ASN1Encoder:new()
+ encoder:registerTagEncoders( tagEncoder )
- local encVal = encoder:encode(val)
+ local encVal = encoder:encode(val)
- if encVal then
- return encVal
- end
+ if encVal then
+ return encVal
+ end
- return ''
+ return ''
end
-- SNMP ASN.1 Decoders
@@ -91,10 +91,10 @@ tagDecoder["A2"] = function( self, encStr, elen, pos )
end
tagDecoder["40"] = function( self, encStr, elen, pos )
- local ip = {}
- pos, ip[1], ip[2], ip[3], ip[4] = bin.unpack("C4", encStr, pos)
- ip._snmp = '40'
- return pos, ip
+ local ip = {}
+ pos, ip[1], ip[2], ip[3], ip[4] = bin.unpack("C4", encStr, pos)
+ ip._snmp = '40'
+ return pos, ip
end
---
@@ -105,35 +105,35 @@ end
-- @return The position after decoding
-- @return The decoded value(s).
function decode(encStr, pos)
- local decoder = asn1.ASN1Decoder:new()
+ local decoder = asn1.ASN1Decoder:new()
- if ( #tagDecoder == 0 ) then
- decoder:registerBaseDecoders()
- -- Application specific tags
- -- tagDecoder["40"] = decoder.decoder["06"] -- IP Address; same as OID
- tagDecoder["41"] = decoder.decoder["02"] -- Counter; same as Integer
- tagDecoder["42"] = decoder.decoder["02"] -- Gauge
- tagDecoder["43"] = decoder.decoder["02"] -- TimeTicks
- tagDecoder["44"] = decoder.decoder["04"] -- Opaque; same as Octet String
- tagDecoder["45"] = decoder.decoder["06"] -- NsapAddress
- tagDecoder["46"] = decoder.decoder["02"] -- Counter64
- tagDecoder["47"] = decoder.decoder["02"] -- UInteger32
+ if ( #tagDecoder == 0 ) then
+ decoder:registerBaseDecoders()
+ -- Application specific tags
+ -- tagDecoder["40"] = decoder.decoder["06"] -- IP Address; same as OID
+ tagDecoder["41"] = decoder.decoder["02"] -- Counter; same as Integer
+ tagDecoder["42"] = decoder.decoder["02"] -- Gauge
+ tagDecoder["43"] = decoder.decoder["02"] -- TimeTicks
+ tagDecoder["44"] = decoder.decoder["04"] -- Opaque; same as Octet String
+ tagDecoder["45"] = decoder.decoder["06"] -- NsapAddress
+ tagDecoder["46"] = decoder.decoder["02"] -- Counter64
+ tagDecoder["47"] = decoder.decoder["02"] -- UInteger32
- -- Context specific tags
- tagDecoder["A0"] = decoder.decoder["30"] -- GetRequest-PDU
- tagDecoder["A1"] = decoder.decoder["30"] -- GetNextRequest-PDU
- --tagDecoder["A2"] = decoder.decoder["30"] -- Response-PDU
- tagDecoder["A3"] = decoder.decoder["30"] -- SetRequest-PDU
- tagDecoder["A4"] = decoder.decoder["30"] -- Trap-PDU
- tagDecoder["A5"] = decoder.decoder["30"] -- GetBulkRequest-PDU
- tagDecoder["A6"] = decoder.decoder["30"] -- InformRequest-PDU (not implemented here yet)
- tagDecoder["A7"] = decoder.decoder["30"] -- SNMPv2-Trap-PDU (not implemented here yet)
- end
+ -- Context specific tags
+ tagDecoder["A0"] = decoder.decoder["30"] -- GetRequest-PDU
+ tagDecoder["A1"] = decoder.decoder["30"] -- GetNextRequest-PDU
+ --tagDecoder["A2"] = decoder.decoder["30"] -- Response-PDU
+ tagDecoder["A3"] = decoder.decoder["30"] -- SetRequest-PDU
+ tagDecoder["A4"] = decoder.decoder["30"] -- Trap-PDU
+ tagDecoder["A5"] = decoder.decoder["30"] -- GetBulkRequest-PDU
+ tagDecoder["A6"] = decoder.decoder["30"] -- InformRequest-PDU (not implemented here yet)
+ tagDecoder["A7"] = decoder.decoder["30"] -- SNMPv2-Trap-PDU (not implemented here yet)
+ end
- decoder:registerTagDecoders( tagDecoder )
+ decoder:registerTagDecoders( tagDecoder )
- return decoder:decode( encStr, pos )
+ return decoder:decode( encStr, pos )
end
---
@@ -143,10 +143,10 @@ end
-- @param pos Current position in the string.
-- @return The decoded value(s).
function dec(encStr, pos)
- local result
- local _
- _, result = decode(encStr, pos)
- return result
+ local result
+ local _
+ _, result = decode(encStr, pos)
+ return result
end
---
@@ -156,17 +156,17 @@ end
-- @param commStr community string, if not already supplied in registry or as
-- the snmpcommunity script argument.
function buildPacket(PDU, version, commStr)
- local comm = nmap.registry.args.snmpcommunity
- if (not comm) then comm = nmap.registry.snmpcommunity end
- if (not comm) then comm = commStr end
- if (not comm) then comm = "public" end
+ local comm = nmap.registry.args.snmpcommunity
+ if (not comm) then comm = nmap.registry.snmpcommunity end
+ if (not comm) then comm = commStr end
+ if (not comm) then comm = "public" end
- if (not version) then version = 0 end
- local packet = {}
- packet[1] = version
- packet[2] = comm
- packet[3] = PDU
- return packet
+ if (not version) then version = 0 end
+ local packet = {}
+ packet[1] = version
+ packet[2] = comm
+ packet[3] = PDU
+ return packet
end
@@ -179,29 +179,29 @@ end
-- @param ... Object identifiers to be queried.
-- @return Table representing PDU.
function buildGetRequest(options, ...)
- if not options then options = {} end
+ if not options then options = {} end
- if not options.reqId then options.reqId = math.fmod(nmap.clock_ms(), 65000) end
- if not options.err then options.err = 0 end
- if not options.errIdx then options.errIdx = 0 end
+ if not options.reqId then options.reqId = math.fmod(nmap.clock_ms(), 65000) end
+ if not options.err then options.err = 0 end
+ if not options.errIdx then options.errIdx = 0 end
- local req = {}
- req._snmp = 'A0'
- req[1] = options.reqId
- req[2] = options.err
- req[3] = options.errIdx
+ local req = {}
+ req._snmp = 'A0'
+ req[1] = options.reqId
+ req[2] = options.err
+ req[3] = options.errIdx
- local payload = {}
- for i=1, select('#', ...) do
- payload[i] = {}
- payload[i][1] = select(i, ...)
- if type(payload[i][1]) == "string" then
- payload[i][1] = str2oid(payload[i][1])
- end
- payload[i][2] = false
- end
- req[4] = payload
- return req
+ local payload = {}
+ for i=1, select('#', ...) do
+ payload[i] = {}
+ payload[i][1] = select(i, ...)
+ if type(payload[i][1]) == "string" then
+ payload[i][1] = str2oid(payload[i][1])
+ end
+ payload[i][2] = false
+ end
+ req[4] = payload
+ return req
end
@@ -214,29 +214,29 @@ end
-- @param ... Object identifiers to be queried.
-- @return Table representing PDU.
function buildGetNextRequest(options, ...)
- if not options then options = {} end
+ if not options then options = {} end
- if not options.reqId then options.reqId = math.fmod(nmap.clock_ms(), 65000) end
- if not options.err then options.err = 0 end
- if not options.errIdx then options.errIdx = 0 end
+ if not options.reqId then options.reqId = math.fmod(nmap.clock_ms(), 65000) end
+ if not options.err then options.err = 0 end
+ if not options.errIdx then options.errIdx = 0 end
- local req = {}
- req._snmp = 'A1'
- req[1] = options.reqId
- req[2] = options.err
- req[3] = options.errIdx
+ local req = {}
+ req._snmp = 'A1'
+ req[1] = options.reqId
+ req[2] = options.err
+ req[3] = options.errIdx
- local payload = {}
- for i=1, select('#', ...) do
- payload[i] = {}
- payload[i][1] = select(i, ...)
- if type(payload[i][1]) == "string" then
- payload[i][1] = str2oid(payload[i][1])
- end
- payload[i][2] = false
- end
- req[4] = payload
- return req
+ local payload = {}
+ for i=1, select('#', ...) do
+ payload[i] = {}
+ payload[i][1] = select(i, ...)
+ if type(payload[i][1]) == "string" then
+ payload[i][1] = str2oid(payload[i][1])
+ end
+ payload[i][2] = false
+ end
+ req[4] = payload
+ return req
end
---
@@ -252,60 +252,60 @@ end
-- table instead of OID/value pair.
-- @return Table representing PDU.
function buildSetRequest(options, oid, value)
- if not options then options = {} end
+ if not options then options = {} end
- if not options.reqId then options.reqId = math.fmod(nmap.clock_ms(), 65000) end
- if not options.err then options.err = 0 end
- if not options.errIdx then options.errIdx = 0 end
+ if not options.reqId then options.reqId = math.fmod(nmap.clock_ms(), 65000) end
+ if not options.err then options.err = 0 end
+ if not options.errIdx then options.errIdx = 0 end
- local req = {}
- req._snmp = 'A3'
- req[1] = options.reqId
- req[2] = options.err
- req[3] = options.errIdx
+ local req = {}
+ req._snmp = 'A3'
+ req[1] = options.reqId
+ req[2] = options.err
+ req[3] = options.errIdx
- if (type(value) == "table") then
- req[4] = value
- else
- local payload = {}
- if (type(oid) == "string") then
- payload[1] = str2oid(oid)
- else
- payload[1] = oid
- end
- payload[2] = value
- req[4] = {}
- req[4][1] = payload
- end
- return req
+ if (type(value) == "table") then
+ req[4] = value
+ else
+ local payload = {}
+ if (type(oid) == "string") then
+ payload[1] = str2oid(oid)
+ else
+ payload[1] = oid
+ end
+ payload[2] = value
+ req[4] = {}
+ req[4][1] = payload
+ end
+ return req
end
---
-- Create an SNMP Trap PDU.
-- @return Table representing PDU
function buildTrap(enterpriseOid, agentIp, genTrap, specTrap, timeStamp)
- local req = {}
- req._snmp = 'A4'
- if (type(enterpriseOid) == "string") then
- req[1] = str2oid(enterpriseOid)
- else
- req[1] = enterpriseOid
- end
- req[2] = {}
- req[2]._snmp = '40'
- for n in string.gmatch(agentIp, "%d+") do
- table.insert(req[2], tonumber(n))
- end
- req[3] = genTrap
- req[4] = specTrap
+ local req = {}
+ req._snmp = 'A4'
+ if (type(enterpriseOid) == "string") then
+ req[1] = str2oid(enterpriseOid)
+ else
+ req[1] = enterpriseOid
+ end
+ req[2] = {}
+ req[2]._snmp = '40'
+ for n in string.gmatch(agentIp, "%d+") do
+ table.insert(req[2], tonumber(n))
+ end
+ req[3] = genTrap
+ req[4] = specTrap
- req[5] = {}
- req[5]._snmp = '43'
- req[5][1] = timeStamp
+ req[5] = {}
+ req[5]._snmp = '43'
+ req[5][1] = timeStamp
- req[6] = {}
+ req[6] = {}
- return req
+ return req
end
---
@@ -320,34 +320,34 @@ end
-- @param value If given a table, use the table instead of OID/value pair.
-- @return Table representing PDU.
function buildGetResponse(options, oid, value)
- if not options then options = {} end
+ if not options then options = {} end
- -- if really a response, should use reqId of request!
- if not options.reqId then options.reqId = math.fmod(nmap.clock_ms(), 65000) end
- if not options.err then options.err = 0 end
- if not options.errIdx then options.errIdx = 0 end
+ -- if really a response, should use reqId of request!
+ if not options.reqId then options.reqId = math.fmod(nmap.clock_ms(), 65000) end
+ if not options.err then options.err = 0 end
+ if not options.errIdx then options.errIdx = 0 end
- local resp = {}
- resp._snmp = 'A2'
- resp[1] = options.reqId
- resp[2] = options.err
- resp[3] = options.errIdx
+ local resp = {}
+ resp._snmp = 'A2'
+ resp[1] = options.reqId
+ resp[2] = options.err
+ resp[3] = options.errIdx
- if (type(value) == "table") then
- resp[4] = value
- else
+ if (type(value) == "table") then
+ resp[4] = value
+ else
- local payload = {}
- if (type(oid) == "string") then
- payload[1] = str2oid(oid)
- else
- payload[1] = oid
- end
- payload[2] = value
- resp[4] = {}
- resp[4][1] = payload
- end
- return resp
+ local payload = {}
+ if (type(oid) == "string") then
+ payload[1] = str2oid(oid)
+ else
+ payload[1] = oid
+ end
+ payload[2] = value
+ resp[4] = {}
+ resp[4][1] = payload
+ end
+ return resp
end
---
@@ -356,12 +356,12 @@ end
-- "1.3.6.1.2.1.1.1.0".
-- @return Table representing OID.
function str2oid(oidStr)
- local oid = {}
- for n in string.gmatch(oidStr, "%d+") do
- table.insert(oid, tonumber(n))
- end
- oid._snmp = '06'
- return oid
+ local oid = {}
+ for n in string.gmatch(oidStr, "%d+") do
+ table.insert(oid, tonumber(n))
+ end
+ oid._snmp = '06'
+ return oid
end
---
@@ -369,8 +369,8 @@ end
-- @param oid Object identifier table.
-- @return OID string.
function oid2str(oid)
- if (type(oid) ~= "table") then return 'invalid oid' end
- return table.concat(oid, '.')
+ if (type(oid) ~= "table") then return 'invalid oid' end
+ return table.concat(oid, '.')
end
---
@@ -378,8 +378,8 @@ end
-- @param ip IP table.
-- @return IP string.
function ip2str(ip)
- if (type(ip) ~= "table") then return 'invalid ip' end
- return table.concat(ip, '.')
+ if (type(ip) ~= "table") then return 'invalid ip' end
+ return table.concat(ip, '.')
end
@@ -388,12 +388,12 @@ end
-- @param ipStr IP as string.
-- @return Table representing IP.
function str2ip(ipStr)
- local ip = {}
- for n in string.gmatch(ipStr, "%d+") do
- table.insert(ip, tonumber(n))
- end
- ip._snmp = '40'
- return ip
+ local ip = {}
+ for n in string.gmatch(ipStr, "%d+") do
+ table.insert(ip, tonumber(n))
+ end
+ ip._snmp = '40'
+ return ip
end
@@ -402,44 +402,44 @@ end
-- @param resp SNMP Response (will be decoded if necessary).
-- @return Table with all decoded responses and their OIDs.
function fetchResponseValues(resp)
- if (type(resp) == "string") then
- local _
- _, resp = decode(resp)
- end
+ if (type(resp) == "string") then
+ local _
+ _, resp = decode(resp)
+ end
- if (type(resp) ~= "table") then
- return {}
- end
+ if (type(resp) ~= "table") then
+ return {}
+ end
- local varBind
- if (resp._snmp and resp._snmp == 'A2') then
- varBind = resp[4]
- elseif (resp[3]._snmp and resp[3]._snmp == 'A2') then
- varBind = resp[3][4]
- end
+ local varBind
+ if (resp._snmp and resp._snmp == 'A2') then
+ varBind = resp[4]
+ elseif (resp[3]._snmp and resp[3]._snmp == 'A2') then
+ varBind = resp[3][4]
+ end
- if (varBind and type(varBind) == "table") then
- local result = {}
- for k, v in ipairs(varBind) do
- local val = v[2]
- if (type(v[2]) == "table") then
- if (v[2]._snmp == '40') then
- val = v[2][1] .. '.' .. v[2][2] .. '.' .. v[2][3] .. '.' .. v[2][4]
- elseif (v[2]._snmp == '41') then
- val = v[2][1]
- elseif (v[2]._snmp == '42') then
- val = v[2][1]
- elseif (v[2]._snmp == '43') then
- val = v[2][1]
- elseif (v[2]._snmp == '44') then
- val = v[2][1]
- end
- end
- table.insert(result, {val, oid2str(v[1]), v[1]})
+ if (varBind and type(varBind) == "table") then
+ local result = {}
+ for k, v in ipairs(varBind) do
+ local val = v[2]
+ if (type(v[2]) == "table") then
+ if (v[2]._snmp == '40') then
+ val = v[2][1] .. '.' .. v[2][2] .. '.' .. v[2][3] .. '.' .. v[2][4]
+ elseif (v[2]._snmp == '41') then
+ val = v[2][1]
+ elseif (v[2]._snmp == '42') then
+ val = v[2][1]
+ elseif (v[2]._snmp == '43') then
+ val = v[2][1]
+ elseif (v[2]._snmp == '44') then
+ val = v[2][1]
+ end
end
- return result
- end
- return {}
+ table.insert(result, {val, oid2str(v[1]), v[1]})
+ end
+ return result
+ end
+ return {}
end
@@ -448,13 +448,13 @@ end
-- @param response SNMP Response (will be decoded if necessary).
-- @return First decoded value of the response.
function fetchFirst(response)
- local result = fetchResponseValues(response)
+ local result = fetchResponseValues(response)
- if type(result) == "table" and result[1] and result[1][1] then
- return result[1][1]
+ if type(result) == "table" and result[1] and result[1][1] then
+ return result[1][1]
else
- return nil
- end
+ return nil
+ end
end
@@ -466,50 +466,50 @@ end
-- @return table containing oid and value
function snmpWalk( socket, base_oid )
- local snmp_table = {}
- local oid = base_oid
- local status, err, payload
+ local snmp_table = {}
+ local oid = base_oid
+ local status, err, payload
- while ( true ) do
+ while ( true ) do
- local value, response, snmpdata, options, item = nil, nil, nil, {}, {}
- payload = encode( buildPacket( buildGetNextRequest(options, oid) ) )
+ local value, response, snmpdata, options, item = nil, nil, nil, {}, {}
+ payload = encode( buildPacket( buildGetNextRequest(options, oid) ) )
- status, err = socket:send(payload)
- if ( not( status ) ) then
- stdnse.print_debug("snmp.snmpWalk: Send failed")
- return false, err
- end
+ status, err = socket:send(payload)
+ if ( not( status ) ) then
+ stdnse.print_debug("snmp.snmpWalk: Send failed")
+ return false, err
+ end
- status, response = socket:receive_bytes(1)
- if ( not( status ) ) then
- -- Unless we don't have a usefull error message, don't report it
- if ( response ~= "ERROR" ) then
- stdnse.print_debug("snmp.snmpWalk: Received no answer (%s)", response)
- return false, response
- end
- return false, nil
- end
+ status, response = socket:receive_bytes(1)
+ if ( not( status ) ) then
+ -- Unless we don't have a usefull error message, don't report it
+ if ( response ~= "ERROR" ) then
+ stdnse.print_debug("snmp.snmpWalk: Received no answer (%s)", response)
+ return false, response
+ end
+ return false, nil
+ end
- snmpdata = fetchResponseValues( response )
+ snmpdata = fetchResponseValues( response )
- value = snmpdata[1][1]
- oid = snmpdata[1][2]
+ value = snmpdata[1][1]
+ oid = snmpdata[1][2]
- if not oid:match( base_oid ) or base_oid == oid then
- break
- end
+ if not oid:match( base_oid ) or base_oid == oid then
+ break
+ end
- item.oid = oid
- item.value = value
+ item.oid = oid
+ item.value = value
- table.insert( snmp_table, item )
+ table.insert( snmp_table, item )
- end
+ end
- snmp_table.baseoid = base_oid
+ snmp_table.baseoid = base_oid
- return true, snmp_table
+ return true, snmp_table
end
diff --git a/nselib/socks.lua b/nselib/socks.lua
index 4e53bf17e..6daca7a3a 100644
--- a/nselib/socks.lua
+++ b/nselib/socks.lua
@@ -12,347 +12,347 @@ _ENV = stdnse.module("socks", stdnse.seeall)
-- SOCKS Authentication methods
AuthMethod = {
- NONE = 0,
- GSSAPI = 1,
- USERPASS = 2,
+ NONE = 0,
+ GSSAPI = 1,
+ USERPASS = 2,
}
Request = {
- -- Class that handles the connection request to the server
- Connect = {
+ -- Class that handles the connection request to the server
+ Connect = {
- -- Creates a new instance of the class
- -- @param auth_method table of requested authentication methods
- -- @return o instance on success, nil on failure
- new = function(self, auth_method)
- local o = {
- version = 5,
- auth_method = ( "table" ~= type(auth_method) and { auth_method } or auth_method )
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new instance of the class
+ -- @param auth_method table of requested authentication methods
+ -- @return o instance on success, nil on failure
+ new = function(self, auth_method)
+ local o = {
+ version = 5,
+ auth_method = ( "table" ~= type(auth_method) and { auth_method } or auth_method )
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Converts the instance to string, so that it can be sent to the
- -- server.
- -- @return string containing the raw request
- __tostring = function(self)
- local methods = ""
- for _, m in ipairs(self.auth_method) do
- methods = methods .. string.char(m)
- end
- return bin.pack("Cp", self.version, methods)
- end,
+ -- Converts the instance to string, so that it can be sent to the
+ -- server.
+ -- @return string containing the raw request
+ __tostring = function(self)
+ local methods = ""
+ for _, m in ipairs(self.auth_method) do
+ methods = methods .. string.char(m)
+ end
+ return bin.pack("Cp", self.version, methods)
+ end,
- },
+ },
- -- Class that handles the authentication request to the server
- Authenticate = {
+ -- Class that handles the authentication request to the server
+ Authenticate = {
- -- Creates a new instance of the class
- -- @param auth_method number with the requested authentication method
- -- @param creds method specific table of credentials
- -- currently only user and pass authentication is supported
- -- this method requires two fields to be present
- -- username and password
- -- @return o instance on success, nil on failure
- new = function(self, auth_method, creds)
- local o = {
- auth_method = auth_method,
- creds = creds
- }
- setmetatable(o, self)
- self.__index = self
- if ( auth_method == 2 ) then
- return o
- end
- end,
+ -- Creates a new instance of the class
+ -- @param auth_method number with the requested authentication method
+ -- @param creds method specific table of credentials
+ -- currently only user and pass authentication is supported
+ -- this method requires two fields to be present
+ -- username and password
+ -- @return o instance on success, nil on failure
+ new = function(self, auth_method, creds)
+ local o = {
+ auth_method = auth_method,
+ creds = creds
+ }
+ setmetatable(o, self)
+ self.__index = self
+ if ( auth_method == 2 ) then
+ return o
+ end
+ end,
- -- Converts the instance to string, so that it can be sent to the
- -- server.
- -- @return string containing the raw request
- __tostring = function(self)
- -- we really don't support anything but 2, but let's pretend that
- -- we actually do
- if ( 2 == self.auth_method ) then
- local version = 1
- local username= self.creds.username or ""
- local password= self.creds.password or ""
+ -- Converts the instance to string, so that it can be sent to the
+ -- server.
+ -- @return string containing the raw request
+ __tostring = function(self)
+ -- we really don't support anything but 2, but let's pretend that
+ -- we actually do
+ if ( 2 == self.auth_method ) then
+ local version = 1
+ local username= self.creds.username or ""
+ local password= self.creds.password or ""
- username = (username == "") and "\0" or username
- password = (password == "") and "\0" or password
+ username = (username == "") and "\0" or username
+ password = (password == "") and "\0" or password
- return bin.pack("Cpp", version, username, password)
- end
- end,
+ return bin.pack("Cpp", version, username, password)
+ end
+ end,
- }
+ }
}
Response = {
- -- Class that handles the connection response
- Connect = {
+ -- Class that handles the connection response
+ Connect = {
- -- Creates a new instance of the class
- -- @param data string containing the data as received over the socket
- -- @return o instance on success, nil on failure
- new = function(self, data)
- local o = { data = data }
- setmetatable(o, self)
- self.__index = self
- if ( o:parse() ) then
- return o
- end
- end,
+ -- Creates a new instance of the class
+ -- @param data string containing the data as received over the socket
+ -- @return o instance on success, nil on failure
+ new = function(self, data)
+ local o = { data = data }
+ setmetatable(o, self)
+ self.__index = self
+ if ( o:parse() ) then
+ return o
+ end
+ end,
- -- Parses the received data and populates member variables
- -- @return true on success, false on failure
- parse = function(self)
- if ( #self.data ~= 2 ) then
- return
- end
- local pos
- pos, self.version, self.method = bin.unpack("CC", self.data)
- return true
- end
+ -- Parses the received data and populates member variables
+ -- @return true on success, false on failure
+ parse = function(self)
+ if ( #self.data ~= 2 ) then
+ return
+ end
+ local pos
+ pos, self.version, self.method = bin.unpack("CC", self.data)
+ return true
+ end
- },
+ },
- -- Class that handles the authentication response
- Authenticate = {
+ -- Class that handles the authentication response
+ Authenticate = {
- Status = {
- SUCCESS = 0,
- -- could be anything but zero
- FAIL = 1,
- },
+ Status = {
+ SUCCESS = 0,
+ -- could be anything but zero
+ FAIL = 1,
+ },
- -- Creates a new instance of the class
- -- @param data string containing the data as received over the socket
- -- @return o instance on success, nil on failure
- new = function(self, data)
- local o = { data = data }
- setmetatable(o, self)
- self.__index = self
- if ( o:parse() ) then
- return o
- end
- end,
+ -- Creates a new instance of the class
+ -- @param data string containing the data as received over the socket
+ -- @return o instance on success, nil on failure
+ new = function(self, data)
+ local o = { data = data }
+ setmetatable(o, self)
+ self.__index = self
+ if ( o:parse() ) then
+ return o
+ end
+ end,
- -- Parses the received data and populates member variables
- -- @return true on success, false on failure
- parse = function(self)
- if ( #self.data ~= 2 ) then
- return
- end
- local pos
- pos, self.version, self.status = bin.unpack("CC", self.data)
- return true
- end,
+ -- Parses the received data and populates member variables
+ -- @return true on success, false on failure
+ parse = function(self)
+ if ( #self.data ~= 2 ) then
+ return
+ end
+ local pos
+ pos, self.version, self.status = bin.unpack("CC", self.data)
+ return true
+ end,
- -- checks if the authentication was successful or not
- -- @return true on success, false on failure
- isSuccess = function(self)
- return ( self.status == self.Status.SUCCESS )
- end,
+ -- checks if the authentication was successful or not
+ -- @return true on success, false on failure
+ isSuccess = function(self)
+ return ( self.status == self.Status.SUCCESS )
+ end,
- }
+ }
}
-- A buffered socket implementation
Socket =
{
- retries = 3,
+ retries = 3,
- -- Creates a new socket instance
- -- @param host table containing the host table
- -- @param port table containing the port table
- -- @param options table containing options, currenlty supports:
- -- timeout - socket timeout in ms
- -- @return o new instance of Socket
- new = function(self, host, port, options)
- local o = {
- host = host,
- port = port,
- options = options or {}
- }
- setmetatable(o, self)
- self.__index = self
- o.Socket = nmap.new_socket()
- o.Buffer = nil
- return o
- end,
+ -- Creates a new socket instance
+ -- @param host table containing the host table
+ -- @param port table containing the port table
+ -- @param options table containing options, currenlty supports:
+ -- timeout - socket timeout in ms
+ -- @return o new instance of Socket
+ new = function(self, host, port, options)
+ local o = {
+ host = host,
+ port = port,
+ options = options or {}
+ }
+ setmetatable(o, self)
+ self.__index = self
+ o.Socket = nmap.new_socket()
+ o.Buffer = nil
+ return o
+ end,
- -- Connects the socket to the server
- -- @return status true on success false on failure
- -- @return err string containing error message on failure
- connect = function( self )
- self.Socket:set_timeout(self.options.timeout or 10000)
- return self.Socket:connect( self.host, self.port )
- end,
+ -- Connects the socket to the server
+ -- @return status true on success false on failure
+ -- @return err string containing error message on failure
+ connect = function( self )
+ self.Socket:set_timeout(self.options.timeout or 10000)
+ return self.Socket:connect( self.host, self.port )
+ 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,
+ -- 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
+ -- 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 ""
+ 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
+ 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)
+ data = self.Buffer:sub( 1, count )
+ self.Buffer = self.Buffer:sub( count + 1)
- return true, data
- end,
+ 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 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,
}
-- The main script interface
Helper = {
- -- Create a new instance of the class
- -- @param host table containing the host table
- -- @param port table containing the port table
- -- @param options table containing library options, currenlty:
- -- timeout - socket timeout in ms
- -- @return o instance of Helper
- new = function(self, host, port, options)
- local o = { host = host, port = port, options = options }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Create a new instance of the class
+ -- @param host table containing the host table
+ -- @param port table containing the port table
+ -- @param options table containing library options, currenlty:
+ -- timeout - socket timeout in ms
+ -- @return o instance of Helper
+ new = function(self, host, port, options)
+ local o = { host = host, port = port, options = options }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Get the authentication method name by number
- -- @param method number containing the authentication method
- -- @return string containing the method name or Unknown
- authNameByNumber = function(self, method)
- local methods = {
- [0] = "No authentication",
- [1] = "GSSAPI",
- [2] = "Username and password",
- }
- return methods[method] or ("Unknown method (%d)"):format(method)
- end,
+ -- Get the authentication method name by number
+ -- @param method number containing the authentication method
+ -- @return string containing the method name or Unknown
+ authNameByNumber = function(self, method)
+ local methods = {
+ [0] = "No authentication",
+ [1] = "GSSAPI",
+ [2] = "Username and password",
+ }
+ return methods[method] or ("Unknown method (%d)"):format(method)
+ end,
- -- Connects to the SOCKS server
- -- @param auth_method table containing the auth. methods to request
- -- @return status true on success, false on failure
- -- @return response table containing the respons or err string on failure
- connect = function(self, auth_method)
- self.socket = Socket:new(self.host, self.port, self.options)
- local status, err = self.socket:connect()
- if ( not(status) ) then
- return status, err
- end
+ -- Connects to the SOCKS server
+ -- @param auth_method table containing the auth. methods to request
+ -- @return status true on success, false on failure
+ -- @return response table containing the respons or err string on failure
+ connect = function(self, auth_method)
+ self.socket = Socket:new(self.host, self.port, self.options)
+ local status, err = self.socket:connect()
+ if ( not(status) ) then
+ return status, err
+ end
- auth_method = auth_method or {AuthMethod.NONE, AuthMethod.GSSAPI, AuthMethod.USERPASS}
- status = self.socket:send( tostring(Request.Connect:new(auth_method)) )
- if ( not(status) ) then
- self.socket:close()
- return false, "Failed to send connection request to server"
- end
+ auth_method = auth_method or {AuthMethod.NONE, AuthMethod.GSSAPI, AuthMethod.USERPASS}
+ status = self.socket:send( tostring(Request.Connect:new(auth_method)) )
+ if ( not(status) ) then
+ self.socket:close()
+ return false, "Failed to send connection request to server"
+ end
- local status, data = self.socket:recv(2)
- if ( not(status) ) then
- self.socket:close()
- return false, "Failed to receive connection response from server"
- end
+ local status, data = self.socket:recv(2)
+ if ( not(status) ) then
+ self.socket:close()
+ return false, "Failed to receive connection response from server"
+ end
- local response = Response.Connect:new(data)
- if ( not(response) ) then
- return false, "Failed to parse response from server"
- end
+ local response = Response.Connect:new(data)
+ if ( not(response) ) then
+ return false, "Failed to parse response from server"
+ end
- if ( response.version ~= 5 ) then
- return false, ("Unsupported SOCKS version (%d)"):format(response.version)
- end
- if ( response.method == 0xFF ) then
- return false, "No acceptable authentication methods"
- end
+ if ( response.version ~= 5 ) then
+ return false, ("Unsupported SOCKS version (%d)"):format(response.version)
+ end
+ if ( response.method == 0xFF ) then
+ return false, "No acceptable authentication methods"
+ end
- -- store the method so authenticate knows what to use
- self.auth_method = response.method
- return true, response
- end,
+ -- store the method so authenticate knows what to use
+ self.auth_method = response.method
+ return true, response
+ end,
- -- Authenticates to the SOCKS server
- -- @param creds table containing authentication method specific fields
- -- currently only authentication method 2 (username and pass) is
- -- implemented. That method requires the following fields:
- -- username - containing the username
- -- password - containing the password
- -- @return status true on success, false on failure
- -- @return err string containing the error message
- authenticate = function(self, creds)
- if ( self.auth_method ~= 2 ) then
- return false, "Authentication method not supported"
- end
- local req = Request.Authenticate:new(self.auth_method, creds)
- if ( not(req) ) then
- return false, "Failed to create authentication request"
- end
+ -- Authenticates to the SOCKS server
+ -- @param creds table containing authentication method specific fields
+ -- currently only authentication method 2 (username and pass) is
+ -- implemented. That method requires the following fields:
+ -- username - containing the username
+ -- password - containing the password
+ -- @return status true on success, false on failure
+ -- @return err string containing the error message
+ authenticate = function(self, creds)
+ if ( self.auth_method ~= 2 ) then
+ return false, "Authentication method not supported"
+ end
+ local req = Request.Authenticate:new(self.auth_method, creds)
+ if ( not(req) ) then
+ return false, "Failed to create authentication request"
+ end
- local status = self.socket:send(tostring(req))
- if ( not(status) ) then
- return false, "Failed to send authentication request"
- end
+ local status = self.socket:send(tostring(req))
+ if ( not(status) ) then
+ return false, "Failed to send authentication request"
+ end
- if ( 2 == self.auth_method ) then
- local status, data = self.socket:recv(2)
- local auth = Response.Authenticate:new(data)
+ if ( 2 == self.auth_method ) then
+ local status, data = self.socket:recv(2)
+ local auth = Response.Authenticate:new(data)
- if ( not(auth) ) then
- return false, "Failed to parse authentication response"
- end
+ if ( not(auth) ) then
+ return false, "Failed to parse authentication response"
+ end
- if ( auth:isSuccess() ) then
- return true, "Authentication was successfull"
- else
- return false, "Authentication failed"
- end
+ if ( auth:isSuccess() ) then
+ return true, "Authentication was successfull"
+ else
+ return false, "Authentication failed"
+ end
- end
- return false, "Unsupported authentication method"
- end,
+ end
+ return false, "Unsupported authentication method"
+ end,
- -- closes the connection to the server
- close = function(self)
- return self.socket:close()
- end,
+ -- closes the connection to the server
+ close = function(self)
+ return self.socket:close()
+ end,
}
diff --git a/nselib/srvloc.lua b/nselib/srvloc.lua
index e6c26fe0b..9277199a7 100644
--- a/nselib/srvloc.lua
+++ b/nselib/srvloc.lua
@@ -4,26 +4,26 @@
--
-- The implementation is based on the following classes:
-- * Request.Service
--- - Contains necessary code to produce a service request
+-- - Contains necessary code to produce a service request
--
-- * Request.Attributes
--- - Contains necessary code to produce a attribute request
+-- - Contains necessary code to produce a attribute request
--
-- * Reply.Service
--- - Contains necessary code to process and parse the response to the
--- service request
+-- - Contains necessary code to process and parse the response to the
+-- service request
--
-- * Reply.Attributes
--- - Contains necessary code to process and parse the response to the
--- attribute request
+-- - Contains necessary code to process and parse the response to the
+-- attribute request
--
-- The following code illustrates intended use of the library:
--
---
--- local helper = srvloc.Helper:new()
--- local status, tree = helper:ServiceRequest("ndap.novell", "DEFAULT")
--- if ( status ) then tree = tree:match("%/%/%/(.*)%.$") end
---
+--
+-- local helper = srvloc.Helper:new()
+-- local status, tree = helper:ServiceRequest("ndap.novell", "DEFAULT")
+-- if ( status ) then tree = tree:match("%/%/%/(.*)%.$") end
+--
--@author Patrik Karlsson
--@copyright Same as Nmap--See http://nmap.org/book/man-legal.html
@@ -39,258 +39,258 @@ local table = require "table"
_ENV = stdnse.module("srvloc", stdnse.seeall)
PacketFunction = {
- SERVICE_REQUEST = 1,
- SERVICE_REPLY = 2,
- ATTRIB_REQUEST = 6,
+ SERVICE_REQUEST = 1,
+ SERVICE_REPLY = 2,
+ ATTRIB_REQUEST = 6,
}
Reply = {
- Service = {
+ Service = {
- --- Creates a new instance of the Reply.Service class
- -- @param data string containing the raw reply as read from the socket
- -- @return o instance of Reply.Service
- new = function(self, data)
- local o = { data = data }
- setmetatable(o, self)
- self.__index = self
- o:parse(data)
- return o
- end,
+ --- Creates a new instance of the Reply.Service class
+ -- @param data string containing the raw reply as read from the socket
+ -- @return o instance of Reply.Service
+ new = function(self, data)
+ local o = { data = data }
+ setmetatable(o, self)
+ self.__index = self
+ o:parse(data)
+ return o
+ end,
- --- Parses the service reply raw packet data
- -- @param data string containing the raw reply as read from the socket
- parse = function(self, data)
- local pos
- local len_hi, len_lo
+ --- Parses the service reply raw packet data
+ -- @param data string containing the raw reply as read from the socket
+ parse = function(self, data)
+ local pos
+ local len_hi, len_lo
- pos, self.version, self.func, len_hi, len_lo = bin.unpack(">CCCS", data)
- self.len = bit.lshift(len_hi, 16) + len_lo
- pos, self.flags = bin.unpack(">S", data, pos)
+ pos, self.version, self.func, len_hi, len_lo = bin.unpack(">CCCS", data)
+ self.len = bit.lshift(len_hi, 16) + len_lo
+ pos, self.flags = bin.unpack(">S", data, pos)
- local neo_hi, neo_lo
- pos, neo_hi, neo_lo = bin.unpack(">CS", data, pos)
- self.next_extension_offset = bit.lshift(neo_hi, 16) + neo_lo
+ local neo_hi, neo_lo
+ pos, neo_hi, neo_lo = bin.unpack(">CS", data, pos)
+ self.next_extension_offset = bit.lshift(neo_hi, 16) + neo_lo
- local lang_tag_len
- pos, self.xid, lang_tag_len = bin.unpack(">SS", data, pos)
- pos, self.lang_tag = bin.unpack("A" .. lang_tag_len, data, pos)
+ local lang_tag_len
+ pos, self.xid, lang_tag_len = bin.unpack(">SS", data, pos)
+ pos, self.lang_tag = bin.unpack("A" .. lang_tag_len, data, pos)
- local no_urls, reserved, url_len
- pos, self.error_code, no_urls = bin.unpack(">SS", data, pos)
+ local no_urls, reserved, url_len
+ pos, self.error_code, no_urls = bin.unpack(">SS", data, pos)
- if ( no_urls > 0 ) then
- pos, reserved, self.url_lifetime, url_len = bin.unpack(">CSS", data, pos)
+ if ( no_urls > 0 ) then
+ pos, reserved, self.url_lifetime, url_len = bin.unpack(">CSS", data, pos)
- local num_auths
- pos, self.url, num_auths = bin.unpack("A" .. url_len .. "C", data, pos)
- end
- end,
+ local num_auths
+ pos, self.url, num_auths = bin.unpack("A" .. url_len .. "C", data, pos)
+ end
+ end,
- --- Attempts to create an instance by reading data off the socket
- -- @param socket socket conected to the SRVLOC service
- -- @return new instance of the Reply.Service class
- fromSocket = function(socket)
- local status, data = socket:receive()
- if ( not(status) ) then return end
- return Reply.Service:new(data)
- end,
+ --- Attempts to create an instance by reading data off the socket
+ -- @param socket socket conected to the SRVLOC service
+ -- @return new instance of the Reply.Service class
+ fromSocket = function(socket)
+ local status, data = socket:receive()
+ if ( not(status) ) then return end
+ return Reply.Service:new(data)
+ end,
- --- Gets the url value from the reply
- -- @return uri string containing the reply url
- getUrl = function(self) return self.url end,
- },
+ --- Gets the url value from the reply
+ -- @return uri string containing the reply url
+ getUrl = function(self) return self.url end,
+ },
- Attribute = {
+ Attribute = {
- --- Creates a new instance of Reply.Attribute
- -- @param data string containing the raw reply as read from the socket
- -- @return o instance of Reply.Attribute
- new = function(self, data)
- local o = { data = data }
- setmetatable(o, self)
- self.__index = self
- o:parse(data)
- return o
- end,
+ --- Creates a new instance of Reply.Attribute
+ -- @param data string containing the raw reply as read from the socket
+ -- @return o instance of Reply.Attribute
+ new = function(self, data)
+ local o = { data = data }
+ setmetatable(o, self)
+ self.__index = self
+ o:parse(data)
+ return o
+ end,
- --- Parses the service reply raw packet data
- -- @param data string containing the raw reply as read from the socket
- parse = function(self, data)
- local pos
- local len_hi, len_lo
+ --- Parses the service reply raw packet data
+ -- @param data string containing the raw reply as read from the socket
+ parse = function(self, data)
+ local pos
+ local len_hi, len_lo
- pos, self.version, self.func, len_hi, len_lo = bin.unpack(">CCCS", data)
- self.len = bit.lshift(len_hi, 16) + len_lo
- pos, self.flags = bin.unpack(">S", data, pos)
+ pos, self.version, self.func, len_hi, len_lo = bin.unpack(">CCCS", data)
+ self.len = bit.lshift(len_hi, 16) + len_lo
+ pos, self.flags = bin.unpack(">S", data, pos)
- local neo_hi, neo_lo
- pos, neo_hi, neo_lo = bin.unpack(">CS", data, pos)
- self.next_extension_offset = bit.lshift(neo_hi, 16) + neo_lo
+ local neo_hi, neo_lo
+ pos, neo_hi, neo_lo = bin.unpack(">CS", data, pos)
+ self.next_extension_offset = bit.lshift(neo_hi, 16) + neo_lo
- local lang_tag_len
- pos, self.xid, lang_tag_len = bin.unpack(">SS", data, pos)
- pos, self.lang_tag = bin.unpack("A" .. lang_tag_len, data, pos)
+ local lang_tag_len
+ pos, self.xid, lang_tag_len = bin.unpack(">SS", data, pos)
+ pos, self.lang_tag = bin.unpack("A" .. lang_tag_len, data, pos)
- local attrib_list_len
- pos, self.error_code, attrib_list_len = bin.unpack(">SS", data, pos)
+ local attrib_list_len
+ pos, self.error_code, attrib_list_len = bin.unpack(">SS", data, pos)
- pos, self.attrib_list = bin.unpack("A"..attrib_list_len, data, pos)
+ pos, self.attrib_list = bin.unpack("A"..attrib_list_len, data, pos)
- local num_auths
- pos, num_auths = bin.unpack("C", data, pos)
- end,
+ local num_auths
+ pos, num_auths = bin.unpack("C", data, pos)
+ end,
- --- Attempts to create an instance by reading data off the socket
- -- @param socket socket conected to the SRVLOC service
- -- @return new instance of the Reply.Attribute class
- fromSocket = function(socket)
- local status, data = socket:receive()
- if ( not(status) ) then return end
- return Reply.Attribute:new(data)
- end,
+ --- Attempts to create an instance by reading data off the socket
+ -- @param socket socket conected to the SRVLOC service
+ -- @return new instance of the Reply.Attribute class
+ fromSocket = function(socket)
+ local status, data = socket:receive()
+ if ( not(status) ) then return end
+ return Reply.Attribute:new(data)
+ end,
- --- Gets the attribute list
- -- @return attrib_list
- getAttribList = function(self) return self.attrib_list end,
- }
+ --- Gets the attribute list
+ -- @return attrib_list
+ getAttribList = function(self) return self.attrib_list end,
+ }
}
Request = {
- -- The attribute request
- Attribute = {
+ -- The attribute request
+ Attribute = {
- --- Creates a new instance of the Attribue request
- -- @return o instance of Attribute
- new = function(self)
- local o = {
- lang_tag = "en", version = 2, service_type = "",
- scope = "", next_extension_offset = 0,
- prev_resp_list_len = 0, slp_spi_len = 0 }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ --- Creates a new instance of the Attribue request
+ -- @return o instance of Attribute
+ new = function(self)
+ local o = {
+ lang_tag = "en", version = 2, service_type = "",
+ scope = "", next_extension_offset = 0,
+ prev_resp_list_len = 0, slp_spi_len = 0 }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- --- Sets the request scope
- -- @param scope string containing the request scope
- setScope = function(self, scope) self.scope = scope end,
+ --- Sets the request scope
+ -- @param scope string containing the request scope
+ setScope = function(self, scope) self.scope = scope end,
- --- Sets the language tag
- -- @param lang string containing the language
- setLangTag = function(self, lang) self.lang_tag = lang end,
+ --- Sets the language tag
+ -- @param lang string containing the language
+ setLangTag = function(self, lang) self.lang_tag = lang end,
- --- Sets the request flags
- -- @param flags number containing the numeric flag representation
- setFlags = function(self, flags) self.flags = flags end,
+ --- Sets the request flags
+ -- @param flags number containing the numeric flag representation
+ setFlags = function(self, flags) self.flags = flags end,
- --- Sets the request XID
- -- @param xid number containing the request XID
- setXID = function(self, xid) self.xid = xid end,
+ --- Sets the request XID
+ -- @param xid number containing the request XID
+ setXID = function(self, xid) self.xid = xid end,
- --- Sets the request function
- -- @param func number containing the request function number
- setFunction = function(self, func) self.func = func end,
+ --- Sets the request function
+ -- @param func number containing the request function number
+ setFunction = function(self, func) self.func = func end,
- --- Sets the request taglist
- -- @param tl string containing the taglist
- setTagList = function(self, tl) self.tag_list = tl end,
+ --- Sets the request taglist
+ -- @param tl string containing the taglist
+ setTagList = function(self, tl) self.tag_list = tl end,
- --- Sets the request url
- -- @param u string containing the url
- setUrl = function(self, u) self.url = u end,
+ --- Sets the request url
+ -- @param u string containing the url
+ setUrl = function(self, u) self.url = u end,
- --- "Serializes" the request to a string
- -- @return data string containing a string representation of the request
- __tostring = function(self)
- assert(self.func, "Packet function was not specified")
- assert(self.scope, "Packet scope was not specified")
+ --- "Serializes" the request to a string
+ -- @return data string containing a string representation of the request
+ __tostring = function(self)
+ assert(self.func, "Packet function was not specified")
+ assert(self.scope, "Packet scope was not specified")
- local BASE_LEN = 24
- local len = BASE_LEN + #self.lang_tag + self.prev_resp_list_len +
- self.slp_spi_len + #self.service_type + #self.url +
- #self.tag_list + #self.scope
- local len_hi = bit.band(bit.rshift(len, 16), 0x00FF)
- local len_lo = bit.band(len, 0xFFFF)
- local neo_hi = bit.band(bit.rshift(self.next_extension_offset, 16),
- 0x00FF)
- local neo_lo = bit.band(self.next_extension_offset, 0xFFFF)
+ local BASE_LEN = 24
+ local len = BASE_LEN + #self.lang_tag + self.prev_resp_list_len +
+ self.slp_spi_len + #self.service_type + #self.url +
+ #self.tag_list + #self.scope
+ local len_hi = bit.band(bit.rshift(len, 16), 0x00FF)
+ local len_lo = bit.band(len, 0xFFFF)
+ local neo_hi = bit.band(bit.rshift(self.next_extension_offset, 16),
+ 0x00FF)
+ local neo_lo = bit.band(self.next_extension_offset, 0xFFFF)
- local data = bin.pack(">CCCSSCSSSASSASASAS", self.version, self.func,
- len_hi, len_lo, self.flags, neo_hi, neo_lo, self.xid, #self.lang_tag, self.lang_tag,
- self.prev_resp_list_len, #self.url, self.url, #self.scope, self.scope,
- #self.tag_list, self.tag_list, self.slp_spi_len)
+ local data = bin.pack(">CCCSSCSSSASSASASAS", self.version, self.func,
+ len_hi, len_lo, self.flags, neo_hi, neo_lo, self.xid, #self.lang_tag, self.lang_tag,
+ self.prev_resp_list_len, #self.url, self.url, #self.scope, self.scope,
+ #self.tag_list, self.tag_list, self.slp_spi_len)
- return data
- end
- },
+ return data
+ end
+ },
- -- The Service request
- Service = {
+ -- The Service request
+ Service = {
- --- Creates a new instance of the Service request
- -- @return o instance of Service
- new = function(self)
- local o = {
- lang_tag = "en", version = 2, service_type = "",
- scope = "", next_extension_offset = 0,
- prev_resp_list_len = 0, predicate_len = 0, slp_spi_len = 0 }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ --- Creates a new instance of the Service request
+ -- @return o instance of Service
+ new = function(self)
+ local o = {
+ lang_tag = "en", version = 2, service_type = "",
+ scope = "", next_extension_offset = 0,
+ prev_resp_list_len = 0, predicate_len = 0, slp_spi_len = 0 }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- --- Sets the service type of the request
- -- @param t string containing the type of the request
- setServiceType = function(self, t) self.service_type = t end,
+ --- Sets the service type of the request
+ -- @param t string containing the type of the request
+ setServiceType = function(self, t) self.service_type = t end,
- --- Sets the request scope
- -- @param scope string containing the request scope
- setScope = function(self, scope) self.scope = scope end,
+ --- Sets the request scope
+ -- @param scope string containing the request scope
+ setScope = function(self, scope) self.scope = scope end,
- --- Sets the language tag
- -- @param lang string containing the language
- setLangTag = function(self, lang) self.lang_tag = lang end,
+ --- Sets the language tag
+ -- @param lang string containing the language
+ setLangTag = function(self, lang) self.lang_tag = lang end,
- --- Sets the request flags
- -- @param flags number containing the numeric flag representation
- setFlags = function(self, flags) self.flags = flags end,
+ --- Sets the request flags
+ -- @param flags number containing the numeric flag representation
+ setFlags = function(self, flags) self.flags = flags end,
- --- Sets the request XID
- -- @param xid number containing the request XID
- setXID = function(self, xid) self.xid = xid end,
+ --- Sets the request XID
+ -- @param xid number containing the request XID
+ setXID = function(self, xid) self.xid = xid end,
- --- Sets the request function
- -- @param func number containing the request function number
- setFunction = function(self, func) self.func = func end,
+ --- Sets the request function
+ -- @param func number containing the request function number
+ setFunction = function(self, func) self.func = func end,
- --- "Serializes" the request to a string
- -- @return data string containing a string representation of the request
- __tostring = function(self)
- assert(self.func, "Packet function was not specified")
- assert(self.scope, "Packet scope was not specified")
+ --- "Serializes" the request to a string
+ -- @return data string containing a string representation of the request
+ __tostring = function(self)
+ assert(self.func, "Packet function was not specified")
+ assert(self.scope, "Packet scope was not specified")
- local BASE_LEN = 24
- local len = BASE_LEN + #self.lang_tag + self.prev_resp_list_len +
- self.predicate_len + self.slp_spi_len + #self.service_type +
- #self.scope
- local len_hi = bit.band(bit.rshift(len, 16), 0x00FF)
- local len_lo = bit.band(len, 0xFFFF)
- local neo_hi = bit.band(bit.rshift(self.next_extension_offset, 16),
- 0x00FF)
- local neo_lo = bit.band(self.next_extension_offset, 0xFFFF)
+ local BASE_LEN = 24
+ local len = BASE_LEN + #self.lang_tag + self.prev_resp_list_len +
+ self.predicate_len + self.slp_spi_len + #self.service_type +
+ #self.scope
+ local len_hi = bit.band(bit.rshift(len, 16), 0x00FF)
+ local len_lo = bit.band(len, 0xFFFF)
+ local neo_hi = bit.band(bit.rshift(self.next_extension_offset, 16),
+ 0x00FF)
+ local neo_lo = bit.band(self.next_extension_offset, 0xFFFF)
- local data = bin.pack(">CCCSSCSSSASSASASS", self.version, self.func,
- len_hi, len_lo, self.flags, neo_hi, neo_lo, self.xid, #self.lang_tag, self.lang_tag,
- self.prev_resp_list_len, #self.service_type, self.service_type, #self.scope,
- self.scope, self.predicate_len, self.slp_spi_len)
+ local data = bin.pack(">CCCSSCSSSASSASASS", self.version, self.func,
+ len_hi, len_lo, self.flags, neo_hi, neo_lo, self.xid, #self.lang_tag, self.lang_tag,
+ self.prev_resp_list_len, #self.service_type, self.service_type, #self.scope,
+ self.scope, self.predicate_len, self.slp_spi_len)
- return data
- end
- }
+ return data
+ end
+ }
}
@@ -298,81 +298,81 @@ Request = {
-- The Helper class serves as primary interface for scripts using the libraryy
Helper = {
- new = function(self, host, port)
- local o = { xid = 1, socket = nmap.new_socket("udp") }
- setmetatable(o, self)
- self.__index = self
- local family = nmap.address_family()
- o.host = host or (family=="inet6" and "FF02::116" or "239.255.255.253")
- o.port = port or { number=427, proto="udp" }
- return o
- end,
+ new = function(self, host, port)
+ local o = { xid = 1, socket = nmap.new_socket("udp") }
+ setmetatable(o, self)
+ self.__index = self
+ local family = nmap.address_family()
+ o.host = host or (family=="inet6" and "FF02::116" or "239.255.255.253")
+ o.port = port or { number=427, proto="udp" }
+ return o
+ end,
- --- Sends a service request and waits for the response
- -- @param srvtype string containing the service type to query
- -- @param scope string containing the scope of the request
- -- @return true on success, false on failure
- -- @return url string (on success) containing the url of the ServiceReply
- -- @return err string (on failure) containing the error message
- ServiceRequest = function(self, srvtype, scope)
- local srvtype = srvtype or ""
- local scope = scope or ""
- local sr = Request.Service:new()
- sr:setXID(self.xid)
- sr:setServiceType(srvtype)
- sr:setScope(scope)
- sr:setFunction(PacketFunction.SERVICE_REQUEST)
- sr:setFlags(0x2000)
+ --- Sends a service request and waits for the response
+ -- @param srvtype string containing the service type to query
+ -- @param scope string containing the scope of the request
+ -- @return true on success, false on failure
+ -- @return url string (on success) containing the url of the ServiceReply
+ -- @return err string (on failure) containing the error message
+ ServiceRequest = function(self, srvtype, scope)
+ local srvtype = srvtype or ""
+ local scope = scope or ""
+ local sr = Request.Service:new()
+ sr:setXID(self.xid)
+ sr:setServiceType(srvtype)
+ sr:setScope(scope)
+ sr:setFunction(PacketFunction.SERVICE_REQUEST)
+ sr:setFlags(0x2000)
- self.socket:set_timeout(5000)
- self.socket:sendto( self.host, self.port, tostring(sr) )
+ self.socket:set_timeout(5000)
+ self.socket:sendto( self.host, self.port, tostring(sr) )
- local result = {}
- repeat
- local r = Reply.Service.fromSocket(self.socket)
- if ( r ) then
- table.insert(result, r:getUrl())
- end
- self.xid = self.xid + 1
- until(not(r))
+ local result = {}
+ repeat
+ local r = Reply.Service.fromSocket(self.socket)
+ if ( r ) then
+ table.insert(result, r:getUrl())
+ end
+ self.xid = self.xid + 1
+ until(not(r))
- if ( #result == 0 ) then
- return false, "ERROR: Helper.Locate no response received"
- end
- return true, result
- end,
+ if ( #result == 0 ) then
+ return false, "ERROR: Helper.Locate no response received"
+ end
+ return true, result
+ end,
- --- Requests an attribute from the server
- -- @param url as retrieved by the Service request
- -- @param scope string containing the request scope
- -- @param taglist string containing the request tag list
- AttributeRequest = function(self, url, scope, taglist)
- local url = url or ""
- local scope = scope or ""
- local taglist = taglist or ""
- local ar = Request.Attribute:new()
- ar:setXID(self.xid)
- ar:setScope(scope)
- ar:setUrl(url)
- ar:setTagList(taglist)
- ar:setFunction(PacketFunction.ATTRIB_REQUEST)
- ar:setFlags(0x2000)
+ --- Requests an attribute from the server
+ -- @param url as retrieved by the Service request
+ -- @param scope string containing the request scope
+ -- @param taglist string containing the request tag list
+ AttributeRequest = function(self, url, scope, taglist)
+ local url = url or ""
+ local scope = scope or ""
+ local taglist = taglist or ""
+ local ar = Request.Attribute:new()
+ ar:setXID(self.xid)
+ ar:setScope(scope)
+ ar:setUrl(url)
+ ar:setTagList(taglist)
+ ar:setFunction(PacketFunction.ATTRIB_REQUEST)
+ ar:setFlags(0x2000)
- self.socket:set_timeout(5000)
- self.socket:sendto( self.host, self.port, tostring(ar) )
+ self.socket:set_timeout(5000)
+ self.socket:sendto( self.host, self.port, tostring(ar) )
- local r = Reply.Attribute.fromSocket(self.socket)
+ local r = Reply.Attribute.fromSocket(self.socket)
- self.xid = self.xid + 1
- if ( not(r) ) then
- return false, "ERROR: Helper.Locate no response received"
- end
- return true, r:getAttribList()
- end,
+ self.xid = self.xid + 1
+ if ( not(r) ) then
+ return false, "ERROR: Helper.Locate no response received"
+ end
+ return true, r:getAttribList()
+ end,
- close = function(self)
- return self.socket:close()
- end,
+ close = function(self)
+ return self.socket:close()
+ end,
}
return _ENV;
diff --git a/nselib/sslcert.lua b/nselib/sslcert.lua
index 2946571d5..aed2cc9d2 100644
--- a/nselib/sslcert.lua
+++ b/nselib/sslcert.lua
@@ -16,229 +16,229 @@ _ENV = stdnse.module("sslcert", stdnse.seeall)
StartTLS = {
- ftp_prepare_tls_without_reconnect = function(host, port)
- local s = nmap.new_socket()
- -- Attempt to negotiate TLS over FTP for services that support it
- -- Works for FTP (21)
+ ftp_prepare_tls_without_reconnect = function(host, port)
+ local s = nmap.new_socket()
+ -- Attempt to negotiate TLS over FTP for services that support it
+ -- Works for FTP (21)
- -- Open a standard TCP socket
- local status, error = s:connect(host, port, "tcp")
- local result
- if not status then
- return false, "Failed to connect to FTP server"
- else
+ -- Open a standard TCP socket
+ local status, error = s:connect(host, port, "tcp")
+ local result
+ if not status then
+ return false, "Failed to connect to FTP server"
+ else
- -- Loop until the service presents a banner to deal with server
- -- load and timing issues. There may be a better way to handle this.
- local i = 0
- repeat
- status, result = s:receive_lines(1)
- i = i + 1
- until string.match(result, "^220") or i == 5
+ -- Loop until the service presents a banner to deal with server
+ -- load and timing issues. There may be a better way to handle this.
+ local i = 0
+ repeat
+ status, result = s:receive_lines(1)
+ i = i + 1
+ until string.match(result, "^220") or i == 5
- -- Send AUTH TLS command, ask the service to start encryption
- local query = "AUTH TLS\r\n"
- status = s:send(query)
- status, result = s:receive_lines(1)
+ -- Send AUTH TLS command, ask the service to start encryption
+ local query = "AUTH TLS\r\n"
+ status = s:send(query)
+ status, result = s:receive_lines(1)
- if not (string.match(result, "^234")) then
- stdnse.print_debug("1","%s",result)
- stdnse.print_debug("1","AUTH TLS failed or unavailable. Enable --script-trace to see what is happening.")
+ if not (string.match(result, "^234")) then
+ stdnse.print_debug("1","%s",result)
+ stdnse.print_debug("1","AUTH TLS failed or unavailable. Enable --script-trace to see what is happening.")
- -- Send QUIT to clean up server side connection
- local query = "QUIT\r\n"
- status = s:send(query)
- result = ""
+ -- Send QUIT to clean up server side connection
+ local query = "QUIT\r\n"
+ status = s:send(query)
+ result = ""
- return false, "Failed to connect to FTP server"
- end
- end
- -- Should have a solid TLS over FTP session now...
- return true, s
- end,
+ return false, "Failed to connect to FTP server"
+ end
+ end
+ -- Should have a solid TLS over FTP session now...
+ return true, s
+ end,
- ftp_prepare_tls = function(host, port)
- local err
- local status, s = StartTLS.ftp_prepare_tls_without_reconnect(host, port)
- if status then
- status,err = s:reconnect_ssl()
- if not status then
- stdnse.print_debug("1","Could not establish SSL session after STARTTLS command.")
- s:close()
- return false, "Failed to connect to SMTP server"
- else
- return true,s
- end
- end
- return false, "Failed to connect to FTP server"
- end,
+ ftp_prepare_tls = function(host, port)
+ local err
+ local status, s = StartTLS.ftp_prepare_tls_without_reconnect(host, port)
+ if status then
+ status,err = s:reconnect_ssl()
+ if not status then
+ stdnse.print_debug("1","Could not establish SSL session after STARTTLS command.")
+ s:close()
+ return false, "Failed to connect to SMTP server"
+ else
+ return true,s
+ end
+ end
+ return false, "Failed to connect to FTP server"
+ end,
- smtp_prepare_tls_without_reconnect = function(host, port)
- local s = nmap.new_socket()
- -- Attempt to negotiate TLS over SMTP for services that support it
- -- Works for SMTP (25) and SMTP Submission (587)
+ smtp_prepare_tls_without_reconnect = function(host, port)
+ local s = nmap.new_socket()
+ -- Attempt to negotiate TLS over SMTP for services that support it
+ -- Works for SMTP (25) and SMTP Submission (587)
- -- Open a standard TCP socket
- local status, error = s:connect(host, port, "tcp")
+ -- Open a standard TCP socket
+ local status, error = s:connect(host, port, "tcp")
- if not status then
- return nil
- else
- local resultEHLO
- -- Loop until the service presents a banner to deal with server
- -- load and timing issues. There may be a better way to handle this.
- local i = 0
- repeat
- status, resultEHLO = s:receive_lines(1)
- i = i + 1
- until string.match(resultEHLO, "^220") or i == 5
+ if not status then
+ return nil
+ else
+ local resultEHLO
+ -- Loop until the service presents a banner to deal with server
+ -- load and timing issues. There may be a better way to handle this.
+ local i = 0
+ repeat
+ status, resultEHLO = s:receive_lines(1)
+ i = i + 1
+ until string.match(resultEHLO, "^220") or i == 5
- -- Send EHLO because the the server expects it
- -- We are not going to check for STARTTLS in the capabilities
- -- list, sometimes it is not advertised.
- local query = "EHLO example.org\r\n"
- status = s:send(query)
- status, resultEHLO = s:receive_lines(1)
+ -- Send EHLO because the the server expects it
+ -- We are not going to check for STARTTLS in the capabilities
+ -- list, sometimes it is not advertised.
+ local query = "EHLO example.org\r\n"
+ status = s:send(query)
+ status, resultEHLO = s:receive_lines(1)
- if not (string.match(resultEHLO, "^250")) then
- stdnse.print_debug("1","%s",resultEHLO)
- stdnse.print_debug("1","EHLO with errors or timeout. Enable --script-trace to see what is happening.")
- return false, "Failed to connect to SMTP server"
- end
+ if not (string.match(resultEHLO, "^250")) then
+ stdnse.print_debug("1","%s",resultEHLO)
+ stdnse.print_debug("1","EHLO with errors or timeout. Enable --script-trace to see what is happening.")
+ return false, "Failed to connect to SMTP server"
+ end
- resultEHLO = ""
+ resultEHLO = ""
- -- Send STARTTLS command ask the service to start encryption
- local query = "STARTTLS\r\n"
- status = s:send(query)
- status, resultEHLO = s:receive_lines(1)
+ -- Send STARTTLS command ask the service to start encryption
+ local query = "STARTTLS\r\n"
+ status = s:send(query)
+ status, resultEHLO = s:receive_lines(1)
- if not (string.match(resultEHLO, "^220")) then
- stdnse.print_debug("1","%s",resultEHLO)
- stdnse.print_debug("1","STARTTLS failed or unavailable. Enable --script-trace to see what is happening.")
+ if not (string.match(resultEHLO, "^220")) then
+ stdnse.print_debug("1","%s",resultEHLO)
+ stdnse.print_debug("1","STARTTLS failed or unavailable. Enable --script-trace to see what is happening.")
- -- Send QUIT to clean up server side connection
- local query = "QUIT\r\n"
- status = s:send(query)
- resultEHLO = ""
+ -- Send QUIT to clean up server side connection
+ local query = "QUIT\r\n"
+ status = s:send(query)
+ resultEHLO = ""
- return false, "Failed to connect to SMTP server"
- end
- end
- -- Should have a solid TLS over SMTP session now...
- return true, s
- end,
+ return false, "Failed to connect to SMTP server"
+ end
+ end
+ -- Should have a solid TLS over SMTP session now...
+ return true, s
+ end,
- smtp_prepare_tls = function(host, port)
- local err
- local status,s = StartTLS.smtp_prepare_tls_without_reconnect(host, port)
- if status then
- status,err = s:reconnect_ssl()
- if not status then
- stdnse.print_debug("1","Could not establish SSL session after STARTTLS command.")
- s:close()
- return false, "Failed to connect to SMTP server"
- else
- return true,s
- end
- end
- return false, "Failed to connect to SMTP server"
- end,
+ smtp_prepare_tls = function(host, port)
+ local err
+ local status,s = StartTLS.smtp_prepare_tls_without_reconnect(host, port)
+ if status then
+ status,err = s:reconnect_ssl()
+ if not status then
+ stdnse.print_debug("1","Could not establish SSL session after STARTTLS command.")
+ s:close()
+ return false, "Failed to connect to SMTP server"
+ else
+ return true,s
+ end
+ end
+ return false, "Failed to connect to SMTP server"
+ end,
- xmpp_prepare_tls_without_reconnect = function(host,port)
- local sock,status,err,result
- local xmppStreamStart = string.format("\r\n\r\n",host.name)
- local xmppStartTLS = "\r\n"
- sock = nmap.new_socket()
- sock:set_timeout(5000)
- status, err = sock:connect(host, port)
- if not status then
- sock:close()
- stdnse.print_debug("Can't send: %s", err)
- return false, "Failed to connect to XMPP server"
- end
- status, err = sock:send(xmppStreamStart)
- if not status then
- stdnse.print_debug("Couldn't send: %s", err)
- sock:close()
- return false, "Failed to connect to XMPP server"
- end
- status, result = sock:receive()
- if not status then
- stdnse.print_debug("Couldn't receive: %s", err)
- sock:close()
- return false, "Failed to connect to XMPP server"
- end
- status, err = sock:send(xmppStartTLS)
- if not status then
- stdnse.print_debug("Couldn't send: %s", err)
- sock:close()
- return false, "Failed to connect to XMPP server"
- end
- status, result = sock:receive()
- if not status then
- stdnse.print_debug("Couldn't receive: %s", err)
- sock:close()
- return false, "Failed to connect to XMPP server"
- end
- if string.find(result,"proceed") then
- return true,sock
- end
+ xmpp_prepare_tls_without_reconnect = function(host,port)
+ local sock,status,err,result
+ local xmppStreamStart = string.format("\r\n\r\n",host.name)
+ local xmppStartTLS = "\r\n"
+ sock = nmap.new_socket()
+ sock:set_timeout(5000)
+ status, err = sock:connect(host, port)
+ if not status then
+ sock:close()
+ stdnse.print_debug("Can't send: %s", err)
+ return false, "Failed to connect to XMPP server"
+ end
+ status, err = sock:send(xmppStreamStart)
+ if not status then
+ stdnse.print_debug("Couldn't send: %s", err)
+ sock:close()
+ return false, "Failed to connect to XMPP server"
+ end
+ status, result = sock:receive()
+ if not status then
+ stdnse.print_debug("Couldn't receive: %s", err)
+ sock:close()
+ return false, "Failed to connect to XMPP server"
+ end
+ status, err = sock:send(xmppStartTLS)
+ if not status then
+ stdnse.print_debug("Couldn't send: %s", err)
+ sock:close()
+ return false, "Failed to connect to XMPP server"
+ end
+ status, result = sock:receive()
+ if not status then
+ stdnse.print_debug("Couldn't receive: %s", err)
+ sock:close()
+ return false, "Failed to connect to XMPP server"
+ end
+ if string.find(result,"proceed") then
+ return true,sock
+ end
- status, result = sock:receive() -- might not be in the first reply
- if not status then
- stdnse.print_debug("Couldn't receive: %s", err)
- sock:close()
- return false, "Failed to connect to XMPP server"
- end
- if string.find(result,"proceed") then
- return true,sock
- else
- return false, "Failed to connect to XMPP server"
- end
- end,
+ status, result = sock:receive() -- might not be in the first reply
+ if not status then
+ stdnse.print_debug("Couldn't receive: %s", err)
+ sock:close()
+ return false, "Failed to connect to XMPP server"
+ end
+ if string.find(result,"proceed") then
+ return true,sock
+ else
+ return false, "Failed to connect to XMPP server"
+ end
+ end,
- xmpp_prepare_tls = function(host, port)
- local ls = xmpp.XMPP:new(host, port, { starttls = true } )
- ls.socket = nmap.new_socket()
- ls.socket:set_timeout(ls.options.timeout * 1000)
+ xmpp_prepare_tls = function(host, port)
+ local ls = xmpp.XMPP:new(host, port, { starttls = true } )
+ ls.socket = nmap.new_socket()
+ ls.socket:set_timeout(ls.options.timeout * 1000)
- local status, err = ls.socket:connect(host, port)
- if not status then
- return nil
- end
+ local status, err = ls.socket:connect(host, port)
+ if not status then
+ return nil
+ end
- status, err = ls:connect()
- if not(status) then
- return false, "Failed to connected"
- end
- return true, ls.socket
- end
+ status, err = ls:connect()
+ if not(status) then
+ return false, "Failed to connected"
+ end
+ return true, ls.socket
+ end
}
-- A table mapping port numbers to specialized SSL negotiation functions.
local SPECIALIZED_PREPARE_TLS = {
- [21] = StartTLS.ftp_prepare_tls,
- [25] = StartTLS.smtp_prepare_tls,
- [587] = StartTLS.smtp_prepare_tls,
- [5222] = StartTLS.xmpp_prepare_tls,
- [5269] = StartTLS.xmpp_prepare_tls
+ [21] = StartTLS.ftp_prepare_tls,
+ [25] = StartTLS.smtp_prepare_tls,
+ [587] = StartTLS.smtp_prepare_tls,
+ [5222] = StartTLS.xmpp_prepare_tls,
+ [5269] = StartTLS.xmpp_prepare_tls
}
local SPECIALIZED_PREPARE_TLS_WITHOUT_RECONNECT = {
- [21] = StartTLS.ftp_prepare_tls_without_reconnect,
- [25] = StartTLS.smtp_prepare_tls_without_reconnect,
- [587] = StartTLS.smtp_prepare_tls_without_reconnect,
- [5222] = StartTLS.xmpp_prepare_tls_without_reconnect,
- [5269] = StartTLS.xmpp_prepare_tls_without_reconnect
+ [21] = StartTLS.ftp_prepare_tls_without_reconnect,
+ [25] = StartTLS.smtp_prepare_tls_without_reconnect,
+ [587] = StartTLS.smtp_prepare_tls_without_reconnect,
+ [5222] = StartTLS.xmpp_prepare_tls_without_reconnect,
+ [5269] = StartTLS.xmpp_prepare_tls_without_reconnect
}
function getPrepareTLSWithoutReconnect(port)
- return SPECIALIZED_PREPARE_TLS_WITHOUT_RECONNECT[port.number]
+ return SPECIALIZED_PREPARE_TLS_WITHOUT_RECONNECT[port.number]
end
function isPortSupported(port)
- return SPECIALIZED_PREPARE_TLS[port.number]
+ return SPECIALIZED_PREPARE_TLS[port.number]
end
--- Gets a certificate for the given host and port
@@ -249,44 +249,44 @@ end
-- @return cert userdata containing the SSL certificate, or error message on
-- failure.
function getCertificate(host, port)
- local mutex = nmap.mutex("sslcert-cache-mutex")
- mutex "lock"
+ local mutex = nmap.mutex("sslcert-cache-mutex")
+ mutex "lock"
- if ( host.registry["ssl-cert"] and
- host.registry["ssl-cert"][port.number] ) then
- stdnse.print_debug(2, "sslcert: Returning cached SSL certificate")
- mutex "done"
- return true, host.registry["ssl-cert"][port.number]
- end
+ if ( host.registry["ssl-cert"] and
+ host.registry["ssl-cert"][port.number] ) then
+ stdnse.print_debug(2, "sslcert: Returning cached SSL certificate")
+ mutex "done"
+ return true, host.registry["ssl-cert"][port.number]
+ end
- -- Is there a specialized function for this port?
- local specialized = SPECIALIZED_PREPARE_TLS[port.number]
- local status
- local socket = nmap.new_socket()
- if specialized then
- status, socket = specialized(host, port)
- if not status then
- mutex "done"
- return false, "Failed to connect to server"
- end
- else
- local status
- status = socket:connect(host, port, "ssl")
- if ( not(status) ) then
- mutex "done"
- return false, "Failed to connect to server"
- end
+ -- Is there a specialized function for this port?
+ local specialized = SPECIALIZED_PREPARE_TLS[port.number]
+ local status
+ local socket = nmap.new_socket()
+ if specialized then
+ status, socket = specialized(host, port)
+ if not status then
+ mutex "done"
+ return false, "Failed to connect to server"
end
- local cert = socket:get_ssl_certificate()
- if ( cert == nil ) then
- return false, "Unable to get cert"
- end
+ else
+ local status
+ status = socket:connect(host, port, "ssl")
+ if ( not(status) ) then
+ mutex "done"
+ return false, "Failed to connect to server"
+ end
+ end
+ local cert = socket:get_ssl_certificate()
+ if ( cert == nil ) then
+ return false, "Unable to get cert"
+ end
- host.registry["ssl-cert"] = host.registry["ssl-cert"] or {}
- host.registry["ssl-cert"][port.number] = host.registry["ssl-cert"][port.number] or {}
- host.registry["ssl-cert"][port.number] = cert
- mutex "done"
- return true, cert
+ host.registry["ssl-cert"] = host.registry["ssl-cert"] or {}
+ host.registry["ssl-cert"][port.number] = host.registry["ssl-cert"][port.number] or {}
+ host.registry["ssl-cert"][port.number] = cert
+ mutex "done"
+ return true, cert
end
diff --git a/nselib/stun.lua b/nselib/stun.lua
index af6dd3a8c..40a9dcd11 100644
--- a/nselib/stun.lua
+++ b/nselib/stun.lua
@@ -19,368 +19,368 @@ _ENV = stdnse.module("stun", stdnse.seeall)
-- The supported request types
MessageType = {
- BINDING_REQUEST = 0x0001,
- BINDING_RESPONSE = 0x0101,
+ BINDING_REQUEST = 0x0001,
+ BINDING_RESPONSE = 0x0101,
}
-- The header used in both request and responses
Header = {
- -- the header size in bytes
- size = 20,
+ -- the header size in bytes
+ size = 20,
- -- creates a new instance of Header
- -- @param type number the request/response type
- -- @param trans_id string the 128-bit transaction id
- -- @param length number the packet length
- new = function(self, type, trans_id, length)
- local o = { type = type, trans_id = trans_id, length = length or 0 }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- creates a new instance of Header
+ -- @param type number the request/response type
+ -- @param trans_id string the 128-bit transaction id
+ -- @param length number the packet length
+ new = function(self, type, trans_id, length)
+ local o = { type = type, trans_id = trans_id, length = length or 0 }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- parses an opaque string and creates a new Header instance
- -- @param data opaque string
- -- @return header new instance of Header
- parse = function(data)
- local header = Header:new()
- local pos
- pos, header.type, header.length, header.trans_id = bin.unpack(">SSA16", data)
- return header
- end,
+ -- parses an opaque string and creates a new Header instance
+ -- @param data opaque string
+ -- @return header new instance of Header
+ parse = function(data)
+ local header = Header:new()
+ local pos
+ pos, header.type, header.length, header.trans_id = bin.unpack(">SSA16", data)
+ return header
+ end,
- -- converts the header to an opaque string
- -- @return string containing the header instance
- __tostring = function(self)
- return bin.pack(">SSA", self.type, self.length, self.trans_id)
- end,
+ -- converts the header to an opaque string
+ -- @return string containing the header instance
+ __tostring = function(self)
+ return bin.pack(">SSA", self.type, self.length, self.trans_id)
+ end,
}
Request = {
- -- The binding request
- Bind = {
+ -- The binding request
+ Bind = {
- -- Creates a new Bind request
- -- @param trans_id string containing the 128 bit transaction ID
- -- @return o new instance of the Bind request
- new = function(self, trans_id)
- local o = {
- header = Header:new(MessageType.BINDING_REQUEST, trans_id),
- attributes = {}
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new Bind request
+ -- @param trans_id string containing the 128 bit transaction ID
+ -- @return o new instance of the Bind request
+ new = function(self, trans_id)
+ local o = {
+ header = Header:new(MessageType.BINDING_REQUEST, trans_id),
+ attributes = {}
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- converts the instance to an opaque string
- -- @return string containing the Bind request as string
- __tostring = function(self)
- local data = ""
- for _, attrib in ipairs(self.attributes) do
- data = data .. tostring(attrib)
- end
- self.header.length = #data
- return tostring(self.header) .. data
- end,
- }
+ -- converts the instance to an opaque string
+ -- @return string containing the Bind request as string
+ __tostring = function(self)
+ local data = ""
+ for _, attrib in ipairs(self.attributes) do
+ data = data .. tostring(attrib)
+ end
+ self.header.length = #data
+ return tostring(self.header) .. data
+ end,
+ }
}
-- The attribute class
Attribute = {
- MAPPED_ADDRESS = 0x0001,
- RESPONSE_ADDRESS = 0x0002,
- CHANGE_REQUEST = 0x0003,
- SOURCE_ADDRESS = 0x0004,
- CHANGED_ADDRESS = 0x0005,
- USERNAME = 0x0006,
- PASSWORD = 0x0007,
- MESSAGE_INTEGRITY = 0x0008,
- ERROR_CODE = 0x0009,
- UNKNOWN_ATTRIBUTES = 0x000a,
- REFLECTED_FROM = 0x000b,
- SERVER = 0x8022,
+ MAPPED_ADDRESS = 0x0001,
+ RESPONSE_ADDRESS = 0x0002,
+ CHANGE_REQUEST = 0x0003,
+ SOURCE_ADDRESS = 0x0004,
+ CHANGED_ADDRESS = 0x0005,
+ USERNAME = 0x0006,
+ PASSWORD = 0x0007,
+ MESSAGE_INTEGRITY = 0x0008,
+ ERROR_CODE = 0x0009,
+ UNKNOWN_ATTRIBUTES = 0x000a,
+ REFLECTED_FROM = 0x000b,
+ SERVER = 0x8022,
- -- creates a new attribute instance
- -- @param type number containing the attribute type
- -- @param data string containing the attribute value
- -- @return o instance of attribute
- new = function(self, type, data)
- local o = {
- type = type,
- length = (data and #data or 0),
- data = data,
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- creates a new attribute instance
+ -- @param type number containing the attribute type
+ -- @param data string containing the attribute value
+ -- @return o instance of attribute
+ new = function(self, type, data)
+ local o = {
+ type = type,
+ length = (data and #data or 0),
+ data = data,
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- parses a string and creates an Attribute instance
- -- @param data string containing the raw attribute
- -- @return o new attribute instance
- parse = function(data)
- local attr = Attribute:new()
- local pos = 1
+ -- parses a string and creates an Attribute instance
+ -- @param data string containing the raw attribute
+ -- @return o new attribute instance
+ parse = function(data)
+ local attr = Attribute:new()
+ local pos = 1
- pos, attr.type, attr.length = bin.unpack(">SS", data, pos)
+ pos, attr.type, attr.length = bin.unpack(">SS", data, pos)
- local function parseAddress(data, pos)
- local _, addr = nil, {}
- pos, _, addr.family, addr.port, addr.ip = bin.unpack("SSA", self.type, self.length, self.data or "")
- end,
+ -- converts an attribute to string
+ -- @return string containing the serialized attribute
+ __tostring = function(self)
+ return bin.pack(">SSA", self.type, self.length, self.data or "")
+ end,
}
-- Response class container
Response = {
- -- Bind response class
- Bind = {
+ -- Bind response class
+ Bind = {
- -- creates a new instance of the Bind response
- -- @param trans_id string containing the 128 bit transaction id
- -- @return o new Bind instance
- new = function(self, trans_id)
- local o = { header = Header:new(MessageType.BINDING_RESPONSE, trans_id) }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- creates a new instance of the Bind response
+ -- @param trans_id string containing the 128 bit transaction id
+ -- @return o new Bind instance
+ new = function(self, trans_id)
+ local o = { header = Header:new(MessageType.BINDING_RESPONSE, trans_id) }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- parses a raw string and creates a new Bind instance
- -- @param data string containing the raw data
- -- @return resp containing a new Bind instance
- parse = function(data)
- local resp = Response.Bind:new()
- local pos = Header.size
+ -- parses a raw string and creates a new Bind instance
+ -- @param data string containing the raw data
+ -- @return resp containing a new Bind instance
+ parse = function(data)
+ local resp = Response.Bind:new()
+ local pos = Header.size
- resp.header = Header.parse(data)
- resp.attributes = {}
+ resp.header = Header.parse(data)
+ resp.attributes = {}
- while( pos < #data ) do
- local attr = Attribute.parse(data:sub(pos))
- table.insert(resp.attributes, attr)
- pos = pos + attr.length + 4
- end
- return resp
- end
- }
+ while( pos < #data ) do
+ local attr = Attribute.parse(data:sub(pos))
+ table.insert(resp.attributes, attr)
+ pos = pos + attr.length + 4
+ end
+ return resp
+ end
+ }
}
-- The communication class
Comm = {
- -- creates a new Comm instance
- -- @param host table
- -- @param port table
- -- @param options table, currently supporting:
- -- timeout - socket timeout in ms.
- -- @param mode containing the mode
- -- @return o new instance of Comm
- new = function(self, host, port, options, mode)
- local o = {
- host = host,
- port = port,
- options = options or { timeout = 10000 },
- socket = nmap.new_socket(),
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- creates a new Comm instance
+ -- @param host table
+ -- @param port table
+ -- @param options table, currently supporting:
+ -- timeout - socket timeout in ms.
+ -- @param mode containing the mode
+ -- @return o new instance of Comm
+ new = function(self, host, port, options, mode)
+ local o = {
+ host = host,
+ port = port,
+ options = options or { timeout = 10000 },
+ socket = nmap.new_socket(),
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- connects the socket to the server
- -- @return status true on success, false on failure
- -- @return err string containing an error message, if status is false
- connect = function(self)
- self.socket:set_timeout(self.options.timeout)
- return self.socket:connect(self.host, self.port)
- end,
+ -- connects the socket to the server
+ -- @return status true on success, false on failure
+ -- @return err string containing an error message, if status is false
+ connect = function(self)
+ self.socket:set_timeout(self.options.timeout)
+ return self.socket:connect(self.host, self.port)
+ end,
- -- sends a request to the server
- -- @return status true on success, false on failure
- -- @return err string containing an error message, if status is false
- send = function(self, data)
- return self.socket:send(data)
- end,
+ -- sends a request to the server
+ -- @return status true on success, false on failure
+ -- @return err string containing an error message, if status is false
+ send = function(self, data)
+ return self.socket:send(data)
+ end,
- -- receives a response from the server
- -- @return status true on success, false on failure
- -- @return response containing a response instance
- -- err string containing an error message, if status is false
- recv = function(self)
- local status, hdr_data = self.socket:receive_buf(match.numbytes(Header.size), false)
- if ( not(status) ) then
- return false, "Failed to receive response from server"
- end
+ -- receives a response from the server
+ -- @return status true on success, false on failure
+ -- @return response containing a response instance
+ -- err string containing an error message, if status is false
+ recv = function(self)
+ local status, hdr_data = self.socket:receive_buf(match.numbytes(Header.size), false)
+ if ( not(status) ) then
+ return false, "Failed to receive response from server"
+ end
- local header = Header.parse(hdr_data)
- if ( not(header) ) then
- return false, "Failed to parse response header"
- end
+ local header = Header.parse(hdr_data)
+ if ( not(header) ) then
+ return false, "Failed to parse response header"
+ end
- local status, data = self.socket:receive_buf(match.numbytes(header.length), false)
- if ( header.type == MessageType.BINDING_RESPONSE ) then
- local resp = Response.Bind.parse(hdr_data .. data)
- return true, resp
- end
+ local status, data = self.socket:receive_buf(match.numbytes(header.length), false)
+ if ( header.type == MessageType.BINDING_RESPONSE ) then
+ local resp = Response.Bind.parse(hdr_data .. data)
+ return true, resp
+ end
- return false, "Unknown response message received"
- end,
+ return false, "Unknown response message received"
+ end,
- -- sends the request instance to the server and receives the response
- -- @param req request class instance
- -- @return status true on success, false on failure
- -- @return response containing a response instance
- -- err string containing an error message, if status is false
- exch = function(self, req)
- local status, err = self:send(tostring(req))
- if ( not(status) ) then
- return false, "Failed to send request to server"
- end
- return self:recv()
- end,
+ -- sends the request instance to the server and receives the response
+ -- @param req request class instance
+ -- @return status true on success, false on failure
+ -- @return response containing a response instance
+ -- err string containing an error message, if status is false
+ exch = function(self, req)
+ local status, err = self:send(tostring(req))
+ if ( not(status) ) then
+ return false, "Failed to send request to server"
+ end
+ return self:recv()
+ end,
- -- closes the connection to the server
- -- @return status true on success, false on failure
- -- @return err string containing an error message, if status is false
- close = function(self)
- self.socket:close()
- end,
+ -- closes the connection to the server
+ -- @return status true on success, false on failure
+ -- @return err string containing an error message, if status is false
+ close = function(self)
+ self.socket:close()
+ end,
}
-- The Util class
Util = {
- -- creates a random string
- -- @param len number containg the length of the generated random string
- -- @return str containing the random string
- randomString = function(len)
- local str = ""
- for i=1, len do str = str .. string.char(math.random(255)) end
- return str
- end
+ -- creates a random string
+ -- @param len number containg the length of the generated random string
+ -- @return str containing the random string
+ randomString = function(len)
+ local str = ""
+ for i=1, len do str = str .. string.char(math.random(255)) end
+ return str
+ end
}
-- The Helper class
Helper = {
- -- creates a new Helper instance
- -- @param host table
- -- @param port table
- -- @param options table, currently supporting:
- -- timeout - socket timeout in ms.
- -- @param mode containing the mode container, currently Classic is the only
- -- supported container
- -- @return o new instance of Comm
- new = function(self, host, port, options, mode)
- local o = {
- mode = mode,
- comm = Comm:new(host, port, options, mode),
- }
- o.mode = stdnse.get_script_args("stun.mode") or "modern"
- assert(o.mode == "modern" or o.mode == "classic", "Unsupported mode")
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- creates a new Helper instance
+ -- @param host table
+ -- @param port table
+ -- @param options table, currently supporting:
+ -- timeout - socket timeout in ms.
+ -- @param mode containing the mode container, currently Classic is the only
+ -- supported container
+ -- @return o new instance of Comm
+ new = function(self, host, port, options, mode)
+ local o = {
+ mode = mode,
+ comm = Comm:new(host, port, options, mode),
+ }
+ o.mode = stdnse.get_script_args("stun.mode") or "modern"
+ assert(o.mode == "modern" or o.mode == "classic", "Unsupported mode")
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- connects to the server
- -- @return status true on success, false on failure
- -- @return err string containing an error message, if status is false
- connect = function(self)
- return self.comm:connect()
- end,
+ -- connects to the server
+ -- @return status true on success, false on failure
+ -- @return err string containing an error message, if status is false
+ connect = function(self)
+ return self.comm:connect()
+ end,
- -- Get's the external public IP
- -- @return status true on success, false on failure
- -- @return result containing the IP as tring
- getExternalAddress = function(self)
- local trans_id
+ -- Get's the external public IP
+ -- @return status true on success, false on failure
+ -- @return result containing the IP as tring
+ getExternalAddress = function(self)
+ local trans_id
- if ( self.mode == "classic" ) then
- trans_id = Util.randomString(16)
- else
- trans_id = bin.pack("HA","2112A442", Util.randomString(12))
- end
- local req = Request.Bind:new(trans_id)
+ if ( self.mode == "classic" ) then
+ trans_id = Util.randomString(16)
+ else
+ trans_id = bin.pack("HA","2112A442", Util.randomString(12))
+ end
+ local req = Request.Bind:new(trans_id)
- local status, response = self.comm:exch(req)
- if ( not(status) ) then
- return false, "Failed to send data to server"
- end
+ local status, response = self.comm:exch(req)
+ if ( not(status) ) then
+ return false, "Failed to send data to server"
+ end
- local result
- for k, attr in pairs(response.attributes) do
- if (attr.type == Attribute.MAPPED_ADDRESS ) then
- result = ( attr.addr and attr.addr.ip or "" )
- end
- if ( attr.type == Attribute.SERVER ) then
- self.cache = self.cache or {}
- self.cache.server = attr.server
- end
- end
+ local result
+ for k, attr in pairs(response.attributes) do
+ if (attr.type == Attribute.MAPPED_ADDRESS ) then
+ result = ( attr.addr and attr.addr.ip or "" )
+ end
+ if ( attr.type == Attribute.SERVER ) then
+ self.cache = self.cache or {}
+ self.cache.server = attr.server
+ end
+ end
- if ( not(result) and not(self.cache) ) then
- return false, "Server returned no response"
- end
+ if ( not(result) and not(self.cache) ) then
+ return false, "Server returned no response"
+ end
- return status, result
- end,
+ return status, result
+ end,
- -- Gets the server version if it was returned by the server
- -- @return status true on success, false on failure
- -- @return version string containing the server product and version
- getVersion = function(self)
- local status, response = false, nil
- -- check if the server version was cached
- if ( not(self.cache) or not(self.cache.version) ) then
- local status, response = self:getExternalAddress()
- if ( status ) then
- return true, (self.cache and self.cache.server or "")
- end
- return false, response
- end
- return true, (self.cache and self.cache.server or "")
- end,
+ -- Gets the server version if it was returned by the server
+ -- @return status true on success, false on failure
+ -- @return version string containing the server product and version
+ getVersion = function(self)
+ local status, response = false, nil
+ -- check if the server version was cached
+ if ( not(self.cache) or not(self.cache.version) ) then
+ local status, response = self:getExternalAddress()
+ if ( status ) then
+ return true, (self.cache and self.cache.server or "")
+ end
+ return false, response
+ end
+ return true, (self.cache and self.cache.server or "")
+ end,
- -- closes the connection to the server
- -- @return status true on success, false on failure
- -- @return err string containing an error message, if status is false
- close = function(self)
- return self.comm:close()
- end,
+ -- closes the connection to the server
+ -- @return status true on success, false on failure
+ -- @return err string containing an error message, if status is false
+ close = function(self)
+ return self.comm:close()
+ end,
}
diff --git a/nselib/tab.lua b/nselib/tab.lua
index 8e376abbc..a008e1013 100644
--- a/nselib/tab.lua
+++ b/nselib/tab.lua
@@ -33,11 +33,11 @@ _ENV = stdnse.module("tab", stdnse.seeall)
--- Create and return a new table.
-- @return A new table.
function new()
- local t = {}
+ local t = {}
- t.current_row = 1
- setmetatable(t, {__tostring=dump})
- return t
+ t.current_row = 1
+ setmetatable(t, {__tostring=dump})
+ return t
end
--- Add a new string item to a table at a given column position.
@@ -48,14 +48,14 @@ end
-- @param v The string to add.
-- @param c The column position at which to add the item.
function add(t, c, v)
- assert(t)
- assert(type(v) == "string")
+ assert(t)
+ assert(type(v) == "string")
- -- add a new row if one doesn't exist
- t[t.current_row] = t[t.current_row] or {}
+ -- add a new row if one doesn't exist
+ t[t.current_row] = t[t.current_row] or {}
- t[t.current_row][c] = v
- return true
+ t[t.current_row][c] = v
+ return true
end
--- Add a complete row to the table and move on to the next row.
@@ -65,10 +65,10 @@ end
-- @param t The table.
-- @param ... The elements to add to the row.
function addrow(t, ...)
- for i = 1, select("#", ...) do
- add(t, i, tostring((select(i, ...))))
- end
- nextrow(t)
+ for i = 1, select("#", ...) do
+ add(t, i, tostring((select(i, ...))))
+ end
+ nextrow(t)
end
--- Move on to the next row in the table. If this is not called
@@ -76,10 +76,10 @@ end
-- values.
-- @param t The table.
function nextrow(t)
- assert(t)
- assert(t.current_row)
- t[t.current_row] = t[t.current_row] or {}
- t.current_row = t.current_row + 1
+ assert(t)
+ assert(t.current_row)
+ t[t.current_row] = t[t.current_row] or {}
+ t.current_row = t.current_row + 1
end
--- Return a formatted string representation of the table.
@@ -88,41 +88,41 @@ end
-- column with an additional two spaces for padding.
-- @param t The table.
function dump(t)
- assert(t)
+ assert(t)
- local column_width = {}
- local num_columns = {}
- local buf = strbuf.new()
+ local column_width = {}
+ local num_columns = {}
+ local buf = strbuf.new()
- -- find widest element in each column
- for i, row in ipairs(t) do
- num_columns[i] = 0
- for x, elem in pairs(row) do
- local elem_width = #elem
- if not column_width[x] or elem_width > column_width[x] then
- column_width[x] = elem_width
- end
- if x > num_columns[i] then
- num_columns[i] = x
- end
- end
- end
+ -- find widest element in each column
+ for i, row in ipairs(t) do
+ num_columns[i] = 0
+ for x, elem in pairs(row) do
+ local elem_width = #elem
+ if not column_width[x] or elem_width > column_width[x] then
+ column_width[x] = elem_width
+ end
+ if x > num_columns[i] then
+ num_columns[i] = x
+ end
+ end
+ end
- -- build buf with padding so all column elements line up
- for i, row in ipairs(t) do
- local text_row = {}
- for x = 1, num_columns[i] do
- local elem = row[x] or ""
- if x < num_columns[i] then
- text_row[#text_row + 1] = elem .. string.rep(" ", column_width[x] - #elem)
- else
- text_row[#text_row + 1] = elem
- end
- end
- buf = buf .. table.concat(text_row, " ") .. "\n"
- end
+ -- build buf with padding so all column elements line up
+ for i, row in ipairs(t) do
+ local text_row = {}
+ for x = 1, num_columns[i] do
+ local elem = row[x] or ""
+ if x < num_columns[i] then
+ text_row[#text_row + 1] = elem .. string.rep(" ", column_width[x] - #elem)
+ else
+ text_row[#text_row + 1] = elem
+ end
+ end
+ buf = buf .. table.concat(text_row, " ") .. "\n"
+ end
- return strbuf.dump(buf)
+ return strbuf.dump(buf)
end
return _ENV;
diff --git a/nselib/tftp.lua b/nselib/tftp.lua
index 709ab74b6..d6ad79ea9 100644
--- a/nselib/tftp.lua
+++ b/nselib/tftp.lua
@@ -41,11 +41,11 @@ srvthread = {}
-- All opcodes supported by TFTP
OpCode = {
- RRQ = 1,
- WRQ = 2,
- DATA = 3,
- ACK = 4,
- ERROR = 5,
+ RRQ = 1,
+ WRQ = 2,
+ DATA = 3,
+ ACK = 4,
+ ERROR = 5,
}
@@ -55,110 +55,110 @@ OpCode = {
-- As the server is write-only the other packet types are not needed
Packet = {
- -- Implements the ACK packet
- ACK = {
+ -- Implements the ACK packet
+ ACK = {
- new = function( self, block )
- local o = {}
- setmetatable(o, self)
- self.__index = self
- o.block = block
- return o
- end,
+ new = function( self, block )
+ local o = {}
+ setmetatable(o, self)
+ self.__index = self
+ o.block = block
+ return o
+ end,
- __tostring = function( self )
- return bin.pack(">SS", OpCode.ACK, self.block)
- end,
+ __tostring = function( self )
+ return bin.pack(">SS", OpCode.ACK, self.block)
+ end,
- },
+ },
- -- Implements the error packet
- ERROR = {
+ -- Implements the error packet
+ ERROR = {
- new = function( self, code, msg )
- local o = {}
- setmetatable(o, self)
- self.__index = self
- o.msg = msg
- o.code = code
- return o
- end,
+ new = function( self, code, msg )
+ local o = {}
+ setmetatable(o, self)
+ self.__index = self
+ o.msg = msg
+ o.code = code
+ return o
+ end,
- __tostring = function( self )
- return bin.pack(">SSz", OpCode.ERROR, self.code, self.msg)
- end,
- }
+ __tostring = function( self )
+ return bin.pack(">SSz", OpCode.ERROR, self.code, self.msg)
+ end,
+ }
}
--- The File class holds files received by the TFTP server
File = {
- --- Creates a new file object
- --
- -- @param filename string containing the filename
- -- @param content string containing the file content
- -- @return o new class instance
- new = function(self, filename, content, sender)
- local o = {}
- setmetatable(o, self)
- self.__index = self
- o.name = filename
- o.content = content
- o.sender = sender
- return o
- end,
+ --- Creates a new file object
+ --
+ -- @param filename string containing the filename
+ -- @param content string containing the file content
+ -- @return o new class instance
+ new = function(self, filename, content, sender)
+ local o = {}
+ setmetatable(o, self)
+ self.__index = self
+ o.name = filename
+ o.content = content
+ o.sender = sender
+ return o
+ end,
- getContent = function(self) return self.content end,
- setContent = function(self, content) self.content = content end,
+ getContent = function(self) return self.content end,
+ setContent = function(self, content) self.content = content end,
- getName = function(self) return self.name end,
- setName = function(self, name) self.name = name end,
+ getName = function(self) return self.name end,
+ setName = function(self, name) self.name = name end,
- setSender = function(self, sender) self.sender = sender end,
- getSender = function(self) return self.sender end,
+ setSender = function(self, sender) self.sender = sender end,
+ getSender = function(self) return self.sender end,
}
-- The thread dispatcher is called by the start function once
local function dispatcher()
- local last = os.time()
- local f_condvar = nmap.condvar(infiles)
- local s_condvar = nmap.condvar(state)
+ local last = os.time()
+ local f_condvar = nmap.condvar(infiles)
+ local s_condvar = nmap.condvar(state)
- while(true) do
+ while(true) do
- -- check if other scripts are active
- local counter = 0
- for t in pairs(running) do
- counter = counter + 1
- end
- if ( counter == 0 ) then
- state = "STOPPING"
- s_condvar "broadcast"
- end
+ -- check if other scripts are active
+ local counter = 0
+ for t in pairs(running) do
+ counter = counter + 1
+ end
+ if ( counter == 0 ) then
+ state = "STOPPING"
+ s_condvar "broadcast"
+ end
- if #threads == 0 then break end
- for i, thread in ipairs(threads) do
- local status, res = coroutine.resume(thread)
- if ( not(res) ) then -- thread finished its task?
- table.remove(threads, i)
- break
- end
- end
+ if #threads == 0 then break end
+ for i, thread in ipairs(threads) do
+ local status, res = coroutine.resume(thread)
+ if ( not(res) ) then -- thread finished its task?
+ table.remove(threads, i)
+ break
+ end
+ end
- -- Make sure to process waitFile atleast every 2 seconds
- -- in case no files have arrived
- if ( os.time() - last >= 2 ) then
- last = os.time()
- f_condvar "broadcast"
- end
+ -- Make sure to process waitFile atleast every 2 seconds
+ -- in case no files have arrived
+ if ( os.time() - last >= 2 ) then
+ last = os.time()
+ f_condvar "broadcast"
+ end
- end
- state = "STOPPED"
- s_condvar "broadcast"
- stdnse.print_debug("Exiting _dispatcher")
+ end
+ state = "STOPPED"
+ s_condvar "broadcast"
+ stdnse.print_debug("Exiting _dispatcher")
end
-- Processes a new incoming file transfer
@@ -168,149 +168,149 @@ end
-- @param port containing the port of the initiating host
-- @param data string containing the initial data passed to the server
local function processConnection( host, port, data )
- local pos, op = bin.unpack(">S", data)
- local socket = nmap.new_socket("udp")
+ local pos, op = bin.unpack(">S", data)
+ local socket = nmap.new_socket("udp")
- socket:set_timeout(1000)
- local status, err = socket:connect(host, port)
- if ( not(status) ) then return status, err end
+ socket:set_timeout(1000)
+ local status, err = socket:connect(host, port)
+ if ( not(status) ) then return status, err end
- socket:set_timeout(10)
+ socket:set_timeout(10)
- -- If we get anything else than a write request, abort the connection
- if ( OpCode.WRQ ~= op ) then
- stdnse.print_debug("Unsupported opcode")
- socket:send( tostring(Packet.ERROR:new(0, "TFTP server has write-only support")))
- end
+ -- If we get anything else than a write request, abort the connection
+ if ( OpCode.WRQ ~= op ) then
+ stdnse.print_debug("Unsupported opcode")
+ socket:send( tostring(Packet.ERROR:new(0, "TFTP server has write-only support")))
+ end
- local pos, filename, enctype = bin.unpack("zz", data, pos)
- status, err = socket:send( tostring( Packet.ACK:new(0) ) )
+ local pos, filename, enctype = bin.unpack("zz", data, pos)
+ status, err = socket:send( tostring( Packet.ACK:new(0) ) )
- local blocks = {}
- local lastread = os.time()
+ local blocks = {}
+ local lastread = os.time()
- while( true ) do
- local status, pdata = socket:receive()
- if ( not(status) ) then
- -- if we're here and havent succesfully read a packet for 5 seconds, abort
- if ( os.time() - lastread > 5 ) then
- coroutine.yield(false)
- else
- coroutine.yield(true)
- end
- else
- -- record last time we had a succesful read
- lastread = os.time()
- pos, op = bin.unpack(">S", pdata)
- if ( OpCode.DATA ~= op ) then
- stdnse.print_debug("Expected a data packet, terminating TFTP transfer")
- end
+ while( true ) do
+ local status, pdata = socket:receive()
+ if ( not(status) ) then
+ -- if we're here and havent succesfully read a packet for 5 seconds, abort
+ if ( os.time() - lastread > 5 ) then
+ coroutine.yield(false)
+ else
+ coroutine.yield(true)
+ end
+ else
+ -- record last time we had a succesful read
+ lastread = os.time()
+ pos, op = bin.unpack(">S", pdata)
+ if ( OpCode.DATA ~= op ) then
+ stdnse.print_debug("Expected a data packet, terminating TFTP transfer")
+ end
- local block, data
- pos, block, data = bin.unpack(">SA" .. #pdata - 4, pdata, pos )
+ local block, data
+ pos, block, data = bin.unpack(">SA" .. #pdata - 4, pdata, pos )
- blocks[block] = data
+ blocks[block] = data
- -- First block was not 1
- if ( #blocks == 0 ) then
- socket:send( tostring(Packet.ERROR:new(0, "Did not receive block 1")))
- break
- end
+ -- First block was not 1
+ if ( #blocks == 0 ) then
+ socket:send( tostring(Packet.ERROR:new(0, "Did not receive block 1")))
+ break
+ end
- -- for every fith block check that we've received the preceeding four
- if ( ( #blocks % 5 ) == 0 ) then
- for b = #blocks - 4, #blocks do
- if ( not(blocks[b]) ) then
- socket:send( tostring(Packet.ERROR:new(0, "Did not receive block " .. b)))
- end
- end
- end
+ -- for every fith block check that we've received the preceeding four
+ if ( ( #blocks % 5 ) == 0 ) then
+ for b = #blocks - 4, #blocks do
+ if ( not(blocks[b]) ) then
+ socket:send( tostring(Packet.ERROR:new(0, "Did not receive block " .. b)))
+ end
+ end
+ end
- -- Ack the data block
- status, err = socket:send( tostring(Packet.ACK:new(block)) )
+ -- Ack the data block
+ status, err = socket:send( tostring(Packet.ACK:new(block)) )
- if ( ( #blocks % 20 ) == 0 ) then
- -- yield every 5th iteration so other threads may work
- coroutine.yield(true)
- end
+ if ( ( #blocks % 20 ) == 0 ) then
+ -- yield every 5th iteration so other threads may work
+ coroutine.yield(true)
+ end
- -- If the data length was less than 512, this was our last block
- if ( #data < 512 ) then
- socket:close()
- break
- end
- end
- end
+ -- If the data length was less than 512, this was our last block
+ if ( #data < 512 ) then
+ socket:close()
+ break
+ end
+ end
+ end
- local filecontent = ""
+ local filecontent = ""
- -- Make sure we received all the blocks needed to proceed
- for i=1, #blocks do
- if ( not(blocks[i]) ) then
- return false, ("Block #%d was missing in transfer")
- end
- filecontent = filecontent .. blocks[i]
- end
- stdnse.print_debug("Finnished receiving file \"%s\"", filename)
+ -- Make sure we received all the blocks needed to proceed
+ for i=1, #blocks do
+ if ( not(blocks[i]) ) then
+ return false, ("Block #%d was missing in transfer")
+ end
+ filecontent = filecontent .. blocks[i]
+ end
+ stdnse.print_debug("Finnished receiving file \"%s\"", filename)
- -- Add anew file to the global infiles table
- table.insert( infiles, File:new(filename, filecontent, host) )
+ -- Add anew file to the global infiles table
+ table.insert( infiles, File:new(filename, filecontent, host) )
- local condvar = nmap.condvar(infiles)
- condvar "broadcast"
+ local condvar = nmap.condvar(infiles)
+ condvar "broadcast"
end
-- Waits for a connection from a client
local function waitForConnection()
- local srvsock = nmap.new_socket("udp")
- local status = srvsock:bind(nil, 69)
- assert(status, "Failed to bind to TFTP server port")
+ local srvsock = nmap.new_socket("udp")
+ local status = srvsock:bind(nil, 69)
+ assert(status, "Failed to bind to TFTP server port")
- srvsock:set_timeout(0)
+ srvsock:set_timeout(0)
- while( state == "RUNNING" ) do
- local status, data = srvsock:receive()
- if ( not(status) ) then
- coroutine.yield(true)
- else
- local status, _, _, rhost, rport = srvsock:get_info()
- local x = coroutine.create( function() processConnection(rhost, rport, data) end )
- table.insert( threads, x )
- coroutine.yield(true)
- end
- end
+ while( state == "RUNNING" ) do
+ local status, data = srvsock:receive()
+ if ( not(status) ) then
+ coroutine.yield(true)
+ else
+ local status, _, _, rhost, rport = srvsock:get_info()
+ local x = coroutine.create( function() processConnection(rhost, rport, data) end )
+ table.insert( threads, x )
+ coroutine.yield(true)
+ end
+ end
end
--- Starts the TFTP server and creates a new thread handing over to the dispatcher
function start()
- local disp = nil
- local mutex = nmap.mutex("srvsocket")
+ local disp = nil
+ local mutex = nmap.mutex("srvsocket")
- -- register a running script
- running[coroutine.running()] = true
+ -- register a running script
+ running[coroutine.running()] = true
- mutex "lock"
- if ( state == "STOPPED" ) then
- srvthread = coroutine.running()
- table.insert( threads, coroutine.create( waitForConnection ) )
- stdnse.new_thread( dispatcher )
- state = "RUNNING"
- end
- mutex "done"
+ mutex "lock"
+ if ( state == "STOPPED" ) then
+ srvthread = coroutine.running()
+ table.insert( threads, coroutine.create( waitForConnection ) )
+ stdnse.new_thread( dispatcher )
+ state = "RUNNING"
+ end
+ mutex "done"
end
local function waitLast()
- -- The thread that started the server needs to wait here until the rest
- -- of the scripts finnish running. We know we are done once the state
- -- shifts to STOPPED and we get a singla from the condvar in the
- -- dispatcher
- local s_condvar = nmap.condvar(state)
- while( srvthread == coroutine.running() and state ~= "STOPPED" ) do
- s_condvar "wait"
- end
+ -- The thread that started the server needs to wait here until the rest
+ -- of the scripts finnish running. We know we are done once the state
+ -- shifts to STOPPED and we get a singla from the condvar in the
+ -- dispatcher
+ local s_condvar = nmap.condvar(state)
+ while( srvthread == coroutine.running() and state ~= "STOPPED" ) do
+ s_condvar "wait"
+ end
end
--- Waits for a file with a specific filename for at least the number of
@@ -324,23 +324,23 @@ end
-- @return status true on success false on failure
-- @return File instance on success, nil on failure
function waitFile( filename, timeout )
- local condvar = nmap.condvar(infiles)
- local t = os.time()
- while(os.time() - t < timeout) do
- for _, f in ipairs(infiles) do
- if (f:getName() == filename) then
- running[coroutine.running()] = nil
- waitLast()
- return true, f
- end
- end
- condvar "wait"
- end
- -- de-register a running script
- running[coroutine.running()] = nil
- waitLast()
+ local condvar = nmap.condvar(infiles)
+ local t = os.time()
+ while(os.time() - t < timeout) do
+ for _, f in ipairs(infiles) do
+ if (f:getName() == filename) then
+ running[coroutine.running()] = nil
+ waitLast()
+ return true, f
+ end
+ end
+ condvar "wait"
+ end
+ -- de-register a running script
+ running[coroutine.running()] = nil
+ waitLast()
- return false
+ return false
end
return _ENV;
diff --git a/nselib/unpwdb.lua b/nselib/unpwdb.lua
index b9fdd7c6e..d39813d66 100644
--- a/nselib/unpwdb.lua
+++ b/nselib/unpwdb.lua
@@ -80,58 +80,58 @@ local customdata = false
local args = nmap.registry.args
local userfile = function()
- if args.userdb then
- customdata = true
- return args.userdb
- end
+ if args.userdb then
+ customdata = true
+ return args.userdb
+ end
- return nmap.fetchfile("nselib/data/usernames.lst")
+ return nmap.fetchfile("nselib/data/usernames.lst")
end
local passfile = function()
- if args.passdb then
- customdata = true
- return args.passdb
- end
+ if args.passdb then
+ customdata = true
+ return args.passdb
+ end
- return nmap.fetchfile("nselib/data/passwords.lst")
+ return nmap.fetchfile("nselib/data/passwords.lst")
end
local filltable = function(filename, table)
- if #table ~= 0 then
- return true
- end
+ if #table ~= 0 then
+ return true
+ end
- local file = io.open(filename, "r")
+ local file = io.open(filename, "r")
- if not file then
- return false
- end
+ if not file then
+ return false
+ end
- for l in file:lines() do
- -- Comments takes up a whole line
- if not l:match("#!comment:") then
- table[#table + 1] = l
- end
- end
+ for l in file:lines() do
+ -- Comments takes up a whole line
+ if not l:match("#!comment:") then
+ table[#table + 1] = l
+ end
+ end
- file:close()
+ file:close()
- return true
+ return true
end
table_iterator = function(table)
- local i = 1
+ local i = 1
- return function(cmd)
- if cmd == "reset" then
- i = 1
- return
- end
- local elem = table[i]
- if elem then i = i + 1 end
- return elem
- end
+ return function(cmd)
+ if cmd == "reset" then
+ i = 1
+ return
+ end
+ local elem = table[i]
+ if elem then i = i + 1 end
+ return elem
+ end
end
--- Returns the suggested number of seconds to attempt a brute force attack,
@@ -145,30 +145,30 @@ end
-- still check for nil return values on the above two functions in
-- case you finish before the time limit is up.
timelimit = function()
- -- If we're reading from a user-defined username or password list,
- -- we'll give them a timeout 1.5x the default. If the "notimelimit"
- -- script argument is used, we return nil.
- local t = nmap.timing_level()
+ -- If we're reading from a user-defined username or password list,
+ -- we'll give them a timeout 1.5x the default. If the "notimelimit"
+ -- script argument is used, we return nil.
+ local t = nmap.timing_level()
- -- Easy enough
- if args.notimelimit then
- return nil
- end
- if args["unpwdb.timelimit"] then
- local limit, err = stdnse.parse_timespec(args["unpwdb.timelimit"])
- if not limit then
- error(err)
- end
- return limit
- end
+ -- Easy enough
+ if args.notimelimit then
+ return nil
+ end
+ if args["unpwdb.timelimit"] then
+ local limit, err = stdnse.parse_timespec(args["unpwdb.timelimit"])
+ if not limit then
+ error(err)
+ end
+ return limit
+ end
- if t <= 3 then
- return (customdata and 900) or 600
- elseif t == 4 then
- return (customdata and 450) or 300
- elseif t == 5 then
- return (customdata and 270) or 180
- end
+ if t <= 3 then
+ return (customdata and 900) or 600
+ elseif t == 4 then
+ return (customdata and 450) or 300
+ elseif t == 5 then
+ return (customdata and 270) or 180
+ end
end
--- Returns a function closure which returns a new username with every call
@@ -177,17 +177,17 @@ end
-- @return boolean Status.
-- @return function The usernames iterator.
local usernames_raw = function()
- local path = userfile()
+ local path = userfile()
- if not path then
- return false, "Cannot find username list"
- end
+ if not path then
+ return false, "Cannot find username list"
+ end
- if not filltable(path, usertable) then
- return false, "Error parsing username list"
- end
+ if not filltable(path, usertable) then
+ return false, "Error parsing username list"
+ end
- return true, table_iterator(usertable)
+ return true, table_iterator(usertable)
end
--- Returns a function closure which returns a new password with every call
@@ -196,17 +196,17 @@ end
-- @return boolean Status.
-- @return function The passwords iterator.
local passwords_raw = function()
- local path = passfile()
+ local path = passfile()
- if not path then
- return false, "Cannot find password list"
- end
+ if not path then
+ return false, "Cannot find password list"
+ end
- if not filltable(path, passtable) then
- return false, "Error parsing password list"
- end
+ if not filltable(path, passtable) then
+ return false, "Error parsing password list"
+ end
- return true, table_iterator(passtable)
+ return true, table_iterator(passtable)
end
--- Wraps time and count limits around an iterator. When either limit expires,
@@ -217,27 +217,27 @@ end
-- @return boolean Status.
-- @return function The wrapped iterator.
limited_iterator = function(iterator, time_limit, count_limit)
- local start, count, elem
+ local start, count, elem
- time_limit = (time_limit and time_limit > 0) and time_limit
- count_limit = (count_limit and count_limit > 0) and count_limit
+ time_limit = (time_limit and time_limit > 0) and time_limit
+ count_limit = (count_limit and count_limit > 0) and count_limit
- start = os.time()
- count = 0
- return function(cmd)
- if cmd == "reset" then
- count = 0
- else
- count = count + 1
- end
- if count_limit and count > count_limit then
- return
- end
- if time_limit and os.time() - start >= time_limit then
- return
- end
- return iterator(cmd)
- end
+ start = os.time()
+ count = 0
+ return function(cmd)
+ if cmd == "reset" then
+ count = 0
+ else
+ count = count + 1
+ end
+ if count_limit and count > count_limit then
+ return
+ end
+ if time_limit and os.time() - start >= time_limit then
+ return
+ end
+ return iterator(cmd)
+ end
end
--- Returns a function closure which returns a new password with every call
@@ -248,19 +248,19 @@ end
-- @return boolean Status.
-- @return function The usernames iterator.
usernames = function(time_limit, count_limit)
- local status, iterator
+ local status, iterator
- status, iterator = usernames_raw()
- if not status then
- return false, iterator
- end
+ status, iterator = usernames_raw()
+ if not status then
+ return false, iterator
+ end
- time_limit = time_limit or timelimit()
- if not count_limit and args["unpwdb.userlimit"] then
- count_limit = tonumber(args["unpwdb.userlimit"])
- end
+ time_limit = time_limit or timelimit()
+ if not count_limit and args["unpwdb.userlimit"] then
+ count_limit = tonumber(args["unpwdb.userlimit"])
+ end
- return true, limited_iterator(iterator, time_limit, count_limit)
+ return true, limited_iterator(iterator, time_limit, count_limit)
end
--- Returns a function closure which returns a new password with every call
@@ -271,19 +271,19 @@ end
-- @return boolean Status.
-- @return function The passwords iterator.
passwords = function(time_limit, count_limit)
- local status, iterator
+ local status, iterator
- status, iterator = passwords_raw()
- if not status then
- return false, iterator
- end
+ status, iterator = passwords_raw()
+ if not status then
+ return false, iterator
+ end
- time_limit = time_limit or timelimit()
- if not count_limit and args["unpwdb.passlimit"] then
- count_limit = tonumber(args["unpwdb.passlimit"])
- end
+ time_limit = time_limit or timelimit()
+ if not count_limit and args["unpwdb.passlimit"] then
+ count_limit = tonumber(args["unpwdb.passlimit"])
+ end
- return true, limited_iterator(iterator, time_limit, count_limit)
+ return true, limited_iterator(iterator, time_limit, count_limit)
end
--- Returns a new iterator that iterates trough it's consecutive iterators,
@@ -308,7 +308,7 @@ function concat_iterators (iter1, iter2)
end
end
return iterator
- end
+end
--- Returns a new iterator that filters it's results based on the filter.
-- @param iterator Iterator that needs to be filtered
@@ -324,6 +324,6 @@ function filter_iterator (iterator, filter)
return helper(iterator(command))
end
return filter
- end
+end
return _ENV;
diff --git a/nselib/upnp.lua b/nselib/upnp.lua
index 9944f6271..354dbd89e 100644
--- a/nselib/upnp.lua
+++ b/nselib/upnp.lua
@@ -45,302 +45,302 @@ _ENV = stdnse.module("upnp", stdnse.seeall)
Util = {
- --- Compare function used for sorting IP-addresses
- --
- -- @param a table containing first item
- -- @param b table containing second item
- -- @return true if a is less than b
- ipCompare = function(a, b)
+ --- Compare function used for sorting IP-addresses
+ --
+ -- @param a table containing first item
+ -- @param b table containing second item
+ -- @return true if a is less than b
+ ipCompare = function(a, b)
return ipOps.compare_ip(a, "lt", b)
- end,
+ end,
}
Comm = {
- --- Creates a new Comm instance
- --
- -- @param host string containing the host name or ip
- -- @param port number containing the port to connect to
- -- @return o a new instance of Comm
- new = function( self, host, port )
- local o = {}
- setmetatable(o, self)
- self.__index = self
- o.host = host
- o.port = port
- o.mcast = false
- return o
- end,
+ --- Creates a new Comm instance
+ --
+ -- @param host string containing the host name or ip
+ -- @param port number containing the port to connect to
+ -- @return o a new instance of Comm
+ new = function( self, host, port )
+ local o = {}
+ setmetatable(o, self)
+ self.__index = self
+ o.host = host
+ o.port = port
+ o.mcast = false
+ return o
+ end,
- --- Connect to the server
- --
- -- @return status true on success, false on failure
- connect = function( self )
- if ( self.mcast ) then
- self.socket = nmap.new_socket("udp")
- self.socket:set_timeout(5000)
- else
- self.socket = nmap.new_socket()
- self.socket:set_timeout(5000)
- local status, err = self.socket:connect(self.host, self.port, "udp" )
- if ( not(status) ) then return false, err end
- end
+ --- Connect to the server
+ --
+ -- @return status true on success, false on failure
+ connect = function( self )
+ if ( self.mcast ) then
+ self.socket = nmap.new_socket("udp")
+ self.socket:set_timeout(5000)
+ else
+ self.socket = nmap.new_socket()
+ self.socket:set_timeout(5000)
+ local status, err = self.socket:connect(self.host, self.port, "udp" )
+ if ( not(status) ) then return false, err end
+ end
- return true
- end,
+ return true
+ end,
- --- Send the UPNP discovery request to the server
- --
- -- @return status true on success, false on failure
- sendRequest = function( self )
- local payload = strbuf.new()
+ --- Send the UPNP discovery request to the server
+ --
+ -- @return status true on success, false on failure
+ sendRequest = function( self )
+ local payload = strbuf.new()
- -- for details about the UPnP message format, see http://upnp.org/resources/documents.asp
- payload = payload .. "M-SEARCH * HTTP/1.1\r\n"
- payload = payload .. "Host:239.255.255.250:1900\r\n"
- payload = payload .. "ST:upnp:rootdevice\r\n"
- payload = payload .. "Man:\"ssdp:discover\"\r\n"
- payload = payload .. "MX:3\r\n\r\n"
+ -- for details about the UPnP message format, see http://upnp.org/resources/documents.asp
+ payload = payload .. "M-SEARCH * HTTP/1.1\r\n"
+ payload = payload .. "Host:239.255.255.250:1900\r\n"
+ payload = payload .. "ST:upnp:rootdevice\r\n"
+ payload = payload .. "Man:\"ssdp:discover\"\r\n"
+ payload = payload .. "MX:3\r\n\r\n"
- local status, err
+ local status, err
- if ( self.mcast ) then
- status, err = self.socket:sendto( self.host, self.port, strbuf.dump(payload) )
- else
- status, err = self.socket:send( strbuf.dump(payload) )
- end
+ if ( self.mcast ) then
+ status, err = self.socket:sendto( self.host, self.port, strbuf.dump(payload) )
+ else
+ status, err = self.socket:send( strbuf.dump(payload) )
+ end
- if ( not(status) ) then return false, err end
+ if ( not(status) ) then return false, err end
- return true
- end,
+ return true
+ end,
- --- Receives one or multiple UPNP responses depending on whether
- -- setBroadcast was enabled or not. The function returns the
- -- status and a response containing:
- -- * an array (table) of responses if broadcast is used
- -- * a single response if broadcast is not in use
- -- * an error message if status was false
- --
- -- @return status true on success, false on failure
- -- @return result table or string containing results or error message
- -- on failure.
- receiveResponse = function( self )
- local status, response
- local result = {}
- local host_responses = {}
+ --- Receives one or multiple UPNP responses depending on whether
+ -- setBroadcast was enabled or not. The function returns the
+ -- status and a response containing:
+ -- * an array (table) of responses if broadcast is used
+ -- * a single response if broadcast is not in use
+ -- * an error message if status was false
+ --
+ -- @return status true on success, false on failure
+ -- @return result table or string containing results or error message
+ -- on failure.
+ receiveResponse = function( self )
+ local status, response
+ local result = {}
+ local host_responses = {}
- repeat
- status, response = self.socket:receive()
- if ( not(status) and #response == 0 ) then
- return false, response
- elseif( not(status) ) then
- break
- end
+ repeat
+ status, response = self.socket:receive()
+ if ( not(status) and #response == 0 ) then
+ return false, response
+ elseif( not(status) ) then
+ break
+ end
- local status, _, _, ip, _ = self.socket:get_info()
- if ( not(status) ) then
- return false, "Failed to retrieve socket information"
- end
- if target.ALLOW_NEW_TARGETS then target.add(ip) end
+ local status, _, _, ip, _ = self.socket:get_info()
+ if ( not(status) ) then
+ return false, "Failed to retrieve socket information"
+ end
+ if target.ALLOW_NEW_TARGETS then target.add(ip) end
- if ( not(host_responses[ip]) ) then
- local status, output = self:decodeResponse( response )
- if ( not(status) ) then
- return false, "Failed to decode UPNP response"
- end
- output = { output }
- output.name = ip
- table.insert( result, output )
- host_responses[ip] = true
- end
- until ( not( self.mcast ) )
+ if ( not(host_responses[ip]) ) then
+ local status, output = self:decodeResponse( response )
+ if ( not(status) ) then
+ return false, "Failed to decode UPNP response"
+ end
+ output = { output }
+ output.name = ip
+ table.insert( result, output )
+ host_responses[ip] = true
+ end
+ until ( not( self.mcast ) )
- if ( self.mcast ) then
- table.sort(result, Util.ipCompare)
- return true, result
- end
+ if ( self.mcast ) then
+ table.sort(result, Util.ipCompare)
+ return true, result
+ end
- if ( status and #result > 0 ) then
- return true, result[1]
- else
- return false, "Received no responses"
- end
- end,
+ if ( status and #result > 0 ) then
+ return true, result[1]
+ else
+ return false, "Received no responses"
+ end
+ end,
- --- Processes a response from a upnp device
- --
- -- @param response as received over the socket
- -- @return status boolean true on success, false on failure
- -- @return response table or string suitable for output or error message if status is false
- decodeResponse = function( self, response )
- local output = {}
+ --- Processes a response from a upnp device
+ --
+ -- @param response as received over the socket
+ -- @return status boolean true on success, false on failure
+ -- @return response table or string suitable for output or error message if status is false
+ decodeResponse = function( self, response )
+ local output = {}
- if response ~= nil then
- -- We should get a response back that has contains one line for the server, and one line for the xml file location
- -- these match any combination of upper and lower case responses
- local server, location
- server = string.match(response, "[Ss][Ee][Rr][Vv][Ee][Rr]:%s*(.-)\r?\n")
- if server ~= nil then table.insert(output, "Server: " .. server ) end
- location = string.match(response, "[Ll][Oo][Cc][Aa][Tt][Ii][Oo][Nn]:%s*(.-)\r?\n")
- if location ~= nil then
- table.insert(output, "Location: " .. location )
+ if response ~= nil then
+ -- We should get a response back that has contains one line for the server, and one line for the xml file location
+ -- these match any combination of upper and lower case responses
+ local server, location
+ server = string.match(response, "[Ss][Ee][Rr][Vv][Ee][Rr]:%s*(.-)\r?\n")
+ if server ~= nil then table.insert(output, "Server: " .. server ) end
+ location = string.match(response, "[Ll][Oo][Cc][Aa][Tt][Ii][Oo][Nn]:%s*(.-)\r?\n")
+ if location ~= nil then
+ table.insert(output, "Location: " .. location )
- local v = nmap.verbosity()
+ local v = nmap.verbosity()
- -- the following check can output quite a lot of information, so we require at least one -v flag
- if v > 0 then
- local status, result = self:retrieveXML( location )
- if status then
- table.insert(output, result)
- end
- end
- end
- if #output > 0 then
- return true, output
- else
- return false, "Could not decode response"
- end
- end
- end,
+ -- the following check can output quite a lot of information, so we require at least one -v flag
+ if v > 0 then
+ local status, result = self:retrieveXML( location )
+ if status then
+ table.insert(output, result)
+ end
+ end
+ end
+ if #output > 0 then
+ return true, output
+ else
+ return false, "Could not decode response"
+ end
+ end
+ end,
- --- Retrieves the XML file that describes the UPNP device
- --
- -- @param location string containing the location of the XML file from the UPNP response
- -- @return status boolean true on success, false on failure
- -- @return response table or string suitable for output or error message if status is false
- retrieveXML = function( self, location )
- local response
- local options = {}
- options['header'] = {}
- options['header']['Accept'] = "text/xml, application/xml, text/html"
+ --- Retrieves the XML file that describes the UPNP device
+ --
+ -- @param location string containing the location of the XML file from the UPNP response
+ -- @return status boolean true on success, false on failure
+ -- @return response table or string suitable for output or error message if status is false
+ retrieveXML = function( self, location )
+ local response
+ local options = {}
+ options['header'] = {}
+ options['header']['Accept'] = "text/xml, application/xml, text/html"
- -- if we're in multicast mode, or if the user doesn't want us to override the IP address,
- -- just use the HTTP library to grab the XML file
- if ( self.mcast or ( not self.override ) ) then
- response = http.get_url( location, options )
- else
- -- otherwise, split the location into an IP address, port, and path name for the xml file
- local xhost, xport, xfile
- xhost = string.match(location, "http://(.-)/")
- -- check to see if the host portion of the location specifies a port
- -- if not, use port 80 as a standard web server port
- if xhost ~= nil and string.match(xhost, ":") then
- xport = string.match(xhost, ":(.*)")
- xhost = string.match(xhost, "(.*):")
- end
+ -- if we're in multicast mode, or if the user doesn't want us to override the IP address,
+ -- just use the HTTP library to grab the XML file
+ if ( self.mcast or ( not self.override ) ) then
+ response = http.get_url( location, options )
+ else
+ -- otherwise, split the location into an IP address, port, and path name for the xml file
+ local xhost, xport, xfile
+ xhost = string.match(location, "http://(.-)/")
+ -- check to see if the host portion of the location specifies a port
+ -- if not, use port 80 as a standard web server port
+ if xhost ~= nil and string.match(xhost, ":") then
+ xport = string.match(xhost, ":(.*)")
+ xhost = string.match(xhost, "(.*):")
+ end
- -- check to see if the IP address returned matches the IP address we scanned
- if xhost ~= self.host.ip then
- stdnse.print_debug("IP addresses did not match! Found %s, using %s instead.", xhost, self.host.ip)
- xhost = self.host.ip
- end
+ -- check to see if the IP address returned matches the IP address we scanned
+ if xhost ~= self.host.ip then
+ stdnse.print_debug("IP addresses did not match! Found %s, using %s instead.", xhost, self.host.ip)
+ xhost = self.host.ip
+ end
- if xport == nil then
- xport = 80
- end
+ if xport == nil then
+ xport = 80
+ end
- -- extract the path name from the location field, but strip off the \r that HTTP servers return
- xfile = string.match(location, "http://.-(/.-)\013")
- if xfile ~= nil then
- response = http.get( xhost, xport, xfile, options )
- end
- end
+ -- extract the path name from the location field, but strip off the \r that HTTP servers return
+ xfile = string.match(location, "http://.-(/.-)\013")
+ if xfile ~= nil then
+ response = http.get( xhost, xport, xfile, options )
+ end
+ end
- if response ~= nil then
- local output = {}
+ if response ~= nil then
+ local output = {}
- -- extract information about the webserver that is handling responses for the UPnP system
- local webserver = response['header']['server']
- if webserver ~= nil then table.insert(output, "Webserver: " .. webserver) end
+ -- extract information about the webserver that is handling responses for the UPnP system
+ local webserver = response['header']['server']
+ if webserver ~= nil then table.insert(output, "Webserver: " .. webserver) end
- -- the schema for UPnP includes a number of entries, which can a number of interesting fields
- for device in string.gmatch(response['body'], "(.-)") do
- local fn, mnf, mdl, nm, ver
+ -- the schema for UPnP includes a number of entries, which can a number of interesting fields
+ for device in string.gmatch(response['body'], "(.-)") do
+ local fn, mnf, mdl, nm, ver
- fn = string.match(device, "(.-)")
- mnf = string.match(device, "(.-)")
- mdl = string.match(device, "(.-)")
- nm = string.match(device, "(.-)")
- ver = string.match(device, "(.-)")
+ fn = string.match(device, "(.-)")
+ mnf = string.match(device, "(.-)")
+ mdl = string.match(device, "(.-)")
+ nm = string.match(device, "(.-)")
+ ver = string.match(device, "(.-)")
- if fn ~= nil then table.insert(output, "Name: " .. fn) end
- if mnf ~= nil then table.insert(output,"Manufacturer: " .. mnf) end
- if mdl ~= nil then table.insert(output,"Model Descr: " .. mdl) end
- if nm ~= nil then table.insert(output,"Model Name: " .. nm) end
- if ver ~= nil then table.insert(output,"Model Version: " .. ver) end
- end
- return true, output
- else
- return false, "Could not retrieve XML file"
- end
- end,
+ if fn ~= nil then table.insert(output, "Name: " .. fn) end
+ if mnf ~= nil then table.insert(output,"Manufacturer: " .. mnf) end
+ if mdl ~= nil then table.insert(output,"Model Descr: " .. mdl) end
+ if nm ~= nil then table.insert(output,"Model Name: " .. nm) end
+ if ver ~= nil then table.insert(output,"Model Version: " .. ver) end
+ end
+ return true, output
+ else
+ return false, "Could not retrieve XML file"
+ end
+ end,
- --- Enables or disables multicast support
- --
- -- @param mcast boolean true if multicast is to be used, false otherwise
- setMulticast = function( self, mcast )
- assert( type(mcast)=="boolean", "mcast has to be either true or false")
- self.mcast = mcast
- local family = nmap.address_family()
- self.host = (family=="inet6" and "FF02::C" or "239.255.255.250")
- self.port = 1900
- end,
+ --- Enables or disables multicast support
+ --
+ -- @param mcast boolean true if multicast is to be used, false otherwise
+ setMulticast = function( self, mcast )
+ assert( type(mcast)=="boolean", "mcast has to be either true or false")
+ self.mcast = mcast
+ local family = nmap.address_family()
+ self.host = (family=="inet6" and "FF02::C" or "239.255.255.250")
+ self.port = 1900
+ end,
- --- Closes the socket
- close = function( self ) self.socket:close() end
+ --- Closes the socket
+ close = function( self ) self.socket:close() end
}
Helper = {
- --- Creates a new helper instance
- --
- -- @param host string containing the host name or ip
- -- @param port number containing the port to connect to
- -- @return o a new instance of Helper
- new = function( self, host, port )
- local o = {}
- setmetatable(o, self)
- self.__index = self
- o.comm = Comm:new( host, port )
- return o
- end,
+ --- Creates a new helper instance
+ --
+ -- @param host string containing the host name or ip
+ -- @param port number containing the port to connect to
+ -- @return o a new instance of Helper
+ new = function( self, host, port )
+ local o = {}
+ setmetatable(o, self)
+ self.__index = self
+ o.comm = Comm:new( host, port )
+ return o
+ end,
- --- Enables or disables multicast support
- --
- -- @param mcast boolean true if multicast is to be used, false otherwise
- setMulticast = function( self, mcast ) self.comm:setMulticast(mcast) end,
+ --- Enables or disables multicast support
+ --
+ -- @param mcast boolean true if multicast is to be used, false otherwise
+ setMulticast = function( self, mcast ) self.comm:setMulticast(mcast) end,
- --- Enables or disables whether the script will override the IP address is the Location URL
- --
- -- @param override boolean true if override is to be enabled, false otherwise
- setOverride = function( self, override )
- assert( type(override)=="boolean", "override has to be either true or false")
- self.comm.override = override
- end,
+ --- Enables or disables whether the script will override the IP address is the Location URL
+ --
+ -- @param override boolean true if override is to be enabled, false otherwise
+ setOverride = function( self, override )
+ assert( type(override)=="boolean", "override has to be either true or false")
+ self.comm.override = override
+ end,
- --- Sends a UPnP queries and collects a single or multiple responses
- --
- -- @return status true on success, false on failure
- -- @return result table or string containing results or error message
- -- on failure.
- queryServices = function( self )
- local status, err = self.comm:connect()
- local response
+ --- Sends a UPnP queries and collects a single or multiple responses
+ --
+ -- @return status true on success, false on failure
+ -- @return result table or string containing results or error message
+ -- on failure.
+ queryServices = function( self )
+ local status, err = self.comm:connect()
+ local response
- if ( not(status) ) then return false, err end
+ if ( not(status) ) then return false, err end
- status, err = self.comm:sendRequest()
- if ( not(status) ) then return false, err end
+ status, err = self.comm:sendRequest()
+ if ( not(status) ) then return false, err end
- status, response = self.comm:receiveResponse()
- self.comm:close()
+ status, response = self.comm:receiveResponse()
+ self.comm:close()
- return status, response
- end,
+ return status, response
+ end,
}
diff --git a/nselib/url.lua b/nselib/url.lua
index a14b0a4e0..fdb4899c8 100644
--- a/nselib/url.lua
+++ b/nselib/url.lua
@@ -43,21 +43,21 @@ _ENV = stdnse.module("url", stdnse.seeall)
_VERSION = "URL 1.0"
- --[[ Internal functions --]]
+--[[ Internal functions --]]
local function make_set(t)
- local s = {}
- for i,v in base.ipairs(t) do
- s[t[i]] = 1
- end
- return s
+ local s = {}
+ for i,v in base.ipairs(t) do
+ s[t[i]] = 1
+ end
+ return s
end
-- these are allowed withing a path segment, along with alphanum
-- other characters must be escaped
local segment_set = make_set {
- "-", "_", ".", "!", "~", "*", "'", "(",
- ")", ":", "@", "&", "=", "+", "$", ",",
+ "-", "_", ".", "!", "~", "*", "'", "(",
+ ")", ":", "@", "&", "=", "+", "$", ",",
}
---
@@ -66,10 +66,10 @@ local segment_set = make_set {
-- @param s Binary string to be encoded.
-- @return Escaped representation of string.
local function protect_segment(s)
- return string.gsub(s, "([^A-Za-z0-9_])", function (c)
- if segment_set[c] then return c
- else return string.format("%%%02x", string.byte(c)) end
- end)
+ return string.gsub(s, "([^A-Za-z0-9_])", function (c)
+ if segment_set[c] then return c
+ else return string.format("%%%02x", string.byte(c)) end
+ end)
end
---
@@ -79,28 +79,28 @@ end
-- @return The corresponding absolute path.
-----------------------------------------------------------------------------
local function absolute_path(base_path, relative_path)
- if string.sub(relative_path, 1, 1) == "/" then return relative_path end
- local path = string.gsub(base_path, "[^/]*$", "")
- path = path .. relative_path
- path = string.gsub(path, "([^/]*%./)", function (s)
- if s ~= "./" then return s else return "" end
+ if string.sub(relative_path, 1, 1) == "/" then return relative_path end
+ local path = string.gsub(base_path, "[^/]*$", "")
+ path = path .. relative_path
+ path = string.gsub(path, "([^/]*%./)", function (s)
+ if s ~= "./" then return s else return "" end
+ end)
+ path = string.gsub(path, "/%.$", "/")
+ local reduced
+ while reduced ~= path do
+ reduced = path
+ path = string.gsub(reduced, "([^/]*/%.%./)", function (s)
+ if s ~= "../../" then return "" else return s end
end)
- path = string.gsub(path, "/%.$", "/")
- local reduced
- while reduced ~= path do
- reduced = path
- path = string.gsub(reduced, "([^/]*/%.%./)", function (s)
- if s ~= "../../" then return "" else return s end
- end)
- end
- path = string.gsub(reduced, "([^/]*/%.%.)$", function (s)
- if s ~= "../.." then return "" else return s end
- end)
- return path
+ end
+ path = string.gsub(reduced, "([^/]*/%.%.)$", function (s)
+ if s ~= "../.." then return "" else return s end
+ end)
+ return path
end
- --[[ External functions --]]
+--[[ External functions --]]
---
-- Encodes a string into its escaped hexadecimal representation.
@@ -108,9 +108,9 @@ end
-- @return Escaped representation of string.
-----------------------------------------------------------------------------
function escape(s)
- return string.gsub(s, "([^A-Za-z0-9_])", function(c)
- return string.format("%%%02x", string.byte(c))
- end)
+ return string.gsub(s, "([^A-Za-z0-9_])", function(c)
+ return string.format("%%%02x", string.byte(c))
+ end)
end
@@ -120,9 +120,9 @@ end
-- @return Decoded string.
-----------------------------------------------------------------------------
function unescape(s)
- return string.gsub(s, "%%(%x%x)", function(hex)
- return string.char(base.tonumber(hex, 16))
- end)
+ return string.gsub(s, "%%(%x%x)", function(hex)
+ return string.char(base.tonumber(hex, 16))
+ end)
end
@@ -149,49 +149,49 @@ end
-- query, and fragment.
-----------------------------------------------------------------------------
function parse(url, default)
- -- initialize default parameters
- local parsed = {}
- for i,v in base.pairs(default or parsed) do parsed[i] = v end
- -- remove whitespace
- -- url = string.gsub(url, "%s", "")
- -- get fragment
- url = string.gsub(url, "#(.*)$", function(f)
- parsed.fragment = f
- return ""
- end)
- -- get scheme. Lower-case according to RFC 3986 section 3.1.
- url = string.gsub(url, "^([%w][%w%+%-%.]*)%:",
- function(s) parsed.scheme = string.lower(s); return "" end)
- -- get authority
- url = string.gsub(url, "^//([^/]*)", function(n)
- parsed.authority = n
- return ""
- end)
- -- get query stringing
- url = string.gsub(url, "%?(.*)", function(q)
- parsed.query = q
- return ""
- end)
- -- get params
- url = string.gsub(url, "%;(.*)", function(p)
- parsed.params = p
- return ""
- end)
- -- path is whatever was left
- parsed.path = url
- local authority = parsed.authority
- if not authority then return parsed end
- authority = string.gsub(authority,"^([^@]*)@",
- function(u) parsed.userinfo = u; return "" end)
- authority = string.gsub(authority, ":([0-9]*)$",
- function(p) if p ~= "" then parsed.port = p end; return "" end)
- if authority ~= "" then parsed.host = authority end
- local userinfo = parsed.userinfo
- if not userinfo then return parsed end
- userinfo = string.gsub(userinfo, ":([^:]*)$",
- function(p) parsed.password = p; return "" end)
- parsed.user = userinfo
- return parsed
+ -- initialize default parameters
+ local parsed = {}
+ for i,v in base.pairs(default or parsed) do parsed[i] = v end
+ -- remove whitespace
+ -- url = string.gsub(url, "%s", "")
+ -- get fragment
+ url = string.gsub(url, "#(.*)$", function(f)
+ parsed.fragment = f
+ return ""
+ end)
+ -- get scheme. Lower-case according to RFC 3986 section 3.1.
+ url = string.gsub(url, "^([%w][%w%+%-%.]*)%:",
+ function(s) parsed.scheme = string.lower(s); return "" end)
+ -- get authority
+ url = string.gsub(url, "^//([^/]*)", function(n)
+ parsed.authority = n
+ return ""
+ end)
+ -- get query stringing
+ url = string.gsub(url, "%?(.*)", function(q)
+ parsed.query = q
+ return ""
+ end)
+ -- get params
+ url = string.gsub(url, "%;(.*)", function(p)
+ parsed.params = p
+ return ""
+ end)
+ -- path is whatever was left
+ parsed.path = url
+ local authority = parsed.authority
+ if not authority then return parsed end
+ authority = string.gsub(authority,"^([^@]*)@",
+ function(u) parsed.userinfo = u; return "" end)
+ authority = string.gsub(authority, ":([0-9]*)$",
+ function(p) if p ~= "" then parsed.port = p end; return "" end)
+ if authority ~= "" then parsed.host = authority end
+ local userinfo = parsed.userinfo
+ if not userinfo then return parsed end
+ userinfo = string.gsub(userinfo, ":([^:]*)$",
+ function(p) parsed.password = p; return "" end)
+ parsed.user = userinfo
+ return parsed
end
---
@@ -202,28 +202,28 @@ end
-- @return A string with the corresponding URL.
-----------------------------------------------------------------------------
function build(parsed)
- local ppath = parse_path(parsed.path or "")
- local url = build_path(ppath)
- if parsed.params then url = url .. ";" .. parsed.params end
- if parsed.query then url = url .. "?" .. parsed.query end
- local authority = parsed.authority
- if parsed.host then
- authority = parsed.host
- if parsed.port then authority = authority .. ":" .. parsed.port end
- local userinfo = parsed.userinfo
- if parsed.user then
- userinfo = parsed.user
- if parsed.password then
- userinfo = userinfo .. ":" .. parsed.password
- end
- end
- if userinfo then authority = userinfo .. "@" .. authority end
- end
- if authority then url = "//" .. authority .. url end
- if parsed.scheme then url = parsed.scheme .. ":" .. url end
- if parsed.fragment then url = url .. "#" .. parsed.fragment end
- -- url = string.gsub(url, "%s", "")
- return url
+ local ppath = parse_path(parsed.path or "")
+ local url = build_path(ppath)
+ if parsed.params then url = url .. ";" .. parsed.params end
+ if parsed.query then url = url .. "?" .. parsed.query end
+ local authority = parsed.authority
+ if parsed.host then
+ authority = parsed.host
+ if parsed.port then authority = authority .. ":" .. parsed.port end
+ local userinfo = parsed.userinfo
+ if parsed.user then
+ userinfo = parsed.user
+ if parsed.password then
+ userinfo = userinfo .. ":" .. parsed.password
+ end
+ end
+ if userinfo then authority = userinfo .. "@" .. authority end
+ end
+ if authority then url = "//" .. authority .. url end
+ if parsed.scheme then url = parsed.scheme .. ":" .. url end
+ if parsed.fragment then url = url .. "#" .. parsed.fragment end
+ -- url = string.gsub(url, "%s", "")
+ return url
end
---
@@ -233,36 +233,36 @@ end
-- @return The corresponding absolute URL.
-----------------------------------------------------------------------------
function absolute(base_url, relative_url)
- local base_parsed;
- if type(base_url) == "table" then
- base_parsed = base_url
- base_url = build(base_parsed)
- else
- base_parsed = parse(base_url)
- end
- local relative_parsed = parse(relative_url)
- if not base_parsed then return relative_url
- elseif not relative_parsed then return base_url
- elseif relative_parsed.scheme then return relative_url
- else
- relative_parsed.scheme = base_parsed.scheme
- if not relative_parsed.authority then
- relative_parsed.authority = base_parsed.authority
- if not relative_parsed.path then
- relative_parsed.path = base_parsed.path
- if not relative_parsed.params then
- relative_parsed.params = base_parsed.params
- if not relative_parsed.query then
- relative_parsed.query = base_parsed.query
- end
- end
- else
- relative_parsed.path = absolute_path(base_parsed.path or "",
- relative_parsed.path)
- end
+ local base_parsed;
+ if type(base_url) == "table" then
+ base_parsed = base_url
+ base_url = build(base_parsed)
+ else
+ base_parsed = parse(base_url)
+ end
+ local relative_parsed = parse(relative_url)
+ if not base_parsed then return relative_url
+ elseif not relative_parsed then return base_url
+ elseif relative_parsed.scheme then return relative_url
+ else
+ relative_parsed.scheme = base_parsed.scheme
+ if not relative_parsed.authority then
+ relative_parsed.authority = base_parsed.authority
+ if not relative_parsed.path then
+ relative_parsed.path = base_parsed.path
+ if not relative_parsed.params then
+ relative_parsed.params = base_parsed.params
+ if not relative_parsed.query then
+ relative_parsed.query = base_parsed.query
+ end
end
- return build(relative_parsed)
+ else
+ relative_parsed.path = absolute_path(base_parsed.path or "",
+ relative_parsed.path)
+ end
end
+ return build(relative_parsed)
+ end
end
---
@@ -271,16 +271,16 @@ end
-- @return A table with one entry per segment.
-----------------------------------------------------------------------------
function parse_path(path)
- local parsed = {}
- path = path or ""
- --path = string.gsub(path, "%s", "")
- string.gsub(path, "([^/]+)", function (s) table.insert(parsed, s) end)
- for i, v in ipairs(parsed) do
- parsed[i] = unescape(v)
- end
- if string.sub(path, 1, 1) == "/" then parsed.is_absolute = 1 end
- if string.sub(path, -1, -1) == "/" then parsed.is_directory = 1 end
- return parsed
+ local parsed = {}
+ path = path or ""
+ --path = string.gsub(path, "%s", "")
+ string.gsub(path, "([^/]+)", function (s) table.insert(parsed, s) end)
+ for i, v in ipairs(parsed) do
+ parsed[i] = unescape(v)
+ end
+ if string.sub(path, 1, 1) == "/" then parsed.is_absolute = 1 end
+ if string.sub(path, -1, -1) == "/" then parsed.is_directory = 1 end
+ return parsed
end
---
@@ -290,29 +290,29 @@ end
-- @return The corresponding path string
-----------------------------------------------------------------------------
function build_path(parsed, unsafe)
- local path = ""
- local n = #parsed
- if unsafe then
- for i = 1, n-1 do
- path = path .. parsed[i]
- path = path .. "/"
- end
- if n > 0 then
- path = path .. parsed[n]
- if parsed.is_directory then path = path .. "/" end
- end
- else
- for i = 1, n-1 do
- path = path .. protect_segment(parsed[i])
- path = path .. "/"
- end
- if n > 0 then
- path = path .. protect_segment(parsed[n])
- if parsed.is_directory then path = path .. "/" end
- end
- end
- if parsed.is_absolute then path = "/" .. path end
- return path
+ local path = ""
+ local n = #parsed
+ if unsafe then
+ for i = 1, n-1 do
+ path = path .. parsed[i]
+ path = path .. "/"
+ end
+ if n > 0 then
+ path = path .. parsed[n]
+ if parsed.is_directory then path = path .. "/" end
+ end
+ else
+ for i = 1, n-1 do
+ path = path .. protect_segment(parsed[i])
+ path = path .. "/"
+ end
+ if n > 0 then
+ path = path .. protect_segment(parsed[n])
+ if parsed.is_directory then path = path .. "/" end
+ end
+ end
+ if parsed.is_absolute then path = "/" .. path end
+ return path
end
---
@@ -327,31 +327,31 @@ end
-- table["name"] = value.
-----------------------------------------------------------------------------
function parse_query(query)
- local parsed = {}
- local pos = 0
+ local parsed = {}
+ local pos = 0
- query = string.gsub(query, "&", "&")
- query = string.gsub(query, "<", "<")
- query = string.gsub(query, ">", ">")
+ query = string.gsub(query, "&", "&")
+ query = string.gsub(query, "<", "<")
+ query = string.gsub(query, ">", ">")
- local function ginsert(qstr)
- local first, last = string.find(qstr, "=")
- if first then
- parsed[string.sub(qstr, 0, first-1)] = string.sub(qstr, first+1)
- end
- end
+ local function ginsert(qstr)
+ local first, last = string.find(qstr, "=")
+ if first then
+ parsed[string.sub(qstr, 0, first-1)] = string.sub(qstr, first+1)
+ end
+ end
- while true do
- local first, last = string.find(query, "&", pos)
- if first then
- ginsert(string.sub(query, pos, first-1));
- pos = last+1
- else
- ginsert(string.sub(query, pos));
- break;
- end
- end
- return parsed
+ while true do
+ local first, last = string.find(query, "&", pos)
+ if first then
+ ginsert(string.sub(query, pos, first-1));
+ pos = last+1
+ else
+ ginsert(string.sub(query, pos));
+ break;
+ end
+ end
+ return parsed
end
---
@@ -363,12 +363,12 @@ end
-- @return A query string (like "name=value2&name=value2").
-----------------------------------------------------------------------------
function build_query(query)
- local qstr = ""
+ local qstr = ""
- for i,v in pairs(query) do
- qstr = qstr .. i .. '=' .. v .. '&'
- end
- return string.sub(qstr, 0, #qstr-1)
+ for i,v in pairs(query) do
+ qstr = qstr .. i .. '=' .. v .. '&'
+ end
+ return string.sub(qstr, 0, #qstr-1)
end
return _ENV;
diff --git a/nselib/versant.lua b/nselib/versant.lua
index c51416038..da9580369 100644
--- a/nselib/versant.lua
+++ b/nselib/versant.lua
@@ -18,270 +18,270 @@ _ENV = stdnse.module("versant", stdnse.seeall)
Versant = {
- -- fallback to these constants when version and user are not given
- USER = "nmap",
- VERSION = "8.0.2",
+ -- fallback to these constants when version and user are not given
+ USER = "nmap",
+ VERSION = "8.0.2",
- -- Creates an instance of the Versant class
- -- @param host table
- -- @param port table
- -- @return o new instance of Versant
- new = function(self, host, port)
- local o = { host = host, port = port, socket = nmap.new_socket() }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates an instance of the Versant class
+ -- @param host table
+ -- @param port table
+ -- @return o new instance of Versant
+ new = function(self, host, port)
+ local o = { host = host, port = port, socket = nmap.new_socket() }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Connects a socket to the Versant server
- -- @return status true on success, false on failure
- -- @return err string containing the error message if status is false
- connect = function(self)
- return self.socket:connect(self.host, self.port)
- end,
+ -- Connects a socket to the Versant server
+ -- @return status true on success, false on failure
+ -- @return err string containing the error message if status is false
+ connect = function(self)
+ return self.socket:connect(self.host, self.port)
+ end,
- -- Closes the socket
- -- @return status true on success, false on failure
- -- @return err string containing the error message if status is false
- close = function(self)
- return self.socket:close()
- end,
+ -- Closes the socket
+ -- @return status true on success, false on failure
+ -- @return err string containing the error message if status is false
+ close = function(self)
+ return self.socket:close()
+ end,
- -- Sends command to the server
- -- @param cmd string containing the command to run
- -- @param arg string containing any arguments
- -- @param user [optional] string containing the user name
- -- @param ver [optional] string containing the version number
- -- @return status true on success, false on failure
- -- @return data opaque string containing the response
- sendCommand = function(self, cmd, arg, user, ver)
+ -- Sends command to the server
+ -- @param cmd string containing the command to run
+ -- @param arg string containing any arguments
+ -- @param user [optional] string containing the user name
+ -- @param ver [optional] string containing the version number
+ -- @return status true on success, false on failure
+ -- @return data opaque string containing the response
+ sendCommand = function(self, cmd, arg, user, ver)
- user = user or Versant.USER
- ver = ver or Versant.VERSION
- arg = arg or ""
+ user = user or Versant.USER
+ ver = ver or Versant.VERSION
+ arg = arg or ""
- local data = bin.pack("H", "000100000000000000020002000000010000000000000000000000000000000000010000")
- data = data .. cmd .. "\0" .. user .. "\0" .. ver .. "\0"
- -- align to even 4 bytes
- if ( #data % 4 ~= 0 ) then
- for i=1, ( 4 - (#data % 4)) do
- data = data .. "\0"
- end
- end
+ local data = bin.pack("H", "000100000000000000020002000000010000000000000000000000000000000000010000")
+ data = data .. cmd .. "\0" .. user .. "\0" .. ver .. "\0"
+ -- align to even 4 bytes
+ if ( #data % 4 ~= 0 ) then
+ for i=1, ( 4 - (#data % 4)) do
+ data = data .. "\0"
+ end
+ end
- data = data .. bin.pack("H", "0000000b000001000000000000000000")
- data = data .. ("%s:%d\0"):format(self.host.ip, self.port.number)
- data = data .. "\0\0\0\0\0\0\0\0\0\0" .. arg
+ data = data .. bin.pack("H", "0000000b000001000000000000000000")
+ data = data .. ("%s:%d\0"):format(self.host.ip, self.port.number)
+ data = data .. "\0\0\0\0\0\0\0\0\0\0" .. arg
- while ( #data < 2048 ) do
- data = data .. "\0"
- end
+ while ( #data < 2048 ) do
+ data = data .. "\0"
+ end
- local status, err = self.socket:send(data)
- if ( not(status) ) then
- return false, "Failed to send request to server"
- end
+ local status, err = self.socket:send(data)
+ if ( not(status) ) then
+ return false, "Failed to send request to server"
+ end
- local status, data = self.socket:receive_buf(match.numbytes(2048), true)
- if ( not(status) ) then
- return false, "Failed to read response from server"
- end
+ local status, data = self.socket:receive_buf(match.numbytes(2048), true)
+ if ( not(status) ) then
+ return false, "Failed to read response from server"
+ end
- return status, data
- end,
+ return status, data
+ end,
- -- Get database node information
- -- @return status true on success, false on failure
- -- @return result table containing an entry for each database. Each entry
- -- contains a table with the following fields:
- -- name - the database name
- -- owner - the database owner
- -- created - the date when the database was created
- -- version - the database version
- getNodeInfo = function(self)
- local status, data = self:sendCommand("o_getnodeinfo", "-nodeinfo")
- if ( not(status) ) then
- return false, data
- end
+ -- Get database node information
+ -- @return status true on success, false on failure
+ -- @return result table containing an entry for each database. Each entry
+ -- contains a table with the following fields:
+ -- name - the database name
+ -- owner - the database owner
+ -- created - the date when the database was created
+ -- version - the database version
+ getNodeInfo = function(self)
+ local status, data = self:sendCommand("o_getnodeinfo", "-nodeinfo")
+ if ( not(status) ) then
+ return false, data
+ end
- status, data = self.socket:receive_buf(match.numbytes(4), true)
- if ( not(status) ) then
- return false, "Failed to read response from server"
- end
+ status, data = self.socket:receive_buf(match.numbytes(4), true)
+ if ( not(status) ) then
+ return false, "Failed to read response from server"
+ end
- local _, db_count = bin.unpack(">I", data)
- if ( db_count == 0 ) then
- return false, "Database count was zero"
- end
+ local _, db_count = bin.unpack(">I", data)
+ if ( db_count == 0 ) then
+ return false, "Database count was zero"
+ end
- status, data = self.socket:receive_buf(match.numbytes(4), true)
- if ( not(status) ) then
- return false, "Failed to read response from server"
- end
+ status, data = self.socket:receive_buf(match.numbytes(4), true)
+ if ( not(status) ) then
+ return false, "Failed to read response from server"
+ end
- local _, buf_size = bin.unpack(">I", data)
- local dbs = {}
+ local _, buf_size = bin.unpack(">I", data)
+ local dbs = {}
- for i=1, db_count do
- status, data = self.socket:receive_buf(match.numbytes(buf_size), true)
- local _, db = nil, {}
+ for i=1, db_count do
+ status, data = self.socket:receive_buf(match.numbytes(buf_size), true)
+ local _, db = nil, {}
- _, db.name = bin.unpack("z", data, 23)
- _, db.owner = bin.unpack("z", data, 599)
- _, db.created= bin.unpack("z", data, 631)
- _, db.version= bin.unpack("z", data, 663)
+ _, db.name = bin.unpack("z", data, 23)
+ _, db.owner = bin.unpack("z", data, 599)
+ _, db.created= bin.unpack("z", data, 631)
+ _, db.version= bin.unpack("z", data, 663)
- -- remove trailing line-feed
- db.created = db.created:match("^(.-)\n*$")
+ -- remove trailing line-feed
+ db.created = db.created:match("^(.-)\n*$")
- table.insert(dbs, db)
- end
- return true, dbs
- end,
+ table.insert(dbs, db)
+ end
+ return true, dbs
+ end,
- -- Gets the database OBE port, this port is dynamically allocated once this
- -- command completes.
- --
- -- @return status true on success, false on failure
- -- @return port table containing the OBE port
- getObePort = function(self)
+ -- Gets the database OBE port, this port is dynamically allocated once this
+ -- command completes.
+ --
+ -- @return status true on success, false on failure
+ -- @return port table containing the OBE port
+ getObePort = function(self)
- local status, data = self:sendCommand("o_oscp", "-utility")
- if ( not(status) ) then
- return false, data
- end
+ local status, data = self:sendCommand("o_oscp", "-utility")
+ if ( not(status) ) then
+ return false, data
+ end
- status, data = self.socket:receive_buf(match.numbytes(256), true)
- if ( not(status) ) then
- return false, "Failed to read response from server"
- end
+ status, data = self.socket:receive_buf(match.numbytes(256), true)
+ if ( not(status) ) then
+ return false, "Failed to read response from server"
+ end
- local pos, success = bin.unpack(">I", data)
- if ( success ~= 0 ) then
- return false, "Response contained invalid data"
- end
+ local pos, success = bin.unpack(">I", data)
+ if ( success ~= 0 ) then
+ return false, "Response contained invalid data"
+ end
- local port = { protocol = "tcp" }
- pos, port.number = bin.unpack(">S", data, pos)
+ local port = { protocol = "tcp" }
+ pos, port.number = bin.unpack(">S", data, pos)
- return true, port
- end,
+ return true, port
+ end,
- -- Get's the XML license file from the database
- -- @return status true on success, false on failure
- -- @return data string containing the XML license file
- getLicense = function(self)
+ -- Get's the XML license file from the database
+ -- @return status true on success, false on failure
+ -- @return data string containing the XML license file
+ getLicense = function(self)
- local status, data = self:sendCommand("o_licfile", "-license")
- if ( not(status) ) then
- return false, data
- end
+ local status, data = self:sendCommand("o_licfile", "-license")
+ if ( not(status) ) then
+ return false, data
+ end
- status, data = self.socket:receive_buf(match.numbytes(4), true)
- if ( not(status) ) then
- return false, "Failed to read response from server"
- end
+ status, data = self.socket:receive_buf(match.numbytes(4), true)
+ if ( not(status) ) then
+ return false, "Failed to read response from server"
+ end
- local _, len = bin.unpack(">I", data)
- if ( len == 0 ) then
- return false, "Failed to retrieve license file"
- end
+ local _, len = bin.unpack(">I", data)
+ if ( len == 0 ) then
+ return false, "Failed to retrieve license file"
+ end
- status, data = self.socket:receive_buf(match.numbytes(len), true)
- if ( not(status) ) then
- return false, "Failed to read response from server"
- end
+ status, data = self.socket:receive_buf(match.numbytes(len), true)
+ if ( not(status) ) then
+ return false, "Failed to read response from server"
+ end
- return true, data
- end,
+ return true, data
+ end,
- -- Gets the TCP port for a given database
- -- @param db string containing the database name
- -- @return status true on success, false on failure
- -- @return port table containing the database port
- getDbPort = function(self, db)
- local status, data = self:sendCommand(db, "")
- if ( not(status) ) then
- return false, data
- end
+ -- Gets the TCP port for a given database
+ -- @param db string containing the database name
+ -- @return status true on success, false on failure
+ -- @return port table containing the database port
+ getDbPort = function(self, db)
+ local status, data = self:sendCommand(db, "")
+ if ( not(status) ) then
+ return false, data
+ end
- if ( not(status) ) then
- return false, "Failed to connect to database"
- end
+ if ( not(status) ) then
+ return false, "Failed to connect to database"
+ end
- local _, port = nil, { protocol = "tcp" }
- _, port.number = bin.unpack(">I", data, 27)
- if ( port == 0 ) then
- return false, "Failed to determine database port"
- end
- return true, port
- end,
+ local _, port = nil, { protocol = "tcp" }
+ _, port.number = bin.unpack(">I", data, 27)
+ if ( port == 0 ) then
+ return false, "Failed to determine database port"
+ end
+ return true, port
+ end,
}
Versant.OBE = {
- -- Creates a new versant OBE instance
- -- @param host table
- -- @param port table
- -- @return o new instance of Versant OBE
- new = function(self, host, port)
- local o = { host = host, port = port, socket = nmap.new_socket() }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new versant OBE instance
+ -- @param host table
+ -- @param port table
+ -- @return o new instance of Versant OBE
+ new = function(self, host, port)
+ local o = { host = host, port = port, socket = nmap.new_socket() }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Connects a socket to the Versant server
- -- @return status true on success, false on failure
- -- @return err string containing the error message if status is false
- connect = function(self)
- return self.socket:connect(self.host, self.port)
- end,
+ -- Connects a socket to the Versant server
+ -- @return status true on success, false on failure
+ -- @return err string containing the error message if status is false
+ connect = function(self)
+ return self.socket:connect(self.host, self.port)
+ end,
- -- Closes the socket
- -- @return status true on success, false on failure
- -- @return err string containing the error message if status is false
- close = function(self)
- return self.socket:close()
- end,
+ -- Closes the socket
+ -- @return status true on success, false on failure
+ -- @return err string containing the error message if status is false
+ close = function(self)
+ return self.socket:close()
+ end,
- -- Get database information including file paths and hostname
- -- @return status true on success false on failure
- -- @return result table containing the fields:
- -- root_path - the database root directory
- -- db_path - the database directory
- -- lib_path - the library directory
- -- hostname - the database host name
- getVODInfo = function(self)
- local data = bin.pack("H", "1002005d00000000000100000000000d000000000000000000000000")
- data = data .. "-noprint -i "
+ -- Get database information including file paths and hostname
+ -- @return status true on success false on failure
+ -- @return result table containing the fields:
+ -- root_path - the database root directory
+ -- db_path - the database directory
+ -- lib_path - the library directory
+ -- hostname - the database host name
+ getVODInfo = function(self)
+ local data = bin.pack("H", "1002005d00000000000100000000000d000000000000000000000000")
+ data = data .. "-noprint -i "
- while( #data < 256 ) do
- data = data .. "\0"
- end
+ while( #data < 256 ) do
+ data = data .. "\0"
+ end
- self.socket:send(data)
- local status, data = self.socket:receive_buf(match.numbytes(256), true)
- if ( not(status) ) then
- return false, "Failed to read response from server"
- end
+ self.socket:send(data)
+ local status, data = self.socket:receive_buf(match.numbytes(256), true)
+ if ( not(status) ) then
+ return false, "Failed to read response from server"
+ end
- local pos, len = bin.unpack(">I", data, 13)
- status, data = self.socket:receive_buf(match.numbytes(len), true)
- if ( not(status) ) then
- return false, "Failed to read response from server"
- end
+ local pos, len = bin.unpack(">I", data, 13)
+ status, data = self.socket:receive_buf(match.numbytes(len), true)
+ if ( not(status) ) then
+ return false, "Failed to read response from server"
+ end
- local result, pos, offset = {}, 1, 13
- pos, result.version = bin.unpack("z", data)
+ local result, pos, offset = {}, 1, 13
+ pos, result.version = bin.unpack("z", data)
- for _, item in ipairs({"root_path", "db_path", "lib_path", "hostname"}) do
- pos, result[item] = bin.unpack("z", data, offset)
- offset = offset + 256
- end
- return true, result
- end,
+ for _, item in ipairs({"root_path", "db_path", "lib_path", "hostname"}) do
+ pos, result[item] = bin.unpack("z", data, offset)
+ offset = offset + 256
+ end
+ return true, result
+ end,
}
return _ENV;
diff --git a/nselib/vnc.lua b/nselib/vnc.lua
index 3af06cb8d..f8f65061d 100644
--- a/nselib/vnc.lua
+++ b/nselib/vnc.lua
@@ -15,7 +15,7 @@
-- The library contains the following classes:
--
-- o VNC
--- - This class contains the core functions needed to communicate with VNC
+-- - This class contains the core functions needed to communicate with VNC
--
-- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html
@@ -36,263 +36,263 @@ local HAVE_SSL, openssl = pcall(require,'openssl')
VNC = {
- -- We currently support version 3.8 of the protocol only
- versions = {
- ["RFB 003.003\n"] = "3.3",
- ["RFB 003.007\n"] = "3.7",
- ["RFB 003.008\n"] = "3.8",
+ -- We currently support version 3.8 of the protocol only
+ versions = {
+ ["RFB 003.003\n"] = "3.3",
+ ["RFB 003.007\n"] = "3.7",
+ ["RFB 003.008\n"] = "3.8",
- -- Mac Screen Sharing, could probably be used to fingerprint OS
- ["RFB 003.889\n"] = "3.889",
- },
+ -- Mac Screen Sharing, could probably be used to fingerprint OS
+ ["RFB 003.889\n"] = "3.889",
+ },
- sectypes = {
- INVALID = 0,
- NONE = 1,
- VNCAUTH = 2,
- RA2 = 5,
- RA2NE = 6,
- TIGHT = 16,
- ULTRA = 17,
- TNS = 18,
- VENCRYPT = 19,
- GTK_VNC_SASL = 20,
- MD5 = 21,
- COLIN_DEAN_XVP = 22,
- MAC_OSX_SECTYPE_30 = 30,
- MAC_OSX_SECTYPE_35 = 35,
- },
+ sectypes = {
+ INVALID = 0,
+ NONE = 1,
+ VNCAUTH = 2,
+ RA2 = 5,
+ RA2NE = 6,
+ TIGHT = 16,
+ ULTRA = 17,
+ TNS = 18,
+ VENCRYPT = 19,
+ GTK_VNC_SASL = 20,
+ MD5 = 21,
+ COLIN_DEAN_XVP = 22,
+ MAC_OSX_SECTYPE_30 = 30,
+ MAC_OSX_SECTYPE_35 = 35,
+ },
- -- Security types are fetched from the rfbproto.pdf
- sectypes_str = {
- [0] = "Invalid security type",
- [1] = "None",
- [2] = "VNC Authentication",
- [5] = "RA2",
- [6] = "RA2ne",
- [16]= "Tight",
- [17]= "Ultra",
- [18]= "TLS",
- [19]= "VeNCrypt",
- [20]= "GTK-VNC SASL",
- [21]= "MD5 hash authentication",
- [22]= "Colin Dean xvp",
+ -- Security types are fetched from the rfbproto.pdf
+ sectypes_str = {
+ [0] = "Invalid security type",
+ [1] = "None",
+ [2] = "VNC Authentication",
+ [5] = "RA2",
+ [6] = "RA2ne",
+ [16]= "Tight",
+ [17]= "Ultra",
+ [18]= "TLS",
+ [19]= "VeNCrypt",
+ [20]= "GTK-VNC SASL",
+ [21]= "MD5 hash authentication",
+ [22]= "Colin Dean xvp",
- -- Mac OS X screen sharing uses 30 and 35
- [30]= "Mac OS X security type",
- [35]= "Mac OS X security type",
- },
+ -- Mac OS X screen sharing uses 30 and 35
+ [30]= "Mac OS X security type",
+ [35]= "Mac OS X security type",
+ },
- new = function(self, host, port)
- local o = {
- host = host,
- port = port,
- socket = nmap.new_socket(),
- cli_version = nmap.registry.args['vnc-brute.version'] or "RFB 003.889\n"
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ new = function(self, host, port)
+ local o = {
+ host = host,
+ port = port,
+ socket = nmap.new_socket(),
+ cli_version = nmap.registry.args['vnc-brute.version'] or "RFB 003.889\n"
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- --- Connects the VNC socket
- connect = function(self)
- if ( not(HAVE_SSL) ) then
- return false, "The VNC module requires OpenSSL support"
- end
- return self.socket:connect(self.host, self.port, "tcp")
- end,
+ --- Connects the VNC socket
+ connect = function(self)
+ if ( not(HAVE_SSL) ) then
+ return false, "The VNC module requires OpenSSL support"
+ end
+ return self.socket:connect(self.host, self.port, "tcp")
+ end,
- --- Disconnects the VNC socket
- disconnect = function(self)
- return self.socket:close()
- end,
+ --- Disconnects the VNC socket
+ disconnect = function(self)
+ return self.socket:close()
+ end,
- --- Performs the VNC handshake and determines
- -- o The RFB Protocol to use
- -- o The supported authentication security types
- --
- -- @return status, true on success, false on failure
- -- @return error string containing error message if status is false
- handshake = function(self)
- local status, data = self.socket:receive_buf(match.numbytes(12), true)
- local vncsec = {
- count = 1,
- types = {}
- }
+ --- Performs the VNC handshake and determines
+ -- o The RFB Protocol to use
+ -- o The supported authentication security types
+ --
+ -- @return status, true on success, false on failure
+ -- @return error string containing error message if status is false
+ handshake = function(self)
+ local status, data = self.socket:receive_buf(match.numbytes(12), true)
+ local vncsec = {
+ count = 1,
+ types = {}
+ }
- if ( not(status) ) then
- return status, "ERROR: VNC:handshake failed to receive protocol version"
- end
+ if ( not(status) ) then
+ return status, "ERROR: VNC:handshake failed to receive protocol version"
+ end
- self.protover = VNC.versions[data]
- if ( not(self.protover) ) then
- stdnse.print_debug("ERROR: VNC:handshake unsupported version (%s)", data:sub(1,11))
- return false, ("Unsupported version (%s)"):format(data:sub(1,11))
- end
+ self.protover = VNC.versions[data]
+ if ( not(self.protover) ) then
+ stdnse.print_debug("ERROR: VNC:handshake unsupported version (%s)", data:sub(1,11))
+ return false, ("Unsupported version (%s)"):format(data:sub(1,11))
+ end
- status = self.socket:send( self.cli_version )
- if ( not(status) ) then
- stdnse.print_debug("ERROR: VNC:handshake failed to send client version")
- return false, "ERROR: VNC:handshake failed"
- end
+ status = self.socket:send( self.cli_version )
+ if ( not(status) ) then
+ stdnse.print_debug("ERROR: VNC:handshake failed to send client version")
+ return false, "ERROR: VNC:handshake failed"
+ end
- local function process_error()
- local status, tmp = self.socket:receive_buf(match.numbytes(4), true)
- if( not(status) ) then
- return false, "VNC:handshake failed to retrieve error message"
- end
- local len = select(2, bin.unpack(">I", tmp))
- local status, err = self.socket:receive_buf(match.numbytes(len), true)
- if( not(status) ) then
- return false, "VNC:handshake failed to retrieve error message"
- end
- return false, err
- end
+ local function process_error()
+ local status, tmp = self.socket:receive_buf(match.numbytes(4), true)
+ if( not(status) ) then
+ return false, "VNC:handshake failed to retrieve error message"
+ end
+ local len = select(2, bin.unpack(">I", tmp))
+ local status, err = self.socket:receive_buf(match.numbytes(len), true)
+ if( not(status) ) then
+ return false, "VNC:handshake failed to retrieve error message"
+ end
+ return false, err
+ end
- if ( self.protover == "3.3" ) then
- local status, tmp = self.socket:receive_buf(match.numbytes(4), true)
- if( not(status) ) then
- return false, "VNC:handshake failed to receive security data"
- end
+ if ( self.protover == "3.3" ) then
+ local status, tmp = self.socket:receive_buf(match.numbytes(4), true)
+ if( not(status) ) then
+ return false, "VNC:handshake failed to receive security data"
+ end
- vncsec.types[1] = select(2, bin.unpack("I", tmp) )
- self.vncsec = vncsec
+ vncsec.types[1] = select(2, bin.unpack("I", tmp) )
+ self.vncsec = vncsec
- -- do we have an invalid security type, if so we need to handle an
- -- error condition
- if ( vncsec.types[1] == 0 ) then
- return process_error()
- end
- else
- local status, tmp = self.socket:receive_buf(match.numbytes(1), true)
- if ( not(status) ) then
- stdnse.print_debug("ERROR: VNC:handshake failed to receive security data")
- return false, "ERROR: VNC:handshake failed to receive security data"
- end
+ -- do we have an invalid security type, if so we need to handle an
+ -- error condition
+ if ( vncsec.types[1] == 0 ) then
+ return process_error()
+ end
+ else
+ local status, tmp = self.socket:receive_buf(match.numbytes(1), true)
+ if ( not(status) ) then
+ stdnse.print_debug("ERROR: VNC:handshake failed to receive security data")
+ return false, "ERROR: VNC:handshake failed to receive security data"
+ end
- vncsec.count = select(2, bin.unpack("C", tmp))
- if ( vncsec.count == 0 ) then
- return process_error()
- end
- status, tmp = self.socket:receive_buf(match.numbytes(vncsec.count), true)
+ vncsec.count = select(2, bin.unpack("C", tmp))
+ if ( vncsec.count == 0 ) then
+ return process_error()
+ end
+ status, tmp = self.socket:receive_buf(match.numbytes(vncsec.count), true)
- if ( not(status) ) then
- stdnse.print_debug("ERROR: VNC:handshake failed to receive security data")
- return false, "ERROR: VNC:handshake failed to receive security data"
- end
+ if ( not(status) ) then
+ stdnse.print_debug("ERROR: VNC:handshake failed to receive security data")
+ return false, "ERROR: VNC:handshake failed to receive security data"
+ end
- for i=1, vncsec.count do
- table.insert( vncsec.types, select(2, bin.unpack("C", tmp, i) ) )
- end
- self.vncsec = vncsec
- end
+ for i=1, vncsec.count do
+ table.insert( vncsec.types, select(2, bin.unpack("C", tmp, i) ) )
+ end
+ self.vncsec = vncsec
+ end
- return true
- end,
+ return true
+ end,
- --- Creates the password bit-flip needed before DES encryption
- --
- -- @param password string containing the password to process
- -- @return password string containing the processed password
- createVNCDESKey = function( self, password )
- if ( #password < 8 ) then
- for i=1, (8 - #password) do
- password = password .. string.char(0x00)
- end
- end
+ --- Creates the password bit-flip needed before DES encryption
+ --
+ -- @param password string containing the password to process
+ -- @return password string containing the processed password
+ createVNCDESKey = function( self, password )
+ if ( #password < 8 ) then
+ for i=1, (8 - #password) do
+ password = password .. string.char(0x00)
+ end
+ end
- local newpass = ""
- for i=1, 8 do
- local _, bitstr = bin.unpack("B", password, i)
- newpass = newpass .. bin.pack("B", bitstr:reverse())
- end
- return newpass
- end,
+ local newpass = ""
+ for i=1, 8 do
+ local _, bitstr = bin.unpack("B", password, i)
+ newpass = newpass .. bin.pack("B", bitstr:reverse())
+ end
+ return newpass
+ end,
- --- Attempts to login to the VNC service
- -- Currently the only supported auth sectype is VNC Authentication
- --
- -- @param username string, could be anything when VNCAuth is used
- -- @param password string containing the password to use for authentication
- -- @return status true on success, false on failure
- -- @return err string containing error message when status is false
- login = function( self, username, password )
- if ( not(password) ) then
- return false, "No password was supplied"
- end
+ --- Attempts to login to the VNC service
+ -- Currently the only supported auth sectype is VNC Authentication
+ --
+ -- @param username string, could be anything when VNCAuth is used
+ -- @param password string containing the password to use for authentication
+ -- @return status true on success, false on failure
+ -- @return err string containing error message when status is false
+ login = function( self, username, password )
+ if ( not(password) ) then
+ return false, "No password was supplied"
+ end
- if ( not( self:supportsSecType( VNC.sectypes.VNCAUTH ) ) ) then
- return false, "The server does not support the \"VNC Authentication\" security type."
- end
+ if ( not( self:supportsSecType( VNC.sectypes.VNCAUTH ) ) ) then
+ return false, "The server does not support the \"VNC Authentication\" security type."
+ end
- -- Announce that we support VNC Authentication
- local status = self.socket:send( bin.pack("C", VNC.sectypes.VNCAUTH) )
- if ( not(status) ) then
- return false, "Failed to select authentication type"
- end
+ -- Announce that we support VNC Authentication
+ local status = self.socket:send( bin.pack("C", VNC.sectypes.VNCAUTH) )
+ if ( not(status) ) then
+ return false, "Failed to select authentication type"
+ end
- local status, chall = self.socket:receive_buf(match.numbytes(16), true)
- if ( not(status) ) then
- return false, "Failed to receive authentication challenge"
- end
+ local status, chall = self.socket:receive_buf(match.numbytes(16), true)
+ if ( not(status) ) then
+ return false, "Failed to receive authentication challenge"
+ end
- local key = self:createVNCDESKey(password)
- local resp = openssl.encrypt("des-ecb", key, nil, chall, false )
+ local key = self:createVNCDESKey(password)
+ local resp = openssl.encrypt("des-ecb", key, nil, chall, false )
- status = self.socket:send( resp )
- if ( not(status) ) then
- return false, "Failed to send authentication response to server"
- end
+ status = self.socket:send( resp )
+ if ( not(status) ) then
+ return false, "Failed to send authentication response to server"
+ end
- local status, result = self.socket:receive_buf(match.numbytes(4), true)
- if ( not(status) ) then
- return false, "Failed to retrieve authentication status from server"
- end
+ local status, result = self.socket:receive_buf(match.numbytes(4), true)
+ if ( not(status) ) then
+ return false, "Failed to retrieve authentication status from server"
+ end
- if ( select(2, bin.unpack("I", result) ) ~= 0 ) then
- return false, ("Authentication failed with password %s"):format(password)
- end
- return true, ""
- end,
+ if ( select(2, bin.unpack("I", result) ) ~= 0 ) then
+ return false, ("Authentication failed with password %s"):format(password)
+ end
+ return true, ""
+ end,
- --- Returns all supported security types as a table
- --
- -- @return table containing a entry for each security type
- getSecTypesAsTable = function( self )
- local tmp = {}
- local typemt = {
- __tostring = function(me)
- return ("%s (%s)"):format(me.name, me.type)
- end
- }
- for i=1, self.vncsec.count do
- local t = {name=VNC.sectypes_str[self.vncsec.types[i]] or "Unknown security type", type=self.vncsec.types[i]}
- setmetatable(t, typemt)
- table.insert( tmp, t )
- end
- return true, tmp
- end,
+ --- Returns all supported security types as a table
+ --
+ -- @return table containing a entry for each security type
+ getSecTypesAsTable = function( self )
+ local tmp = {}
+ local typemt = {
+ __tostring = function(me)
+ return ("%s (%s)"):format(me.name, me.type)
+ end
+ }
+ for i=1, self.vncsec.count do
+ local t = {name=VNC.sectypes_str[self.vncsec.types[i]] or "Unknown security type", type=self.vncsec.types[i]}
+ setmetatable(t, typemt)
+ table.insert( tmp, t )
+ end
+ return true, tmp
+ end,
- --- Checks if the supplied security type is supported or not
- --
- -- @param sectype number containing the security type to check for
- -- @return status true if supported, false if not supported
- supportsSecType = function( self, sectype )
- for i=1, self.vncsec.count do
- if ( self.vncsec.types[i] == sectype ) then
- return true
- end
- end
- return false
- end,
+ --- Checks if the supplied security type is supported or not
+ --
+ -- @param sectype number containing the security type to check for
+ -- @return status true if supported, false if not supported
+ supportsSecType = function( self, sectype )
+ for i=1, self.vncsec.count do
+ if ( self.vncsec.types[i] == sectype ) then
+ return true
+ end
+ end
+ return false
+ end,
- --- Returns the protocol version reported by the server
- --
- -- @param version string containing the version number
- getProtocolVersion = function( self )
- return self.protover
- end,
+ --- Returns the protocol version reported by the server
+ --
+ -- @param version string containing the version number
+ getProtocolVersion = function( self )
+ return self.protover
+ end,
}
diff --git a/nselib/vuzedht.lua b/nselib/vuzedht.lua
index ddc819e54..1e738ae98 100644
--- a/nselib/vuzedht.lua
+++ b/nselib/vuzedht.lua
@@ -35,364 +35,364 @@ _ENV = stdnse.module("vuzedht", stdnse.seeall)
Request = {
- Actions = {
- ACTION_PING = 1024,
- FIND_NODE = 1028,
- },
+ Actions = {
+ ACTION_PING = 1024,
+ FIND_NODE = 1028,
+ },
- -- The request Header class shared by all Requests classes
- Header = {
+ -- The request Header class shared by all Requests classes
+ Header = {
- -- Creates a new Header instance
- -- @param action number containing the request action
- -- @param session instance of Session
- -- @return o new instance of Header
- new = function(self, action, session)
- local o = {
- conn_id = string.char(255) .. openssl.rand_pseudo_bytes(7),
- -- we need to handle this one like this, due to a bug in nsedoc
- -- it used to be action = action, but that breaks parsing
- ["action"] = action,
- trans_id = session:getTransactionId(),
- proto_version = 0x32,
- vendor_id = 0,
- network_id = 0,
- local_proto_version = 0x32,
- address = session:getAddress(),
- port = session:getPort(),
- instance_id = session:getInstanceId(),
- time = os.time(),
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new Header instance
+ -- @param action number containing the request action
+ -- @param session instance of Session
+ -- @return o new instance of Header
+ new = function(self, action, session)
+ local o = {
+ conn_id = string.char(255) .. openssl.rand_pseudo_bytes(7),
+ -- we need to handle this one like this, due to a bug in nsedoc
+ -- it used to be action = action, but that breaks parsing
+ ["action"] = action,
+ trans_id = session:getTransactionId(),
+ proto_version = 0x32,
+ vendor_id = 0,
+ network_id = 0,
+ local_proto_version = 0x32,
+ address = session:getAddress(),
+ port = session:getPort(),
+ instance_id = session:getInstanceId(),
+ time = os.time(),
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Converts the header to a string
- __tostring = function(self)
- local lhost = ipOps.todword(self.address)
- return bin.pack( ">AIICCICCISIL", self.conn_id, self.action, self.trans_id,
- self.proto_version, self.vendor_id, self.network_id, self.local_proto_version,
- 4, lhost, self.port, self.instance_id, self.time )
- end,
+ -- Converts the header to a string
+ __tostring = function(self)
+ local lhost = ipOps.todword(self.address)
+ return bin.pack( ">AIICCICCISIL", self.conn_id, self.action, self.trans_id,
+ self.proto_version, self.vendor_id, self.network_id, self.local_proto_version,
+ 4, lhost, self.port, self.instance_id, self.time )
+ end,
- },
+ },
- -- The PING Request class
- Ping = {
+ -- The PING Request class
+ Ping = {
- -- Creates a new Ping instance
- -- @param session instance of Session
- -- @return o new instance of Ping
- new = function(self, session)
- local o = {
- header = Request.Header:new(Request.Actions.ACTION_PING, session)
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new Ping instance
+ -- @param session instance of Session
+ -- @return o new instance of Ping
+ new = function(self, session)
+ local o = {
+ header = Request.Header:new(Request.Actions.ACTION_PING, session)
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Converts a Ping Request to a string
- __tostring = function(self)
- return tostring(self.header)
- end,
+ -- Converts a Ping Request to a string
+ __tostring = function(self)
+ return tostring(self.header)
+ end,
- },
+ },
- -- The FIND_NODES Request class
- FindNode = {
+ -- The FIND_NODES Request class
+ FindNode = {
- -- Creates a new FindNode instance
- -- @param session instance of Session
- -- @return o new instance of FindNode
- new = function(self, session)
- local o = {
- header = Request.Header:new(Request.Actions.FIND_NODE, session),
- id_length = 20,
- node_id = '\xA7' .. openssl.rand_pseudo_bytes(19),
- status = 0xFFFFFFFF,
- dht_size = 0,
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new FindNode instance
+ -- @param session instance of Session
+ -- @return o new instance of FindNode
+ new = function(self, session)
+ local o = {
+ header = Request.Header:new(Request.Actions.FIND_NODE, session),
+ id_length = 20,
+ node_id = '\xA7' .. openssl.rand_pseudo_bytes(19),
+ status = 0xFFFFFFFF,
+ dht_size = 0,
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Converts a FindNode Request to a string
- __tostring = function(self)
- local data = tostring(self.header)
- data = data .. bin.pack(">CAII", self.id_length, self.node_id, self.status, self.dht_size)
- return data
- end,
- }
+ -- Converts a FindNode Request to a string
+ __tostring = function(self)
+ local data = tostring(self.header)
+ data = data .. bin.pack(">CAII", self.id_length, self.node_id, self.status, self.dht_size)
+ return data
+ end,
+ }
}
Response = {
- -- A table of currently supported Actions (Responses)
- -- It's used in the fromString method to determine which class to create.
- Actions = {
- ACTION_PING = 1025,
- FIND_NODE = 1029,
- ERROR = 1032,
- },
+ -- A table of currently supported Actions (Responses)
+ -- It's used in the fromString method to determine which class to create.
+ Actions = {
+ ACTION_PING = 1025,
+ FIND_NODE = 1029,
+ ERROR = 1032,
+ },
- -- Creates an address record based on received data
- -- @param data containing an address record [C][I|H][S] where
- -- [C] is the length of the address (4 or 16)
- -- [I|H] is the address as a dword or hex string
- -- [S] is the port number as a short
- -- @return o Address instance on success, nil on failure
- Address = {
- new = function(self, data)
- local o = { data = data }
- setmetatable(o, self)
- self.__index = self
- if ( o:parse() ) then
- return o
- end
- end,
+ -- Creates an address record based on received data
+ -- @param data containing an address record [C][I|H][S] where
+ -- [C] is the length of the address (4 or 16)
+ -- [I|H] is the address as a dword or hex string
+ -- [S] is the port number as a short
+ -- @return o Address instance on success, nil on failure
+ Address = {
+ new = function(self, data)
+ local o = { data = data }
+ setmetatable(o, self)
+ self.__index = self
+ if ( o:parse() ) then
+ return o
+ end
+ end,
- -- Parses the received data
- -- @return true on success, false on failure
- parse = function(self)
- local pos, addr_len = bin.unpack("C", self.data)
- if ( addr_len == 4 ) then
- self.length = 4 + 2 + 1
- pos, self.ip = bin.unpack("S", self.data, pos)
- return true
- end
- },
+ -- Parses the received data
+ -- @return true on success, false on failure
+ parse = function(self)
+ local pos, addr_len = bin.unpack("C", self.data)
+ if ( addr_len == 4 ) then
+ self.length = 4 + 2 + 1
+ pos, self.ip = bin.unpack("S", self.data, pos)
+ return true
+ end
+ },
- -- The reponse header, present in all packets
- Header = {
+ -- The reponse header, present in all packets
+ Header = {
- Vendors = {
- [0] = "Azureus",
- [1] = "ShareNet",
- [255] = "Unknown", -- to be honest, we report all except 0 and 1 as unknown
- },
+ Vendors = {
+ [0] = "Azureus",
+ [1] = "ShareNet",
+ [255] = "Unknown", -- to be honest, we report all except 0 and 1 as unknown
+ },
- Networks = {
- [0] = "Stable",
- [1] = "CVS"
- },
+ Networks = {
+ [0] = "Stable",
+ [1] = "CVS"
+ },
- -- Creates a new Header instance
- -- @param data string containing the received data
- -- @return o instance of Header
- new = function(self, data)
- local o = { data = data }
- setmetatable(o, self)
- self.__index = self
- o:parse()
- return o
- end,
+ -- Creates a new Header instance
+ -- @param data string containing the received data
+ -- @return o instance of Header
+ new = function(self, data)
+ local o = { data = data }
+ setmetatable(o, self)
+ self.__index = self
+ o:parse()
+ return o
+ end,
- -- parses the header
- parse = function(self)
- local pos
- pos, self.action, self.trans_id, self.conn_id,
- self.proto_version, self.vendor_id, self.network_id,
- self.instance_id = bin.unpack(">IIH8CCII", self.data)
- end,
+ -- parses the header
+ parse = function(self)
+ local pos
+ pos, self.action, self.trans_id, self.conn_id,
+ self.proto_version, self.vendor_id, self.network_id,
+ self.instance_id = bin.unpack(">IIH8CCII", self.data)
+ end,
- -- Converts the header to a suitable string representation
- __tostring = function(self)
- local result = {}
- table.insert(result, ("Transaction id: %d"):format(self.trans_id))
- table.insert(result, ("Connection id: 0x%s"):format(self.conn_id))
- table.insert(result, ("Protocol version: %d"):format(self.proto_version))
- table.insert(result, ("Vendor id: %s (%d)"):format(
- Response.Header.Vendors[self.vendor_id] or "Unknown", self.vendor_id))
- table.insert(result, ("Network id: %s (%d)"):format(
- Response.Header.Networks[self.network_id] or "Unknown", self.network_id))
- table.insert(result, ("Instance id: %d"):format(self.instance_id))
- return stdnse.format_output(true, result)
- end,
+ -- Converts the header to a suitable string representation
+ __tostring = function(self)
+ local result = {}
+ table.insert(result, ("Transaction id: %d"):format(self.trans_id))
+ table.insert(result, ("Connection id: 0x%s"):format(self.conn_id))
+ table.insert(result, ("Protocol version: %d"):format(self.proto_version))
+ table.insert(result, ("Vendor id: %s (%d)"):format(
+ Response.Header.Vendors[self.vendor_id] or "Unknown", self.vendor_id))
+ table.insert(result, ("Network id: %s (%d)"):format(
+ Response.Header.Networks[self.network_id] or "Unknown", self.network_id))
+ table.insert(result, ("Instance id: %d"):format(self.instance_id))
+ return stdnse.format_output(true, result)
+ end,
- },
+ },
- -- The PING response
- PING = {
+ -- The PING response
+ PING = {
- -- Creates a new instance of PING
- -- @param data string containing the received data
- -- @return o new PING instance
- new = function(self, data)
- local o = {
- header = Response.Header:new(data)
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new instance of PING
+ -- @param data string containing the received data
+ -- @return o new PING instance
+ new = function(self, data)
+ local o = {
+ header = Response.Header:new(data)
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Creates a new PING instance based on received data
- -- @param data string containing received data
- -- @return status true on success, false on failure
- -- @return new instance of PING on success, error message on failure
- fromString = function(data)
- local ping = Response.PING:new(data)
- if ( ping ) then
- return true, ping
- end
- return false, "Failed to parse PING response"
- end,
+ -- Creates a new PING instance based on received data
+ -- @param data string containing received data
+ -- @return status true on success, false on failure
+ -- @return new instance of PING on success, error message on failure
+ fromString = function(data)
+ local ping = Response.PING:new(data)
+ if ( ping ) then
+ return true, ping
+ end
+ return false, "Failed to parse PING response"
+ end,
- -- Converts the PING response to a response suitable for script output
- -- @return result formatted script output
- __tostring = function(self)
- return tostring(self.header)
- end,
- },
+ -- Converts the PING response to a response suitable for script output
+ -- @return result formatted script output
+ __tostring = function(self)
+ return tostring(self.header)
+ end,
+ },
- -- A class to process the response from a FIND_NODE query
- FIND_NODE = {
+ -- A class to process the response from a FIND_NODE query
+ FIND_NODE = {
- -- Creates a new FIND_NODE instance
- -- @param data string containing the received data
- -- @return o new instance of FIND_NODE
- new = function(self, data)
- local o = {
- header = Response.Header:new(data),
- data = data:sub(27)
- }
- setmetatable(o, self)
- self.__index = self
- o:parse()
- return o
- end,
+ -- Creates a new FIND_NODE instance
+ -- @param data string containing the received data
+ -- @return o new instance of FIND_NODE
+ new = function(self, data)
+ local o = {
+ header = Response.Header:new(data),
+ data = data:sub(27)
+ }
+ setmetatable(o, self)
+ self.__index = self
+ o:parse()
+ return o
+ end,
- -- Parses the FIND_NODE response
- parse = function(self)
- local pos
- pos, self.spoof_id, self.node_type, self.dht_size,
- self.network_coords = bin.unpack(">IIIH20", self.data)
+ -- Parses the FIND_NODE response
+ parse = function(self)
+ local pos
+ pos, self.spoof_id, self.node_type, self.dht_size,
+ self.network_coords = bin.unpack(">IIIH20", self.data)
- local contact_count
- pos, contact_count = bin.unpack("C", self.data, pos)
- self.contacts = {}
- for i=1, contact_count do
- local contact, addr_len, address = {}
- pos, contact.type, contact.proto_version, addr_len = bin.unpack("CCC", self.data, pos)
+ local contact_count
+ pos, contact_count = bin.unpack("C", self.data, pos)
+ self.contacts = {}
+ for i=1, contact_count do
+ local contact, addr_len, address = {}
+ pos, contact.type, contact.proto_version, addr_len = bin.unpack("CCC", self.data, pos)
- if ( addr_len == 4 ) then
- pos, address = bin.unpack("S", self.data, pos)
- table.insert(self.contacts, contact)
- end
- end,
+ if ( addr_len == 4 ) then
+ pos, address = bin.unpack("S", self.data, pos)
+ table.insert(self.contacts, contact)
+ end
+ end,
- -- Creates a new instance of FIND_NODE based on received data
- -- @param data string containing received data
- -- @return status true on success, false on failure
- -- @return new instance of FIND_NODE on success, error message on failure
- fromString = function(data)
- local find = Response.FIND_NODE:new(data)
- if ( find.header.proto_version < 13 ) then
- stdnse.print_debug("ERROR: Unsupported version %d", find.header.proto_version)
- return false
- end
+ -- Creates a new instance of FIND_NODE based on received data
+ -- @param data string containing received data
+ -- @return status true on success, false on failure
+ -- @return new instance of FIND_NODE on success, error message on failure
+ fromString = function(data)
+ local find = Response.FIND_NODE:new(data)
+ if ( find.header.proto_version < 13 ) then
+ stdnse.print_debug("ERROR: Unsupported version %d", find.header.proto_version)
+ return false
+ end
- return true, find
- end,
+ return true, find
+ end,
- -- Convert the FIND_NODE response to formatted string data, suitable
- -- for script output.
- -- @return string with formatted FIND_NODE data
- __tostring = function(self)
- if ( not(self.contacts) ) then
- return ""
- end
+ -- Convert the FIND_NODE response to formatted string data, suitable
+ -- for script output.
+ -- @return string with formatted FIND_NODE data
+ __tostring = function(self)
+ if ( not(self.contacts) ) then
+ return ""
+ end
- local result = {}
- for _, contact in ipairs(self.contacts) do
- table.insert(result, ("%s:%d"):format(contact.address, contact.port))
- end
- return stdnse.format_output(true, result)
- end
- },
+ local result = {}
+ for _, contact in ipairs(self.contacts) do
+ table.insert(result, ("%s:%d"):format(contact.address, contact.port))
+ end
+ return stdnse.format_output(true, result)
+ end
+ },
- -- The ERROR action
- ERROR = {
+ -- The ERROR action
+ ERROR = {
- -- Creates a new ERROR instance based on received socket data
- -- @return o new ERROR instance on success, nil on failure
- new = function(self, data)
- local o = {
- header = Response.Header:new(data),
- data = data:sub(27)
- }
- setmetatable(o, self)
- self.__index = self
- if ( o:parse() ) then
- return o
- end
- end,
+ -- Creates a new ERROR instance based on received socket data
+ -- @return o new ERROR instance on success, nil on failure
+ new = function(self, data)
+ local o = {
+ header = Response.Header:new(data),
+ data = data:sub(27)
+ }
+ setmetatable(o, self)
+ self.__index = self
+ if ( o:parse() ) then
+ return o
+ end
+ end,
- -- parses the received data and attempts to create an ERROR response
- -- @return true on success, false on failure
- parse = function(self)
- local pos, err_type = bin.unpack(">I", self.data)
- if ( 1 == err_type ) then
- self.addr = Response.Address:new(self.data:sub(5))
- return true
- end
- return false
- end,
+ -- parses the received data and attempts to create an ERROR response
+ -- @return true on success, false on failure
+ parse = function(self)
+ local pos, err_type = bin.unpack(">I", self.data)
+ if ( 1 == err_type ) then
+ self.addr = Response.Address:new(self.data:sub(5))
+ return true
+ end
+ return false
+ end,
- -- creates a new ERROR instance based on the received data
- -- @return true on success, false on failure
- fromString = function(data)
- local err = Response.ERROR:new(data)
- if ( err ) then
- return true, err
- end
- return false
- end,
+ -- creates a new ERROR instance based on the received data
+ -- @return true on success, false on failure
+ fromString = function(data)
+ local err = Response.ERROR:new(data)
+ if ( err ) then
+ return true, err
+ end
+ return false
+ end,
- -- Converts the ERROR action to a formatted response
- -- @return string containing the formatted response
- __tostring = function(self)
- return ("Wrong address, expected: %s"):format(self.addr.ip)
- end,
+ -- Converts the ERROR action to a formatted response
+ -- @return string containing the formatted response
+ __tostring = function(self)
+ return ("Wrong address, expected: %s"):format(self.addr.ip)
+ end,
- },
+ },
- -- creates a suitable Response class based on the Action received
- -- @return true on success, false on failure
- -- @return response instance of suitable Response class on success,
- -- err string error message if status is false
- fromString = function(data)
- local pos, action = bin.unpack(">I", data)
+ -- creates a suitable Response class based on the Action received
+ -- @return true on success, false on failure
+ -- @return response instance of suitable Response class on success,
+ -- err string error message if status is false
+ fromString = function(data)
+ local pos, action = bin.unpack(">I", data)
- if ( action == Response.Actions.ACTION_PING ) then
- return Response.PING.fromString(data)
- elseif ( action == Response.Actions.FIND_NODE ) then
- return Response.FIND_NODE.fromString(data)
- elseif ( action == Response.Actions.ERROR ) then
- return Response.ERROR.fromString(data)
- end
+ if ( action == Response.Actions.ACTION_PING ) then
+ return Response.PING.fromString(data)
+ elseif ( action == Response.Actions.FIND_NODE ) then
+ return Response.FIND_NODE.fromString(data)
+ elseif ( action == Response.Actions.ERROR ) then
+ return Response.ERROR.fromString(data)
+ end
- stdnse.print_debug("ERROR: Unknown response received from server")
- return false, "Failed to parse response"
- end,
+ stdnse.print_debug("ERROR: Unknown response received from server")
+ return false, "Failed to parse response"
+ end,
@@ -401,157 +401,157 @@ Response = {
-- The Session
Session = {
- -- Creates a new Session instance to keep track on some of the protocol
- -- stuff, such as transaction- and instance- identities.
- -- @param address the local address to pass in the requests to the server
- -- this could be either the local address or the IP of the router
- -- depending on if NAT is used or not.
- -- @param port the local port to pass in the requests to the server
- -- @return o new instance of Session
- new = function(self, address, port)
- local o = {
- trans_id = math.random(12345678),
- instance_id = math.random(12345678),
- address = address,
- port = port,
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new Session instance to keep track on some of the protocol
+ -- stuff, such as transaction- and instance- identities.
+ -- @param address the local address to pass in the requests to the server
+ -- this could be either the local address or the IP of the router
+ -- depending on if NAT is used or not.
+ -- @param port the local port to pass in the requests to the server
+ -- @return o new instance of Session
+ new = function(self, address, port)
+ local o = {
+ trans_id = math.random(12345678),
+ instance_id = math.random(12345678),
+ address = address,
+ port = port,
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Gets the next transaction ID
- -- @return trans_id number
- getTransactionId = function(self)
- self.trans_id = self.trans_id + 1
- return self.trans_id
- end,
+ -- Gets the next transaction ID
+ -- @return trans_id number
+ getTransactionId = function(self)
+ self.trans_id = self.trans_id + 1
+ return self.trans_id
+ end,
- -- Gets the next instance ID
- -- @return instance_id number
- getInstanceId = function(self)
- self.instance_id = self.instance_id + 1
- return self.instance_id
- end,
+ -- Gets the next instance ID
+ -- @return instance_id number
+ getInstanceId = function(self)
+ self.instance_id = self.instance_id + 1
+ return self.instance_id
+ end,
- -- Gets the stored local address used to create the session
- -- @return string containing the IP passed to the session
- getAddress = function(self)
- return self.address
- end,
+ -- Gets the stored local address used to create the session
+ -- @return string containing the IP passed to the session
+ getAddress = function(self)
+ return self.address
+ end,
- -- Get the stored local port used to create the session
- -- @return number containing the local port
- getPort = function(self)
- return self.port
- end
+ -- Get the stored local port used to create the session
+ -- @return number containing the local port
+ getPort = function(self)
+ return self.port
+ end
}
-- The Helper class, used as main interface between the scripts and the library
Helper = {
- -- Creates a new instance of the Helper class
- -- @param host table as passed to the action method
- -- @param port table as passed to the action method
- -- @param lhost [optional] used if an alternate local address is to be
- -- passed in the requests to the remote node (ie. NAT is in play).
- -- @param lport [optional] used if an alternate port is to be passed in
- -- the requests to the remote node.
- -- @return o new instance of Helper
- new = function(self, host, port, lhost, lport)
- local o = {
- host = host,
- port = port,
- lhost = lhost,
- lport = lport
- }
- setmetatable(o, self)
- self.__index = self
- math.randomseed(os.time())
- return o
- end,
+ -- Creates a new instance of the Helper class
+ -- @param host table as passed to the action method
+ -- @param port table as passed to the action method
+ -- @param lhost [optional] used if an alternate local address is to be
+ -- passed in the requests to the remote node (ie. NAT is in play).
+ -- @param lport [optional] used if an alternate port is to be passed in
+ -- the requests to the remote node.
+ -- @return o new instance of Helper
+ new = function(self, host, port, lhost, lport)
+ local o = {
+ host = host,
+ port = port,
+ lhost = lhost,
+ lport = lport
+ }
+ setmetatable(o, self)
+ self.__index = self
+ math.randomseed(os.time())
+ return o
+ end,
- -- Connects to the remote Vuze Node
- -- @return true on success, false on failure
- -- @return err string error message if status is false
- connect = function(self)
- local lhost = self.lhost or stdnse.get_script_args('vuzedht.lhost')
- local lport = self.lport or stdnse.get_script_args('vuzedht.lport')
+ -- Connects to the remote Vuze Node
+ -- @return true on success, false on failure
+ -- @return err string error message if status is false
+ connect = function(self)
+ local lhost = self.lhost or stdnse.get_script_args('vuzedht.lhost')
+ local lport = self.lport or stdnse.get_script_args('vuzedht.lport')
- self.socket = nmap.new_socket()
+ self.socket = nmap.new_socket()
- if ( lport ) then
- self.socket:bind(nil, lport)
- end
- local status, err = self.socket:connect(self.host, self.port)
- if ( not(status) ) then
- return false, "Failed to connect to server"
- end
+ if ( lport ) then
+ self.socket:bind(nil, lport)
+ end
+ local status, err = self.socket:connect(self.host, self.port)
+ if ( not(status) ) then
+ return false, "Failed to connect to server"
+ end
- if ( not(lhost) or not(lport) ) then
- local status, lh, lp, _, _ = self.socket:get_info()
- if ( not(status) ) then
- return false, "Failed to get socket information"
- end
- lhost = lhost or lh
- lport = lport or lp
- end
+ if ( not(lhost) or not(lport) ) then
+ local status, lh, lp, _, _ = self.socket:get_info()
+ if ( not(status) ) then
+ return false, "Failed to get socket information"
+ end
+ lhost = lhost or lh
+ lport = lport or lp
+ end
- self.session = Session:new(lhost, lport)
- return true
- end,
+ self.session = Session:new(lhost, lport)
+ return true
+ end,
- -- Sends a Vuze PING request to the server and parses the response
- -- @return status true on succes, false on failure
- -- @return response PING response instance on success,
- -- err string containing the error message on failure
- ping = function(self)
- local ping = Request.Ping:new(self.session)
- local status, err = self.socket:send(tostring(ping))
- if ( not(status) ) then
- return false, "Failed to send PING request to server"
- end
+ -- Sends a Vuze PING request to the server and parses the response
+ -- @return status true on succes, false on failure
+ -- @return response PING response instance on success,
+ -- err string containing the error message on failure
+ ping = function(self)
+ local ping = Request.Ping:new(self.session)
+ local status, err = self.socket:send(tostring(ping))
+ if ( not(status) ) then
+ return false, "Failed to send PING request to server"
+ end
- local data
- status, data = self.socket:receive()
- if ( not(status) ) then
- return false, "Failed to receive PING response from server"
- end
- local response
- status, response = Response.fromString(data)
- if ( not(status) ) then
- return false, "Failed to parse PING response from server"
- end
- return true, response
- end,
+ local data
+ status, data = self.socket:receive()
+ if ( not(status) ) then
+ return false, "Failed to receive PING response from server"
+ end
+ local response
+ status, response = Response.fromString(data)
+ if ( not(status) ) then
+ return false, "Failed to parse PING response from server"
+ end
+ return true, response
+ end,
- -- Requests a list of known nodes by sending the FIND_NODES request
- -- to the remote node and parses the response.
- -- @return status true on success, false on failure
- -- @return response FIND_NODE response instance on success
- -- err string containing the error message on failure
- findNodes = function(self)
- local find = Request.FindNode:new(self.session)
- local status, err = self.socket:send(tostring(find))
- if ( not(status) ) then
- return false, "Failed to send FIND_NODE request to server"
- end
+ -- Requests a list of known nodes by sending the FIND_NODES request
+ -- to the remote node and parses the response.
+ -- @return status true on success, false on failure
+ -- @return response FIND_NODE response instance on success
+ -- err string containing the error message on failure
+ findNodes = function(self)
+ local find = Request.FindNode:new(self.session)
+ local status, err = self.socket:send(tostring(find))
+ if ( not(status) ) then
+ return false, "Failed to send FIND_NODE request to server"
+ end
- local data
- status, data = self.socket:receive()
- local response
- status, response = Response.fromString(data)
- if ( not(status) ) then
- return false, "Failed to parse FIND_NODE response from server"
- end
- return true, response
- end,
+ local data
+ status, data = self.socket:receive()
+ local response
+ status, response = Response.fromString(data)
+ if ( not(status) ) then
+ return false, "Failed to parse FIND_NODE response from server"
+ end
+ return true, response
+ end,
- -- Closes the socket connect to the remote node
- close = function(self)
- self.socket:close()
- end,
+ -- Closes the socket connect to the remote node
+ close = function(self)
+ self.socket:close()
+ end,
}
return _ENV;
diff --git a/nselib/wsdd.lua b/nselib/wsdd.lua
index d0fd63cb7..fdbf15973 100644
--- a/nselib/wsdd.lua
+++ b/nselib/wsdd.lua
@@ -23,9 +23,9 @@
--
-- The following code snipplet shows how the library can be used:
--
--- local helper = wsdd.Helper:new()
--- helper:setMulticast(true)
--- return stdnse.format_output( helper:discoverDevices() )
+-- local helper = wsdd.Helper:new()
+-- helper:setMulticast(true)
+-- return stdnse.format_output( helper:discoverDevices() )
--
--
-- @author "Patrik Karlsson "
@@ -44,47 +44,47 @@ local HAVE_SSL, openssl = pcall(require,'openssl')
-- The different probes
local probes = {
- -- Detects devices supporting the WSDD protocol
- {
- name = 'general',
- desc = 'Devices',
- data = '' ..
- '' ..
- '' ..
- 'urn:schemas-xmlsoap-org:ws:2005:04:discovery' ..
- '' ..
- 'http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe' ..
- 'urn:uuid:#uuid#' ..
- ''
- },
+ -- Detects devices supporting the WSDD protocol
+ {
+ name = 'general',
+ desc = 'Devices',
+ data = '' ..
+ '' ..
+ '' ..
+ 'urn:schemas-xmlsoap-org:ws:2005:04:discovery' ..
+ '' ..
+ 'http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe' ..
+ 'urn:uuid:#uuid#' ..
+ ''
+ },
- -- Detects Windows Communication Framework (WCF) web services
- {
- name = 'wcf',
- desc = 'WCF Services',
- data = '' ..
- '' ..
- '' ..
- 'http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01/Probe' ..
- '' ..
- 'urn:uuid:#uuid#' ..
- '' ..
- 'urn:docs-oasis-open-org:ws-dd:ns:discovery:2009:01' ..
- '' ..
- '' ..
- '' ..
- '' ..
- '' ..
- 'PT20S' ..
- '' ..
- '' ..
- '' ..
- '',
- }
+ -- Detects Windows Communication Framework (WCF) web services
+ {
+ name = 'wcf',
+ desc = 'WCF Services',
+ data = '' ..
+ '' ..
+ '' ..
+ 'http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01/Probe' ..
+ '' ..
+ 'urn:uuid:#uuid#' ..
+ '' ..
+ 'urn:docs-oasis-open-org:ws-dd:ns:discovery:2009:01' ..
+ '' ..
+ '' ..
+ '' ..
+ '' ..
+ '' ..
+ 'PT20S' ..
+ '' ..
+ '' ..
+ '' ..
+ '',
+ }
}
-- A table that keeps track of received probe matches
@@ -92,291 +92,291 @@ local probe_matches = {}
Util = {
- --- Creates a UUID
- --
- -- @return uuid string containing a uuid
- generateUUID = function()
- local rnd_bytes = select(2, bin.unpack( "H16", openssl.rand_bytes( 16 ) ) ):lower()
+ --- Creates a UUID
+ --
+ -- @return uuid string containing a uuid
+ generateUUID = function()
+ local rnd_bytes = select(2, bin.unpack( "H16", openssl.rand_bytes( 16 ) ) ):lower()
- return ("%s-%s-%s-%s-%s"):format( rnd_bytes:sub(1, 8),
- rnd_bytes:sub(9, 12), rnd_bytes:sub( 13, 16 ), rnd_bytes:sub( 17, 20 ),
- rnd_bytes:sub(21, 32) )
- end,
+ return ("%s-%s-%s-%s-%s"):format( rnd_bytes:sub(1, 8),
+ rnd_bytes:sub(9, 12), rnd_bytes:sub( 13, 16 ), rnd_bytes:sub( 17, 20 ),
+ rnd_bytes:sub(21, 32) )
+ end,
- --- Retrieves a probe from the probes table by name
- --
- -- @param name string containing the name of the probe to retrieve
- -- @return probe table containing the probe or nil if not found
- getProbeByName = function( name )
- for _, probe in ipairs(probes) do
- if ( probe.name == name ) then
- return probe
- end
- end
- return
- end,
+ --- Retrieves a probe from the probes table by name
+ --
+ -- @param name string containing the name of the probe to retrieve
+ -- @return probe table containing the probe or nil if not found
+ getProbeByName = function( name )
+ for _, probe in ipairs(probes) do
+ if ( probe.name == name ) then
+ return probe
+ end
+ end
+ return
+ end,
- getProbes = function() return probes end,
+ getProbes = function() return probes end,
- sha1sum = function(data) return openssl.sha1(data) end
+ sha1sum = function(data) return openssl.sha1(data) end
}
Decoders = {
- --- Decodes a wcf probe response
- --
- -- @param data string containing the response as received over the wire
- -- @return status true on success, false on failure
- -- @return response table containing the following fields
- -- msgid, xaddrs, types
- -- err string containing the error message
- ['wcf'] = function( data )
- local response = {}
+ --- Decodes a wcf probe response
+ --
+ -- @param data string containing the response as received over the wire
+ -- @return status true on success, false on failure
+ -- @return response table containing the following fields
+ -- msgid, xaddrs, types
+ -- err string containing the error message
+ ['wcf'] = function( data )
+ local response = {}
- -- extracts the messagid, so we can check if we already got a response
- response.msgid = data:match("<.*:MessageID>urn:uuid:(.*)")
+ -- extracts the messagid, so we can check if we already got a response
+ response.msgid = data:match("<.*:MessageID>urn:uuid:(.*)")
- -- if unable to parse msgid return nil
- if ( not(response.msgid) ) then
- return false, "No message id was found"
- end
+ -- if unable to parse msgid return nil
+ if ( not(response.msgid) ) then
+ return false, "No message id was found"
+ end
- response.xaddrs = data:match("<.*:*XAddrs>(.*)")
- response.types = data:match("<.*:Types>[wsdp:]*(.*)")
+ response.xaddrs = data:match("<.*:*XAddrs>(.*)")
+ response.types = data:match("<.*:Types>[wsdp:]*(.*)")
- return true, response
- end,
+ return true, response
+ end,
- --- Decodes a general probe response
- --
- -- @param data string containing the response as received over the wire
- -- @return status true on success, false on failure
- -- @return response table containing the following fields
- -- msgid, xaddrs, types
- -- err string containing the error message
- ['general'] = function( data )
- return Decoders['wcf'](data)
- end,
+ --- Decodes a general probe response
+ --
+ -- @param data string containing the response as received over the wire
+ -- @return status true on success, false on failure
+ -- @return response table containing the following fields
+ -- msgid, xaddrs, types
+ -- err string containing the error message
+ ['general'] = function( data )
+ return Decoders['wcf'](data)
+ end,
- --- Decodes an error message received from the service
- --
- -- @param data string containing the response as received over the wire
- -- @return status true on success, false on failure
- -- @return err string containing the error message
- ['error'] = function( data )
- local response = "Failed to decode response from device: "
- local err = data:match("(.-)<")
- response = response .. (err or "Unknown error")
+ --- Decodes an error message received from the service
+ --
+ -- @param data string containing the response as received over the wire
+ -- @return status true on success, false on failure
+ -- @return err string containing the error message
+ ['error'] = function( data )
+ local response = "Failed to decode response from device: "
+ local err = data:match("(.-)<")
+ response = response .. (err or "Unknown error")
- return true, response
- end,
+ return true, response
+ end,
}
Comm = {
- --- Creates a new Comm instance
- --
- -- @param host string containing the host name or ip
- -- @param port number containing the port to connect to
- -- @return o a new instance of Comm
- new = function( self, host, port, mcast )
- local o = {}
- setmetatable(o, self)
- self.__index = self
- o.host = host
- o.port = port
- o.mcast = mcast or false
- o.sendcount = 2
- o.timeout = 5000
- return o
- end,
+ --- Creates a new Comm instance
+ --
+ -- @param host string containing the host name or ip
+ -- @param port number containing the port to connect to
+ -- @return o a new instance of Comm
+ new = function( self, host, port, mcast )
+ local o = {}
+ setmetatable(o, self)
+ self.__index = self
+ o.host = host
+ o.port = port
+ o.mcast = mcast or false
+ o.sendcount = 2
+ o.timeout = 5000
+ return o
+ end,
- --- Sets the timeout for socket reads
- setTimeout = function( self, timeout ) self.timeout = timeout end,
+ --- Sets the timeout for socket reads
+ setTimeout = function( self, timeout ) self.timeout = timeout end,
- --- Sends a probe over the wire
- --
- -- @return status true on success, false on failure
- sendProbe = function( self )
- local status, err
+ --- Sends a probe over the wire
+ --
+ -- @return status true on success, false on failure
+ sendProbe = function( self )
+ local status, err
- -- replace all instances of #uuid# in the probe
- local probedata = self.probe.data:gsub("#uuid#", Util.generateUUID())
+ -- replace all instances of #uuid# in the probe
+ local probedata = self.probe.data:gsub("#uuid#", Util.generateUUID())
- if ( self.mcast ) then
- self.socket = nmap.new_socket("udp")
- self.socket:set_timeout(self.timeout)
- else
- self.socket = nmap.new_socket()
- self.socket:set_timeout(self.timeout)
- status, err = self.socket:connect( self.host, self.port, "udp" )
- if ( not(status) ) then return err end
- end
+ if ( self.mcast ) then
+ self.socket = nmap.new_socket("udp")
+ self.socket:set_timeout(self.timeout)
+ else
+ self.socket = nmap.new_socket()
+ self.socket:set_timeout(self.timeout)
+ status, err = self.socket:connect( self.host, self.port, "udp" )
+ if ( not(status) ) then return err end
+ end
- for i=1, self.sendcount do
- if ( self.mcast ) then
- status, err = self.socket:sendto( self.host, self.port, probedata )
- else
- status, err = self.socket:send( probedata )
- end
- if ( not(status) ) then return err end
- end
- return true
- end,
+ for i=1, self.sendcount do
+ if ( self.mcast ) then
+ status, err = self.socket:sendto( self.host, self.port, probedata )
+ else
+ status, err = self.socket:send( probedata )
+ end
+ if ( not(status) ) then return err end
+ end
+ return true
+ end,
- --- Sets a probe from the probes table to send
- --
- -- @param probe table containing a probe from probes
- setProbe = function( self, probe )
- self.probe = probe
- end,
+ --- Sets a probe from the probes table to send
+ --
+ -- @param probe table containing a probe from probes
+ setProbe = function( self, probe )
+ self.probe = probe
+ end,
- --- Receives one or more responses for a Probe
- --
- -- @return table containing decoded responses suitable for
- -- stdnse.format_output
- recvProbeMatches = function( self )
- local responses = {}
- repeat
- local data
+ --- Receives one or more responses for a Probe
+ --
+ -- @return table containing decoded responses suitable for
+ -- stdnse.format_output
+ recvProbeMatches = function( self )
+ local responses = {}
+ repeat
+ local data
- local status, data = self.socket:receive()
- if ( not(status) ) then
- if ( data == "TIMEOUT" ) then
- break
- else
- return false, data
- end
- end
+ local status, data = self.socket:receive()
+ if ( not(status) ) then
+ if ( data == "TIMEOUT" ) then
+ break
+ else
+ return false, data
+ end
+ end
- local _, ip
- status, _, _, ip, _ = self.socket:get_info()
- if( not(status) ) then
- stdnse.print_debug( 3, "wsdd.recvProbeMatches: ERROR: Failed to get socket info" )
- return false, "ERROR: Failed to get socket info"
- end
+ local _, ip
+ status, _, _, ip, _ = self.socket:get_info()
+ if( not(status) ) then
+ stdnse.print_debug( 3, "wsdd.recvProbeMatches: ERROR: Failed to get socket info" )
+ return false, "ERROR: Failed to get socket info"
+ end
- -- push the unparsed response to the response table
- local status, response = Decoders[self.probe.name]( data )
- local id, output
- -- if we failed to decode the response indicate this
- if ( status ) then
- output = {}
- table.insert(output, "Message id: " .. response.msgid)
- if ( response.xaddrs ) then
- table.insert(output, "Address: " .. response.xaddrs)
- end
- if ( response.types ) then
- table.insert(output, "Type: " .. response.types)
- end
- id = response.msgid
- else
- status, response = Decoders["error"](data)
- output = response
- id = Util.sha1sum(data)
- end
+ -- push the unparsed response to the response table
+ local status, response = Decoders[self.probe.name]( data )
+ local id, output
+ -- if we failed to decode the response indicate this
+ if ( status ) then
+ output = {}
+ table.insert(output, "Message id: " .. response.msgid)
+ if ( response.xaddrs ) then
+ table.insert(output, "Address: " .. response.xaddrs)
+ end
+ if ( response.types ) then
+ table.insert(output, "Type: " .. response.types)
+ end
+ id = response.msgid
+ else
+ status, response = Decoders["error"](data)
+ output = response
+ id = Util.sha1sum(data)
+ end
- if ( self.mcast and not(probe_matches[id]) ) then
- if target.ALLOW_NEW_TARGETS then target.add(ip) end
- table.insert( responses, { name=ip, output } )
- elseif ( not(probe_matches[id]) ) then
- responses = output
- end
+ if ( self.mcast and not(probe_matches[id]) ) then
+ if target.ALLOW_NEW_TARGETS then target.add(ip) end
+ table.insert( responses, { name=ip, output } )
+ elseif ( not(probe_matches[id]) ) then
+ responses = output
+ end
- -- avoid duplicates
- probe_matches[id] = true
- until( not(self.mcast) )
+ -- avoid duplicates
+ probe_matches[id] = true
+ until( not(self.mcast) )
- -- we're done with the socket
- self.socket:close()
+ -- we're done with the socket
+ self.socket:close()
- return true, responses
- end
+ return true, responses
+ end
}
Helper = {
- --- Creates a new helper instance
- --
- -- @param host string containing the host name or ip
- -- @param port number containing the port to connect to
- -- @return o a new instance of Helper
- new = function( self, host, port )
- local o = {}
- setmetatable(o, self)
- self.__index = self
- o.host = host
- o.port = port
- o.mcast = false
- o.timeout = 5000
- return o
- end,
+ --- Creates a new helper instance
+ --
+ -- @param host string containing the host name or ip
+ -- @param port number containing the port to connect to
+ -- @return o a new instance of Helper
+ new = function( self, host, port )
+ local o = {}
+ setmetatable(o, self)
+ self.__index = self
+ o.host = host
+ o.port = port
+ o.mcast = false
+ o.timeout = 5000
+ return o
+ end,
- --- Instructs the helper to use unconnected sockets supporting multicast
- --
- -- @param mcast boolean true if multicast is to be used, false otherwise
- setMulticast = function( self, mcast )
- assert( type(mcast)=="boolean", "mcast has to be either true or false")
- local family = nmap.address_family()
- self.mcast = mcast
- self.host = (family=="inet6" and "FF02::C" or "239.255.255.250")
- self.port = 3702
- end,
+ --- Instructs the helper to use unconnected sockets supporting multicast
+ --
+ -- @param mcast boolean true if multicast is to be used, false otherwise
+ setMulticast = function( self, mcast )
+ assert( type(mcast)=="boolean", "mcast has to be either true or false")
+ local family = nmap.address_family()
+ self.mcast = mcast
+ self.host = (family=="inet6" and "FF02::C" or "239.255.255.250")
+ self.port = 3702
+ end,
- --- Sets the timeout for socket reads
- setTimeout = function( self, timeout ) self.timeout = timeout end,
+ --- Sets the timeout for socket reads
+ setTimeout = function( self, timeout ) self.timeout = timeout end,
- --- Sends a probe, receives and decodes a probematch
- --
- -- @param probename string containing the name of the probe to send
- -- check probes for available probes
- -- @return status true on success, false on failure
- -- @return matches table containing responses, suitable for printing using
- -- the stdnse.format_output function
- discoverServices = function( self, probename )
- if ( not(HAVE_SSL) ) then return false, "The wsdd library requires OpenSSL" end
+ --- Sends a probe, receives and decodes a probematch
+ --
+ -- @param probename string containing the name of the probe to send
+ -- check probes for available probes
+ -- @return status true on success, false on failure
+ -- @return matches table containing responses, suitable for printing using
+ -- the stdnse.format_output function
+ discoverServices = function( self, probename )
+ if ( not(HAVE_SSL) ) then return false, "The wsdd library requires OpenSSL" end
- local comm = Comm:new(self.host, self.port, self.mcast)
- local probe = Util.getProbeByName(probename)
- comm:setProbe( probe )
- comm:setTimeout( self.timeout )
+ local comm = Comm:new(self.host, self.port, self.mcast)
+ local probe = Util.getProbeByName(probename)
+ comm:setProbe( probe )
+ comm:setTimeout( self.timeout )
- local status = comm:sendProbe()
- if ( not(status) ) then
- return false, "ERROR: wcf.discoverServices failed"
- end
+ local status = comm:sendProbe()
+ if ( not(status) ) then
+ return false, "ERROR: wcf.discoverServices failed"
+ end
- local status, matches = comm:recvProbeMatches()
- if ( not(status) ) then
- return false, "ERROR: wcf.recvProbeMatches failed"
- end
+ local status, matches = comm:recvProbeMatches()
+ if ( not(status) ) then
+ return false, "ERROR: wcf.recvProbeMatches failed"
+ end
- if ( #matches > 0 ) then matches.name = probe.desc end
- return true, matches
- end,
+ if ( #matches > 0 ) then matches.name = probe.desc end
+ return true, matches
+ end,
- --- Sends a general probe to attempt to discover WSDD supporting devices
- --
- -- @return status true on success, false on failure
- -- @return matches table containing responses, suitable for printing using
- -- the stdnse.format_output function
- discoverDevices = function( self )
- return self:discoverServices('general')
- end,
+ --- Sends a general probe to attempt to discover WSDD supporting devices
+ --
+ -- @return status true on success, false on failure
+ -- @return matches table containing responses, suitable for printing using
+ -- the stdnse.format_output function
+ discoverDevices = function( self )
+ return self:discoverServices('general')
+ end,
- --- Sends a probe that attempts to discover WCF web services
- --
- -- @return status true on success, false on failure
- -- @return matches table containing responses, suitable for printing using
- -- the stdnse.format_output function
- discoverWCFServices = function( self )
- return self:discoverServices('wcf')
- end,
+ --- Sends a probe that attempts to discover WCF web services
+ --
+ -- @return status true on success, false on failure
+ -- @return matches table containing responses, suitable for printing using
+ -- the stdnse.format_output function
+ discoverWCFServices = function( self )
+ return self:discoverServices('wcf')
+ end,
}
diff --git a/nselib/xdmcp.lua b/nselib/xdmcp.lua
index bef87ce0d..1b4c89420 100644
--- a/nselib/xdmcp.lua
+++ b/nselib/xdmcp.lua
@@ -13,388 +13,388 @@ _ENV = stdnse.module("xdmcp", stdnse.seeall)
-- Supported operations
OpCode = {
- BCAST_QUERY = 1,
- QUERY = 2,
- WILLING = 5,
- REQUEST = 7,
- ACCEPT = 8,
- MANAGE = 10,
+ BCAST_QUERY = 1,
+ QUERY = 2,
+ WILLING = 5,
+ REQUEST = 7,
+ ACCEPT = 8,
+ MANAGE = 10,
}
-- Packet class
Packet = {
- -- The cdmcp header
- Header = {
+ -- The cdmcp header
+ Header = {
- -- Creates a new instance of class
- -- @param version number containing the protocol version
- -- @param opcode number containing the opcode type
- -- @param length number containing the length of the data
- -- @return o instance of class
- new = function(self, version, opcode, length)
- local o = { version = version, opcode = opcode, length = length }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new instance of class
+ -- @param version number containing the protocol version
+ -- @param opcode number containing the opcode type
+ -- @param length number containing the length of the data
+ -- @return o instance of class
+ new = function(self, version, opcode, length)
+ local o = { version = version, opcode = opcode, length = length }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Parses data based on which a new object is instantiated
- -- @param data opaque string containing data received over the wire
- -- @return hdr instance of class
- parse = function(data)
- local pos, hdr = nil, Packet.Header:new()
- pos, hdr.version, hdr.opcode, hdr.length = bin.unpack(">SSS", data)
- return hdr
- end,
+ -- Parses data based on which a new object is instantiated
+ -- @param data opaque string containing data received over the wire
+ -- @return hdr instance of class
+ parse = function(data)
+ local pos, hdr = nil, Packet.Header:new()
+ pos, hdr.version, hdr.opcode, hdr.length = bin.unpack(">SSS", data)
+ return hdr
+ end,
- -- Converts the instance to an opaque string
- -- @return str string containing the instance
- __tostring = function(self)
- assert(self.length, "No header length was supplied")
- return bin.pack(">SSS", self.version, self.opcode, self.length)
- end,
- },
+ -- Converts the instance to an opaque string
+ -- @return str string containing the instance
+ __tostring = function(self)
+ assert(self.length, "No header length was supplied")
+ return bin.pack(">SSS", self.version, self.opcode, self.length)
+ end,
+ },
- [OpCode.QUERY] = {
+ [OpCode.QUERY] = {
- -- Creates a new instance of class
- -- @param authnames table of strings containing authentication
- -- mechanism names.
- -- @return o instance of class
- new = function(self, authnames)
- local o = {
- header = Packet.Header:new(1, OpCode.QUERY),
- authnames = authnames or {},
- }
- o.header.length = #o.authnames + 1
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new instance of class
+ -- @param authnames table of strings containing authentication
+ -- mechanism names.
+ -- @return o instance of class
+ new = function(self, authnames)
+ local o = {
+ header = Packet.Header:new(1, OpCode.QUERY),
+ authnames = authnames or {},
+ }
+ o.header.length = #o.authnames + 1
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Converts the instance to an opaque string
- -- @return str string containing the instance
- __tostring = function(self)
- local data = tostring(self.header)
- data = data .. bin.pack("C", #self.authnames)
- for _, name in ipairs(self.authnames) do
- data = data .. bin.pack("P", name)
- end
- return data
- end,
+ -- Converts the instance to an opaque string
+ -- @return str string containing the instance
+ __tostring = function(self)
+ local data = tostring(self.header)
+ data = data .. bin.pack("C", #self.authnames)
+ for _, name in ipairs(self.authnames) do
+ data = data .. bin.pack("P", name)
+ end
+ return data
+ end,
- },
+ },
- [OpCode.BCAST_QUERY] = {
- new = function(...)
- local packet = Packet[OpCode.QUERY]:new(...)
- packet.header.opcode = OpCode.BCAST_QUERY
- return packet
- end,
+ [OpCode.BCAST_QUERY] = {
+ new = function(...)
+ local packet = Packet[OpCode.QUERY]:new(...)
+ packet.header.opcode = OpCode.BCAST_QUERY
+ return packet
+ end,
- __tostring = function(...)
- return Packet[OpCode.QUERY]:__tostring(...)
- end
+ __tostring = function(...)
+ return Packet[OpCode.QUERY]:__tostring(...)
+ end
- },
+ },
- [OpCode.WILLING] = {
+ [OpCode.WILLING] = {
- -- Creates a new instance of class
- -- @return o instance of class
- new = function(self)
- local o = {
- header = Packet.Header:new(1, OpCode.WILLING)
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new instance of class
+ -- @return o instance of class
+ new = function(self)
+ local o = {
+ header = Packet.Header:new(1, OpCode.WILLING)
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Parses data based on which a new object is instantiated
- -- @param data opaque string containing data received over the wire
- -- @return hdr instance of class
- parse = function(data)
- local willing = Packet[OpCode.WILLING]:new()
- willing.header = Packet.Header.parse(data)
+ -- Parses data based on which a new object is instantiated
+ -- @param data opaque string containing data received over the wire
+ -- @return hdr instance of class
+ parse = function(data)
+ local willing = Packet[OpCode.WILLING]:new()
+ willing.header = Packet.Header.parse(data)
- local pos = 7
- pos, willing.authname, willing.hostname,
- willing.status = bin.unpack("ppp", data, pos)
- return willing
- end,
+ local pos = 7
+ pos, willing.authname, willing.hostname,
+ willing.status = bin.unpack("ppp", data, pos)
+ return willing
+ end,
- },
+ },
- [OpCode.REQUEST] = {
+ [OpCode.REQUEST] = {
- -- The connection class
- Connection = {
+ -- The connection class
+ Connection = {
- IpType = {
- IPv4 = 0,
- IPv6 = 6,
- },
+ IpType = {
+ IPv4 = 0,
+ IPv6 = 6,
+ },
- -- Creates a new instance of class
- -- @param iptype number
- -- @param ip opaque string containing the ip
- -- @return o instance of class
- new = function(self, iptype, ip)
- local o = {
- iptype = iptype,
- ip = ip,
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new instance of class
+ -- @param iptype number
+ -- @param ip opaque string containing the ip
+ -- @return o instance of class
+ new = function(self, iptype, ip)
+ local o = {
+ iptype = iptype,
+ ip = ip,
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- },
+ },
- -- Creates a new instance of class
- -- @param disp_no number containing the display name
- -- @param auth_name string containing the authentication name
- -- @param auth_data string containing additional authentication data
- -- @param authr_names string containing authorization mechanisms
- -- @param manf_id string containing the manufacturer id
- -- @return o instance of class
- new = function(self, disp_no, conns, auth_name, auth_data, authr_names, manf_id )
- local o = {
- header = Packet.Header:new(1, OpCode.REQUEST),
- disp_no = disp_no or 1,
- conns = conns or {},
- auth_name = auth_name or "",
- auth_data = auth_data or "",
- authr_names = authr_names or {},
- manf_id = manf_id or "",
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new instance of class
+ -- @param disp_no number containing the display name
+ -- @param auth_name string containing the authentication name
+ -- @param auth_data string containing additional authentication data
+ -- @param authr_names string containing authorization mechanisms
+ -- @param manf_id string containing the manufacturer id
+ -- @return o instance of class
+ new = function(self, disp_no, conns, auth_name, auth_data, authr_names, manf_id )
+ local o = {
+ header = Packet.Header:new(1, OpCode.REQUEST),
+ disp_no = disp_no or 1,
+ conns = conns or {},
+ auth_name = auth_name or "",
+ auth_data = auth_data or "",
+ authr_names = authr_names or {},
+ manf_id = manf_id or "",
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Adds a new connection entry
- -- @param conn instance of Connections
- addConnection = function(self, conn)
- table.insert(self.conns, conn)
- end,
+ -- Adds a new connection entry
+ -- @param conn instance of Connections
+ addConnection = function(self, conn)
+ table.insert(self.conns, conn)
+ end,
- -- Adds a new authorization entry
- -- @param str string containing the name of the authorization mechanism
- addAuthrName = function(self, str)
- table.insert(self.authr_names, str)
- end,
+ -- Adds a new authorization entry
+ -- @param str string containing the name of the authorization mechanism
+ addAuthrName = function(self, str)
+ table.insert(self.authr_names, str)
+ end,
- -- Converts the instance to an opaque string
- -- @return str string containing the instance
- __tostring = function(self)
- local data = bin.pack(">SC", self.disp_no, #self.conns)
- for _, conn in ipairs(self.conns) do
- data = data .. bin.pack(">S", conn.iptype)
- end
- data = data .. bin.pack("C", #self.conns)
- for _, conn in ipairs(self.conns) do
- data = data .. bin.pack(">P", ipOps.ip_to_str(conn.ip))
- end
- data = data .. bin.pack(">PP", self.auth_name, self.auth_data)
- data = data .. bin.pack("C", #self.authr_names)
- for _, authr in ipairs(self.authr_names) do
- data = data .. bin.pack(">P", authr)
- end
- data = data .. bin.pack(">P", self.manf_id)
- self.header.length = #data
+ -- Converts the instance to an opaque string
+ -- @return str string containing the instance
+ __tostring = function(self)
+ local data = bin.pack(">SC", self.disp_no, #self.conns)
+ for _, conn in ipairs(self.conns) do
+ data = data .. bin.pack(">S", conn.iptype)
+ end
+ data = data .. bin.pack("C", #self.conns)
+ for _, conn in ipairs(self.conns) do
+ data = data .. bin.pack(">P", ipOps.ip_to_str(conn.ip))
+ end
+ data = data .. bin.pack(">PP", self.auth_name, self.auth_data)
+ data = data .. bin.pack("C", #self.authr_names)
+ for _, authr in ipairs(self.authr_names) do
+ data = data .. bin.pack(">P", authr)
+ end
+ data = data .. bin.pack(">P", self.manf_id)
+ self.header.length = #data
- return tostring(self.header) .. data
- end,
+ return tostring(self.header) .. data
+ end,
- },
+ },
- [OpCode.ACCEPT] = {
+ [OpCode.ACCEPT] = {
- -- Creates a new instance of class
- -- @param session_id number containing the session id
- -- @param auth_name string containing the authentication name
- -- @param auth_data string containing additional authentication data
- -- @param authr_name string containing the authorization mechanism name
- -- @param authr_names string containing authorization mechanisms
- -- @return o instance of class
- new = function(self, session_id, auth_name, auth_data, authr_name, authr_data)
- local o = {
- header = Packet.Header:new(1, OpCode.ACCEPT),
- session_id = session_id,
- auth_name = auth_name,
- auth_data = auth_data,
- authr_name = authr_name,
- authr_data = authr_data,
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new instance of class
+ -- @param session_id number containing the session id
+ -- @param auth_name string containing the authentication name
+ -- @param auth_data string containing additional authentication data
+ -- @param authr_name string containing the authorization mechanism name
+ -- @param authr_names string containing authorization mechanisms
+ -- @return o instance of class
+ new = function(self, session_id, auth_name, auth_data, authr_name, authr_data)
+ local o = {
+ header = Packet.Header:new(1, OpCode.ACCEPT),
+ session_id = session_id,
+ auth_name = auth_name,
+ auth_data = auth_data,
+ authr_name = authr_name,
+ authr_data = authr_data,
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Parses data based on which a new object is instantiated
- -- @param data opaque string containing data received over the wire
- -- @return hdr instance of class
- parse = function(data)
- local accept = Packet[OpCode.ACCEPT]:new()
- accept.header = Packet.Header.parse(data)
- local pos = 7
- pos, accept.session_id, accept.auth_name, accept.auth_data,
- accept.authr_name, accept.authr_data = bin.unpack(">IPPPP", data, pos)
- return accept
- end,
+ -- Parses data based on which a new object is instantiated
+ -- @param data opaque string containing data received over the wire
+ -- @return hdr instance of class
+ parse = function(data)
+ local accept = Packet[OpCode.ACCEPT]:new()
+ accept.header = Packet.Header.parse(data)
+ local pos = 7
+ pos, accept.session_id, accept.auth_name, accept.auth_data,
+ accept.authr_name, accept.authr_data = bin.unpack(">IPPPP", data, pos)
+ return accept
+ end,
- },
+ },
- [OpCode.MANAGE] = {
+ [OpCode.MANAGE] = {
- -- Creates a new instance of class
- -- @param session_id number containing the session id
- -- @param disp_no number containing the display number
- -- @param disp_class string containing the display class
- -- @return o instance of class
- new = function(self, sess_id, disp_no, disp_class)
- local o = {
- header = Packet.Header:new(1, OpCode.MANAGE),
- session_id = sess_id,
- disp_no = disp_no,
- disp_class = disp_class or ""
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new instance of class
+ -- @param session_id number containing the session id
+ -- @param disp_no number containing the display number
+ -- @param disp_class string containing the display class
+ -- @return o instance of class
+ new = function(self, sess_id, disp_no, disp_class)
+ local o = {
+ header = Packet.Header:new(1, OpCode.MANAGE),
+ session_id = sess_id,
+ disp_no = disp_no,
+ disp_class = disp_class or ""
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- Converts the instance to an opaque string
- -- @return str string containing the instance
- __tostring = function(self)
- local data = bin.pack(">ISP", self.session_id, self.disp_no, self.disp_class)
- self.header.length = #data
- return tostring(self.header) .. data
- end,
+ -- Converts the instance to an opaque string
+ -- @return str string containing the instance
+ __tostring = function(self)
+ local data = bin.pack(">ISP", self.session_id, self.disp_no, self.disp_class)
+ self.header.length = #data
+ return tostring(self.header) .. data
+ end,
- }
+ }
}
-- The Helper class serves as the main script interface
Helper = {
- -- Creates a new instance of Helper
- -- @param host table as received by the action method
- -- @param port table as received by the action method
- -- @param options table
- -- @retun o new instance of Helper
- new = function(self, host, port, options)
- local o = {
- host = host,
- port = port,
- options = options or {},
- }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ -- Creates a new instance of Helper
+ -- @param host table as received by the action method
+ -- @param port table as received by the action method
+ -- @param options table
+ -- @retun o new instance of Helper
+ new = function(self, host, port, options)
+ local o = {
+ host = host,
+ port = port,
+ options = options or {},
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- -- "Connects" to the server (ie. creates the socket)
- -- @return status, true on success, false on failure
- connect = function(self)
- self.socket = nmap.new_socket("udp")
- self.socket:set_timeout(self.options.timeout or 10000)
- return true
- end,
+ -- "Connects" to the server (ie. creates the socket)
+ -- @return status, true on success, false on failure
+ connect = function(self)
+ self.socket = nmap.new_socket("udp")
+ self.socket:set_timeout(self.options.timeout or 10000)
+ return true
+ end,
- -- Creates a xdmcp session
- -- @param auth_name string containing the authentication name
- -- @param authr_name string containing the authorization mechanism name
- -- @param disp_class string containing the display class
- -- @return status true on success, false on failure
- -- @return response table or err string containing an error message
- createSession = function(self, auth_names, authr_names, disp_no)
- local info = nmap.get_interface_info(self.host.interface)
- if ( not(info) ) then
- return false, ("Failed to get information for interface %s"):format(self.host.interface)
- end
+ -- Creates a xdmcp session
+ -- @param auth_name string containing the authentication name
+ -- @param authr_name string containing the authorization mechanism name
+ -- @param disp_class string containing the display class
+ -- @return status true on success, false on failure
+ -- @return response table or err string containing an error message
+ createSession = function(self, auth_names, authr_names, disp_no)
+ local info = nmap.get_interface_info(self.host.interface)
+ if ( not(info) ) then
+ return false, ("Failed to get information for interface %s"):format(self.host.interface)
+ end
- local req = Packet[OpCode.QUERY]:new(auth_names)
- local status, response = self:exch(req)
- if ( not(status) ) then
- return false, response
- elseif ( response.header.opcode ~= OpCode.WILLING ) then
- return false, "Received unexpected response"
- end
+ local req = Packet[OpCode.QUERY]:new(auth_names)
+ local status, response = self:exch(req)
+ if ( not(status) ) then
+ return false, response
+ elseif ( response.header.opcode ~= OpCode.WILLING ) then
+ return false, "Received unexpected response"
+ end
- local REQ = Packet[OpCode.REQUEST]
- local iptype = REQ.Connection.IpType.IPv4
- if ( nmap.address_family() == 'inet6' ) then
- iptype = REQ.Connection.IpType.IPv6
- end
+ local REQ = Packet[OpCode.REQUEST]
+ local iptype = REQ.Connection.IpType.IPv4
+ if ( nmap.address_family() == 'inet6' ) then
+ iptype = REQ.Connection.IpType.IPv6
+ end
- local conns = { REQ.Connection:new(iptype, info.address) }
- local req = REQ:new(disp_no, conns, nil, nil, authr_names)
- local status, response = self:exch(req)
- if ( not(status) ) then
- return false, response
- elseif ( response.header.opcode ~= OpCode.ACCEPT ) then
- return false, "Received unexpected response"
- end
+ local conns = { REQ.Connection:new(iptype, info.address) }
+ local req = REQ:new(disp_no, conns, nil, nil, authr_names)
+ local status, response = self:exch(req)
+ if ( not(status) ) then
+ return false, response
+ elseif ( response.header.opcode ~= OpCode.ACCEPT ) then
+ return false, "Received unexpected response"
+ end
- -- Sending this last manage packet doesn't make any sense as we can't
- -- set up a listening TCP server anyway. When we can, we could enable
- -- this and wait for the incoming request and retrieve X protocol info.
+ -- Sending this last manage packet doesn't make any sense as we can't
+ -- set up a listening TCP server anyway. When we can, we could enable
+ -- this and wait for the incoming request and retrieve X protocol info.
- -- local manage = Packet[OpCode.MANAGE]:new(response.session_id,
- -- disp_no, "MIT-unspecified")
- -- local status, response = self:exch(manage)
- -- if ( not(status) ) then
- -- return false, response
- -- end
+ -- local manage = Packet[OpCode.MANAGE]:new(response.session_id,
+ -- disp_no, "MIT-unspecified")
+ -- local status, response = self:exch(manage)
+ -- if ( not(status) ) then
+ -- return false, response
+ -- end
- return true, {
- session_id = response.session_id,
- auth_name = response.auth_name,
- auth_data = response.auth_data,
- authr_name = response.authr_name,
- authr_data = response.authr_data,
- }
- end,
+ return true, {
+ session_id = response.session_id,
+ auth_name = response.auth_name,
+ auth_data = response.auth_data,
+ authr_name = response.authr_name,
+ authr_data = response.authr_data,
+ }
+ end,
- send = function(self, req)
- return self.socket:sendto(self.host, self.port, tostring(req))
- end,
+ send = function(self, req)
+ return self.socket:sendto(self.host, self.port, tostring(req))
+ end,
- recv = function(self)
- local status, data = self.socket:receive()
- if ( not(status) ) then
- return false, data
- end
- local header = Packet.Header.parse(data)
- if ( not(header) ) then
- return false, "Failed to parse xdmcp header"
- end
- if ( not(Packet[header.opcode]) ) then
- return false, ("No parser for opcode: %d"):format(header.opcode)
- end
- local resp = Packet[header.opcode].parse(data)
- if ( not(resp) ) then
- return false, "Failed to parse response"
- end
- return true, resp
- end,
+ recv = function(self)
+ local status, data = self.socket:receive()
+ if ( not(status) ) then
+ return false, data
+ end
+ local header = Packet.Header.parse(data)
+ if ( not(header) ) then
+ return false, "Failed to parse xdmcp header"
+ end
+ if ( not(Packet[header.opcode]) ) then
+ return false, ("No parser for opcode: %d"):format(header.opcode)
+ end
+ local resp = Packet[header.opcode].parse(data)
+ if ( not(resp) ) then
+ return false, "Failed to parse response"
+ end
+ return true, resp
+ end,
- -- Sends a request to the server, receives and parses a response
- -- @param req instance of Packet
- -- @return status true on success, false on failure
- -- @return response instance of response packet
- exch = function(self, req)
- local status, err = self:send(req)
- if ( not(status) ) then
- return false, "Failed to send xdmcp request"
- end
- return self:recv()
- end,
+ -- Sends a request to the server, receives and parses a response
+ -- @param req instance of Packet
+ -- @return status true on success, false on failure
+ -- @return response instance of response packet
+ exch = function(self, req)
+ local status, err = self:send(req)
+ if ( not(status) ) then
+ return false, "Failed to send xdmcp request"
+ end
+ return self:recv()
+ end,
}
diff --git a/nselib/xmpp.lua b/nselib/xmpp.lua
index 6deedf376..e47e63f08 100644
--- a/nselib/xmpp.lua
+++ b/nselib/xmpp.lua
@@ -7,20 +7,20 @@
-- script written by Vasiliy Kulikov.
--
-- The library consist of the following classes:
--- * XML - containing a minimal XML parser written by
--- Vasiliy Kulikov.
--- * TagProcessor - Contains processing code for common tags
--- * XMPP - containing the low-level functions used to
--- communicate with the Jabber server.
--- * Helper - containing the main interface for script
--- writers
+-- * XML - containing a minimal XML parser written by
+-- Vasiliy Kulikov.
+-- * TagProcessor - Contains processing code for common tags
+-- * XMPP - containing the low-level functions used to
+-- communicate with the Jabber server.
+-- * Helper - containing the main interface for script
+-- writers
--
-- The following sample illustrates how to use the library to authenticate
-- to a XMPP sever:
--
--- local helper = xmpp.Helper:new(host, port, options)
--- local status, err = helper:connect()
--- status, err = helper:login(user, pass, "DIGEST-MD5")
+-- local helper = xmpp.Helper:new(host, port, options)
+-- local status, err = helper:connect()
+-- status, err = helper:login(user, pass, "DIGEST-MD5")
--
--
-- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html
@@ -29,7 +29,7 @@
-- Version 0.2
-- Created 07/19/2011 - v0.1 - Created by Patrik Karlsson
-- Revised 07/22/2011 - v0.2 - Added TagProcessors and two new auth mechs:
--- CRAM-MD5 and LOGIN
+-- CRAM-MD5 and LOGIN
local base64 = require "base64"
local nmap = require "nmap"
@@ -42,381 +42,381 @@ _ENV = stdnse.module("xmpp", stdnse.seeall)
XML = {
- -- This is a trivial XML processor written by Vasiliy Kulikov. It doesn't
- -- fully support XML, but it should be sufficient for the basic XMPP
- -- stream handshake. If you see stanzas with uncommon symbols, feel
- -- free to enhance these regexps.
- parse_tag = function(s)
- local _, _, contents, empty, name = string.find(s, "([^<]*)<(/?)([?:%w-]+)")
- local attrs = {}
- if not name then
- return
- end
- for k, v in string.gmatch(s, "%s([%w:]+)='([^']+)'") do
- attrs[k] = v
- end
- for k, v in string.gmatch(s, "%s([%w:]+)=\"([^\"]+)\"") do
- attrs[k] = v
- end
+ -- This is a trivial XML processor written by Vasiliy Kulikov. It doesn't
+ -- fully support XML, but it should be sufficient for the basic XMPP
+ -- stream handshake. If you see stanzas with uncommon symbols, feel
+ -- free to enhance these regexps.
+ parse_tag = function(s)
+ local _, _, contents, empty, name = string.find(s, "([^<]*)<(/?)([?:%w-]+)")
+ local attrs = {}
+ if not name then
+ return
+ end
+ for k, v in string.gmatch(s, "%s([%w:]+)='([^']+)'") do
+ attrs[k] = v
+ end
+ for k, v in string.gmatch(s, "%s([%w:]+)=\"([^\"]+)\"") do
+ attrs[k] = v
+ end
- local finish = (empty ~= "") or (s:sub(#s-1) == '/>')
+ local finish = (empty ~= "") or (s:sub(#s-1) == '/>')
- return { name = name,
- attrs = attrs,
- start = (empty == ""),
- contents = contents,
- finish = finish }
- end,
+ return { name = name,
+ attrs = attrs,
+ start = (empty == ""),
+ contents = contents,
+ finish = finish }
+ end,
}
TagProcessor = {
- ["failure"] = function(socket, tag)
- return TagProcessor["success"](socket,tag)
- end,
+ ["failure"] = function(socket, tag)
+ return TagProcessor["success"](socket,tag)
+ end,
- ["success"] = function(socket, tag)
- if ( tag.finish ) then return true end
- local newtag
- repeat
- local status, data = socket:receive_buf(">", true)
- if ( not(status) ) then
- return false, ("ERROR: Failed to process %s tag"):format(tag.name)
- end
- newtag = XML.parse_tag(data)
- until( newtag.finish and newtag.name == tag.name )
- if ( newtag.name == tag.name ) then return true, tag end
- return false, ("ERROR: Failed to process %s tag"):format(tag.name)
- end,
+ ["success"] = function(socket, tag)
+ if ( tag.finish ) then return true end
+ local newtag
+ repeat
+ local status, data = socket:receive_buf(">", true)
+ if ( not(status) ) then
+ return false, ("ERROR: Failed to process %s tag"):format(tag.name)
+ end
+ newtag = XML.parse_tag(data)
+ until( newtag.finish and newtag.name == tag.name )
+ if ( newtag.name == tag.name ) then return true, tag end
+ return false, ("ERROR: Failed to process %s tag"):format(tag.name)
+ end,
- ["challenge"] = function(socket, tag)
- local status, data = socket:receive_buf(">", true)
- if ( not(status) ) then return false, "ERROR: Failed to read challenge tag" end
- local tag = XML.parse_tag(data)
+ ["challenge"] = function(socket, tag)
+ local status, data = socket:receive_buf(">", true)
+ if ( not(status) ) then return false, "ERROR: Failed to read challenge tag" end
+ local tag = XML.parse_tag(data)
- if ( not(status) or tag.name ~= "challenge" ) then
- return false, "ERROR: Failed to process challenge"
- end
- return status, (tag.contents and base64.dec(tag.contents))
- end,
+ if ( not(status) or tag.name ~= "challenge" ) then
+ return false, "ERROR: Failed to process challenge"
+ end
+ return status, (tag.contents and base64.dec(tag.contents))
+ end,
}
XMPP = {
- --- Creates a new instance of the XMPP class
- --
- -- @param host table as receieved by the action function
- -- @param port table as receieved by the action function
- -- @param options table containing options, currently supported
- -- timeout - sets the socket timeout
- -- servername - sets the server name to use in
- -- communication with the server.
- -- starttls - start TLS handshake even if it is optional.
- new = function(self, host, port, options)
- local o = { host = host,
- port = port,
- options = options or {},
- auth = { mechs = {} } }
- o.options.timeout = o.options.timeout and o.options.timeout or 10
- o.servername = stdnse.get_hostname(host) or o.options.servername
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ --- Creates a new instance of the XMPP class
+ --
+ -- @param host table as receieved by the action function
+ -- @param port table as receieved by the action function
+ -- @param options table containing options, currently supported
+ -- timeout - sets the socket timeout
+ -- servername - sets the server name to use in
+ -- communication with the server.
+ -- starttls - start TLS handshake even if it is optional.
+ new = function(self, host, port, options)
+ local o = { host = host,
+ port = port,
+ options = options or {},
+ auth = { mechs = {} } }
+ o.options.timeout = o.options.timeout and o.options.timeout or 10
+ o.servername = stdnse.get_hostname(host) or o.options.servername
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- --- Sends data to XMPP server
- -- @param data string containing data to send to server
- -- @return status true on success false on failure
- -- @return err string containing error message
- send = function(self, data)
+ --- Sends data to XMPP server
+ -- @param data string containing data to send to server
+ -- @return status true on success false on failure
+ -- @return err string containing error message
+ send = function(self, data)
- -- this ain't pretty, but we try to "flush" what's left of the receive
- -- buffer, prior to send. This way we account for not reading to the
- -- end of one message resulting in the next read reading from our
- -- previous message.
- self.socket:set_timeout(1)
- repeat
- local status = self.socket:receive_buf("\0", false)
- until(not(status))
- self.socket:set_timeout(self.options.timeout * 1000)
+ -- this ain't pretty, but we try to "flush" what's left of the receive
+ -- buffer, prior to send. This way we account for not reading to the
+ -- end of one message resulting in the next read reading from our
+ -- previous message.
+ self.socket:set_timeout(1)
+ repeat
+ local status = self.socket:receive_buf("\0", false)
+ until(not(status))
+ self.socket:set_timeout(self.options.timeout * 1000)
- return self.socket:send(data)
- end,
+ return self.socket:send(data)
+ end,
- --- Receives a XML tag from the server
- --
- -- @param tag [optional] if unset, receives the next available tag
- -- if set, reads until the given tag has been found
- -- @param close [optional] if set, matches a closing tag
- receive_tag = function(self, tag, close)
- local result
- repeat
- local status, data = self.socket:receive_buf(">", true)
- if ( not(status) ) then return false, data end
- result = XML.parse_tag(data)
- until( ( not(tag) and (close == nil or result.finish == close ) ) or
- ( tag == result.name and ( close == nil or result.finish == close ) ) )
- return true, result
- end,
+ --- Receives a XML tag from the server
+ --
+ -- @param tag [optional] if unset, receives the next available tag
+ -- if set, reads until the given tag has been found
+ -- @param close [optional] if set, matches a closing tag
+ receive_tag = function(self, tag, close)
+ local result
+ repeat
+ local status, data = self.socket:receive_buf(">", true)
+ if ( not(status) ) then return false, data end
+ result = XML.parse_tag(data)
+ until( ( not(tag) and (close == nil or result.finish == close ) ) or
+ ( tag == result.name and ( close == nil or result.finish == close ) ) )
+ return true, result
+ end,
- --- Connects to the XMPP server
- -- @return status true on success, false on failure
- -- @return err string containing an error message if status is false
- connect = function(self)
- assert(self.servername,
- "Cannot connect to XMPP server without valid server name")
+ --- Connects to the XMPP server
+ -- @return status true on success, false on failure
+ -- @return err string containing an error message if status is false
+ connect = function(self)
+ assert(self.servername,
+ "Cannot connect to XMPP server without valid server name")
- -- we may be reconnecting using SSL
- if ( not(self.socket) ) then
- self.socket = nmap.new_socket()
- self.socket:set_timeout(self.options.timeout * 1000)
- local status, err = self.socket:connect(self.host, self.port)
- if ( not(status) ) then
- return false, err
- end
- end
- local data = (""):format(self.servername)
+ -- we may be reconnecting using SSL
+ if ( not(self.socket) ) then
+ self.socket = nmap.new_socket()
+ self.socket:set_timeout(self.options.timeout * 1000)
+ local status, err = self.socket:connect(self.host, self.port)
+ if ( not(status) ) then
+ return false, err
+ end
+ end
+ local data = (""):format(self.servername)
- local status, err = self:send(data)
- if ( not(status) ) then return false, "ERROR: Failed to connect to server" end
+ local status, err = self:send(data)
+ if ( not(status) ) then return false, "ERROR: Failed to connect to server" end
- local version, start_tls
- repeat
- local status, tag = self:receive_tag()
- if ( not(status) ) then return false, "ERROR: Failed to connect to server" end
+ local version, start_tls
+ repeat
+ local status, tag = self:receive_tag()
+ if ( not(status) ) then return false, "ERROR: Failed to connect to server" end
- if ( tag.name == "stream:stream" ) then
- version = tag.attrs and tag.attrs.version
- elseif ( tag.name == "starttls" and tag.start ) then
- status, tag = self:receive_tag()
- if ( not(status) ) then
- return false, "ERROR: Failed to connect to server"
- end
- if ( tag.name ~= "starttls" ) then
- start_tls = tag.name
- else
- start_tls = "optional"
- end
- elseif ( tag.name == "mechanism" and tag.finish ) then
- self.auth.mechs[tag.contents] = true
- end
- until(tag.name == "stream:features" and tag.finish)
+ if ( tag.name == "stream:stream" ) then
+ version = tag.attrs and tag.attrs.version
+ elseif ( tag.name == "starttls" and tag.start ) then
+ status, tag = self:receive_tag()
+ if ( not(status) ) then
+ return false, "ERROR: Failed to connect to server"
+ end
+ if ( tag.name ~= "starttls" ) then
+ start_tls = tag.name
+ else
+ start_tls = "optional"
+ end
+ elseif ( tag.name == "mechanism" and tag.finish ) then
+ self.auth.mechs[tag.contents] = true
+ end
+ until(tag.name == "stream:features" and tag.finish)
- if ( version ~= "1.0" ) then
- return false, "ERROR: Only version 1.0 is supported"
- end
+ if ( version ~= "1.0" ) then
+ return false, "ERROR: Only version 1.0 is supported"
+ end
- if ( start_tls == "required" or self.options.starttls) then
- status, err = self:send("")
- if ( not(status) ) then return false, "ERROR: Failed to initiate STARTTLS" end
- local status, tag = self:receive_tag()
- if ( not(status) ) then return false, "ERROR: Failed to recevice from server" end
- if ( tag.name == "proceed" ) then
- status, err = self.socket:reconnect_ssl()
- self.options.starttls = false
- return self:connect()
- end
- end
+ if ( start_tls == "required" or self.options.starttls) then
+ status, err = self:send("")
+ if ( not(status) ) then return false, "ERROR: Failed to initiate STARTTLS" end
+ local status, tag = self:receive_tag()
+ if ( not(status) ) then return false, "ERROR: Failed to recevice from server" end
+ if ( tag.name == "proceed" ) then
+ status, err = self.socket:reconnect_ssl()
+ self.options.starttls = false
+ return self:connect()
+ end
+ end
- return true
- end,
+ return true
+ end,
- --- Logs in to the XMPP server
- --
- -- @param username string
- -- @param password string
- -- @param mech string containing a supported authentication mechanism
- -- @return status true on success, false on failure
- -- @return err string containing error message if status is false
- login = function(self, username, password, mech)
- assert(mech == "PLAIN" or
- mech == "DIGEST-MD5" or
- mech == "CRAM-MD5" or
- mech == "LOGIN",
- "Unsupported authentication mechanism")
+ --- Logs in to the XMPP server
+ --
+ -- @param username string
+ -- @param password string
+ -- @param mech string containing a supported authentication mechanism
+ -- @return status true on success, false on failure
+ -- @return err string containing error message if status is false
+ login = function(self, username, password, mech)
+ assert(mech == "PLAIN" or
+ mech == "DIGEST-MD5" or
+ mech == "CRAM-MD5" or
+ mech == "LOGIN",
+ "Unsupported authentication mechanism")
- local auth = (""):format(mech)
+ local auth = (""):format(mech)
- -- we currently don't do anything with the realm
- local realm
+ -- we currently don't do anything with the realm
+ local realm
- -- we need to cut the @domain.tld from the username
- if ( username:match("@") ) then
- username, realm = username:match("^(.*)@(.*)$")
- end
+ -- we need to cut the @domain.tld from the username
+ if ( username:match("@") ) then
+ username, realm = username:match("^(.*)@(.*)$")
+ end
- local status, result
+ local status, result
- if ( mech == "PLAIN" ) then
- local mech_params = { username, password }
- local auth_data = sasl.Helper:new(mech):encode(table.unpack(mech_params))
- auth = ("%s"):format(mech, base64.enc(auth_data))
+ if ( mech == "PLAIN" ) then
+ local mech_params = { username, password }
+ local auth_data = sasl.Helper:new(mech):encode(table.unpack(mech_params))
+ auth = ("%s"):format(mech, base64.enc(auth_data))
- status, result = self.socket:send(auth)
- if ( not(status) ) then return false, "ERROR: Failed to send SASL PLAIN authentication" end
+ status, result = self.socket:send(auth)
+ if ( not(status) ) then return false, "ERROR: Failed to send SASL PLAIN authentication" end
- status, result = self:receive_tag()
- if ( not(status) ) then return false, "ERROR: Failed to receive login response" end
+ status, result = self:receive_tag()
+ if ( not(status) ) then return false, "ERROR: Failed to receive login response" end
- if ( result.name == "failure" ) then
- status = TagProcessor[result.name](self.socket, result)
- end
- else
- local status, err = self.socket:send(auth)
- if(not(status)) then return false, "ERROR: Failed to initiate SASL login" end
+ if ( result.name == "failure" ) then
+ status = TagProcessor[result.name](self.socket, result)
+ end
+ else
+ local status, err = self.socket:send(auth)
+ if(not(status)) then return false, "ERROR: Failed to initiate SASL login" end
- local chall
- status, result = self:receive_tag()
- if ( not(status) ) then return false, "ERROR: Failed to retrieve challenge" end
- status, chall = TagProcessor[result.name](self.socket, result)
+ local chall
+ status, result = self:receive_tag()
+ if ( not(status) ) then return false, "ERROR: Failed to retrieve challenge" end
+ status, chall = TagProcessor[result.name](self.socket, result)
- if ( mech == "LOGIN" ) then
- if ( chall ~= "User Name" ) then
- return false, ("ERROR: Login expected 'User Name' received: %s"):format(chall)
- end
- self.socket:send("" ..
- base64.enc(username) ..
- "")
+ if ( mech == "LOGIN" ) then
+ if ( chall ~= "User Name" ) then
+ return false, ("ERROR: Login expected 'User Name' received: %s"):format(chall)
+ end
+ self.socket:send("" ..
+ base64.enc(username) ..
+ "")
- status, result = self:receive_tag()
- if ( not(status) or result.name ~= "challenge") then
- return false, "ERROR: Receiving tag from server"
- end
- status, chall = TagProcessor[result.name](self.socket, result)
+ status, result = self:receive_tag()
+ if ( not(status) or result.name ~= "challenge") then
+ return false, "ERROR: Receiving tag from server"
+ end
+ status, chall = TagProcessor[result.name](self.socket, result)
- if ( chall ~= "Password" ) then
- return false, ("ERROR: Login expected 'Password' received: %s"):format(chall)
- end
+ if ( chall ~= "Password" ) then
+ return false, ("ERROR: Login expected 'Password' received: %s"):format(chall)
+ end
- self.socket:send("" ..
- base64.enc(password) ..
- "")
+ self.socket:send("" ..
+ base64.enc(password) ..
+ "")
- status, result = self:receive_tag()
- if ( not(status) ) then return false, "ERROR: Failed to receive login challenge" end
- if ( result.name == "failure" ) then
- status = TagProcessor[result.name](self.socket, result)
- return false, "Login failed"
- end
- else
- local mech_params = { username, password, chall, "xmpp", "xmpp/" .. self.servername }
- local auth_data = sasl.Helper:new(mech):encode(table.unpack(mech_params))
- auth_data = "" ..
- base64.enc(auth_data) .. ""
+ status, result = self:receive_tag()
+ if ( not(status) ) then return false, "ERROR: Failed to receive login challenge" end
+ if ( result.name == "failure" ) then
+ status = TagProcessor[result.name](self.socket, result)
+ return false, "Login failed"
+ end
+ else
+ local mech_params = { username, password, chall, "xmpp", "xmpp/" .. self.servername }
+ local auth_data = sasl.Helper:new(mech):encode(table.unpack(mech_params))
+ auth_data = "" ..
+ base64.enc(auth_data) .. ""
- status, err = self.socket:send(auth_data)
+ status, err = self.socket:send(auth_data)
- -- read to the end tag regardless of what it is
- -- it should be one of either: success, challenge or error
- repeat
- status, result = self:receive_tag()
- if ( not(status) ) then return false, "ERROR: Failed to receive login challenge" end
+ -- read to the end tag regardless of what it is
+ -- it should be one of either: success, challenge or error
+ repeat
+ status, result = self:receive_tag()
+ if ( not(status) ) then return false, "ERROR: Failed to receive login challenge" end
- if ( result.name == "failure" ) then
- status = TagProcessor[result.name](self.socket, result)
- return false, "Login failed"
- elseif ( result.name == "success" ) then
- status = TagProcessor[result.name](self.socket, result)
- if ( not(status) ) then return false, "Failed to process success message" end
- return true, "Login success"
- elseif ( result.name ~= "challenge" ) then
- return false, "ERROR: Failed to receive login challenge"
- end
- until( result.name == "challenge" and result.finish )
+ if ( result.name == "failure" ) then
+ status = TagProcessor[result.name](self.socket, result)
+ return false, "Login failed"
+ elseif ( result.name == "success" ) then
+ status = TagProcessor[result.name](self.socket, result)
+ if ( not(status) ) then return false, "Failed to process success message" end
+ return true, "Login success"
+ elseif ( result.name ~= "challenge" ) then
+ return false, "ERROR: Failed to receive login challenge"
+ end
+ until( result.name == "challenge" and result.finish )
- if ( result.name == "challenge" and mech == "DIGEST-MD5" ) then
- status, result = self.socket:send("")
- if ( not(status) ) then return false, "ERROR: Failed to send DIGEST-MD5 request" end
- status, result = self:receive_tag()
- if ( not(status) ) then return false, "ERROR: Failed to receive DIGEST-MD5 response" end
- end
- end
- end
- if ( result.name == "success" ) then
- return true, "Login success"
- end
+ if ( result.name == "challenge" and mech == "DIGEST-MD5" ) then
+ status, result = self.socket:send("")
+ if ( not(status) ) then return false, "ERROR: Failed to send DIGEST-MD5 request" end
+ status, result = self:receive_tag()
+ if ( not(status) ) then return false, "ERROR: Failed to receive DIGEST-MD5 response" end
+ end
+ end
+ end
+ if ( result.name == "success" ) then
+ return true, "Login success"
+ end
- return false, "Login failed"
- end,
+ return false, "Login failed"
+ end,
- --- Retrieves the available authentication mechanisms
- -- @return table containing all available authentication mechanisms
- getAuthMechs = function(self) return self.auth.mechs end,
+ --- Retrieves the available authentication mechanisms
+ -- @return table containing all available authentication mechanisms
+ getAuthMechs = function(self) return self.auth.mechs end,
- --- Disconnects the socket from the server
- -- @return status true on success, false on failure
- disconnect = function(self)
- local status, err = self.socket:close()
- self.socket = nil
- return status, err
- end,
+ --- Disconnects the socket from the server
+ -- @return status true on success, false on failure
+ disconnect = function(self)
+ local status, err = self.socket:close()
+ self.socket = nil
+ return status, err
+ end,
}
Helper = {
- --- Creates a new Helper instance
- -- @param host table as receieved by the action function
- -- @param port table as receieved by the action function
- -- @param options table containing options, currently supported
- -- timeout - sets the socket timeout
- -- servername - sets the server name to use in
- -- communication with the server.
- new = function(self, host, port, options)
- local o = { host = host,
- port = port,
- options = options or {},
- xmpp = XMPP:new(host, port, options),
- state = "" }
- setmetatable(o, self)
- self.__index = self
- return o
- end,
+ --- Creates a new Helper instance
+ -- @param host table as receieved by the action function
+ -- @param port table as receieved by the action function
+ -- @param options table containing options, currently supported
+ -- timeout - sets the socket timeout
+ -- servername - sets the server name to use in
+ -- communication with the server.
+ new = function(self, host, port, options)
+ local o = { host = host,
+ port = port,
+ options = options or {},
+ xmpp = XMPP:new(host, port, options),
+ state = "" }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+ end,
- --- Connects to the XMPP server and starts the initial communication
- -- @return status true on success, false on failure
- -- @return err string containing an error message is status is false
- connect = function(self)
- if ( not(self.host.targetname) and
- not(self.options.servername) ) then
- return false, "ERROR: Cannot connect to XMPP server without valid server name"
- end
- self.state = "CONNECTED"
- return self.xmpp:connect()
- end,
+ --- Connects to the XMPP server and starts the initial communication
+ -- @return status true on success, false on failure
+ -- @return err string containing an error message is status is false
+ connect = function(self)
+ if ( not(self.host.targetname) and
+ not(self.options.servername) ) then
+ return false, "ERROR: Cannot connect to XMPP server without valid server name"
+ end
+ self.state = "CONNECTED"
+ return self.xmpp:connect()
+ end,
- --- Login to the XMPP server
- --
- -- @param username string
- -- @param password string
- -- @param mech string containing a supported authentication mechanism
- -- (@see getAuthMechs)
- login = function(self, username, password, mech)
- return self.xmpp:login(username, password, mech)
- end,
+ --- Login to the XMPP server
+ --
+ -- @param username string
+ -- @param password string
+ -- @param mech string containing a supported authentication mechanism
+ -- (@see getAuthMechs)
+ login = function(self, username, password, mech)
+ return self.xmpp:login(username, password, mech)
+ end,
- --- Retrieves the available authentication mechanisms
- -- @return table containing all available authentication mechanisms
- getAuthMechs = function(self)
- if ( self.state == "CONNECTED" ) then
- return self.xmpp:getAuthMechs()
- end
- return
- end,
+ --- Retrieves the available authentication mechanisms
+ -- @return table containing all available authentication mechanisms
+ getAuthMechs = function(self)
+ if ( self.state == "CONNECTED" ) then
+ return self.xmpp:getAuthMechs()
+ end
+ return
+ end,
- --- Closes the connection to the server
- close = function(self)
- self.xmpp:disconnect()
- self.state = "DISCONNECTED"
- end,
+ --- Closes the connection to the server
+ close = function(self)
+ self.xmpp:disconnect()
+ self.state = "DISCONNECTED"
+ end,
}