---
-- This module was written to marshall parameters for Microsoft RPC (MSRPC) calls. The values passed in and out are based
-- on structs defined by the protocol, and documented by Samba developers. For detailed breakdowns of the types, take a
-- look at Samba 4.0's .idl
files.
--
-- There is nothing simple about how this all comes together, so I'll take some time to explain how it's done. This
-- is fairly technical and, when it comes right down to it, unnecessary for how to use these functions (although if you
-- want to write one of these, you best understand it).
--
-- There are base types, like int32 and int16. These are marshalled the way you'd expect (converted to a 4- or
-- 2-byte little endian string). The only trick with these is that they have to end up aligned on 4-byte boundaries.
-- So, a 2-byte integer requires 2 bytes of padding, and a 1-byte integer requires 3 bytes of padding. The functions
-- marshall_int32
, marshall_int16
, etc. will marshall the base types, and unmarshall_int32
,
-- unmarshall_int16
, etc. will unmarshall them.
--
-- Strings are a little bit trickier. A string is preceded by three 32-bit values: the max length, the offset, and
-- the length. Additionally, strings may or may not be null terminated, depending on where they're being used. For
-- more information on strings, see the comments on marshall_unicode
. The functions marshall_unicode
-- and unmarshall_unicode
can be used to mashall/unmarshall strings.
--
-- Pointers also have interesting properties. A pointer is preceeded by a 4-byte value called (at least by Wireshark)
-- the "referent id". For a valid pointer, this can be anything except 0 (I use 'NMAP' for it). If it's '0', then
-- it's a null pointer and the data doesn't actually follow. To help clarify, a pointer to the integer '4' could be
-- marshalled as the hex string 78 56 34 12 04 00 00 00
(the referent_id is 0x12345678 and the integer
-- itself is 0x00000004). If the integer is nil, then it's marshalled as 00 00 00 00
, which is simply
-- a referent_id of 0.
--
-- From the perspective of the program, pointers can be marshalled by using the "_ptr
" versions of normal functions
-- (for example, marshall_int32_ptr
and unmarshall_unicode_ptr
. From the perspective
-- of functions within this module, especially functions for marshalling structs and arrays, the marshall_ptr
-- and unmarshall_ptr
functions should be used. These can marshall any data type; the marshalling function
-- is passed as a parameter.
--
-- So far, this is fairly straight forward. Arrays are where everything falls apart.
--
-- An array of basic types is simply the types themselves, preceeded by the "max length" of the array (which can be
-- longer than the actual length). When pointers are used in an array, however, things get hairy. The 'referent_id's
-- of the pointers are all put at the start of the array, along with the base types. Then, the data is put at the
-- end of the array, for all the referent_ids that aren't null. Let's say you have four strings, "abc", "def", null, and
-- "jkl", in an array. The array would look like this:
--
-- 0x00200000 (referent_id for "abc")
-- 0x00400000 (referent_id for "def")
-- 0x00000000 (null referent_id)
-- 0x00800000 (referent_id for "jkl")
-- "abc" (note that this also has the standard string stuff, the max_length, offset, and actual_length)
-- "def"
-- "ghi"
--
--
-- If you mix in a base type, it goes at the front along with the referent_ids. So, let's say you have a structure
-- that contains two integers and a string. You have an array of these. It would encode like this:
--
-- 0x00200000 (referent_id for the string in the first struct)
-- 0x00000001 (first integer in the first struct)
-- 0x00000002 (second integer in the first struct)
-- 0x00400000 (referent_id for the string in the second struct)
-- 0x00000003 (first integer in the second struct)
-- 0x00000004 (second integer in the second struct)
-- "string1" (contains max_length, offset, and actual_length)
-- "string2"
--
--
-- From the perspective of the program, arrays shouldn't need to be marshalled/unmarshalled, this is tricky and should be
-- left up to functions within this module. Functions within this module should use marshall_array
and
-- unmarshall_array
to interact with arrays. These take callback functions for the datatype being stored
-- in the array; these callback functions have to be in a particular format, so care should be taken when writing them.
-- In particular, the first parameter has to be location
, which is used to separate the header (the part with the
-- referent_ids) and the body (the part with the pointer data). These are explained more thoroughly in the function headers.
--
-- Structs are handled the same as arrays. The referent_ids and base types go at the top, and the values being pointed to
-- go at the bottom. An array of struct, as has already been shown, will have all the base types and referent_ids for all the
-- members at the top, and all the values for all the pointers at the bottom.
--
-- Structs tend to be custom functions. Sometimes, these functions are passed as the callback to marshall_ptr
or
-- marshall_array
(and the equivalent unmarshall_
functions). This means that the custom struct
-- functions have to be able to split themselves into the base types and the pointer data automatically. For an example, see
-- the functions that have already been written.
--
-- In the case where you need to unmarshall the same struct from both an array and a pointer, there's an issue; they require
-- different prototypes. There's really no way to directly fix this, at least, none that I could come up with, so I write
-- a function called unmarshall_struct
. unmarshall_struct
basically calls a struct unmarshalling
-- function the same way unmarshall_array
would. This is a bit of a kludge, but it's the best I could come up
-- with.
--
-- There are different sections in here, which correspond to "families" of types. I modelled these after Samba's .idl
files.
-- MISC corresponds to misc.idl
, LSA to lsa.idl
, etc. Each of these sections has possible dependencies; for example, SAMR
-- functions use LSA strings, and everything uses SECURITY and MISC. So the order is important -- dependencies have to go
-- above the module.
--
-- The datatypes used here are modelled after the datatypes used by Microsoft's functions. Each function that represents
-- a struct will have the struct definition in its comment; and that struct (or the closest representation to it) will be
-- returned. Often, this requires scripts to access something like result['names']['names'][0]['name']
, which is
-- rather unwieldy, but I decided that following Microsoft's definitions was the most usable way for many reasons. I find
-- the best way to figure out how to work a function is to call a print_table()-style function on the result and look at
-- how the response is laid out.
--
-- Many datatypes are automatically encoded when sent and decoded when received to make life easier for developers. Some
-- examples are:
-- * All absolute time values will be seconds from 1970
-- * All relative time values will be in seconds (this includes the hyper
datatype); when possible, the milliseconds/microseconds (as far down as we have access to) will be preserved as a decimal
-- * All enumerations will be a string representing the constant (which can be converted to a user-readable string using one of the _tostr
functions); what that means is, enumeration values are never used, only the names
-- * SIDs will be converted to user-readable strings in the standard format (S-x-y-...)
-- * GUIDs are stored as tables of values; however, I might change this to a string representation at some point
module(... or "msrpctypes", package.seeall)
require 'bit'
require 'bin'
require 'stdnse'
local REFERENT_ID = 0x50414d4e
local HEAD = 'HEAD'
local BODY = 'BODY'
local ALL = 'ALL'
--- Convert a string to fake unicode (ascii with null characters between them), optionally add a null terminator,
-- and optionally align it to 4-byte boundaries. This is frequently used in MSRPC calls, so I put it here, but
-- it might be a good idea to move this function (and the converse one below) into a separate library.
--
--@param string The string to convert.
--@param do_null [optional] Add a null-terminator to the unicode string. Default false.
--@return The unicode version of the string.
function string_to_unicode(string, do_null)
local i
local result = ""
stdnse.print_debug(4, "MSRPC: Entering string_to_unicode(string = %s)", string)
if(do_null == nil) then
do_null = false
end
-- Try converting the value to a string
if(type(string) ~= 'string') then
string = tostring(string)
end
if(string == nil) then
stdnse.print_debug(1, "MSRPC: WARNING: couldn't convert value to string in string_to_unicode()")
end
-- Loop through the string, adding each character followed by a char(0)
for i = 1, #string, 1 do
result = result .. string.sub(string, i, i) .. string.char(0)
end
-- Add a null, if the caller requestd it
if(do_null == true) then
result = result .. string.char(0) .. string.char(0)
end
-- Align it to a multiple of 4, if necessary
if(#result % 4 ~= 0) then
result = result .. string.char(0) .. string.char(0)
end
stdnse.print_debug(4, "MSRPC: Leaving string_to_unicode()")
return result
end
--- Read a unicode string from a buffer, similar to how bin.unpack
would, optionally eat the null terminator,
-- and optionally align it to 4-byte boundaries.
--
--@param buffer The buffer to read from, typically the full 'arguments' value for MSRPC
--@param pos The position in the buffer to start (just like bin.unpack
)
--@param length The number of ascii characters that will be read (including the null, if do_null is set).
--@param do_null [optional] Remove a null terminator from the string as the last character. Default false.
--@return (pos, string) The new position and the string read, again imitating bin.unpack
. If there was an
-- attempt to read off the end of the string, then 'nil' is returned for both parameters.
function unicode_to_string(buffer, pos, length, do_null)
local i, j, ch, dummy
local string = ""
stdnse.print_debug(4, string.format("MSRPC: Entering unicode_to_string(pos = %d, length = %d)", pos, length))
if(do_null == nil) then
do_null = false
end
if(do_null == true and length > 0) then
length = length - 1
end
for j = 1, length, 1 do
pos, ch, dummy = bin.unpack("func is called, which is passed as
-- a parameter, with the arguments args
. This function has to return a marshalled
-- parameter, but other than that it can be any marshalling function. The 'value' parameter
-- simply determined whether or not it's a null pointer, and will probably be a repease of
-- one of the arguments.
--
-- Note that the function func
doesn't have to conform to any special prototype,
-- as long as the args
array matches what the function wants.
--
-- This can be used to marshall an int16 value of 0x1234 with padding like this:
--
-- marshall_ptr(ALL, marshall_int16, {0x1234, true}, 0x1234)
--
--
-- And here's how a 'nil' string might be marshalled:
--
-- local str = nil
-- marshall_ptr(ALL, marshall_unicode, {str, true}, str)
--
--
--@param location The part of the pointer wanted, either HEAD (for the referent_id), BODY
-- (for the pointer data), or ALL (for both together). Generally, unless the
-- referent_id is split from the data (for example, in an array), you will want
-- ALL.
--@param func The function to call when encoding the body. Should convert the arguments passed
-- in the args
parameter to a string.
--@param args An array of arguments that will be directly passed to the function func
--@param value The value that's actually being encoded. This is simply used to determine whether or
-- not the pointer is null.
--@return A string representing the marshalled data.
local function marshall_ptr(location, func, args, value)
local result = ""
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_ptr(location = %s)", location))
-- If we're marshalling the HEAD section, add a REFERENT_ID.
if(location == HEAD or location == ALL) then
if(func == nil or args == nil or value == nil) then
result = result .. bin.pack("result
-- parameter, it is the result from the first time this is called.
--
-- The function func
has to conform to this format:
--
-- func(data, pos, )
--
--
--@param location The part of the pointer being processed, either HEAD (for the referent_id), BODY
-- (for the pointer data), or ALL (for both together). Generally, unless the
-- referent_id is split from the data (for example, in an array), you will want
-- ALL.
--@param data The data being processed.
--@param pos The position within data
--@param func The function that's used to process the body data (only called if it isn't a null
-- pointer). This function has to conform to a specific prototype, see above.
--@param args The arguments that'll be passed to the function func
, after the data
-- array and the position.
--@param result This is required when unmarshalling the BODY section, which always comes after
-- unmarshalling the HEAD. It is the result returned for this parameter during the
-- HEAD unmarshall. If the referent_id was '0', then this function doesn't unmarshall
-- anything.
--@return (pos, result) The new position along with the result. For HEAD the result is either true
-- for valid pointers or false
for null pointers. For BODY or ALL, the result is
-- nil
for null pointers, or the data for valid pointers.
local function unmarshall_ptr(location, data, pos, func, args, result)
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_ptr()"))
if(args == nil) then
args = {}
end
-- If we're unmarshalling the header, then pull off a referent_id.
if(location == HEAD or location == ALL) then
local referent_id
pos, referent_id = bin.unpack("marshall_ptr, except that this marshalls a type that isn't a pointer.
-- It also understands pointers, in the sense that it'll only return data in the HEAD section, since
-- basetypes are printed in the HEAD and not the BODY.
--
-- Using this isn't strictly necessary, but it cleans up functions for generating structs containing
-- both pointers and basetypes (see marshall_srvsvc_NetShareInfo2
).
--
-- Like marshall_ptr
, the function doesn't have to match any prototype, as long as the
-- proper arguments are passed to it.
--
--@param location The part of the pointer wanted, either HEAD (for the data itself), BODY
-- (for nothing, since this isn't a pointer), or ALL (for the data). Generally, unless the
-- referent_id is split from the data (for example, in an array), you will want
-- ALL.
--@param func The function to call when encoding the body. Should convert the arguments passed
-- in the args
parameter to a string.
--@param args An array of arguments that will be directly passed to the function func
--@return A string representing the marshalled data.
local function marshall_basetype(location, func, args)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_basetype()"))
if(location == HEAD or location == ALL) then
result = bin.pack("
-- func(location, )
--
-- where "location" is the standard HEAD/BODY/ALL location used throughout the functions.
--
--@param array An array of tables. Each table contains 'func', a pointer to the marshalling
-- function and 'args', the arguments to pass to the marshalling function after the
-- 'location' variable.
--@return A string representing the marshalled data.
function marshall_array(array)
local i
local result = ""
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_array()"))
-- The max count is always at the front of the array (at least, in my tests). It is possible that
-- this won't always hold true, so if you're having an issue that you've traced back to this function,
-- you might want to double-check my assumption.
result = result .. bin.pack("func has to conform to a very specific prototype:
--
-- func(location, data, pos, result, )
--
-- Where location is the standard HEAD/BODY location, data and pos
-- are the packet and position within it, result is the result from the HEAD section (if
-- it's nil, it isn't used), and args are arbitrary arguments passed to it.
--
-- I made the call to pass the same arguments to each function when it's called. This is, for example,
-- whether or not to null-terminate a string, or whether or not to pad an int16. If different types are
-- required, you're probably out of luck.
--
--@param data The data being processed.
--@param pos The position within data
.
--@param count The number of elements in the array.
--@param func The function to call to unmarshall each parameter. Has to match a specific prototype;
-- see the function comment.
--@param args Arbitrary arguments to pass to the function.
--@return (pos, result) The new position and the result of unmarshalling this value.
local function unmarshall_array(data, pos, count, func, args)
local i
local size
local result = {}
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_array()"))
if(args == nil) then
args = {}
end
local pos, max_count = bin.unpack("unmarshall_array
. This allows the same
-- struct to be used in unmarshall_array
and in unmarshall_ptr
. It is kind
-- of a kludge, but it makes sense, and was the cleanest solution I could come up with to this problem
-- (although I'm sure that there's a better one staring me in the face).
--
-- The func
parameter, obviously, has to match the same prototype as strings being passed to
-- unmarshall_array
, which is:
--
-- func(location, data, pos, result, )
--
--
--@param data The data being processed.
--@param pos The position within data
.
--@param func The function to call to unmarshall each parameter. Has to match a specific prototype;
-- see the function comment.
--@param args Arbitrary arguments to pass to the function.
--@return (pos, result) The new position and the result of unmarshalling this value.
local function unmarshall_struct(data, pos, func, args)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_struct()"))
if(args == nil) then
args = {}
end
pos, result = func(ALL, data, pos, nil, args)
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_struct()"))
return pos, result
end
-------------------------------------
-- BASE TYPES
-- (dependencies: n/a)
-------------------------------------
--- Marshall a string that is in the format:
-- [string,charset(UTF16)] uint16 *str
--
-- This has the max size of the buffer, the offset (I'm not sure what the offset does, I've
-- never seen it used), the actual size, and the string itself. This will always align to
-- the 4-byte boundary.
--
--@param str The string to insert. Cannot be nil.
--@param do_null [optional] Appends a null to the end of the string. Default false.
--@param max_length [optional] Sets a max length that's different than the string's length. Length
-- is in characters, not bytes.
--@return A string representing the marshalled data.
function marshall_unicode(str, do_null, max_length)
local buffer_length
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_unicode()"))
if(do_null == nil) then
do_null = false
end
if(do_null) then
buffer_length = #str + 1
else
buffer_length = #str
end
if(max_length == nil) then
max_length = buffer_length
end
result = bin.pack("marshall_unicode
, except it's ascii and the null terminator is always used.
--
--@param str The string to marshall.
--@param max_length [optional] The maximum length; default: actual length.
function marshall_ascii(str, max_length)
local buffer_length
local result
local padding = ""
buffer_length = #str + 1
if(max_length == nil) then
max_length = buffer_length
end
while((#(str .. string.char(0 .. padding)) % 4) ~= 0) do
padding = padding .. string.char(0)
end
result = bin.pack("[string,charset(UTF16)] uint16 *str
--
-- See marshall_unicode
for more information.
--
--@param data The data buffer.
--@param pos The position in the data buffer.
--@param do_null [optional] Discards the final character, the string terminator. Default false.
--
--@return (pos, str) The new position, and the string. The string may be nil.
function unmarshall_unicode(data, pos, do_null)
local ptr, str
local max, offset, actual
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_unicode()"))
if(do_null == nil) then
do_null = false
end
pos, max, offset, actual = bin.unpack("data
.
--@param do_null [optional] Assumes a null is at the end of the string. Default false.
--@return (pos, result) The new position and the string.
function unmarshall_unicode_ptr(data, pos, do_null)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_unicode_ptr()"))
pos, result = unmarshall_ptr(ALL, data, pos, unmarshall_unicode, {do_null})
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_unicode_ptr()"))
return pos, result
end
---Marshall an array of unicode strings. This is a perfect demonstration of how to use
-- marshall_array
.
--
--@param strings The array of strings to marshall
--@param do_null [optional] Appends a null to the end of the string. Default false.
--@return A string representing the marshalled data.
function marshall_unicode_array(strings, do_null)
local array = {}
local result
for i = 1, #strings, 1 do
array[i] = {}
array[i]['func'] = marshall_ptr
array[i]['args'] = {marshall_unicode, {strings[i], do_null}, strings[i]}
end
result = marshall_array(array)
return result
end
---Marshall a pointer to an array of unicode strings. See marshall_unicode_array
-- for more information.
--
--@param strings The array of strings to marshall
--@param do_null [optional] Appends a null to the end of the string. Default false.
--@return A string representing the marshalled data.
function marshall_unicode_array_ptr(strings, do_null)
local result
result = marshall_ptr(ALL, marshall_unicode_array, {strings, do_null}, strings)
return result
end
--- Marshall an int64. This is simply an 8-byte integer inserted into the buffer, nothing fancy.
--@param int64 The integer to insert
--@return A string representing the marshalled data.
function marshall_int64(int64)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_int64()"))
result = bin.pack(" [in] uint32 var
--
-- This is simply an integer inserted into the buffer, nothing fancy.
--@param int32 The integer to insert
--@return A string representing the marshalled data.
function marshall_int32(int32)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_int32()"))
result = bin.pack(" [in] uint16 var
--
-- This is simply an integer inserted into the buffer, nothing fancy.
--@param int16 The integer to insert
--@param pad [optional] If set, will align the insert on 4-byte boundaries. Default: true.
--@return A string representing the marshalled data.
function marshall_int16(int16, pad)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_int16()"))
if(pad == false) then
return bin.pack(" [in] uint8 var
--
-- This is simply an integer inserted into the buffer, nothing fancy.
--
--@param int8 The integer to insert
--@param pad [optional] If set, will align the insert on 4-byte boundaries. Default: true.
--@return A string representing the marshalled data.
function marshall_int8(int8, pad)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_int8()"))
if(pad == false) then
return bin.pack("marshall_int64
for more information.
--
--@param data The data being processed.
--@param pos The position within data
.
--@return (pos, int64) The new position, and the value.
function unmarshall_int64(data, pos)
local value
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_int64()"))
pos, value = bin.unpack("marshall_int32
for more information.
--
--@param data The data being processed.
--@param pos The position within data
.
--@return (pos, int32) The new position, and the value.
function unmarshall_int32(data, pos)
local value
pos, value = bin.unpack("marshall_int16
for more information.
--
--@param data The data packet.
--@param pos The position within the data.
--@param pad [optional] If set, will remove extra bytes to align the packet, Default: true
--@return (pos, int16) The new position, and the value.
function unmarshall_int16(data, pos, pad)
local value
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_int16()"))
pos, value = bin.unpack("marshall_int8 for more information.
--
--@param data The data packet.
--@param pos The position within the data.
--@param pad [optional] If set, will remove extra bytes to align the packet, Default: true
--@return (pos, int8) The new position, and the value.
function unmarshall_int8(data, pos, pad)
local value
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_int8()"))
pos, value = bin.unpack(" [in,out] uint32 *ptr
-- If the pointer is null, it simply marshalls the integer '0'. Otherwise,
-- it uses a referent id followed by the integer.
--
--@param int32 The value of the integer pointer
--@return A string representing the marshalled data.
function marshall_int32_ptr(int32)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_int32_ptr()"))
result = marshall_ptr(ALL, marshall_int32, {int32}, int32)
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_int32_ptr()"))
return result
end
--- Marshall a pointer to an int16, which has the following format:
-- [in,out] uint16 *ptr
-- If the pointer is null, it simply marshalls the integer '0'. Otherwise,
-- it uses a referent id followed by the integer.
--
--@param int16 The value of the integer pointer
--@param pad [optional] If set, will align the insert on 4-byte boundaries. Default: true.
--@return A string representing the marshalled data.
function marshall_int16_ptr(int16, pad)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_int16_ptr()"))
result = marshall_ptr(ALL, marshall_int16, {int16, pad}, int16)
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_int16_ptr()"))
return result
end
--- Marshall a pointer to an int8, which has the following format:
-- [in,out] uint8 *ptr
-- If the pointer is null, it simply marshalls the integer '0'. Otherwise,
-- it uses a referent id followed by the integer.
--
--@param int8 The value of the integer pointer
--@param pad [optional] If set, will align the insert on 4-byte boundaries. Default: true.
--@return A string representing the marshalled data.
function marshall_int8_ptr(int8, pad)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_int8_ptr()"))
result = marshall_ptr(ALL, marshall_int8, {int8, pad}, int8)
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_int8_ptr()"))
return result
end
--- Unmarshall a pointer to an int32. See marshall_int32_ptr
for more information.
--
--@param data The data packet.
--@param pos The position within the data.
--@return (pos, int32) The new position, and the value.
function unmarshall_int32_ptr(data, pos)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_int32_ptr()"))
pos, result = unmarshall_ptr(ALL, data, pos, unmarshall_int32, {})
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_int32_ptr()"))
return pos, result
end
--- Unmarshall a pointer to an int16. See marshall_int16_ptr
for more information.
--
--@param data The data packet.
--@param pos The position within the data.
--@param pad [optional] If set, will remove extra bytes to align the packet, Default: true
--@return (pos, int16) The new position, and the value.
function unmarshall_int16_ptr(data, pos, pad)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_int16_ptr()"))
pos, result = unmarshall_ptr(ALL, data, pos, unmarshall_int16, {pad})
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_int16_ptr()"))
return pos, result
end
--- Unmarshall a pointer to an int8. See marshall_int8_ptr
for more information.
--
--@param data The data packet.
--@param pos The position within the data.
--@param pad [optional] If set, will remove extra bytes to align the packet, Default: true
--@return (pos, int8) The new position, and the value.
function unmarshall_int8_ptr(data, pos, pad)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_int8_ptr()"))
pos, result = unmarshall_ptr(ALL, data, pos, unmarshall_int8, {pad})
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_int8_ptr()"))
return pos, result
end
--- Marshall an array of int8s, with an optional max_length set.
--
--@param data The array to marshall, as a string. Cannot be nil.
--@param max_length [optional] The maximum length of the buffer. Default: the length of
-- data
.
--@return A string representing the marshalled data.
function marshall_int8_array(data, max_length)
local result = ""
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_int8_array()"))
if(max_length == nil) then
max_length = #data
end
result = result .. bin.pack("data.
--@return A string representing the marshalled data.
function marshall_int8_array_ptr(data, max_length)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_int8_array_ptr()"))
result = marshall_ptr(ALL, marshall_int8_array, {data, max_length}, data)
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_int8_array_ptr()"))
return result
end
--- Unmarshall a pointer to an array of int8s. By default, aligns the result to 4-byte
-- boundaries.
--
--@param data The data packet.
--@param pos The position within the data.
--@param pad [optional] If set to true, will align data on 4-byte boundaries. Default:
-- true.
--@return (pos, str) The position, and the resulting string, which cannot be nil.
function unmarshall_int8_array_ptr(data, pos, pad)
local str
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_int8_array_ptr()"))
pos, str = unmarshall_ptr(ALL, data, pos, unmarshall_int8_array, {pad})
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_int8_array_ptr()"))
return pos, str
end
--- Unmarshall an array of int32s.
--
--@param data The data packet.
--@param pos The position within the data.
--@return (pos, str) The position, and the resulting string, which cannot be nil.
function unmarshall_int32_array(data, pos, count)
local maxcount
local result = {}
pos, maxcount = unmarshall_int32(data, pos)
for i = 1, count, 1 do
pos, result[i] = unmarshall_int32(data, pos)
end
return pos, result
end
--- Unmarshall a pointer to an array of int32s.
--
--@param data The data packet.
--@param pos The position within the data.
--@return (pos, str) The position, and the resulting string, which cannot be nil.
function unmarshall_int32_array_ptr(data, pos)
local count, array
pos, count = unmarshall_int32(data, pos)
pos, array = unmarshall_ptr(ALL, data, pos, unmarshall_int32_array, {count})
return pos, array
end
---Marshalls an NTTIME. This is sent as the number of 1/10 microseconds since 1601; however
-- the internal representation is the number of seconds since 1970. Because doing conversions
-- in code is annoying, the user will never have to understand anything besides seconds since
-- 1970.
--
--@param time The time, in seconds since 1970.
--@return A string representing the marshalled data.
function marshall_NTTIME(time)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_NTTIME()"))
if(time == 0) then
result = bin.pack("marshall_NTTIME for more information.
--
--@param data The data packet.
--@param pos The position within the data.
--@return (pos, time) The new position, and the time in seconds since 1970.
function unmarshall_NTTIME(data, pos)
local time
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_NTTIME()"))
pos, time = bin.unpack("NTTIME*.
--
--@param data The data packet.
--@param pos The position within the data.
--@return (pos, time) The new position, and the time in seconds since 1970.
function unmarshall_NTTIME_ptr(data, pos)
local time
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_NTTIME_ptr()"))
pos, time = unmarshall_ptr(ALL, data, pos, unmarshall_NTTIME, {})
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_NTTIME_ptr()"))
return pos, time
end
---Unmarshall a SYSTEMTIME structure, converting it to a standard representation. The structure is a
-- follows:
--
--
-- typedef struct _SYSTEMTIME {
-- WORD wYear;
-- WORD wMonth;
-- WORD wDayOfWeek;
-- WORD wDay;
-- WORD wHour;
-- WORD wMinute;
-- WORD wSecond;
-- WORD wMilliseconds;
-- } SYSTEMTIME
--
--
--@param data The data packet.
--@param pos The position within the data.
--@return (pos, time) The new position, and the time in seconds since 1970.
function unmarshall_SYSTEMTIME(data, pos)
local date = {}
local _
pos, date['year'], date['month'], _, date['day'], date['hour'], date['min'], date['sec'], _ = bin.unpack("hyper. I have no idea what a hyper
is, just that it seems
-- to be a 64-bit data type used for measuring time, and that the units happen to be negative
-- microseconds. This function converts the value to seconds and returns it.
--
--@param data The data packet.
--@param pos The position within the data.
--@return (pos, val) The new position, and the result in seconds.
function unmarshall_hyper(data, pos)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_hyper()"))
pos, result = unmarshall_int64(data, pos)
result = result / -10000000
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_hyper()"))
return pos, result
end
---Marshall an entry in a table. Basically, converts the string to a number based on the entries in
-- table
before sending. Multiple values can be ORed together (like flags) by separating
-- them with pipes ("|").
--
--@param val The value to look up. Can be multiple values with pipes between, eg, "A|B|C".
--@param table The table to use for lookups. The keys should be the names, and the values should be
-- the numbers.
--@return A string representing the marshalled data.
local function marshall_Enum32(val, table)
local result = 0
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_Enum32()"))
local vals = stdnse.strsplit("|", val)
local i
for i = 1, #vals, 1 do
result = bit.bor(result, table[vals[i]])
end
result = marshall_int32(result)
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_Enum32()"))
return result
end
---Unmarshall an entry in a table. Basically, converts the next int32 in the buffer to a string
-- based on the entries in table
before returning.
--
--@param data The data packet.
--@param pos The position within the data.
--@param table The table to use for lookups. The keys should be the names, and the values should be
-- the numbers.
--@param default The default value to return if the lookup was unsuccessful.
--@return (pos, policy_handle) The new position, and a table representing the policy_handle.
local function unmarshall_Enum32(data, pos, table, default)
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_Enum32()"))
if(default == nil) then
default = ""
end
local pos, val = unmarshall_int32(data, pos)
for i, v in pairs(table) do
if(v == val) then
return pos, i
end
end
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_Enum32()"))
return pos, default
end
---Unmarshall an entry in a table. Basically, converts the next int16 in the buffer to a string
-- based on the entries in table
before returning.
--
--@param data The data packet.
--@param pos The position within the data.
--@param table The table to use for lookups. The keys should be the names, and the values should be
-- the numbers.
--@param default The default value to return if the lookup was unsuccessful.
--@param pad [optional] If set, will ensure that we end up on an even multiple of 4. Default: true.
--@return (pos, policy_handle) The new position, and a table representing the policy_handle.
local function unmarshall_Enum16(data, pos, table, default, pad)
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_Enum16()"))
if(default == nil) then
default = ""
end
local pos, val = unmarshall_int16(data, pos, pad)
for i, v in pairs(table) do
if(v == val) then
return pos, i
end
end
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_Enum16()"))
return pos, default
end
---Marshall an entry in a table. Basically, converts the string to a number based on the entries in
-- table
before sending. Multiple values can be ORed together (like flags) by separating
-- them with pipes ("|").
--
--@param val The value to look up. Can be multiple values with pipes between, eg, "A|B|C".
--@param table The table to use for lookups. The keys should be the names, and the values should be
-- the numbers.
--@param pad [optional] If set, will ensure that we end up on an even multiple of 4. Default: true.
--@return A string representing the marshalled data.
local function marshall_Enum8(val, table, pad)
local result = 0
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_Enum8()"))
local vals = stdnse.strsplit("|", val)
local i
for i = 1, #vals, 1 do
result = bit.bor(result, table[vals[i]])
end
result = marshall_int8(result, pad)
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_Enum8()"))
return result
end
---Similar to unmarshall_Enum32
, except it'll return every value that could be ANDed together to
-- create the resulting value (except a 0 value). This is effective for parsing flag data types.
--@param data The data packet.
--@param pos The position within the data.
--@param table The table to use for lookups. The keys should be the names, and the values should be
-- the numbers.
--@return (pos, array) The new position, and a table representing the enumeration values.
local function unmarshall_Enum32_array(data, pos, table)
local array = {}
local i, v
local val
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_Enum32_array()"))
pos, val = unmarshall_int32(data, pos)
for i, v in pairs(table) do
if(bit.band(v, val) ~= 0) then
array[#array + 1] = i
end
end
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_Enum32_array()"))
return pos, array
end
---Unmarshall raw data.
--@param data The data packet.
--@param pos The position within the data.
--@param length The number of bytes to unmarshall.
--@return (pos, data) The new position in the packet, and a string representing the raw data.
function unmarshall_raw(data, pos, length)
local val
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_raw()"))
pos, val = bin.unpack(string.format("A%d", length), data, pos)
if(val == nil) then
stdnse.print_debug(1, "MSRPC: ERROR: Ran off the end of a packet in unmarshall_raw(). Please report!")
end
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_raw()"))
return pos, val
end
-------------------------------------
-- MISC
-- (dependencies: n/a)
-------------------------------------
---Marshalls a GUID, which looks like this:
--
--
-- typedef [public,noprint,gensize,noejs] struct {
-- uint32 time_low;
-- uint16 time_mid;
-- uint16 time_hi_and_version;
-- uint8 clock_seq[2];
-- uint8 node[6];
-- } GUID;
--
--
--@param guid A table representing the GUID.
--@return A string representing the marshalled data.
local function marshall_guid(guid)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_guid()"))
result = bin.pack("marshall_guid for the structure.
--
--@param data The data packet.
--@param pos The position within the data.
--@return (pos, result) The new position in data
, and a table representing the datatype.
local function unmarshall_guid(data, pos)
local guid = {}
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_guid()"))
pos, guid['time_low'], guid['time_high'], guid['time_hi_and_version'], guid['clock_seq'], guid['node'] = bin.unpack("
-- typedef struct {
-- uint32 handle_type;
-- GUID uuid;
-- } policy_handle;
--
--
--@param policy_handle The policy_handle to marshall.
--@return A string representing the marshalled data.
function marshall_policy_handle(policy_handle)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_policy_handle()"))
result = bin.pack("marshall_policy_handle for the structure.
--
--@param data The data packet.
--@param pos The position within the data.
--@return (pos, result) The new position in data
, and a table representing the datatype.
function unmarshall_policy_handle(data, pos)
local policy_handle = {}
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_policy_handle()"))
pos, policy_handle['handle_type'] = unmarshall_int32(data, pos)
pos, policy_handle['uuid'] = unmarshall_guid(data, pos)
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_policy_handle()"))
return pos, policy_handle
end
----------------------------------
-- SECURITY
-- (dependencies: MISC)
----------------------------------
---Unmarshall a struct with the following definition:
--
--
-- typedef [public,gensize,noprint,noejs,nosize] struct {
-- uint8 sid_rev_num; /**< SID revision number */
-- [range(0,15)] int8 num_auths; /**< Number of sub-authorities */
-- uint8 id_auth[6]; /**< Identifier Authority */
-- uint32 sub_auths[num_auths];
-- } dom_sid;
--
--
--@param data The data being processed.
--@param pos The position within data
.
--@return (pos, result) The new position in data
, and a table representing the datatype.
function unmarshall_dom_sid2(data, pos)
local i
-- Read the SID from the packet
local sid = {}
pos, sid['count'] = unmarshall_int32(data, pos)
pos, sid['sid_rev_num'] = unmarshall_int8(data, pos, false)
pos, sid['num_auths'] = unmarshall_int8(data, pos, false)
-- Note that authority is big endian (I guess it's an array, not really an integer like we're handling it)
pos, sid['authority_high'], sid['authority_low'] = bin.unpack(">SI", data, pos)
if(sid['authority_low'] == nil) then
stdnse.print_debug(1, "MSRPC: ERROR: Ran off the end of a packet in unmarshall_dom_sid2(). Please report!")
end
sid['authority'] = bit.bor(bit.lshift(sid['authority_high'], 32), sid['authority_low'])
sid['sub_auths'] = {}
for i = 1, sid['num_auths'], 1 do
pos, sid['sub_auths'][i] = unmarshall_int32(data, pos)
end
-- Convert the SID to a string
local result = string.format("S-%u-%u", sid['sid_rev_num'], sid['authority'])
for i = 1, sid['num_auths'], 1 do
result = result .. string.format("-%u", sid['sub_auths'][i])
end
return pos, result
end
---Unmarshall a pointer to a dom_sid2
struct. See the unmarshall_dom_sid2
function
-- for more information.
--
--@param data The data being processed.
--@param pos The position within data
.
--@return (pos, result) The new position in data
, and a table representing the datatype.
function unmarshall_dom_sid2_ptr(data, pos)
return unmarshall_ptr(ALL, data, pos, unmarshall_dom_sid2, {})
end
---Marshall a struct with the following definition:
--
--
-- typedef [public,gensize,noprint,noejs,nosize] struct {
-- uint8 sid_rev_num; /**< SID revision number */
-- [range(0,15)] int8 num_auths; /**< Number of sub-authorities */
-- uint8 id_auth[6]; /**< Identifier Authority */
-- uint32 sub_auths[num_auths];
-- } dom_sid;
--
--
--@return A string representing the marshalled data.
function marshall_dom_sid2(sid)
local i
local pos_next
local sid_array = {}
local result = ""
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_dom_sid2()"))
if(string.find(sid, "^S-") == nil) then
stdnse.print_debug(1, "MSRPC: ERROR: Invalid SID encountered: %s\n", sid)
return nil
end
if(string.find(sid, "-%d+$") == nil) then
stdnse.print_debug(1, "MSRPC: ERROR: Invalid SID encountered: %s\n", sid)
return nil
end
local pos = 3
pos_next = string.find(sid, "-", pos)
sid_array['sid_rev_num'] = string.sub(sid, pos, pos_next - 1)
pos = pos_next + 1
pos_next = string.find(sid, "-", pos)
sid_array['authority_high'] = bit.rshift(string.sub(sid, pos, pos_next - 1), 32)
sid_array['authority_low'] = bit.band(string.sub(sid, pos, pos_next - 1), 0xFFFFFFFF)
sid_array['sub_auths'] = {}
i = 1
repeat
pos = pos_next + 1
pos_next = string.find(sid, "-", pos)
if(pos_next == nil) then
sid_array['sub_auths'][i] = string.sub(sid, pos)
else
sid_array['sub_auths'][i] = string.sub(sid, pos, pos_next - 1)
end
i = i + 1
until pos_next == nil
sid_array['num_auths'] = i - 1
result = bin.pack("SI", sid_array['sid_rev_num'], sid_array['num_auths'], sid_array['authority_high'], sid_array['authority_low'])
for i = 1, sid_array['num_auths'], 1 do
result = result .. bin.pack("lsa_String is a buffer that holds a non-null-terminated string. It can have a max size that's different
-- from its actual size. I tagged this one as "internal" because I don't want the user to have to provide
-- a "location".
--
-- This is the format:
--
--
-- typedef [public,noejs] struct {
-- [value(2*strlen_m(string))] uint16 length;
-- [value(2*strlen_m(string))] uint16 size;
-- [charset(UTF16),size_is(size/2),length_is(length/2)] uint16 *string;
-- } lsa_String;
--
--
--@param location The part of the pointer wanted, either HEAD (for the referent_id), BODY
-- (for the pointer data), or ALL (for both together). Generally, unless the
-- referent_id is split from the data (for example, in an array), you will want
-- ALL.
--@param str The string to marshall
--@param max_length [optional] The maximum size of the buffer, in characters, including the null terminator.
-- Defaults to the length of the string, including the null.
--@param do_null [optional] Appends a null to the end of the string. Default false.
--@return A string representing the marshalled data.
local function marshall_lsa_String_internal(location, str, max_length, do_null)
local length
local result = ""
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_lsa_String_internal()"))
-- Handle default max lengths
if(max_length == nil) then
if(str == nil) then
max_length = 0
else
max_length = #str
end
end
if(str == nil) then
length = 0
else
length = #str
end
if(do_null == nil) then
do_null = false
end
if(location == HEAD or location == ALL) then
result = result .. bin.pack("lsa_String value. See marshall_lsa_String_internal
for more information.
--
--@param location The part of the pointer wanted, either HEAD (for the data itself), BODY
-- (for nothing, since this isn't a pointer), or ALL (for the data). Generally, unless the
-- referent_id is split from the data (for example, in an array), you will want
-- ALL.
--@param data The data packet.
--@param pos The position within the data.
--@param result This is required when unmarshalling the BODY section, which always comes after
-- unmarshalling the HEAD. It is the result returned for this parameter during the
-- HEAD unmarshall. If the referent_id was '0', then this function doesn't unmarshall
-- anything.
--@return (pos, str) The new position, and the unmarshalled string.
local function unmarshall_lsa_String_internal(location, data, pos, result)
local length, size
local str
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_lsa_String_internal()"))
if(location == HEAD or location == ALL) then
pos, length = unmarshall_int16(data, pos, false)
pos, size = unmarshall_int16(data, pos, false)
pos, str = unmarshall_ptr(HEAD, data, pos, unmarshall_unicode, {false})
end
if(location == BODY or location == ALL) then
pos, str = unmarshall_ptr(BODY, data, pos, unmarshall_unicode, {false}, result)
end
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_lsa_String_internal()"))
return pos, str
end
---Public version of marshall_lsa_String_internal
-- see that function on that for more information.
-- This version doesn't require a location
, so it's suitable to be a public function.
--
--@param str The string to marshall
--@param max_length [optional] The maximum size of the buffer, in characters, including the null terminator.
-- Defaults to the length of the string, including the null.
--@return A string representing the marshalled data.
function marshall_lsa_String(str, max_length)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_lsa_String()"))
result = marshall_lsa_String_internal(ALL, str, max_length)
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_lsa_String()"))
return result
end
---Marshall an array of lsa_String objects. This is a perfect demonstration of how to use
-- marshall_array
.
--
--@param strings The array of strings to marshall
--@return A string representing the marshalled data.
function marshall_lsa_String_array(strings)
local array = {}
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_lsa_String_array()"))
for i = 1, #strings, 1 do
array[i] = {}
array[i]['func'] = marshall_lsa_String_internal
array[i]['args'] = {strings[i]}
end
result = marshall_array(array)
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_lsa_String_array()"))
return result
end
---Basically the same as marshall_lsa_String_array
, except it has a different structure
--
--@param strings The array of strings to marshall
function marshall_lsa_String_array2(strings)
local array = {}
local result
for i = 1, #strings, 1 do
array[i] = {}
array[i]['func'] = marshall_lsa_String_internal
array[i]['args'] = {strings[i], nil, nil, false}
end
result = marshall_int32(1000) -- Max length
result = result .. marshall_int32(0) -- Offset
result = result .. marshall_array(array)
--require 'nsedebug'
--nsedebug.print_hex(result)
--os.exit()
return result
end
---Table of SID types.
local lsa_SidType =
{
SID_NAME_USE_NONE = 0, -- NOTUSED
SID_NAME_USER = 1, -- user
SID_NAME_DOM_GRP = 2, -- domain group
SID_NAME_DOMAIN = 3, -- domain: don't know what this is
SID_NAME_ALIAS = 4, -- local group
SID_NAME_WKN_GRP = 5, -- well-known group
SID_NAME_DELETED = 6, -- deleted account: needed for c2 rating
SID_NAME_INVALID = 7, -- invalid account
SID_NAME_UNKNOWN = 8, -- oops.
SID_NAME_COMPUTER = 9 -- machine
}
---String versions of SID types
local lsa_SidType_str =
{
SID_NAME_USE_NONE = "n/a",
SID_NAME_USER = "User",
SID_NAME_DOM_GRP = "Domain group",
SID_NAME_DOMAIN = "Domain",
SID_NAME_ALIAS = "Local group",
SID_NAME_WKN_GRP = "Well known group",
SID_NAME_DELETED = "Deleted account",
SID_NAME_INVALID = "Invalid account",
SID_NAME_UNKNOWN = "Unknown account",
SID_NAME_COMPUTER = "Machine"
}
---Marshall a lsa_SidType
. This datatype is tied to the table above with that
-- name.
--
--@param sid_type The value to marshall, as a string
--@return The marshalled integer representing the given value, or nil
if it wasn't
-- found.
function marshall_lsa_SidType(sid_type)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_lsa_SidType()"))
result = marshall_Enum32(sid_type, lsa_SidType)
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_lsa_SidType()"))
return result
end
---Unmarshall a lsa_SidType
. This datatype is tied to the table with that name.
--
--@param data The data packet.
--@param pos The position within the data.
--@return (pos, str) The new position, and the string representing the datatype.
function unmarshall_lsa_SidType(data, pos)
local str
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_lsa_SidType()"))
pos, str = unmarshall_Enum16(data, pos, lsa_SidType)
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_lsa_SidType()"))
return pos, str
end
---Convert a lsa_SidType
value to a string that can be shown to the user. This is
-- based on the _str table.
--
--@param val The string value (returned by the unmarshall_
function) to convert.
--@return A string suitable for displaying to the user, or nil
if it wasn't found.
function lsa_SidType_tostr(val)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering lsa_SidType_tostr()"))
result = lsa_SidType_str[val]
stdnse.print_debug(4, string.format("MSRPC: Leaving lsa_SidType_tostr()"))
return result
end
---LSA name levels.
local lsa_LookupNamesLevel =
{
LOOKUP_NAMES_ALL = 1,
LOOKUP_NAMES_DOMAINS_ONLY = 2,
LOOKUP_NAMES_PRIMARY_DOMAIN_ONLY = 3,
LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY = 4,
LOOKUP_NAMES_FOREST_TRUSTS_ONLY = 5,
LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY2 = 6
}
---LSA name level strings.
local lsa_LookupNamesLevel_str =
{
LOOKUP_NAMES_ALL = "All",
LOOKUP_NAMES_DOMAINS_ONLY = "Domains only",
LOOKUP_NAMES_PRIMARY_DOMAIN_ONLY = "Primary domains only",
LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY = "Uplevel trusted domains only",
LOOKUP_NAMES_FOREST_TRUSTS_ONLY = "Forest trusted domains only",
LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY2 = "Uplevel trusted domains only (2)"
}
---Marshall a lsa_LookupNamesLevel
. This datatype is tied to the table above with that
-- name.
--
--@param names_level The value to marshall, as a string
--@return The marshalled integer representing the given value, or nil
if it wasn't
-- found.
function marshall_lsa_LookupNamesLevel(names_level)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_lsa_LookupNamesLevel()"))
result = marshall_Enum32(names_level, lsa_LookupNamesLevel)
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_lsa_LookupNamesLevel()"))
return result
end
---Unmarshall a lsa_LookupNamesLevel
. This datatype is tied to the table with that name.
--
--@param data The data packet.
--@param pos The position within the data.
--@return (pos, str) The new position, and the string representing the datatype.
function unmarshall_lsa_LookupNamesLevel(data, pos)
local str
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_lsa_LookupNamesLevel()"))
pos, str = unmarshall_Enum32(data, pos, lsa_LookupNamesLevel)
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_lsa_LookupNamesLevel()"))
return pos, str
end
---Convert a lsa_LookupNamesLevel
value to a string that can be shown to the user. This is
-- based on the _str table.
--
--@param val The string value (returned by the unmarshall_
function) to convert.
--@return A string suitable for displaying to the user, or nil
if it wasn't found.
function lsa_LookupNamesLevel_tostr(val)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering lsa_LookupNamesLevel_tostr()"))
result = lsa_LookupNamesLevel_str[val]
stdnse.print_debug(4, string.format("MSRPC: Leaving lsa_LookupNamesLevel_tostr()"))
return result
end
---Marshall a struct with the following definition:
--
--
-- typedef struct {
-- lsa_SidType sid_type;
-- uint32 rid;
-- uint32 sid_index;
-- uint32 unknown;
-- } lsa_TranslatedSid2;
--
--
--@param location The part of the pointer wanted, either HEAD (for the data itself), BODY
-- (for nothing, since this isn't a pointer), or ALL (for the data). Generally, unless the
-- referent_id is split from the data (for example, in an array), you will want
-- ALL.
--@param sid_type The sid_type
value (I don't know what this means)
--@param rid The rid
(a number representing the user)
--@param sid_index The sid_index
value (I don't know what this means, either)
--@param unknown An unknown value (is normaly 0).
--@return A string representing the marshalled data.
local function marshall_lsa_TranslatedSid2(location, sid_type, rid, sid_index, unknown)
local result = ""
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_lsa_TranslatedSid2()"))
-- Set some default values
if(sid_type == nil) then sid_type = "SID_NAME_USE_NONE" end
if(rid == nil) then rid = 0 end
if(sid_index == nil) then sid_index = 0 end
if(unknown == nil) then unknown = 0 end
if(location == HEAD or location == ALL) then
result = result .. marshall_lsa_SidType(sid_type)
result = result .. marshall_int32(rid)
result = result .. marshall_int32(sid_index)
result = result .. marshall_int32(unknown)
end
if(location == BODY or location == ALL) then
end
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_lsa_TranslatedSid2()"))
return result
end
---Unmarshall a struct with the following definition:
--
--
-- typedef struct {
-- lsa_SidType sid_type;
-- uint32 rid;
-- uint32 sid_index;
-- uint32 unknown;
-- } lsa_TranslatedSid2;
--
--
--@param location The part of the pointer wanted, either HEAD (for the data itself), BODY
-- (for nothing, since this isn't a pointer), or ALL (for the data). Generally, unless the
-- referent_id is split from the data (for example, in an array), you will want
-- ALL.
--@param data The data being processed.
--@param pos The position within data
.
--@param result This is required when unmarshalling the BODY section, which always comes after
-- unmarshalling the HEAD. It is the result returned for this parameter during the
-- HEAD unmarshall. If the referent_id was '0', then this function doesn't unmarshall
-- anything.
--@return (pos, result) The new position in data
, and a table representing the datatype.
local function unmarshall_lsa_TranslatedSid2(location, data, pos, result)
if(result == nil) then
result = {}
end
if(location == HEAD or location == ALL) then
pos, result['sid_type'] = unmarshall_lsa_SidType(data, pos)
pos, result['rid'] = unmarshall_int32(data, pos)
pos, result['sid_index'] = unmarshall_int32(data, pos)
pos, result['unknown'] = unmarshall_int32(data, pos)
end
if(location == BODY or location == ALL) then
end
return pos, result
end
---Marshall a struct with the following definition:
--
--
-- typedef struct {
-- lsa_SidType sid_type;
-- lsa_String name;
-- uint32 sid_index;
-- uint32 unknown;
-- } lsa_TranslatedName2;
--
--
--@param location The part of the pointer wanted, either HEAD (for the data itself), BODY
-- (for nothing, since this isn't a pointer), or ALL (for the data). Generally, unless the
-- referent_id is split from the data (for example, in an array), you will want
-- ALL.
--@param sid_type The sid_type
value, as a string
--@param name The name of the user
--@param sid_index The sid_index (I don't know what this is)
--@param unknown An unknown value, normally 0
--@return A string representing the marshalled data.
local function marshall_lsa_TranslatedName2(location, sid_type, name, sid_index, unknown)
local result = ""
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_lsa_TranslatedName2()"))
-- Set some default values
if(sid_type == nil) then sid_type = "SID_NAME_USE_NONE" end
if(name == nil) then name = "" end
if(sid_index == nil) then sid_index = 0 end
if(unknown == nil) then unknown = 0 end
if(location == HEAD or location == ALL) then
result = result .. marshall_lsa_SidType(sid_type)
result = result .. marshall_lsa_String_internal(HEAD, name)
result = result .. marshall_int32(sid_index)
result = result .. marshall_int32(unknown)
end
if(location == BODY or location == ALL) then
result = result .. marshall_lsa_String_internal(BODY, name)
end
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_lsa_TranslatedName2()"))
return result
end
--@param location The part of the pointer wanted, either HEAD (for the data itself), BODY
-- (for nothing, since this isn't a pointer), or ALL (for the data). Generally, unless the
-- referent_id is split from the data (for example, in an array), you will want
-- ALL.
--@param data The data being processed.
--@param pos The position within data
.
--@param result This is required when unmarshalling the BODY section, which always comes after
-- unmarshalling the HEAD. It is the result returned for this parameter during the
-- HEAD unmarshall. If the referent_id was '0', then this function doesn't unmarshall
-- anything.
--@return (pos, result) The new position in data
, and a table representing the datatype.
local function unmarshall_lsa_TranslatedName2(location, data, pos, result)
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_lsa_TranslatedName2()"))
if(result == nil) then
result = {}
end
if(location == HEAD or location == ALL) then
pos, result['sid_type'] = unmarshall_lsa_SidType(data, pos)
pos, result['name'] = unmarshall_lsa_String_internal(HEAD, data, pos)
pos, result['sid_index'] = unmarshall_int32(data, pos)
pos, result['unknown'] = unmarshall_int32(data, pos)
end
if(location == BODY or location == ALL) then
pos, result['name'] = unmarshall_lsa_String_internal(BODY, data, pos, result['name'])
end
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_lsa_TranslatedName2()"))
return pos, result
end
---Marshall a struct with the following definition:
--
--
-- typedef struct {
-- [range(0,1000)] uint32 count;
-- [size_is(count)] lsa_TranslatedSid2 *sids;
-- } lsa_TransSidArray2;
--
--
--@param sids An array of SIDs to translate (as strings)
--@return A string representing the marshalled data.
function marshall_lsa_TransSidArray2(sids)
local result = ""
local array = {}
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_lsa_TransSidArray2()"))
result = result .. marshall_int32(#sids)
for i = 1, #sids, 1 do
array[i] = {}
array[i]['func'] = marshall_lsa_TranslatedSid2
array[i]['args'] = {sids[i]['sid_type'], sids[i]['rid'], sids[i]['sid_index'], sids[i]['unknown']}
end
result = result .. marshall_ptr(ALL, marshall_array, {array}, array)
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_lsa_TransSidArray2()"))
return result
end
---Marshall a struct with the following definition:
--
--
-- typedef [public] struct {
-- [value(2*strlen_m(string))] uint16 length;
-- [value(2*(strlen_m(string)+1))] uint16 size;
-- [charset(UTF16),size_is(size/2),length_is(length/2)] uint16 *string;
-- } lsa_StringLarge;
--
--
--@param location The part of the pointer wanted, either HEAD (for the data itself), BODY
-- (for nothing, since this isn't a pointer), or ALL (for the data). Generally, unless the
-- referent_id is split from the data (for example, in an array), you will want
-- ALL.
--@param data The data being processed.
--@param pos The position within data
.
--@param result This is required when unmarshalling the BODY section, which always comes after
-- unmarshalling the HEAD. It is the result returned for this parameter during the
-- HEAD unmarshall. If the referent_id was '0', then this function doesn't unmarshall
-- anything.
--@return (pos, result) The new position in data
, and the string value.
local function unmarshall_lsa_StringLarge(location, data, pos, result)
local length, size
local str
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_lsa_StringLarge()"))
if(location == HEAD or location == ALL) then
pos, length = unmarshall_int16(data, pos, false)
pos, size = unmarshall_int16(data, pos, false)
pos, str = unmarshall_ptr(HEAD, data, pos, unmarshall_unicode, {false})
end
if(location == BODY or location == ALL) then
pos, str = unmarshall_ptr(BODY, data, pos, unmarshall_unicode, {false}, result)
end
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_lsa_StringLarge()"))
return pos, str
end
---Unmarshall a struct with the following definition:
--
--
-- typedef struct {
-- lsa_StringLarge name;
-- dom_sid2 *sid;
-- } lsa_DomainInfo;
--
--
--@param location The part of the pointer wanted, either HEAD (for the data itself), BODY
-- (for nothing, since this isn't a pointer), or ALL (for the data). Generally, unless the
-- referent_id is split from the data (for example, in an array), you will want
-- ALL.
--@param data The data being processed.
--@param pos The position within data
.
--@param result This is required when unmarshalling the BODY section, which always comes after
-- unmarshalling the HEAD. It is the result returned for this parameter during the
-- HEAD unmarshall. If the referent_id was '0', then this function doesn't unmarshall
-- anything.
--@return (pos, result) The new position in data
, and a table representing the datatype.
local function unmarshall_lsa_DomainInfo(location, data, pos, result)
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_lsa_DomainInfo()"))
if(result == nil) then
result = {}
end
if(location == HEAD or location == ALL) then
pos, result['name'] = unmarshall_lsa_StringLarge(HEAD, data, pos)
pos, result['sid'] = unmarshall_ptr(HEAD, data, pos, unmarshall_dom_sid2)
end
if(location == BODY or location == ALL) then
pos, result['name'] = unmarshall_lsa_StringLarge(BODY, data, pos, result['name'])
pos, result['sid'] = unmarshall_ptr(BODY, data, pos, unmarshall_dom_sid2, {}, result['sid'])
end
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_lsa_DomainInfo()"))
return pos, result
end
---Unmarshall a struct with the following definition:
--
--
-- typedef struct {
-- [range(0,1000)] uint32 count;
-- [size_is(count)] lsa_DomainInfo *domains;
-- uint32 max_size;
-- } lsa_RefDomainList;
--
--
--@param data The data being processed.
--@param pos The position within data
.
--@return (pos, result) The new position in data
, and a table representing the datatype.
function unmarshall_lsa_RefDomainList(data, pos)
local result = {}
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_lsa_RefDomainList()"))
-- Head
pos, result['count'] = unmarshall_int32(data, pos)
pos, result['domains'] = unmarshall_ptr(HEAD, data, pos, unmarshall_array, {result['count'], unmarshall_lsa_DomainInfo, {}})
pos, result['max_size'] = unmarshall_int32(data, pos)
-- Body
pos, result['domains'] = unmarshall_ptr(BODY, data, pos, unmarshall_array, {result['count'], unmarshall_lsa_DomainInfo, {}}, result['domains'])
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_lsa_RefDomainList()"))
return pos, result
end
---Unmarshall a pointer to a lsa_RefDomainList
. See the unmarshall_lsa_RefDomainList
function
-- for more information.
--
--@param data The data being processed.
--@param pos The position within data
.
--@return (pos, result) The new position in data
, and a table representing the datatype.
function unmarshall_lsa_RefDomainList_ptr(data, pos)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_lsa_RefDomainList_ptr()"))
pos, result = unmarshall_ptr(ALL, data, pos, unmarshall_lsa_RefDomainList, nil)
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_lsa_RefDomainList_ptr()"))
return pos, result
end
---Unmarshall a struct with the following definition:
--
--
-- typedef struct {
-- [range(0,1000)] uint32 count;
-- [size_is(count)] lsa_TranslatedSid2 *sids;
-- } lsa_TransSidArray2;
--
--
--@param data The data being processed.
--@param pos The position within data
.
--@return (pos, result) The new position in data
, and a table representing the datatype.
function unmarshall_lsa_TransSidArray2(data, pos)
local result = {}
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_lsa_TransSidArray2()"))
pos, result['count'] = unmarshall_int32(data, pos)
pos, result['sid'] = unmarshall_ptr(ALL, data, pos, unmarshall_array, {result['count'], unmarshall_lsa_TranslatedSid2, {}})
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_lsa_TransSidArray2()"))
return pos, result
end
---Marshall a struct with the following definition:
--
--
-- typedef struct {
-- uint32 len; /* ignored */
-- uint16 impersonation_level;
-- uint8 context_mode;
-- uint8 effective_only;
-- } lsa_QosInfo;
--
--
-- I didn't bother letting the user specify values, since I don't know what any of them do. The
-- defaults seem to work really well.
--
--@return A string representing the marshalled data.
function marshall_lsa_QosInfo()
local result = ""
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_lsa_QosInfo()"))
result = result .. marshall_int32(12)
result = result .. marshall_int16(2, false)
result = result .. marshall_int8(1, false)
result = result .. marshall_int8(0, false)
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_lsa_QosInfo()"))
return result
end
---Marshall a struct with the following definition:
--
--
-- typedef struct {
-- uint32 len; /* ignored */
-- uint8 *root_dir;
-- [string,charset(UTF16)] uint16 *object_name;
-- uint32 attributes;
-- security_descriptor *sec_desc;
-- lsa_QosInfo *sec_qos;
-- } lsa_ObjectAttribute;
--
--
-- I didn't bother letting the user specify values, since I don't know what any of them do. The
-- defaults seem to work really well.
--
--@return A string representing the marshalled data.
function marshall_lsa_ObjectAttribute()
local result = ""
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_lsa_ObjectAttribute()"))
result = result .. marshall_int32(24)
result = result .. marshall_int32(0) -- Null'ing out these pointers for now. Maybe we'll need them in the future...
result = result .. marshall_int32(0)
result = result .. marshall_int32(0)
result = result .. marshall_int32(0)
result = result .. marshall_ptr(ALL, marshall_lsa_QosInfo, {})
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_lsa_ObjectAttribute()"))
return result
end
---Marshall a struct with the following definition:
--
--
-- typedef struct {
-- dom_sid2 *sid;
-- } lsa_SidPtr;
--
--
--@param location The part of the pointer wanted, either HEAD (for the data itself), BODY
-- (for nothing, since this isn't a pointer), or ALL (for the data). Generally, unless the
-- referent_id is split from the data (for example, in an array), you will want
-- ALL.
--@param sid The SID to marshall (as a string).
--@return A string representing the marshalled data.
local function marshall_lsa_SidPtr(location, sid)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_lsa_SidPtr()"))
result = marshall_ptr(location, marshall_dom_sid2, {sid}, sid)
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_lsa_SidPtr()"))
return result
end
---Marshall a struct with the following definition:
--
--
-- typedef [public] struct {
-- [range(0,1000)] uint32 num_sids;
-- [size_is(num_sids)] lsa_SidPtr *sids;
-- } lsa_SidArray;
--
--
--@param sids The array of SIDs to marshall (as strings).
--@return A string representing the marshalled data.
function marshall_lsa_SidArray(sids)
local result = ""
local array = {}
result = result .. marshall_int32(#sids)
for i = 1, #sids, 1 do
array[i] = {}
array[i]['func'] = marshall_lsa_SidPtr
array[i]['args'] = {sids[i]}
end
result = result .. marshall_ptr(ALL, marshall_array, {array}, array)
return result
end
---Unmarshall a struct with the following definition:
-- typedef struct {
-- dom_sid2 *sid;
-- } lsa_SidPtr;
--
--@param location The part of the pointer wanted, either HEAD (for the data itself), BODY
-- (for nothing, since this isn't a pointer), or ALL (for the data). Generally, unless the
-- referent_id is split from the data (for example, in an array), you will want
-- ALL.
--@param data The data being processed.
--@param pos The position within data
.
--@param result This is required when unmarshalling the BODY section, which always comes after
-- unmarshalling the HEAD. It is the result returned for this parameter during the
-- HEAD unmarshall. If the referent_id was '0', then this function doesn't unmarshall
-- anything.
--@return (pos, result) The new position in data
, and a table representing the datatype.
function unmarshall_lsa_SidPtr(location, data, pos, result)
return unmarshall_ptr(location, data, pos, unmarshall_dom_sid2, {}, result)
end
---Unmarshall a struct with the following definition:
--
-- typedef [public] struct {
-- [range(0,1000)] uint32 num_sids;
-- [size_is(num_sids)] lsa_SidPtr *sids;
-- } lsa_SidArray;
--
--@param data The data being processed.
--@param pos The position within data
.
--@return (pos, result) The new position in data
, and a table representing the datatype.
function unmarshall_lsa_SidArray(data, pos)
local sidarray = {}
pos, sidarray['count'] = unmarshall_int32(data, pos)
pos, sidarray['sids'] = unmarshall_ptr(ALL, data, pos, unmarshall_array, {sidarray['count'], unmarshall_lsa_SidPtr, {}})
return pos, sidarray
end
---Marshall a struct with the following definition:
--
--
-- typedef struct {
-- [range(0,1000)] uint32 count;
-- [size_is(count)] lsa_TranslatedName2 *names;
-- } lsa_TransNameArray2;
--
--
--@param names An array of names to translate.
--@return A string representing the marshalled data.
function marshall_lsa_TransNameArray2(names)
local result = ""
local array = {}
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_lsa_TransNameArray2()"))
if(names == nil) then
result = result .. marshall_int32(0)
array = nil
else
result = result .. marshall_int32(#names)
for i = 1, #names, 1 do
array[i] = {}
array[i]['func'] = marshall_lsa_TranslatedName2
array[i]['args'] = {names[i]['sid_type'], names[i]['name'], names[i]['sid_index'], names[i]['unknown']}
end
end
result = result .. marshall_ptr(ALL, marshall_array, {array}, array)
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_lsa_TransNameArray2()"))
return result
end
---Unmarshall a lsa_TransNameArray2
structure. See the marshall_lsa_TransNameArray2
for more
-- information.
--
--@param data The data being processed.
--@param pos The position within data
.
--@return (pos, result) The new position in data
, and a table representing the datatype.
function unmarshall_lsa_TransNameArray2(data, pos)
local result = {}
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_lsa_TransNameArray2()"))
pos, result['count'] = unmarshall_int32(data, pos)
pos, result['names'] = unmarshall_ptr(ALL, data, pos, unmarshall_array, {result['count'], unmarshall_lsa_TranslatedName2, {}})
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_lsa_TransNameArray2()"))
return pos, result
end
-------------------------------------
-- WINREG
-- (dependencies: LSA, INITSHUTDOWN, SECURITY)
-------------------------------------
--- Access masks for Windows registry calls
local winreg_AccessMask =
{
DELETE_ACCESS = 0x00010000,
READ_CONTROL_ACCESS = 0x00020000,
WRITE_DAC_ACCESS = 0x00040000,
WRITE_OWNER_ACCESS = 0x00080000,
SYNCHRONIZE_ACCESS = 0x00100000,
ACCESS_SACL_ACCESS = 0x00800000,
SYSTEM_SECURITY_ACCESS = 0x01000000,
MAXIMUM_ALLOWED_ACCESS = 0x02000000,
GENERIC_ALL_ACCESS = 0x10000000,
GENERIC_EXECUTE_ACCESS = 0x20000000,
GENERIC_WRITE_ACCESS = 0x40000000,
GENERIC_READ_ACCESS = 0x80000000
}
--- String versions of access masks for Windows registry calls
local winreg_AccessMask_str =
{
DELETE_ACCESS = "Delete",
READ_CONTROL_ACCESS = "Read",
WRITE_DAC_ACCESS = "Write",
WRITE_OWNER_ACCESS = "Write (owner)",
SYNCHRONIZE_ACCESS = "Synchronize",
ACCESS_SACL_ACCESS = "Access SACL",
SYSTEM_SECURITY_ACCESS = "System security",
MAXIMUM_ALLOWED_ACCESS = "Maximum allowed access",
GENERIC_ALL_ACCESS = "All access",
GENERIC_EXECUTE_ACCESS = "Execute access",
GENERIC_WRITE_ACCESS = "Write access",
GENERIC_READ_ACCESS = "Read access"
}
---Marshall a winreg_AccessMask
.
--
--@param accessmask The access mask as a string (see the winreg_AccessMask
-- table)
--@return A string representing the marshalled data.
function marshall_winreg_AccessMask(accessmask)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_winreg_AccessMask()"))
result = marshall_Enum32(accessmask, winreg_AccessMask)
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_winreg_AccessMask()"))
return result
end
---Unmarshall a winreg_AccessMask
. This datatype is tied to the table with that name.
--
--@param data The data packet.
--@param pos The position within the data.
--@return (pos, str) The new position, and the string representing the datatype.
function unmarshall_winreg_AccessMask(data, pos)
local str
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_winreg_AccessMask()"))
pos, str = unmarshall_Enum32(data, pos, winreg_AccessMask)
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_winreg_AccessMask()"))
return pos, str
end
---Convert a winreg_AccessMask
value to a string that can be shown to the user. This is
-- based on the _str table.
--
--@param val The string value (returned by the unmarshall_
function) to convert.
--@return A string suitable for displaying to the user, or nil
if it wasn't found.
function winreg_AccessMask_tostr(val)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering winreg_AccessMask_tostr()"))
result = winreg_AccessMask_str[val]
stdnse.print_debug(4, string.format("MSRPC: Leaving winreg_AccessMask_tostr()"))
return result
end
---Registry types
winreg_Type =
{
REG_NONE = 0,
REG_SZ = 1,
REG_EXPAND_SZ = 2,
REG_BINARY = 3,
REG_DWORD = 4,
REG_DWORD_BIG_ENDIAN = 5,
REG_LINK = 6,
REG_MULTI_SZ = 7,
REG_RESOURCE_LIST = 8,
REG_FULL_RESOURCE_DESCRIPTOR = 9,
REG_RESOURCE_REQUIREMENTS_LIST = 10,
REG_QWORD = 11
}
---Registry type strings
winreg_Type_str =
{
REG_NONE = "None",
REG_SZ = "String",
REG_EXPAND_SZ = "String (expanded)",
REG_BINARY = "Binary",
REG_DWORD = "Dword",
REG_DWORD_BIG_ENDIAN = "Dword (big endian)",
REG_LINK = "Link",
REG_MULTI_SZ = "String (multi)",
REG_RESOURCE_LIST = "Resource list",
REG_FULL_RESOURCE_DESCRIPTOR = "Full resource descriptor",
REG_RESOURCE_REQUIREMENTS_LIST = "Resource requirements list",
REG_QWORD = "Qword"
}
---Marshall a winreg_Type
. This datatype is tied to the table above with that
-- name.
--
--@param winregtype The value to marshall, as a string
--@return The marshalled integer representing the given value, or nil
if it wasn't
-- found.
function marshall_winreg_Type(winregtype)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_winreg_Type()"))
result = marshall_Enum32(winregtype, winreg_Type)
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_winreg_Type()"))
return result
end
---Unmarshall a winreg_Type
. This datatype is tied to the table with that name.
--
--@param data The data packet.
--@param pos The position within the data.
--@return (pos, str) The new position, and the string representing the datatype.
function unmarshall_winreg_Type(data, pos)
local str
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_winreg_Type()"))
pos, str = unmarshall_Enum32(data, pos, winreg_Type)
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_winreg_Type()"))
return pos, str
end
---Marshall a pointer to a winreg_Type
. This datatype is tied to the table above with that
-- name.
--
--@param winreg_type The value to marshall, as a string
--@return The marshalled integer representing the given value, or nil
if it wasn't
-- found.
function marshall_winreg_Type_ptr(winreg_type)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_winreg_Type_ptr()"))
result = marshall_ptr(ALL, marshall_winreg_Type, {winreg_type}, winreg_type)
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_winreg_Type_ptr()"))
return result
end
---Unmarshall a pointer to a winreg_Type
. This datatype is tied to the table with that name.
--
--@param data The data packet.
--@param pos The position within the data.
--@return (pos, str) The new position, and the string representing the datatype.
function unmarshall_winreg_Type_ptr(data, pos)
local str
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_winreg_Type_ptr()"))
pos, str = unmarshall_ptr(ALL, data, pos, unmarshall_winreg_Type, {})
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_winreg_Type_ptr()"))
return pos, str
end
---Convert a winreg_Type
value to a string that can be shown to the user. This is
-- based on the _str table.
--
--@param val The string value (returned by the unmarshall_
function) to convert.
--@return A string suitable for displaying to the user, or nil
if it wasn't found.
function winreg_Type_tostr(val)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering winreg_Type_tostr()"))
result = winreg_Type_str[val]
stdnse.print_debug(4, string.format("MSRPC: Leaving winreg_Type_tostr()"))
return result
end
--- A winreg_stringbuf is a buffer that holds a null-terminated string. It can have a max size that's different
-- from its actual size.
--
-- This is the format:
--
--
-- typedef struct {
-- [value(strlen_m_term(name)*2)] uint16 length;
-- uint16 size;
-- [size_is(size/2),length_is(length/2),charset(UTF16)] uint16 *name;
-- } winreg_StringBuf;
--
--
--@param table The table to marshall. Will probably contain just the 'name' entry.
--@param max_length [optional] The maximum size of the buffer, in characters, including the null terminator.
-- Defaults to the length of the string, including the null.
--@return A string representing the marshalled data.
function marshall_winreg_StringBuf(table, max_length)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_winreg_StringBuf()"))
local name = table['name']
local length
-- Handle default max lengths
if(max_length == nil) then
if(name == nil) then
max_length = 0
else
max_length = #name + 1
end
end
-- For some reason, 0-length strings are handled differently (no null terminator)...
if(name == "") then
length = 0
result = bin.pack("marshall_winreg_StringBuf
, except
-- the string can be nil
.
--
--@param table The table representing the String.
--@param max_length [optional] The maximum size of the buffer, in characters. Defaults to the length of the string, including the null.
--@return A string representing the marshalled data.
function marshall_winreg_StringBuf_ptr(table, max_length)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_winreg_StringBuf_ptr()"))
result = marshall_ptr(ALL, marshall_winreg_StringBuf, {table, max_length}, table)
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_winreg_StringBuf_ptr()"))
return result
end
---Unmarshall a winreg_StringBuffer pointer
--
--@param data The data buffer.
--@param pos The position in the data buffer.
--@return (pos, str) The new position and the string.
function unmarshall_winreg_StringBuf_ptr(data, pos)
local str
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_winreg_StringBuf_ptr()"))
pos, str = unmarshall_ptr(ALL, data, pos, unmarshall_winreg_StringBuf, {})
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_winreg_StringBuf_ptr()"))
return pos, str
end
--- A winreg_String has the same makup as a winreg_StringBuf, as far as I can tell, so delegate to that function.
--
--@param table The table representing the String.
--@param max_length [optional] The maximum size of the buffer, in characters. Defaults to the length of the string, including the null.
--@return A string representing the marshalled data.
function marshall_winreg_String(table, max_length)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_winreg_String()"))
result = marshall_winreg_StringBuf(table, max_length)
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_winreg_String()"))
return result
end
---Unmarshall a winreg_String. Since ti has the same makup as winreg_StringBuf, delegate to that.
--
--@param data The data buffer.
--@param pos The position in the data buffer.
--@return (pos, str) The new position and the string.
function unmarshall_winreg_String(data, pos)
local str
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_winreg_String()"))
pos, str = unmarshall_winreg_StringBuf(data, pos)
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_winreg_String()"))
return pos, str
end
-------------------------------------
-- SRVSVC
-- (dependencies: SECURITY, SVCCTL)
-------------------------------------
---Share types
local srvsvc_ShareType =
{
STYPE_DISKTREE = 0x00000000,
STYPE_DISKTREE_TEMPORARY = 0x40000000,
STYPE_DISKTREE_HIDDEN = 0x80000000,
STYPE_PRINTQ = 0x00000001,
STYPE_PRINTQ_TEMPORARY = 0x40000001,
STYPE_PRINTQ_HIDDEN = 0x80000001,
STYPE_DEVICE = 0x00000002, -- Serial device
STYPE_DEVICE_TEMPORARY = 0x40000002,
STYPE_DEVICE_HIDDEN = 0x80000002,
STYPE_IPC = 0x00000003, -- Interprocess communication (IPC)
STYPE_IPC_TEMPORARY = 0x40000003,
STYPE_IPC_HIDDEN = 0x80000003
}
---Share type strings
local srvsvc_ShareType_str =
{
STYPE_DISKTREE = "Disk",
STYPE_DISKTREE_TEMPORARY = "Disk (temporary)",
STYPE_DISKTREE_HIDDEN = "Disk (hidden)",
STYPE_PRINTQ = "Print queue",
STYPE_PRINTQ_TEMPORARY = "Print queue (temporary)",
STYPE_PRINTQ_HIDDEN = "Print queue (hidden)",
STYPE_DEVICE = "Serial device",
STYPE_DEVICE_TEMPORARY = "Serial device (temporary)",
STYPE_DEVICE_HIDDEN = "Serial device (hidden)",
STYPE_IPC = "Interprocess Communication",
STYPE_IPC_TEMPORARY = "Interprocess Communication (temporary)",
STYPE_IPC_HIDDEN = "Interprocess Communication (hidden)"
}
---Marshall a srvsvc_ShareType
. This datatype is tied to the table above with that
-- name.
--
--@param sharetype The value to marshall, as a string
--@return The marshalled integer representing the given value, or nil
if it wasn't
-- found.
function marshall_srvsvc_ShareType(sharetype)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_srvsvc_ShareType()"))
result = marshall_Enum32(sharetype, srvsvc_ShareType)
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_srvsvc_ShareType()"))
return result
end
---Unmarshall a srvsvc_ShareType
. This datatype is tied to the table with that name.
--
--@param data The data packet.
--@param pos The position within the data.
--@return (pos, str) The new position, and the string representing the datatype.
function unmarshall_srvsvc_ShareType(data, pos)
local str
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_srvsvc_ShareType()"))
pos, str = unmarshall_Enum32(data, pos, srvsvc_ShareType)
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_srvsvc_ShareType()"))
return pos, str
end
---Convert a srvsvc_ShareType
value to a string that can be shown to the user. This is
-- based on the _str table.
--
--@param val The string value (returned by the unmarshall_
function) to convert.
--@return A string suitable for displaying to the user, or nil
if it wasn't found.
function srvsvc_ShareType_tostr(val)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering srvsvc_ShareType_tostr()"))
result = srvsvc_ShareType_str[val]
stdnse.print_debug(4, string.format("MSRPC: Leaving srvsvc_ShareType_tostr()"))
return result
end
---Marshall a NetShareInfo type 0, which is just a name.
--
--
-- typedef struct {
-- [string,charset(UTF16)] uint16 *name;
-- } srvsvc_NetShareInfo0;
--
--
--@param location The part of the pointer wanted, either HEAD (for the data itself), BODY
-- (for nothing, since this isn't a pointer), or ALL (for the data). Generally, unless the
-- referent_id is split from the data (for example, in an array), you will want
-- ALL.
--@param name The name to marshall.
--@return A string representing the marshalled data.
local function marshall_srvsvc_NetShareInfo0(location, name)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_srvsvc_NetShareInfo0()"))
result = marshall_ptr(location, marshall_unicode, {name, true}, name)
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_srvsvc_NetShareInfo0()"))
return result
end
---Unmarshall a NetShareInfo type 0, which is just a name. See the marshall function for more information.
--
--@param location The part of the pointer wanted, either HEAD (for the data itself), BODY
-- (for nothing, since this isn't a pointer), or ALL (for the data). Generally, unless the
-- referent_id is split from the data (for example, in an array), you will want
-- ALL.
--@param data The data packet.
--@param pos The position within the data.
--@param result This is required when unmarshalling the BODY section, which always comes after
-- unmarshalling the HEAD. It is the result returned for this parameter during the
-- HEAD unmarshall. If the referent_id was '0', then this function doesn't unmarshall
-- anything.
--@return (pos, result) The new position in data
, and a table representing the datatype.
local function unmarshall_srvsvc_NetShareInfo0(location, data, pos, result)
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_srvsvc_NetShareInfo0()"))
if(result == nil) then
result = {}
end
if(location == HEAD or location == ALL) then
pos, result['name'] = unmarshall_ptr(HEAD, data, pos, unmarshall_unicode, {true})
end
if(location == BODY or location == ALL) then
pos, result['name'] = unmarshall_ptr(BODY, data, pos, unmarshall_unicode, {true}, result['name'])
end
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_srvsvc_NetShareInfo0()"))
return pos, result
end
---Marshall a NetShareInfo type 1, which is the name and a few other things.
--
--
-- typedef struct {
-- [string,charset(UTF16)] uint16 *name;
-- srvsvc_ShareType type;
-- [string,charset(UTF16)] uint16 *comment;
-- } srvsvc_NetShareInfo1;
--
--
--@param location The part of the pointer wanted, either HEAD (for the data itself), BODY
-- (for nothing, since this isn't a pointer), or ALL (for the data). Generally, unless the
-- referent_id is split from the data (for example, in an array), you will want
-- ALL.
--@param name The name to marshall.
--@param sharetype The sharetype to marshall (as a string).
--@param comment The comment to marshall.
--@return A string representing the marshalled data.
local function marshall_srvsvc_NetShareInfo1(location, name, sharetype, comment)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_srvsvc_NetShareInfo1()"))
local name = marshall_ptr(location, marshall_unicode, {name, true}, name)
local sharetype = marshall_basetype(location, marshall_srvsvc_ShareType, {sharetype})
local comment = marshall_ptr(location, marshall_unicode, {comment, true}, comment)
result = bin.pack("data
, and a table representing the datatype.
local function unmarshall_srvsvc_NetShareInfo1(location, data, pos, result)
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_srvsvc_NetShareInfo1()"))
if(result == nil) then
result = {}
end
if(location == HEAD or location == ALL) then
pos, result['name'] = unmarshall_ptr(HEAD, data, pos, unmarshall_unicode, {true})
pos, result['sharetype'] = unmarshall_srvsvc_ShareType(data, pos)
pos, result['comment'] = unmarshall_ptr(HEAD, data, pos, unmarshall_unicode, {true})
end
if(location == BODY or location == ALL) then
pos, result['name'] = unmarshall_ptr(BODY, data, pos, unmarshall_unicode, {true}, result['name'])
pos, result['comment'] = unmarshall_ptr(BODY, data, pos, unmarshall_unicode, {true}, result['comment'])
end
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_srvsvc_NetShareInfo1()"))
return pos, result
end
---Marshall a NetShareInfo type 2, which is the name and a few other things.
--
--
-- typedef struct {
-- [string,charset(UTF16)] uint16 *name;
-- srvsvc_ShareType type;
-- [string,charset(UTF16)] uint16 *comment;
-- uint32 permissions;
-- uint32 max_users;
-- uint32 current_users;
-- [string,charset(UTF16)] uint16 *path;
-- [string,charset(UTF16)] uint16 *password;
-- } srvsvc_NetShareInfo2;
--
--
--@param location The part of the pointer wanted, either HEAD (for the data itself), BODY
-- (for nothing, since this isn't a pointer), or ALL (for the data). Generally, unless the
-- referent_id is split from the data (for example, in an array), you will want
-- ALL.
--@param name The name to marshall.
--@param sharetype The sharetype to marshall (as a string).
--@param comment The comment to marshall.
--@param permissions The permissions, an integer.
--@param max_users The max users, an integer.
--@param current_users The current users, an integer.
--@param path The path, a string.
--@param password The share-level password, a string (never used on Windows).
--@return A string representing the marshalled data.
local function marshall_srvsvc_NetShareInfo2(location, name, sharetype, comment, permissions, max_users, current_users, path, password)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_srvsvc_NetShareInfo2()"))
local name = marshall_ptr(location, marshall_unicode, {name, true}, name)
local sharetype = marshall_basetype(location, marshall_srvsvc_ShareType, {sharetype})
local comment = marshall_ptr(location, marshall_unicode, {comment, true}, comment)
local permissions = marshall_basetype(location, marshall_int32, {permissions})
local max_users = marshall_basetype(location, marshall_int32, {max_users})
local current_users = marshall_basetype(location, marshall_int32, {current_users})
local path = marshall_ptr(location, marshall_unicode, {path, true}, path)
local password = marshall_ptr(location, marshall_unicode, {password, true}, password)
result = name .. sharetype .. comment .. permissions .. max_users .. current_users .. path .. password
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_srvsvc_NetShareInfo2()"))
return result
end
---Unmarshall a NetShareInfo type 2, which is a name and a few other things. See the marshall
-- function for more information.
--
--@param location The part of the pointer wanted, either HEAD (for the data itself), BODY
-- (for nothing, since this isn't a pointer), or ALL (for the data). Generally, unless the
-- referent_id is split from the data (for example, in an array), you will want
-- ALL.
--@param data The data packet.
--@param pos The position within the data.
--@param result This is required when unmarshalling the BODY section, which always comes after
-- unmarshalling the HEAD. It is the result returned for this parameter during the
-- HEAD unmarshall. If the referent_id was '0', then this function doesn't unmarshall
-- anything.
--@return (pos, result) The new position in data
, and a table representing the datatype.
local function unmarshall_srvsvc_NetShareInfo2(location, data, pos, result)
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_srvsvc_NetShareInfo2()"))
if(result == nil) then
result = {}
end
if(location == HEAD or location == ALL) then
pos, result['name'] = unmarshall_ptr(HEAD, data, pos, unmarshall_unicode, {true})
pos, result['sharetype'] = unmarshall_srvsvc_ShareType(data, pos)
pos, result['comment'] = unmarshall_ptr(HEAD, data, pos, unmarshall_unicode, {true})
pos, result['permissions'] = unmarshall_int32(data, pos)
pos, result['max_users'] = unmarshall_int32(data, pos)
pos, result['current_users'] = unmarshall_int32(data, pos)
pos, result['path'] = unmarshall_ptr(HEAD, data, pos, unmarshall_unicode, {true})
pos, result['password'] = unmarshall_ptr(HEAD, data, pos, unmarshall_unicode, {true})
end
if(location == BODY or location == ALL) then
pos, result['name'] = unmarshall_ptr(BODY, data, pos, unmarshall_unicode, {true}, result['name'])
pos, result['comment'] = unmarshall_ptr(BODY, data, pos, unmarshall_unicode, {true}, result['comment'])
pos, result['path'] = unmarshall_ptr(BODY, data, pos, unmarshall_unicode, {true}, result['path'])
pos, result['password'] = unmarshall_ptr(BODY, data, pos, unmarshall_unicode, {true}, result['password'])
end
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_srvsvc_NetShareInfo2()"))
return pos, result
end
---Marshall a NetShareCtr (container) type 0. It is a simple array with the following definition:
--
--
-- typedef struct {
-- uint32 count;
-- [size_is(count)] srvsvc_NetShareInfo0 *array;
-- } srvsvc_NetShareCtr0;
--
--
--@param NetShareCtr0 A table representing the structure.
--@return A string representing the marshalled data.
function marshall_srvsvc_NetShareCtr0(NetShareCtr0)
local i
local result = ""
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_srvsvc_NetShareCtr0()"))
if(NetShareCtr0 == nil) then
result = result .. bin.pack("data
, and a table representing the datatype.
function unmarshall_srvsvc_NetShareCtr0(data, pos)
local count
local result = {}
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_srvsvc_NetShareCtr0()"))
pos, count = unmarshall_int32(data, pos)
pos, result['array'] = unmarshall_ptr(ALL, data, pos, unmarshall_array, {count, unmarshall_srvsvc_NetShareInfo0, {}})
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_srvsvc_NetShareCtr0()"))
return pos, result
end
---Marshall a NetShareCtr (container) type 1. It is a simple array with the following definition:
--
--
-- typedef struct {
-- uint32 count;
-- [size_is(count)] srvsvc_NetShareInfo1 *array;
-- } srvsvc_NetShareCtr1;
--
--
--@param NetShareCtr1 A table representing the structure.
--@return A string representing the marshalled data.
function marshall_srvsvc_NetShareCtr1(NetShareCtr1)
local i
local result = ""
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_srvsvc_NetShareCtr1()"))
if(NetShareCtr1 == nil) then
result = result .. bin.pack("
-- typedef struct {
-- uint32 count;
-- [size_is(count)] srvsvc_NetShareInfo2 *array;
-- } srvsvc_NetShareCtr2;
--
--
--@param NetShareCtr2 A pointer to the structure.
--@return A string representing the marshalled data.
function marshall_srvsvc_NetShareCtr2(NetShareCtr2)
local i
local result = ""
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_srvsvc_NetShareCtr2()"))
if(NetShareCtr2 == nil) then
result = result .. bin.pack("
-- typedef union {
-- [case(0)] srvsvc_NetShareCtr0 *ctr0;
-- [case(1)] srvsvc_NetShareCtr1 *ctr1;
-- [case(2)] srvsvc_NetShareCtr2 *ctr2;
-- [case(501)] srvsvc_NetShareCtr501 *ctr501;
-- [case(502)] srvsvc_NetShareCtr502 *ctr502;
-- [case(1004)] srvsvc_NetShareCtr1004 *ctr1004;
-- [case(1005)] srvsvc_NetShareCtr1005 *ctr1005;
-- [case(1006)] srvsvc_NetShareCtr1006 *ctr1006;
-- [case(1007)] srvsvc_NetShareCtr1007 *ctr1007;
-- [case(1501)] srvsvc_NetShareCtr1501 *ctr1501;
-- [default] ;
-- } srvsvc_NetShareCtr;
--
--
-- Not all of them are implemented, however; look at the code to see which are implemented (at the
-- time of this writing, it's 0, 1, and 2).
--
--@param level The level to request. Different levels will return different results, but also require
-- different access levels to call.
--@param data The data to populate the array with. Depending on the level, this data will be different.
-- For level 0, you'll probably want a table containing array=nil.
--@return A string representing the marshalled data, or 'nil' if it couldn't be marshalled.
function marshall_srvsvc_NetShareCtr(level, data)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_srvsvc_NetShareCtr()"))
if(level == 0) then
result = bin.pack("data, and a table representing the datatype.
-- The result may be nil
if there's an error.
function unmarshall_srvsvc_NetShareCtr(data, pos)
local level
local result
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_srv_NetShareCtr()"))
pos, level = unmarshall_int32(data, pos)
if(level == 0) then
pos, result = unmarshall_ptr(ALL, data, pos, unmarshall_srvsvc_NetShareCtr0, {})
else
stdnse.print_debug(1, "MSRPC: ERROR: Server returned an unknown level for srvsvc_NetShareCtr: %d", level)
pos, result = nil, nil
end
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_srv_NetShareCtr()"))
return pos, result
end
---Unmarshall the top-level NetShareInfo. This is a union of a bunch of different structs:
--
--
-- typedef union {
-- [case(0)] srvsvc_NetShareInfo0 *info0;
-- [case(1)] srvsvc_NetShareInfo1 *info1;
-- [case(2)] srvsvc_NetShareInfo2 *info2;
-- [case(501)] srvsvc_NetShareInfo501 *info501;
-- [case(502)] srvsvc_NetShareInfo502 *info502;
-- [case(1004)] srvsvc_NetShareInfo1004 *info1004;
-- [case(1005)] srvsvc_NetShareInfo1005 *info1005;
-- [case(1006)] srvsvc_NetShareInfo1006 *info1006;
-- [case(1007)] srvsvc_NetShareInfo1007 *info1007;
-- [case(1501)] sec_desc_buf *info1501;
-- [default] ;
-- } srvsvc_NetShareInfo;
--
--
-- Not all of them are implemented, however; look at the code to see which are implemented (at the
-- time of this writing, it's 0, 1, and 2).
--
--@param data The data being processed.
--@param pos The position within data
.
--@return (pos, result) The new position in data
, and a table representing the datatype. This may be
-- nil
if there was an error.
function unmarshall_srvsvc_NetShareInfo(data, pos)
local level
local result
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_srvsvc_NetShareInfo()"))
pos, level = unmarshall_int32(data, pos)
if(level == 0) then
pos, result = unmarshall_ptr(ALL, data, pos, unmarshall_struct, {unmarshall_srvsvc_NetShareInfo0, {}})
elseif(level == 1) then
pos, result = unmarshall_ptr(ALL, data, pos, unmarshall_struct, {unmarshall_srvsvc_NetShareInfo1, {}})
elseif(level == 2) then
pos, result = unmarshall_ptr(ALL, data, pos, unmarshall_struct, {unmarshall_srvsvc_NetShareInfo2, {}})
else
stdnse.print_debug(1, "MSRPC: ERROR: Invalid level returned by NetShareInfo: %d\n", level)
pos, result = nil, nil
end
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_srvsvc_NetShareInfo()"))
return pos, result
end
---Marshall a NetSessInfo type 10.
--
--
-- typedef struct {
-- [string,charset(UTF16)] uint16 *client;
-- [string,charset(UTF16)] uint16 *user;
-- uint32 time;
-- uint32 idle_time;
-- } srvsvc_NetSessInfo10;
--
--
--@param location The part of the pointer wanted, either HEAD (for the data itself), BODY
-- (for nothing, since this isn't a pointer), or ALL (for the data). Generally, unless the
-- referent_id is split from the data (for example, in an array), you will want
-- ALL.
--@param client The client string.
--@param user The user string.
--@param time The number of seconds that the user has been logged on.
--@param idle_time The number of seconds that the user's been idle.
--@return A string representing the marshalled data.
local function marshall_srvsvc_NetSessInfo10(location, client, user, time, idle_time)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_srvsvc_NetShareInfo10()"))
local client = marshall_ptr(location, marshall_unicode, {client, true}, client)
local user = marshall_ptr(location, marshall_unicode, {user, true}, user)
local time = marshall_basetype(location, marshall_int32, {time})
local idle_time = marshall_basetype(location, marshall_int32, {idle_time})
result = bin.pack("data, and a table representing the datatype.
local function unmarshall_srvsvc_NetSessInfo10(location, data, pos, result)
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_srvsvc_NetSessInfo10()"))
if(result == nil) then
result = {}
end
if(location == HEAD or location == ALL) then
pos, result['client'] = unmarshall_ptr(HEAD, data, pos, unmarshall_unicode, {true})
pos, result['user'] = unmarshall_ptr(HEAD, data, pos, unmarshall_unicode, {true})
pos, result['time'] = unmarshall_int32(data, pos)
pos, result['idle_time'] = unmarshall_int32(data, pos)
end
if(location == BODY or location == ALL) then
pos, result['client'] = unmarshall_ptr(BODY, data, pos, unmarshall_unicode, {true}, result['client'])
pos, result['user'] = unmarshall_ptr(BODY, data, pos, unmarshall_unicode, {true}, result['user'])
end
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_srvsvc_NetSessInfo10()"))
return pos, result
end
---Marshall a NetSessCtr (session container) type 10. It is a simple array with the following definition:
--
--
-- typedef struct {
-- uint32 count;
-- [size_is(count)] srvsvc_NetSessInfo10 *array;
-- } srvsvc_NetSessCtr10;
--
--
--@param NetSessCtr10 A table representing the structure.
--@return A string representing the marshalled data.
function marshall_srvsvc_NetSessCtr10(NetSessCtr10)
local i
local result = ""
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_srvsvc_NetSessCtr10()"))
if(NetSessCtr10 == nil) then
result = result .. bin.pack("data, and a table representing the datatype.
function unmarshall_srvsvc_NetSessCtr10(data, pos)
local count
local result = {}
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_srvsvc_NetSessCtr10()"))
pos, count = unmarshall_int32(data, pos)
pos, result['array'] = unmarshall_ptr(ALL, data, pos, unmarshall_array, {count, unmarshall_srvsvc_NetSessInfo10, {}})
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_srvsvc_NetSessCtr10()"))
return pos, result
end
---Marshall the top-level NetShareCtr. This is a union of a bunch of different containers:
--
--
-- typedef union {
-- [case(0)] srvsvc_NetSessCtr0 *ctr0;
-- [case(1)] srvsvc_NetSessCtr1 *ctr1;
-- [case(2)] srvsvc_NetSessCtr2 *ctr2;
-- [case(10)] srvsvc_NetSessCtr10 *ctr10;
-- [case(502)] srvsvc_NetSessCtr502 *ctr502;
-- [default] ;
-- } srvsvc_NetSessCtr;
--
--
-- Not all of them are implemented, however; look at the code to see which are implemented (at the
-- time of this writing, it's just 10).
--
--@param level The level to request. Different levels will return different results, but also require
-- different access levels to call.
--@param data The data to populate the array with. Depending on the level, this data will be different.
--@return A string representing the marshalled data.
function marshall_srvsvc_NetSessCtr(level, data)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_srvsvc_NetShareCtr()"))
if(level == 10) then
result = bin.pack("data
--@return (pos, result) The new position in data
, and a table representing the datatype. Can be
-- nil
if there's an error.
function unmarshall_srvsvc_NetSessCtr(data, pos)
local level
local result
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_srvsvc_NetSessCtr()"))
pos, level = bin.unpack("srvsvc_Statistics packet. This is basically a great big struct:
--
--
-- typedef struct {
-- uint32 start;
-- uint32 fopens;
-- uint32 devopens;
-- uint32 jobsqueued;
-- uint32 sopens;
-- uint32 stimeouts;
-- uint32 serrorout;
-- uint32 pwerrors;
-- uint32 permerrors;
-- uint32 syserrors;
-- uint32 bytessent_low;
-- uint32 bytessent_high;
-- uint32 bytesrcvd_low;
-- uint32 bytesrcvd_high;
-- uint32 avresponse;
-- uint32 reqbufneed;
-- uint32 bigbufneed;
-- } srvsvc_Statistics;
--
--
-- Note that Wireshark (at least, the version I'm using, 1.0.3) gets this wrong, so be careful.
--
--@param data The data being processed.
--@param pos The position within data
--@return (pos, result) The new position in data
, and a table representing the datatype.
function unmarshall_srvsvc_Statistics(data, pos)
local response = {}
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_srvsvc_Statistics()"))
pos, response['start'] = unmarshall_int32(data, pos)
pos, response['fopens'] = unmarshall_int32(data, pos)
pos, response['devopens'] = unmarshall_int32(data, pos)
pos, response['jobsqueued'] = unmarshall_int32(data, pos)
pos, response['sopens'] = unmarshall_int32(data, pos)
pos, response['stimeouts'] = unmarshall_int32(data, pos)
pos, response['serrorout'] = unmarshall_int32(data, pos)
pos, response['pwerrors'] = unmarshall_int32(data, pos)
pos, response['permerrors'] = unmarshall_int32(data, pos)
pos, response['syserrors'] = unmarshall_int32(data, pos)
pos, response['bytessent_low'] = unmarshall_int32(data, pos)
pos, response['bytessent_high'] = unmarshall_int32(data, pos)
pos, response['bytesrcvd_low'] = unmarshall_int32(data, pos)
pos, response['bytesrcvd_high'] = unmarshall_int32(data, pos)
pos, response['avresponse'] = unmarshall_int32(data, pos)
pos, response['reqbufneed'] = unmarshall_int32(data, pos)
pos, response['bigbufneed'] = unmarshall_int32(data, pos)
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_srvsvc_Statistics()"))
return pos, response
end
---Unmarshalls a srvsvc_Statistics
as a pointer. Wireshark fails to do this, and ends
-- up parsing the packet wrong, so take care when packetlogging.
--
-- See unmarshall_srvsvc_Statistics
for more information.
--
--@param data The data being processed.
--@param pos The position within data
--@return (pos, result) The new position in data
, and a table representing the datatype.
function unmarshall_srvsvc_Statistics_ptr(data, pos)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_srvsvc_Statistics_ptr()"))
pos, result = unmarshall_ptr(ALL, data, pos, unmarshall_srvsvc_Statistics, {})
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_srvsvc_Statistics_ptr()"))
return pos, result
end
----------------------------------
-- SAMR
-- (dependencies: MISC, LSA, SECURITY)
----------------------------------
local samr_ConnectAccessMask =
{
SAMR_ACCESS_CONNECT_TO_SERVER = 0x00000001,
SAMR_ACCESS_SHUTDOWN_SERVER = 0x00000002,
SAMR_ACCESS_INITIALIZE_SERVER = 0x00000004,
SAMR_ACCESS_CREATE_DOMAIN = 0x00000008,
SAMR_ACCESS_ENUM_DOMAINS = 0x00000010,
SAMR_ACCESS_OPEN_DOMAIN = 0x00000020
}
local samr_ConnectAccessMask_str =
{
SAMR_ACCESS_CONNECT_TO_SERVER = "Connect to server",
SAMR_ACCESS_SHUTDOWN_SERVER = "Shutdown server",
SAMR_ACCESS_INITIALIZE_SERVER = "Initialize server",
SAMR_ACCESS_CREATE_DOMAIN = "Create domain",
SAMR_ACCESS_ENUM_DOMAINS = "Enum domains",
SAMR_ACCESS_OPEN_DOMAIN = "Open domain"
}
---Marshall a samr_ConnectAccessMask
. This datatype is tied to the table above with that
-- name.
--
--@param accessmask The value to marshall, as a string
--@return The marshalled integer representing the given value, or nil
if it wasn't
-- found.
function marshall_samr_ConnectAccessMask(accessmask)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_samr_ConnectAccessMask()"))
result = marshall_Enum32(accessmask, samr_ConnectAccessMask)
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_samr_ConnectAccessMask()"))
return result
end
---Unmarshall a samr_ConnectAccessMask
. This datatype is tied to the table with that name.
--
--@param data The data packet.
--@param pos The position within the data.
--@return (pos, result) The new position in data
, and a table representing the datatype.
function unmarshall_samr_ConnectAccessMask(data, pos)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_samr_ConnectAccessMask()"))
pos, result = unmarshall_Enum32(data, pos, samr_ConnectAccessMask)
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_samr_ConnectAccessMask()"))
return pos, result
end
---Convert a samr_ConnectAccessMask
value to a string that can be shown to the user. This is
-- based on the _str table.
--
--@param val The string value (returned by the unmarshall_
function) to convert.
--@return A string suitable for displaying to the user, or nil
if it wasn't found.
function samr_ConnectAccessMask_tostr(val)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering samr_ConnectAccessMask_tostr()"))
result = samr_ConnectAccessMask_str[val]
stdnse.print_debug(4, string.format("MSRPC: Leaving samr_ConnectAccessMask_tostr()"))
return result
end
local samr_DomainAccessMask =
{
DOMAIN_ACCESS_LOOKUP_INFO_1 = 0x00000001,
DOMAIN_ACCESS_SET_INFO_1 = 0x00000002,
DOMAIN_ACCESS_LOOKUP_INFO_2 = 0x00000004,
DOMAIN_ACCESS_SET_INFO_2 = 0x00000008,
DOMAIN_ACCESS_CREATE_USER = 0x00000010,
DOMAIN_ACCESS_CREATE_GROUP = 0x00000020,
DOMAIN_ACCESS_CREATE_ALIAS = 0x00000040,
DOMAIN_ACCESS_LOOKUP_ALIAS = 0x00000080,
DOMAIN_ACCESS_ENUM_ACCOUNTS = 0x00000100,
DOMAIN_ACCESS_OPEN_ACCOUNT = 0x00000200,
DOMAIN_ACCESS_SET_INFO_3 = 0x00000400
}
local samr_DomainAccessMask_str =
{
DOMAIN_ACCESS_LOOKUP_INFO_1 = "Lookup info (1)",
DOMAIN_ACCESS_SET_INFO_1 = "Set info (1)",
DOMAIN_ACCESS_LOOKUP_INFO_2 = "Lookup info (2)",
DOMAIN_ACCESS_SET_INFO_2 = "Set info (2)",
DOMAIN_ACCESS_CREATE_USER = "Create user",
DOMAIN_ACCESS_CREATE_GROUP = "Create group",
DOMAIN_ACCESS_CREATE_ALIAS = "Create alias",
DOMAIN_ACCESS_LOOKUP_ALIAS = "Lookup alias",
DOMAIN_ACCESS_ENUM_ACCOUNTS = "Enum accounts",
DOMAIN_ACCESS_OPEN_ACCOUNT = "Open account",
DOMAIN_ACCESS_SET_INFO_3 = "Set info (3)"
}
---Marshall a samr_DomainAccessMask
. This datatype is tied to the table above with that
-- name.
--
--@param accessmask The value to marshall, as a string
--@return The marshalled integer representing the given value, or nil
if it wasn't
-- found.
function marshall_samr_DomainAccessMask(accessmask)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_samr_DomainAccessMask()"))
result = marshall_Enum32(accessmask, samr_DomainAccessMask)
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_samr_DomainAccessMask()"))
return result
end
---Unmarshall a samr_DomainAccessMask
. This datatype is tied to the table with that name.
--
--@param data The data packet.
--@param pos The position within the data.
--@return (pos, result) The new position in data
, and a table representing the datatype.
function unmarshall_samr_DomainAccessMask(data, pos)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_samr_DomainAccessMask()"))
pos, result = unmarshall_Enum32(data, pos, samr_DomainAccessMask)
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_samr_DomainAccessMask()"))
return pos, result
end
---Convert a samr_DomainAccessMask
value to a string that can be shown to the user. This is
-- based on the _str table.
--
--@param val The string value (returned by the unmarshall_
function) to convert.
--@return A string suitable for displaying to the user, or nil
if it wasn't found.
function samr_DomainAccessMask_tostr(val)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering samr_DomainAccessMask_tostr()"))
result = samr_DomainAccessMask_str[val]
stdnse.print_debug(4, string.format("MSRPC: Leaving samr_DomainAccessMask_tostr()"))
return result
end
local samr_AcctFlags =
{
ACB_NONE = 0x0000000,
ACB_DISABLED = 0x00000001, -- User account disabled
ACB_HOMDIRREQ = 0x00000002, -- Home directory required
ACB_PWNOTREQ = 0x00000004, -- User password not required
ACB_TEMPDUP = 0x00000008, -- Temporary duplicate account
ACB_NORMAL = 0x00000010, -- Normal user account
ACB_MNS = 0x00000020, -- MNS logon user account
ACB_DOMTRUST = 0x00000040, -- Interdomain trust account
ACB_WSTRUST = 0x00000080, -- Workstation trust account
ACB_SVRTRUST = 0x00000100, -- Server trust account
ACB_PWNOEXP = 0x00000200, -- User password does not expire
ACB_AUTOLOCK = 0x00000400, -- Account auto locked
ACB_ENC_TXT_PWD_ALLOWED = 0x00000800, -- Encryped text password is allowed
ACB_SMARTCARD_REQUIRED = 0x00001000, -- Smart Card required
ACB_TRUSTED_FOR_DELEGATION = 0x00002000, -- Trusted for Delegation
ACB_NOT_DELEGATED = 0x00004000, -- Not delegated
ACB_USE_DES_KEY_ONLY = 0x00008000, -- Use DES key only
ACB_DONT_REQUIRE_PREAUTH = 0x00010000, -- Preauth not required
ACB_PW_EXPIRED = 0x00020000, -- Password Expired
ACB_NO_AUTH_DATA_REQD = 0x00080000 -- No authorization data required
}
local samr_AcctFlags_str =
{
ACB_NONE = "n/a",
ACB_DISABLED = "Account disabled",
ACB_HOMDIRREQ = "Home directory required",
ACB_PWNOTREQ = "Password not required",
ACB_TEMPDUP = "Temporary duplicate account",
ACB_NORMAL = "Normal user account",
ACB_MNS = "MNS logon user account",
ACB_DOMTRUST = "Interdomain trust account",
ACB_WSTRUST = "Workstation trust account",
ACB_SVRTRUST = "Server trust account",
ACB_PWNOEXP = "Password does not expire",
ACB_AUTOLOCK = "Auto locked",
ACB_ENC_TXT_PWD_ALLOWED = "Encryped text password is allowed",
ACB_SMARTCARD_REQUIRED = "Smart Card required",
ACB_TRUSTED_FOR_DELEGATION = "Trusted for Delegation",
ACB_NOT_DELEGATED = "Not delegated",
ACB_USE_DES_KEY_ONLY = "Use DES key only",
ACB_DONT_REQUIRE_PREAUTH = "Preauth not required",
ACB_PW_EXPIRED = "Password Expired",
ACB_NO_AUTH_DATA_REQD = "No authorization data required"
}
---Marshall a samr_AcctFlags
. This datatype is tied to the table above with that
-- name.
--
--@param flags The value to marshall, as a string
--@return The marshalled integer representing the given value, or nil
if it wasn't
-- found.
function marshall_samr_AcctFlags(flags)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_samr_AcctFlags()"))
result = marshall_Enum32(flags, samr_AcctFlags)
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_samr_AcctFlags()"))
return result
end
---Unmarshall a samr_AcctFlags
. This datatype is tied to the table with that name.
--
--@param data The data packet.
--@param pos The position within the data.
--@return (pos, str) The new position, and the string representing the datatype.
function unmarshall_samr_AcctFlags(data, pos)
local str
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_samr_AcctFlags()"))
pos, str = unmarshall_Enum32_array(data, pos, samr_AcctFlags)
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_samr_AcctFlags()"))
return pos, str
end
---Convert a samr_AcctFlags
value to a string that can be shown to the user. This is
-- based on the _str table.
--
--@param val The string value (returned by the unmarshall_
function) to convert.
--@return A string suitable for displaying to the user, or nil
if it wasn't found.
function samr_AcctFlags_tostr(val)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering samr_AcctFlags_tostr()"))
result = samr_AcctFlags_str[val]
stdnse.print_debug(4, string.format("MSRPC: Leaving samr_AcctFlags_tostr()"))
return result
end
local samr_PasswordProperties =
{
DOMAIN_PASSWORD_COMPLEX = 0x00000001,
DOMAIN_PASSWORD_NO_ANON_CHANGE = 0x00000002,
DOMAIN_PASSWORD_NO_CLEAR_CHANGE = 0x00000004,
DOMAIN_PASSWORD_LOCKOUT_ADMINS = 0x00000008,
DOMAIN_PASSWORD_STORE_CLEARTEXT = 0x00000010,
DOMAIN_REFUSE_PASSWORD_CHANGE = 0x00000020
}
local samr_PasswordProperties_str =
{
DOMAIN_PASSWORD_COMPLEX = "Complexity requirements exist",
DOMAIN_PASSWORD_NO_ANON_CHANGE = "Must be logged in to change password",
DOMAIN_PASSWORD_NO_CLEAR_CHANGE = "Cannot change passwords in cleartext",
DOMAIN_PASSWORD_LOCKOUT_ADMINS = "Admin account can be locked out",
DOMAIN_PASSWORD_STORE_CLEARTEXT = "Cleartext passwords can be stored",
DOMAIN_REFUSE_PASSWORD_CHANGE = "Passwords cannot be changed"
}
---Marshall a samr_PasswordProperties
. This datatype is tied to the table above with that
-- name.
--
--@param properties The value to marshall, as a string
--@return The marshalled integer representing the given value, or nil
if it wasn't
-- found.
function marshall_samr_PasswordProperties(properties)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_samr_PasswordProperties()"))
result = marshall_Enum32(properties, samr_PasswordProperties)
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_samr_PasswordProperties()"))
return result
end
---Unmarshall a samr_PasswordProperties
. This datatype is tied to the table with that name.
--
--@param data The data packet.
--@param pos The position within the data.
--@return (pos, str) The new position, and the string representing the datatype.
function unmarshall_samr_PasswordProperties(data, pos)
local str
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_samr_PasswordProperties()"))
pos, str = unmarshall_Enum32_array(data, pos, samr_PasswordProperties)
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_samr_PasswordProperties()"))
return pos, str
end
---Convert a samr_PasswordProperties
value to a string that can be shown to the user. This is
-- based on the _str table.
--
--@param val The string value (returned by the unmarshall_
function) to convert.
--@return A string suitable for displaying to the user, or nil
if it wasn't found.
function samr_PasswordProperties_tostr(val)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering samr_PasswordProperties_tostr()"))
result = samr_PasswordProperties_str[val]
stdnse.print_debug(4, string.format("MSRPC: Leaving samr_PasswordProperties_tostr()"))
return result
end
---Unmarshall a struct with the following definition:
--
--
-- typedef struct {
-- uint32 idx;
-- lsa_String name;
-- } samr_SamEntry;
--
--
--@param location The part of the pointer wanted, either HEAD (for the data itself), BODY
-- (for nothing, since this isn't a pointer), or ALL (for the data). Generally, unless the
-- referent_id is split from the data (for example, in an array), you will want
-- ALL.
--@param data The data being processed.
--@param pos The position within data
.
--@param result This is required when unmarshalling the BODY section, which always comes after
-- unmarshalling the HEAD. It is the result returned for this parameter during the
-- HEAD unmarshall. If the referent_id was '0', then this function doesn't unmarshall
-- anything.
--@return (pos, result) The new position in data
, and a table representing the datatype.
local function unmarshall_samr_SamEntry(location, data, pos, result)
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_samr_SamEntry()"))
if(result == nil) then
result = {}
end
if(location == HEAD or location == ALL) then
pos, result['idx'] = unmarshall_int32(data, pos)
pos, result['name'] = unmarshall_lsa_String_internal(HEAD, data, pos)
end
if(location == BODY or location == ALL) then
pos, result['name'] = unmarshall_lsa_String_internal(BODY, data, pos, result['name'])
end
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_samr_SamEntry()"))
return pos, result
end
---Unmarshall a struct with the following definition:
--
--
-- typedef struct {
-- uint32 count;
-- [size_is(count)] samr_SamEntry *entries;
-- } samr_SamArray;
--
--
--@param data The data being processed.
--@param pos The position within data
.
--@return (pos, result) The new position in data
, and a table representing the datatype.
function unmarshall_samr_SamArray(data, pos)
local result = {}
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_samr_SamArray()"))
pos, result['count'] = unmarshall_int32(data, pos)
pos, result['entries'] = unmarshall_ptr(ALL, data, pos, unmarshall_array, {result['count'], unmarshall_samr_SamEntry, {}})
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_samr_SamArray()"))
return pos, result
end
---Unmarshall a pointer to a samr_SamArray
type. See unmarshall_samr_SamArray
for
-- more information.
--
--@param data The data being processed.
--@param pos The position within data
.
--@return (pos, result) The new position in data
, and a table representing the datatype.
function unmarshall_samr_SamArray_ptr(data, pos)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_samr_SamArray_ptr()"))
pos, result = unmarshall_ptr(ALL, data, pos, unmarshall_samr_SamArray, {})
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_samr_SamArray_ptr()"))
return pos, result
end
---Unmarshall a struct with the following definition:
--
--
-- typedef struct {
-- uint32 idx;
-- uint32 rid;
-- samr_AcctFlags acct_flags;
-- lsa_String account_name;
-- lsa_String description;
-- lsa_String full_name;
-- } samr_DispEntryGeneral;
--
--
--@param location The part of the pointer wanted, either HEAD (for the data itself), BODY
-- (for nothing, since this isn't a pointer), or ALL (for the data). Generally, unless the
-- referent_id is split from the data (for example, in an array), you will want
-- ALL.
--@param data The data being processed.
--@param pos The position within data
.
--@param result This is required when unmarshalling the BODY section, which always comes after
-- unmarshalling the HEAD. It is the result returned for this parameter during the
-- HEAD unmarshall. If the referent_id was '0', then this function doesn't unmarshall
-- anything.
--@return (pos, result) The new position in data
, and a table representing the datatype.
local function unmarshall_samr_DispEntryGeneral(location, data, pos, result)
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_samr_DispEntryGeneral()"))
if(result == nil) then
result = {}
end
if(location == HEAD or location == ALL) then
pos, result['idx'] = unmarshall_int32(data, pos)
pos, result['rid'] = unmarshall_int32(data, pos)
pos, result['acct_flags'] = unmarshall_samr_AcctFlags(data, pos)
pos, result['account_name'] = unmarshall_lsa_String_internal(HEAD, data, pos)
pos, result['description'] = unmarshall_lsa_String_internal(HEAD, data, pos)
pos, result['full_name'] = unmarshall_lsa_String_internal(HEAD, data, pos)
end
if(location == BODY or location == ALL) then
pos, result['account_name'] = unmarshall_lsa_String_internal(BODY, data, pos, result['account_name'])
pos, result['description'] = unmarshall_lsa_String_internal(BODY, data, pos, result['description'])
pos, result['full_name'] = unmarshall_lsa_String_internal(BODY, data, pos, result['full_name'])
end
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_samr_DispEntryGeneral()"))
return pos, result
end
---Unmarshall a struct with the following definition:
--
--
-- typedef struct {
-- uint32 count;
-- [size_is(count)] samr_DispEntryGeneral *entries;
-- } samr_DispInfoGeneral;
--
--
--@param data The data being processed.
--@param pos The position within data
.
--@return (pos, result) The new position in data
, and a table representing the datatype.
function unmarshall_samr_DispInfoGeneral(data, pos)
local result = {}
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_samr_DispInfoGeneral()"))
pos, result['count'] = unmarshall_int32(data, pos)
pos, result['entries'] = unmarshall_ptr(ALL, data, pos, unmarshall_array, {result['count'], unmarshall_samr_DispEntryGeneral, {}})
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_samr_DispInfoGeneral()"))
return pos, result
end
---Unmarshall a struct with the following definition:
--
--
-- typedef [switch_type(uint16)] union {
-- [case(1)] samr_DispInfoGeneral info1;/* users */
-- [case(2)] samr_DispInfoFull info2; /* trust accounts? */
-- [case(3)] samr_DispInfoFullGroups info3; /* groups */
-- [case(4)] samr_DispInfoAscii info4; /* users */
-- [case(5)] samr_DispInfoAscii info5; /* groups */
-- } samr_DispInfo;
--
--
--@param data The data being processed.
--@param pos The position within data
.
--@return (pos, result) The new position in data
, and a table representing the datatype. It may also return
-- nil
, if there was an error.
function unmarshall_samr_DispInfo(data, pos)
local level
local result
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_samr_DispInfo()"))
pos, level = msrpctypes.unmarshall_int16(data, pos)
if(level == 1) then
pos, result = unmarshall_samr_DispInfoGeneral(data, pos)
else
stdnse.print_debug(1, "MSRPC: ERROR: Server returned an unknown level for samr_DispInfo: %d", level)
pos, result = nil, nil
end
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_samr_DispInfo()"))
return pos, result
end
---Unmarshall a struct with the following definition:
--
--
-- typedef struct {
-- uint16 min_password_length;
-- uint16 password_history_length;
-- samr_PasswordProperties password_properties;
-- /* yes, these are signed. They are in negative 100ns */
-- dlong max_password_age;
-- dlong min_password_age;
-- } samr_DomInfo1;
--
--
--@param data The data being processed.
--@param pos The position within data
.
--@return (pos, result) The new position in data
, and a table representing the datatype.
function unmarshall_samr_DomInfo1(data, pos)
local result = {}
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_samr_DomInfo1()"))
pos, result['min_password_length'] = unmarshall_int16(data, pos, false)
pos, result['password_history_length'] = unmarshall_int16(data, pos, false)
pos, result['password_properties'] = unmarshall_samr_PasswordProperties(data, pos)
pos, result['max_password_age'] = unmarshall_hyper(data, pos)
pos, result['min_password_age'] = unmarshall_hyper(data, pos)
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_samr_DomInfo1()"))
return pos, result
end
---Unmarshall a struct with the following definition:
--
--
-- typedef struct {
-- hyper sequence_num;
-- NTTIME domain_create_time;
-- } samr_DomInfo8;
--
--
--@param data The data being processed.
--@param pos The position within data
.
--@return (pos, result) The new position in data
, and a table representing the datatype.
function unmarshall_samr_DomInfo8(data, pos)
local result = {}
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_samr_DomInfo8()"))
pos, result['sequence_num'] = unmarshall_hyper(data, pos)
pos, result['domain_create_time'] = unmarshall_NTTIME(data, pos)
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_samr_DomInfo8()"))
return pos, result
end
---Unmarshall a struct with the following definition:
--
--
-- typedef struct {
-- hyper lockout_duration;
-- hyper lockout_window;
-- uint16 lockout_threshold;
-- } samr_DomInfo12;
--
--
--@param data The data being processed.
--@param pos The position within data
.
--@return (pos, result) The new position in data
, and a table representing the datatype.
function unmarshall_samr_DomInfo12(data, pos)
local result = {}
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_samr_DomInfo12()"))
pos, result['lockout_duration'] = unmarshall_hyper(data, pos)
pos, result['lockout_window'] = unmarshall_hyper(data, pos)
pos, result['lockout_threshold'] = unmarshall_int16(data, pos)
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_samr_DomInfo12()"))
return pos, result
end
---Unmarshall a union with the following definition:
--
--
-- typedef [switch_type(uint16)] union {
-- [case(1)] samr_DomInfo1 info1;
-- [case(2)] samr_DomInfo2 info2;
-- [case(3)] samr_DomInfo3 info3;
-- [case(4)] samr_DomInfo4 info4;
-- [case(5)] samr_DomInfo5 info5;
-- [case(6)] samr_DomInfo6 info6;
-- [case(7)] samr_DomInfo7 info7;
-- [case(8)] samr_DomInfo8 info8;
-- [case(9)] samr_DomInfo9 info9;
-- [case(11)] samr_DomInfo11 info11;
-- [case(12)] samr_DomInfo12 info12;
-- [case(13)] samr_DomInfo13 info13;
-- } samr_DomainInfo;
--
--
--@param data The data being processed.
--@param pos The position within data
.
--@return (pos, result) The new position in data
, and a table representing the datatype. May return
-- nil
if there was an error.
function unmarshall_samr_DomainInfo(data, pos)
local level
local result
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_samr_DomainInfo()"))
pos, level = unmarshall_int16(data, pos)
if(level == 1) then
pos, result = unmarshall_samr_DomInfo1(data, pos)
elseif(level == 8) then
pos, result = unmarshall_samr_DomInfo8(data, pos)
elseif(level == 12) then
pos, result = unmarshall_samr_DomInfo12(data, pos)
else
stdnse.print_debug(1, "MSRPC: ERROR: Server returned an unknown level for samr_DomainInfo: %d", level)
pos, result = nil, nil
end
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_samr_DomainInfo()"))
return pos, result
end
---Unmarshall a pointer to a samr_DomainInfo
. See unmarshall_samr_DomainInfo
for
-- more information.
--
--@param data The data being processed.
--@param pos The position within data
.
--@return (pos, result) The new position in data
, and a table representing the datatype. May return
-- nil
if there was an error.
function unmarshall_samr_DomainInfo_ptr(data, pos)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_samr_DomainInfo_ptr()"))
pos, result = unmarshall_ptr(ALL, data, pos, unmarshall_samr_DomainInfo, {})
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_samr_DomainInfo_ptr()"))
return pos, result
end
---Unmarshall a structure with the following definition:
--
--
-- typedef struct {
-- [range(0,1024)] uint32 count;
-- [size_is(count)] uint32 *ids;
-- } samr_Ids;
--
--
--@param data The data being processed.
--@param pos The position within data
.
--@return (pos, result) The new position in data
, and a table representing the datatype. May return
-- nil
if there was an error.
function unmarshall_samr_Ids(data, pos)
local array
pos, array = unmarshall_int32_array_ptr(data, pos)
return pos, array
end
----------------------------------
-- SVCCTL
-- (dependencies: MISC)
----------------------------------
local svcctl_ControlCode =
{
SERVICE_CONTROL_CONTINUE = 0x00000003,
SERVICE_CONTROL_INTERROGATE = 0x00000004,
SERVICE_CONTROL_NETBINDADD = 0x00000007,
SERVICE_CONTROL_NETBINDDISABLE = 0x0000000A,
SERVICE_CONTROL_NETBINDENABLE = 0x00000009,
SERVICE_CONTROL_NETBINDREMOVE = 0x00000008,
SERVICE_CONTROL_PARAMCHANGE = 0x00000006,
SERVICE_CONTROL_PAUSE = 0x00000002,
SERVICE_CONTROL_STOP = 0x00000001,
}
local svcctl_ControlCode_str =
{
SERVICE_CONTROL_CONTINUE = "Notifies a paused service that it should resume.",
SERVICE_CONTROL_INTERROGATE = "Notifies a service that it should report its current status information to the service control manager.",
SERVICE_CONTROL_NETBINDADD = "Notifies a network service that there is a new component for binding. Deprecated.",
SERVICE_CONTROL_NETBINDDISABLE = "Notifies a network service that one of its bindings has been disabled. Deprecated.",
SERVICE_CONTROL_NETBINDENABLE = "Notifies a network service that a disabled binding has been enabled. Deprecated",
SERVICE_CONTROL_NETBINDREMOVE = "Notifies a network service that a component for binding has been removed. Deprecated",
SERVICE_CONTROL_PARAMCHANGE = "Notifies a service that its startup parameters have changed.",
SERVICE_CONTROL_PAUSE = "Notifies a service that it should pause.",
SERVICE_CONTROL_STOP = "Notifies a service that it should stop."
}
---Marshall a svcctl_ControlCode
. This datatype is tied to the table above with that
-- name.
--
--@param flags The value to marshall, as a string
--@return The marshalled integer representing the given value, or nil
if it wasn't
-- found.
function marshall_svcctl_ControlCode(flags)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_svcctl_ControlCode()"))
result = marshall_Enum32(flags, svcctl_ControlCode)
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_svcctl_ControlCode()"))
return result
end
---Unmarshall a svcctl_ControlCode
. This datatype is tied to the table with that name.
--
--@param data The data packet.
--@param pos The position within the data.
--@return (pos, str) The new position, and the string representing the datatype.
function unmarshall_svcctl_ControlCode(data, pos)
local str
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_svcctl_ControlCode()"))
pos, str = unmarshall_Enum32_array(data, pos, svcctl_ControlCode)
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_svcctl_ControlCode()"))
return pos, str
end
---Convert a svcctl_ControlCode
value to a string that can be shown to the user. This is
-- based on the _str table.
--
--@param val The string value (returned by the unmarshall_
function) to convert.
--@return A string suitable for displaying to the user, or nil
if it wasn't found.
function svcctl_ControlCode_tostr(val)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering svcctl_ControlCode_tostr()"))
result = svcctl_ControlCode_str[val]
stdnse.print_debug(4, string.format("MSRPC: Leaving svcctl_ControlCode_tostr()"))
return result
end
local svcctl_Type =
{
SERVICE_TYPE_KERNEL_DRIVER = 0x01,
SERVICE_TYPE_FS_DRIVER = 0x02,
SERVICE_TYPE_ADAPTER = 0x04,
SERVICE_TYPE_RECOGNIZER_DRIVER = 0x08,
SERVICE_TYPE_DRIVER = 0x0B,
SERVICE_TYPE_WIN32_OWN_PROCESS = 0x10,
SERVICE_TYPE_WIN32_SHARE_PROCESS = 0x20,
SERVICE_TYPE_WIN32 = 0x30
}
---Marshall a svcctl_Type
. This datatype is tied to the table above with that
-- name.
--
--@param flags The value to marshall, as a string
--@return The marshalled integer representing the given value, or nil
if it wasn't
-- found.
function marshall_svcctl_Type(flags)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_svcctl_Type()"))
result = marshall_Enum32(flags, svcctl_Type)
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_svcctl_Type()"))
return result
end
---Unmarshall a svcctl_Type
. This datatype is tied to the table with that name.
--
--@param data The data packet.
--@param pos The position within the data.
--@return (pos, str) The new position, and the string representing the datatype.
function unmarshall_svcctl_Type(data, pos)
local str
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_svcctl_Type()"))
pos, str = unmarshall_Enum32_array(data, pos, svcctl_Type)
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_svcctl_Type()"))
return pos, str
end
--[[Convert a svcctl_Type
value to a string that can be shown to the user. This is
-- based on the _str table.
--
--@param val The string value (returned by the unmarshall_
function) to convert.
--@return A string suitable for displaying to the user, or nil
if it wasn't found.
function svcctl_Type_tostr(val)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering svcctl_Type_tostr()"))
result = svcctl_Type_str[val]
stdnse.print_debug(4, string.format("MSRPC: Leaving svcctl_Type_tostr()"))
return result
end]]--
local svcctl_State =
{
SERVICE_STATE_ACTIVE = 0x01,
SERVICE_STATE_INACTIVE = 0x02,
SERVICE_STATE_ALL = 0x03
}
---Marshall a svcctl_State
. This datatype is tied to the table above with that
-- name.
--
--@param flags The value to marshall, as a string
--@return The marshalled integer representing the given value, or nil
if it wasn't
-- found.
function marshall_svcctl_State(flags)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_svcctl_State()"))
result = marshall_Enum32(flags, svcctl_State)
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_svcctl_State()"))
return result
end
---Unmarshall a svcctl_State
. This datatype is tied to the table with that name.
--
--@param data The data packet.
--@param pos The position within the data.
--@return (pos, str) The new position, and the string representing the datatype.
function unmarshall_svcctl_State(data, pos)
local str
stdnse.print_debug(4, string.format("MSRPC: Entering unmarshall_svcctl_State()"))
pos, str = unmarshall_Enum32_array(data, pos, svcctl_State)
stdnse.print_debug(4, string.format("MSRPC: Leaving unmarshall_svcctl_State()"))
return pos, str
end
--[[Convert a svcctl_State
value to a string that can be shown to the user. This is
-- based on the _str table.
--
--@param val The string value (returned by the unmarshall_
function) to convert.
--@return A string suitable for displaying to the user, or nil
if it wasn't found.
function svcctl_State_tostr(val)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering svcctl_State_tostr()"))
result = svcctl_State_str[val]
stdnse.print_debug(4, string.format("MSRPC: Leaving svcctl_State_tostr()"))
return result
end]]--
---Unmarshall a SERVICE_STATUS struct, converting it to a table. The structure is as
-- follows:
--
--
-- typedef struct {
-- uint32 type;
-- uint32 state;
-- uint32 controls_accepted;
-- WERROR win32_exit_code;
-- uint32 service_exit_code;
-- uint32 check_point;
-- uint32 wait_hint;
-- } SERVICE_STATUS;
--
--
--@param data The data packet.
--@param pos The position within the data.
--@return (pos, table) The new position, and the table of values.
function unmarshall_SERVICE_STATUS(data, pos)
local result = {}
pos, result['type'] = unmarshall_svcctl_Type(data, pos)
pos, result['state'] = unmarshall_svcctl_State(data, pos)
pos, result['controls_accepted'] = unmarshall_svcctl_ControlCode(data, pos)
pos, result['win32_exit_code'] = unmarshall_int32(data, pos)
pos, result['service_exit_code'] = unmarshall_int32(data, pos)
pos, result['check_point'] = unmarshall_int32(data, pos)
pos, result['wait_hint'] = unmarshall_int32(data, pos)
return pos, result
end
local atsvc_DaysOfMonth =
{
First = 0x00000001,
Second = 0x00000002,
Third = 0x00000004,
Fourth = 0x00000008,
Fifth = 0x00000010,
Sixth = 0x00000020,
Seventh = 0x00000040,
Eight = 0x00000080,
Ninth = 0x00000100,
Tenth = 0x00000200,
Eleventh = 0x00000400,
Twelfth = 0x00000800,
Thitteenth = 0x00001000,
Fourteenth = 0x00002000,
Fifteenth = 0x00004000,
Sixteenth = 0x00008000,
Seventeenth = 0x00010000,
Eighteenth = 0x00020000,
Ninteenth = 0x00040000,
Twentyth = 0x00080000,
Twentyfirst = 0x00100000,
Twentysecond = 0x00200000,
Twentythird = 0x00400000,
Twentyfourth = 0x00800000,
Twentyfifth = 0x01000000,
Twentysixth = 0x02000000,
Twentyseventh = 0x04000000,
Twentyeighth = 0x08000000,
Twentyninth = 0x10000000,
Thirtieth = 0x20000000,
Thirtyfirst = 0x40000000
}
---Marshall a atsvc_DaysOfMonth
. This datatype is tied to the table above with that
-- name.
--
--@param flags The value to marshall, as a string
--@return The marshalled integer representing the given value, or nil
if it wasn't
-- found.
function marshall_atsvc_DaysOfMonth(flags)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_atsvc_DaysOfMonth()"))
result = marshall_Enum32(flags, atsvc_DaysOfMonth)
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_atsvc_DaysOfMonth()"))
return result
end
local atsvc_Flags =
{
JOB_RUN_PERIODICALLY = 0x01,
JOB_EXEC_ERROR = 0x02,
JOB_RUNS_TODAY = 0x04,
JOB_ADD_CURRENT_DATE = 0x08,
JOB_NONINTERACTIVE = 0x10
}
---Marshall a atsvc_Flags
. This datatype is tied to the table above with that
-- name.
--
--@param flags The value to marshall, as a string
--@return The marshalled integer representing the given value, or nil
if it wasn't
-- found.
function marshall_atsvc_Flags(flags)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_atsvc_Flags()"))
result = marshall_Enum8(flags, atsvc_Flags, false)
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_atsvc_Flags()"))
return result
end
local atsvc_DaysOfWeek =
{
DAYSOFWEEK_MONDAY = 0x01,
DAYSOFWEEK_TUESDAY = 0x02,
DAYSOFWEEK_WEDNESDAY = 0x04,
DAYSOFWEEK_THURSDAY = 0x08,
DAYSOFWEEK_FRIDAY = 0x10,
DAYSOFWEEK_SATURDAY = 0x20,
DAYSOFWEEK_SUNDAY = 0x40
}
---Marshall a atsvc_DaysOfWeek
. This datatype is tied to the table above with that
-- name.
--
--@param flags The value to marshall, as a string
--@return The marshalled integer representing the given value, or nil
if it wasn't
-- found.
function marshall_atsvc_DaysOfWeek(flags)
local result
stdnse.print_debug(4, string.format("MSRPC: Entering marshall_atsvc_DaysOfWeek()"))
result = marshall_Enum8(flags, atsvc_DaysOfWeek, false)
stdnse.print_debug(4, string.format("MSRPC: Leaving marshall_atsvc_DaysOfWeek()"))
return result
end
---Marshall a JobInfo struct. The structure is as follows:
--
--
-- typedef struct {
-- uint32 job_time;
-- atsvc_DaysOfMonth days_of_month;
-- atsvc_DaysOfWeek days_of_week;
-- atsvc_Flags flags;
-- [string,charset(UTF16)] uint16 *command;
-- } atsvc_JobInfo;
--
--
--@param command The command to run. This has to be just the command, no parameters; if a
-- program requires parameters, then the best way to run it is through a batch
-- file.
--@param time The time at which to run the job, in milliseconds from midnight.
function marshall_atsvc_JobInfo(command, time)
local result = ""
result = result .. marshall_int32(time) -- Job time
result = result .. marshall_int32(0) -- Day of month
result = result .. marshall_int8(0, false) -- Day of week
result = result .. marshall_atsvc_Flags("JOB_NONINTERACTIVE") -- Flags
result = result .. marshall_int16(0, false) -- Padding
result = result .. marshall_unicode_ptr(command, true) -- Command
return result
end