summaryrefslogtreecommitdiffstats
path: root/nselib/msrpctypes.lua
diff options
context:
space:
mode:
Diffstat (limited to 'nselib/msrpctypes.lua')
-rw-r--r--nselib/msrpctypes.lua4712
1 files changed, 4712 insertions, 0 deletions
diff --git a/nselib/msrpctypes.lua b/nselib/msrpctypes.lua
new file mode 100644
index 0000000..bb355b9
--- /dev/null
+++ b/nselib/msrpctypes.lua
@@ -0,0 +1,4712 @@
+---
+-- 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 <code>.idl</code> 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
+-- <code>marshall_int32</code>, <code>marshall_int16</code>, etc. will marshall the base types, and <code>unmarshall_int32</code>,
+-- <code>unmarshall_int16</code>, 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 <code>marshall_unicode</code>. The functions <code>marshall_unicode</code>
+-- and <code>unmarshall_unicode</code> can be used to marshall/unmarshall strings.
+--
+-- Pointers also have interesting properties. A pointer is preceded 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 <code>78 56 34 12 04 00 00 00</code> (the referent_id is 0x12345678 and the integer
+-- itself is 0x00000004). If the integer is nil, then it's marshalled as <code>00 00 00 00</code>, which is simply
+-- a referent_id of 0.
+--
+-- From the perspective of the program, pointers can be marshalled by using the "<code>_ptr</code>" versions of normal functions
+-- (for example, <code>marshall_int32_ptr</code> and <code>unmarshall_unicode_ptr</code>. From the perspective
+-- of functions within this module, especially functions for marshalling structs and arrays, the <code>marshall_ptr</code>
+-- and <code>unmarshall_ptr</code> 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, preceded 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:
+-- <code>
+-- 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"
+-- </code>
+--
+-- 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:
+-- <code>
+-- 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"
+-- </code>
+--
+-- 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 <code>marshall_array</code> and
+-- <code>unmarshall_array</code> 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 <code>location</code>, 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 <code>marshall_ptr</code> or
+-- <code>marshall_array</code> (and the equivalent <code>unmarshall_</code> 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 <code>unmarshall_struct</code>. <code>unmarshall_struct</code> basically calls a struct unmarshalling
+-- function the same way <code>unmarshall_array</code> 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 modeled these after Samba's <code>.idl</code> files.
+-- MISC corresponds to <code>misc.idl</code>, LSA to <code>lsa.idl</code>, 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 modeled 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 <code>result['names']['names'][0]['name']</code>, 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 <code>hyper</code> 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 <code>_tostr</code> 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
+
+local os = require "os"
+local stdnse = require "stdnse"
+local string = require "string"
+local stringaux = require "stringaux"
+local table = require "table"
+local unicode = require "unicode"
+_ENV = stdnse.module("msrpctypes", stdnse.seeall)
+
+local REFERENT_ID = 0x50414d4e
+local HEAD = 'HEAD'
+local BODY = 'BODY'
+local ALL = 'ALL'
+
+--- Convert a string to Unicode (UTF-16 LE), optionally add a null terminator,
+-- and 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
+
+ stdnse.debug4("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.debug1("MSRPC: WARNING: couldn't convert value to string in string_to_unicode()")
+ end
+
+
+ local result = unicode.utf8to16(string)
+
+ -- Add a null, if the caller requested it
+ if(do_null == true) then
+ result = result .. "\0\0"
+ end
+
+ -- Align it to a multiple of 4, if necessary
+ if(#result % 4 ~= 0) then
+ result = result .. "\0\0"
+ end
+
+ stdnse.debug4("MSRPC: Leaving string_to_unicode()")
+
+ return result
+end
+
+--- Read a unicode string from a buffer, 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
+--@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 The new position
+--@return string The string read. 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)
+ stdnse.debug4("MSRPC: Entering unicode_to_string(pos = %s, length = %d)", tostring(pos), length)
+
+ pos = pos or 1
+ local endpos = pos + length * 2 - 1
+
+ if endpos > #buffer then
+ stdnse.debug1("MSRPC: ERROR: Ran off the end of a string in unicode_to_string(), this likely means we are reading a packet incorrectly. Please report! (pos = %d, #buffer = %d, endpos = %d)", pos, #buffer, endpos)
+
+ return nil, nil
+ end
+
+ local str = unicode.utf16to8(string.sub(buffer, pos, endpos))
+
+ if do_null then
+ str = string.sub(str, 1, -2) -- Eat the null terminator
+ end
+
+ -- Align to 4-byte boundary
+ endpos = endpos + (endpos + 1 - pos) % 4
+
+ stdnse.debug4("MSRPC: Leaving unicode_to_string()")
+
+ return endpos + 1, str
+end
+
+-------------------------------------
+-- SPECIAL
+-- (dependencies: n/a)
+-------------------------------------
+
+---Marshalls a pointer to another datatype.
+--
+-- This function will optionally separate the REFERENT_ID of the pointer (which
+-- goes at location = HEAD) from the data part of the pointer (which goes at
+-- location = BODY). If the entire pointer is needed, then location should be
+-- set to ALL.
+--
+-- When marshalling the body, the function <code>func</code> is called, which
+-- is passed as a parameter, with the arguments <code>args</code>. 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 repeat of one of the
+-- arguments.
+--
+-- Note that the function <code>func</code> doesn't have to conform to any
+-- special prototype, as long as the <code>args</code> array matches what the
+-- function wants.
+--
+-- This can be used to marshall an int16 value of 0x1234 with padding like this:
+-- <code>
+-- marshall_ptr(ALL, marshall_int16, {0x1234, true}, 0x1234)
+-- </code>
+--
+-- And here's how a 'nil' string might be marshalled:
+-- <code>
+-- local str = nil
+-- marshall_ptr(ALL, marshall_unicode, {str, true}, str)
+-- </code>
+--
+--@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 <code>args</code> parameter to a string.
+--@param args An array of arguments that will be directly passed to the
+-- function <code>func</code>
+--@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.debug4("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 .. string.pack("<I4", 0)
+ else
+ result = result .. string.pack("<I4", REFERENT_ID)
+ end
+ end
+
+ -- If we're marshalling the BODY section, and the value isn't null, call the function to marshall
+ -- the data.
+ if(location == BODY or location == ALL) then
+ if(func == nil or args == nil or value == nil) then
+ else
+ result = result .. func(table.unpack(args))
+ end
+ end
+
+ stdnse.debug4("MSRPC: Leaving marshall_ptr()")
+
+ return result
+end
+
+---Unmarshalls a pointer by removing the referent_id in the HEAD section and
+--the data in the BODY section (or both in the ALL section).
+--
+-- Because the unmarshall function for the body is called if and only if the
+-- referent_id is non-zero, if the head and the body are split apart, the
+-- second call to this function has to know the context. This is the purpose
+-- for the <code>result</code> parameter, it is the result from the first time
+-- this is called.
+--
+-- The function <code>func</code> has to conform to this format:
+--<code>
+-- func(data, pos, <args>)
+--</code>
+--
+--@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 <code>data</code>
+--@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
+-- <code>func</code>, 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 The new position
+--@reutrn The result. For HEAD the result is either <code>true</code> for valid
+-- pointers or <code>false</code> for null pointers. For BODY or ALL,
+-- the result is <code>nil</code> for null pointers, or the data for
+-- valid pointers.
+local function unmarshall_ptr(location, data, pos, func, args, result)
+ stdnse.debug4("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
+ pos = pos or 1
+ if #data - pos + 1 < 4 then
+ stdnse.debug1("MSRPC: ERROR: Ran off the end of a packet in unmarshall_ptr(). Please report!")
+ return pos, nil
+ end
+ local referent_id
+ referent_id, pos = string.unpack("<I4", data, pos)
+
+ if(location == HEAD) then
+ if(referent_id == 0) then
+ result = false
+ else
+ result = true
+ end
+ else
+ if(referent_id == 0) then
+ result = nil
+ else
+ result = true
+ end
+ end
+ end
+
+ if(location == BODY or location == ALL) then
+ if(result == true) then
+ pos, result = func(data, pos, table.unpack(args))
+ else
+ result = nil
+ end
+ end
+
+ return pos, result
+end
+
+---Similar to <code>marshall_ptr</code>, 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
+-- <code>marshall_srvsvc_NetShareInfo2</code>).
+--
+-- Like <code>marshall_ptr</code>, 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 <code>args</code> parameter to a string.
+--@param args An array of arguments that will be directly passed to the
+-- function <code>func</code>
+--@return A string representing the marshalled data.
+local function marshall_basetype(location, func, args)
+ local result
+ stdnse.debug4("MSRPC: Entering marshall_basetype()")
+
+ if(location == HEAD or location == ALL) then
+ result = func(table.unpack(args))
+ else
+ result = ""
+ end
+
+ stdnse.debug4("MSRPC: Leaving marshall_basetype()")
+
+ return result
+end
+
+---Marshalls an array.
+--
+-- Recall (from the module comment) that the data in an array is split into the
+-- referent_ids and base types at the top and the data at the bottom. This
+-- function will call any number of location-aware functions twice (once for
+-- the top and once for the bottom).
+--
+-- Each element in the array can technically have a different function. I don't
+-- know why I allowed that, and may refactor it out in the future. For now, I
+-- strongly recommend setting the function to the same for every element.
+--
+-- The function that's called has to have the prototype:
+--<code>
+-- func(location, <args>)
+--</code>
+-- 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)
+
+ stdnse.debug4("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.
+ local result = {string.pack("<I4", #array)}
+
+ -- Encode the HEAD sections of all the elements in the array
+ for i = 1, #array, 1 do
+ local func = array[i]['func']
+ local args = array[i]['args']
+
+ result[#result+1] = func(HEAD, table.unpack(args))
+ end
+
+ -- Encode the BODY sections of all the elements in the array
+ for i = 1, #array, 1 do
+ local func = array[i]['func']
+ local args = array[i]['args']
+
+ result[#result+1] = func(BODY, table.unpack(args))
+ end
+
+ stdnse.debug4("MSRPC: Leaving marshall_array()")
+ return table.concat(result)
+end
+
+---Unmarshalls an array.
+--
+-- This function starts to get a little hairy, due to the number of parameters
+-- that need to be propagated, but it isn't too bad. Basically, this
+-- unmarshalls an array by calling the given function for each element.
+--
+-- The function <code>func</code> has to conform to a very specific prototype:
+--<code>
+-- func(location, data, pos, result, <args>)
+--</code>
+-- Where <code>location<code> is the standard HEAD/BODY location,
+-- <code>data<code> and <code>pos<code> are the packet and position within it,
+-- <code>result<code> is the result from the HEAD section (if it's nil, it
+-- isn't used), and <code>args<code> 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 <code>data</code>.
+--@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 The new position
+--@return The result of unmarshalling this value.
+local function unmarshall_array(data, pos, count, func, args)
+ stdnse.debug4("MSRPC: Entering unmarshall_array()")
+
+ if(args == nil) then
+ args = {}
+ end
+
+ pos = pos or 1
+ if #data - pos + 1 < 4 then
+ stdnse.debug1("MSRPC: ERROR: Ran off the end of a packet in unmarshall_array(). Please report!")
+ return pos, nil
+ end
+ local max_count, pos = string.unpack("<I4", data, pos)
+
+ local result = {}
+
+ -- Unmarshall the header, which will be referent_ids and base types.
+ for i = 1, count, 1 do
+ pos, result[i] = func(HEAD, data, pos, nil, table.unpack(args))
+ end
+
+ -- Unmarshall the body. Note that the original result (result[i]) is passed back
+ -- into this function. This is required for pointers because, to unmarshall a pointer,
+ -- we have to remember whether or not it's null.
+ for i = 1, count, 1 do
+ pos, result[i] = func(BODY, data, pos, result[i], table.unpack(args))
+ end
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_array()")
+
+ return pos, result
+end
+
+---Call a function that matches the prototype for <code>unmarshall_array</code>.
+--
+-- This allows the same struct to be used in <code>unmarshall_array</code> and
+-- in <code>unmarshall_ptr</code>. 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 <code>func</code> parameter, obviously, has to match the same prototype
+-- as strings being passed to <code>unmarshall_array</code>, which is:
+--<code>
+-- func(location, data, pos, result, <args>)
+--</code>
+--
+--@param data The data being processed.
+--@param pos The position within <code>data</code>.
+--@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 The new position
+--@return The result of unmarshalling this value.
+local function unmarshall_struct(data, pos, func, args)
+ local result
+
+ stdnse.debug4("MSRPC: Entering unmarshall_struct()")
+
+ if(args == nil) then
+ args = {}
+ end
+
+ pos, result = func(ALL, data, pos, nil, args)
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_struct()")
+
+ return pos, result
+end
+
+-------------------------------------
+-- BASE TYPES
+-- (dependencies: n/a)
+-------------------------------------
+
+--- Marshall a string that is in the format:
+-- <code>[string,charset(UTF16)] uint16 *str</code>
+--
+-- 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.debug4("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 = string.pack("<I4I4I4",
+ max_length, -- Max count
+ 0, -- Offset
+ buffer_length) -- Actual count
+ .. string_to_unicode(str, do_null, true)
+
+ stdnse.debug4("MSRPC: Leaving marshall_unicode()")
+
+ return result
+end
+
+--- Marshall a null-terminated ascii string, with the length/maxlength prepended. Very similar
+-- to <code>marshall_unicode</code>, 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
+
+ buffer_length = #str + 1
+
+ if(max_length == nil) then
+ max_length = buffer_length
+ end
+
+ local padding = string.rep('\0', (4 - (buffer_length % 4)) % 4)
+
+ result = string.pack("<I4I4I4z",
+ max_length,
+ 0,
+ buffer_length,
+ str)
+ .. padding
+
+ return result
+end
+
+--- Marshall a pointer to a unicode string.
+--
+--@param str The string to insert. Can 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_ptr(str, do_null, max_length)
+ local result
+
+ stdnse.debug4("MSRPC: Entering marshall_unicode()")
+
+ result = marshall_ptr(ALL, marshall_unicode, {str, do_null, max_length}, str)
+
+ stdnse.debug4("MSRPC: Leaving marshall_unicode()")
+
+ return result
+end
+
+--- Marshall a pointer to an ascii string.
+--
+--@param str The string to insert. Can be nil.
+--@param max_length [optional] Sets a max length that's different than the string's length.
+--@return A string representing the marshalled data.
+function marshall_ascii_ptr(str, max_length)
+ local result
+
+ result = marshall_ptr(ALL, marshall_ascii, {str, max_length}, str)
+
+ return result
+end
+
+--- Unmarshall a string that is in the format:
+-- <code>[string,charset(UTF16)] uint16 *str</code>
+--
+-- See <code>marshall_unicode</code> 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.debug4("MSRPC: Entering unmarshall_unicode()")
+
+ if(do_null == nil) then
+ do_null = false
+ end
+
+ pos = pos or 1
+ if #data - pos + 1 < 3*4 then
+ stdnse.debug1("MSRPC: ERROR: Ran off the end of a packet in unmarshall_unicode(). Please report!")
+ return pos, nil
+ end
+ max, offset, actual, pos = string.unpack("<I4I4I4", data, pos)
+
+ pos, str = unicode_to_string(data, pos, actual, do_null, true)
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_unicode()")
+
+ return pos, str
+end
+
+---Unmarshall a pointer to a unicode string.
+--
+--@param data The data being processed.
+--@param pos The position within <code>data</code>.
+--@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.debug4("MSRPC: Entering unmarshall_unicode_ptr()")
+ pos, result = unmarshall_ptr(ALL, data, pos, unmarshall_unicode, {do_null})
+ stdnse.debug4("MSRPC: Leaving unmarshall_unicode_ptr()")
+
+ return pos, result
+end
+
+---Marshall an array of unicode strings. This is a perfect demonstration of how to use
+-- <code>marshall_array</code>.
+--
+--@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 <code>marshall_unicode_array</code>
+-- 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.debug4("MSRPC: Entering marshall_int64()")
+ result = string.pack("<I8", int64)
+ stdnse.debug4("MSRPC: Leaving marshall_int64()")
+
+ return result
+end
+
+--- Marshall an int32
+--
+-- <code> [in] uint32 var</code>
+--
+-- 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.debug4("MSRPC: Entering marshall_int32()")
+ result = string.pack("<I4", int32)
+ stdnse.debug4("MSRPC: Leaving marshall_int32()")
+
+ return result
+end
+
+---Marshall an array of int32 values.
+--
+--@param data The array
+--@return A string representing the marshalled data
+function marshall_int32_array(data)
+ local result = {
+ marshall_int32(0x0400), -- Max count
+ marshall_int32(0), -- Offset
+ marshall_int32(#data), -- Actual count
+ }
+
+ for _, v in ipairs(data) do
+ result[#result+1] = marshall_int32(v)
+ end
+
+ return table.concat(result)
+end
+
+--- Marshall an int16
+--
+-- <code> [in] uint16 var</code>
+--
+-- 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.debug4("MSRPC: Entering marshall_int16()")
+
+ if(pad == false) then
+ return string.pack("<I2", int16)
+ end
+
+ result = string.pack("<I2xx", int16)
+
+ stdnse.debug4("MSRPC: Leaving marshall_int16()")
+
+ return result
+end
+
+--- Marshall an int8
+--
+-- <code> [in] uint8 var</code>
+--
+-- 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.debug4("MSRPC: Entering marshall_int8()")
+
+ if(pad == false) then
+ return string.pack("<B", int8)
+ end
+
+ result = string.pack("<Bxxx", int8)
+ stdnse.debug4("MSRPC: Leaving marshall_int8()")
+
+ return result
+end
+
+--- Unmarshall an int64. See <code>marshall_int64</code> for more information.
+--
+--@param data The data being processed.
+--@param pos The position within <code>data</code>.
+--@return (pos, int64) The new position, and the value.
+function unmarshall_int64(data, pos)
+ local value
+
+ stdnse.debug4("MSRPC: Entering unmarshall_int64()")
+ pos = pos or 1
+ if #data - pos + 1 < 8 then
+ stdnse.debug1("MSRPC: ERROR: Ran off the end of a packet in unmarshall_int64(). Please report!")
+ return pos, nil
+ end
+ value, pos = string.unpack("<i8", data, pos)
+ stdnse.debug4("MSRPC: Leaving unmarshall_int64()")
+
+ return pos, value
+end
+
+--- Unmarshall an int32. See <code>marshall_int32</code> for more information.
+--
+--@param data The data being processed.
+--@param pos The position within <code>data</code>.
+--@return (pos, int32) The new position, and the value.
+function unmarshall_int32(data, pos)
+ local value
+
+ pos = pos or 1
+ if #data - pos + 1 < 4 then
+ stdnse.debug1("MSRPC: ERROR: Ran off the end of a packet in unmarshall_int32(). Please report!")
+ return pos, nil
+ end
+ value, pos = string.unpack("<I4", data, pos)
+
+ return pos, value
+end
+
+--- Unmarshall an int16. See <code>marshall_int16</code> 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.debug4("MSRPC: Entering unmarshall_int16()")
+
+ pos = pos or 1
+ if #data - pos + 1 < 2 then
+ stdnse.debug1("MSRPC: ERROR: Ran off the end of a packet in unmarshall_int16(). Please report!")
+ return pos, nil
+ end
+ value, pos = string.unpack("<I2", data, pos)
+
+ if(pad == nil or pad == true) then
+ pos = pos + 2
+ end
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_int16()")
+
+ return pos, value
+end
+
+--- Unmarshall an int8. See <code>marshall_int8</code> 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.debug4("MSRPC: Entering unmarshall_int8()")
+
+ pos = pos or 1
+ if #data - pos + 1 < 1 then
+ stdnse.debug1("MSRPC: ERROR: Ran off the end of a packet in unmarshall_int8(). Please report!")
+ return pos, nil
+ end
+ value, pos = string.unpack("<B", data, pos)
+
+ if(pad == nil or pad == true) then
+ pos = pos + 3
+ end
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_int8()")
+
+ return pos, value
+end
+
+--- Marshall a pointer to an int64.
+--
+-- If the pointer is null, it simply marshalls the
+-- integer '0'. Otherwise, it uses a referent id followed by the integer.
+--
+--@param int64 The value of the integer pointer
+--@return A string representing the marshalled data.
+function marshall_int64_ptr(int64)
+ local result
+
+ stdnse.debug4("MSRPC: Entering marshall_int64_ptr()")
+ result = marshall_ptr(ALL, marshall_int64, {int64}, int64)
+ stdnse.debug4("MSRPC: Leaving marshall_int64_ptr()")
+
+ return result
+end
+
+--- Marshall a pointer to an int32
+--
+-- <code> [in,out] uint32 *ptr</code>
+--
+-- 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.debug4("MSRPC: Entering marshall_int32_ptr()")
+ result = marshall_ptr(ALL, marshall_int32, {int32}, int32)
+ stdnse.debug4("MSRPC: Leaving marshall_int32_ptr()")
+
+ return result
+end
+
+--- Marshall a pointer to an int16
+--
+-- <code> [in,out] uint16 *ptr</code>
+--
+-- 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.debug4("MSRPC: Entering marshall_int16_ptr()")
+ result = marshall_ptr(ALL, marshall_int16, {int16, pad}, int16)
+ stdnse.debug4("MSRPC: Leaving marshall_int16_ptr()")
+
+ return result
+end
+
+--- Marshall a pointer to an int8
+--
+-- <code> [in,out] uint8 *ptr</code>
+--
+-- 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.debug4("MSRPC: Entering marshall_int8_ptr()")
+ result = marshall_ptr(ALL, marshall_int8, {int8, pad}, int8)
+ stdnse.debug4("MSRPC: Leaving marshall_int8_ptr()")
+
+ return result
+end
+
+--- Unmarshall a pointer to an int32. See <code>marshall_int32_ptr</code> 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.debug4("MSRPC: Entering unmarshall_int32_ptr()")
+ pos, result = unmarshall_ptr(ALL, data, pos, unmarshall_int32, {})
+ stdnse.debug4("MSRPC: Leaving unmarshall_int32_ptr()")
+
+ return pos, result
+end
+
+--- Unmarshall a pointer to an int16. See <code>marshall_int16_ptr</code> 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.debug4("MSRPC: Entering unmarshall_int16_ptr()")
+ pos, result = unmarshall_ptr(ALL, data, pos, unmarshall_int16, {pad})
+ stdnse.debug4("MSRPC: Leaving unmarshall_int16_ptr()")
+
+ return pos, result
+end
+
+--- Unmarshall a pointer to an int8. See <code>marshall_int8_ptr</code> 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.debug4("MSRPC: Entering unmarshall_int8_ptr()")
+ pos, result = unmarshall_ptr(ALL, data, pos, unmarshall_int8, {pad})
+ stdnse.debug4("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
+-- <code>data</code>.
+--@return A string representing the marshalled data.
+function marshall_int8_array(data, max_length)
+ stdnse.debug4("MSRPC: Entering marshall_int8_array()")
+
+ if(max_length == nil) then
+ max_length = #data
+ end
+
+ local result = string.pack("<I4I4", max_length, 0) .. data
+
+ stdnse.debug4("MSRPC: Leaving marshall_int8_array()")
+
+ return result
+end
+
+--- Unmarshall an array of int8s.
+--
+--@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(data, pos, pad)
+ local max, offset, actual
+ local str
+
+ stdnse.debug4("MSRPC: Entering unmarshall_int8_array()")
+
+ pos = pos or 1
+ if #data - pos + 1 < 3*4 then
+ stdnse.debug1("MSRPC: ERROR: Ran off the end of a packet in unmarshall_int8_array(). Please report!")
+ return pos, nil
+ end
+ max, offset, actual, pos = string.unpack("<I4I4I4", data, pos)
+
+ if #data - pos + 1 < actual then
+ stdnse.debug1("MSRPC: ERROR: Ran off the end of a packet in unmarshall_int8_array() [2]. Please report!")
+ return pos - 3*4, nil
+ end
+ str, pos = string.unpack("<c"..actual, data, pos)
+
+ -- Do the alignment (note the "- 1", it's there because of 1-based arrays)
+ if(pad == nil or pad == true) then
+ while(((pos - 1) % 4) ~= 0) do
+ pos = pos + 1
+ end
+ end
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_int8_array()")
+
+ return pos, str
+end
+
+--- Marshall a pointer to an array of int8s.
+--
+--@param data The array to marshall, as a string. Can be nil.
+--@param max_length [optional] The maximum length of the buffer. Default: the length of
+-- <code>data</code>.
+--@return A string representing the marshalled data.
+function marshall_int8_array_ptr(data, max_length)
+ local result
+ stdnse.debug4("MSRPC: Entering marshall_int8_array_ptr()")
+
+ result = marshall_ptr(ALL, marshall_int8_array, {data, max_length}, data)
+
+ stdnse.debug4("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.debug4("MSRPC: Entering unmarshall_int8_array_ptr()")
+
+ pos, str = unmarshall_ptr(ALL, data, pos, unmarshall_int8_array, {pad})
+
+ stdnse.debug4("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.debug4("MSRPC: Entering marshall_NTTIME()")
+
+ if(time == 0) then
+ result = string.pack("<I8", 0)
+ else
+ result = string.pack("<I8", (time + 11644473600) * 10000000)
+ end
+
+ stdnse.debug4("MSRPC: Leaving marshall_NTTIME()")
+ return result
+end
+
+---Unmarshalls an NTTIME. See <code>marshall_NTTIME</code> 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.debug4("MSRPC: Entering unmarshall_NTTIME()")
+
+ pos = pos or 1
+ if #data - pos + 1 < 8 then
+ stdnse.debug1("MSRPC: ERROR: Ran off the end of a packet in unmarshall_NTTIME(). Please report!")
+ return pos, nil
+ end
+ time, pos = string.unpack("<I8", data, pos)
+
+ if(time ~= 0) then
+ time = (time // 10000000) - 11644473600
+ end
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_NTTIME()")
+ return pos, time
+end
+
+---Marshalls an NTTIME*.
+--
+--@param time The time, in seconds since 1970.
+--@return A string representing the marshalled data.
+function marshall_NTTIME_ptr(time)
+ local result
+ stdnse.debug4("MSRPC: Entering marshall_NTTIME_ptr()")
+
+ result = marshall_ptr(ALL, marshall_NTTIME, {time}, time)
+
+ stdnse.debug4("MSRPC: Leaving marshall_NTTIME_ptr()")
+ return result
+end
+
+---Unmarshalls an <code>NTTIME*</code>.
+--
+--@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.debug4("MSRPC: Entering unmarshall_NTTIME_ptr()")
+
+ pos, time = unmarshall_ptr(ALL, data, pos, unmarshall_NTTIME, {})
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_NTTIME_ptr()")
+ return pos, time
+end
+
+---Unmarshall a SYSTEMTIME structure, converting it to a standard representation.
+--
+--The structure is as follows:
+--
+-- <code>
+-- typedef struct _SYSTEMTIME {
+-- WORD wYear;
+-- WORD wMonth;
+-- WORD wDayOfWeek;
+-- WORD wDay;
+-- WORD wHour;
+-- WORD wMinute;
+-- WORD wSecond;
+-- WORD wMilliseconds;
+-- } SYSTEMTIME
+-- </code>
+--
+--@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 fmt = "<I2I2I2I2I2I2I2I2"
+ pos = pos or 1
+ if #data - pos + 1 < string.packsize(fmt) then
+ stdnse.debug1("MSRPC: ERROR: Ran off the end of a packet in unmarshall_SYSTEMTIME(). Please report!")
+ return pos, nil
+ end
+ local date = {}
+
+ -- TODO: consider returning the date table instead, allowing the caller to see milliseconds.
+ date.year, date.month, date.dow, date.day, date.hour, date.min, date.sec, date.msec, pos = string.unpack(fmt, data, pos)
+
+ return pos, os.time(date)
+end
+
+---Unmarshalls a <code>hyper</code>.
+--
+-- I have no idea what a <code>hyper</code> 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.debug4("MSRPC: Entering unmarshall_hyper()")
+
+ pos, result = unmarshall_int64(data, pos)
+ result = result // -10000000
+
+ stdnse.debug4("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
+-- <code>table</code> 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,
+-- e.g. "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.debug4("MSRPC: Entering marshall_Enum32()")
+
+ local vals = stringaux.strsplit("|", val)
+ local i
+
+ for i = 1, #vals, 1 do
+ result = result | table[vals[i]]
+ end
+
+ result = marshall_int32(result)
+
+ stdnse.debug4("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 <code>table</code> 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.debug4("MSRPC: Entering unmarshall_Enum32()")
+
+ if(default == nil) then
+ default = "<unknown>"
+ 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.debug4("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 <code>table</code> 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.debug4("MSRPC: Entering unmarshall_Enum16()")
+
+ if(default == nil) then
+ default = "<unknown>"
+ 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.debug4("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
+-- <code>table</code> 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,
+-- e.g. "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.debug4("MSRPC: Entering marshall_Enum8()")
+
+ local vals = stringaux.strsplit("|", val)
+ local i
+
+ for i = 1, #vals, 1 do
+ result = result | table[vals[i]]
+ end
+
+ result = marshall_int8(result, pad)
+
+ stdnse.debug4("MSRPC: Leaving marshall_Enum8()")
+ return result
+end
+
+
+
+---Similar to <code>unmarshall_Enum32</code>, 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.debug4("MSRPC: Entering unmarshall_Enum32_array()")
+
+ pos, val = unmarshall_int32(data, pos)
+
+ for i, v in pairs(table) do
+ if (v & val) ~= 0 then
+ array[#array + 1] = i
+ end
+ end
+
+ stdnse.debug4("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.debug4("MSRPC: Entering unmarshall_raw()")
+
+ pos = pos or 1
+ if #data - pos + 1 < length then
+ stdnse.debug1("MSRPC: ERROR: Ran off the end of a packet in unmarshall_raw(). Please report!")
+ return pos, nil
+ end
+ val, pos = string.unpack(("c%d"):format(length), data, pos)
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_raw()")
+ return pos, val
+end
+
+
+-------------------------------------
+-- MISC
+-- (dependencies: n/a)
+-------------------------------------
+
+---Marshalls a GUID, which looks like this:
+--
+--<code>
+-- 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;
+--</code>
+--
+--@param guid A table representing the GUID.
+--@return A string representing the marshalled data.
+local function marshall_guid(guid)
+ local result
+ stdnse.debug4("MSRPC: Entering marshall_guid()")
+
+ result = string.pack("<I4I2I2", guid.time_low, guid.time_high, guid.time_hi_and_version) .. guid.clock_seq .. guid.node
+
+ stdnse.debug4("MSRPC: Leaving marshall_guid()")
+ return result
+end
+
+---Unmarshalls a GUID. See <code>marshall_guid</code> for the structure.
+--
+--@param data The data packet.
+--@param pos The position within the data.
+--@return (pos, result) The new position in <code>data</code>, and a table representing the datatype.
+local function unmarshall_guid(data, pos)
+ local fmt = "<I4I2I2c2c6"
+ stdnse.debug4("MSRPC: Entering unmarshall_guid()")
+
+ pos = pos or 1
+ if #data - pos + 1 < string.packsize(fmt) then
+ stdnse.debug1("MSRPC: ERROR: Ran off the end of a packet in unmarshall_guid(). Please report!")
+ return pos, nil
+ end
+ local guid = {}
+ guid.time_low, guid.time_high, guid.time_hi_and_version, guid.clock_seq, guid.node, pos = string.unpack(fmt, data, pos)
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_guid()")
+ return pos, guid
+end
+
+---Marshalls a policy_handle, which looks like this:
+--
+--<code>
+-- typedef struct {
+-- uint32 handle_type;
+-- GUID uuid;
+-- } policy_handle;
+--</code>
+--
+--@param policy_handle The policy_handle to marshall.
+--@return A string representing the marshalled data.
+function marshall_policy_handle(policy_handle)
+ local result
+ stdnse.debug4("MSRPC: Entering marshall_policy_handle()")
+
+ result = string.pack("<I4", policy_handle.handle_type) .. marshall_guid(policy_handle.uuid)
+
+ stdnse.debug4("MSRPC: Leaving marshall_policy_handle()")
+ return result
+end
+
+---Unmarshalls a policy_handle. See <code>marshall_policy_handle</code> for the structure.
+--
+--@param data The data packet.
+--@param pos The position within the data.
+--@return (pos, result) The new position in <code>data</code>, and a table representing the datatype.
+function unmarshall_policy_handle(data, pos)
+ local policy_handle = {}
+ stdnse.debug4("MSRPC: Entering unmarshall_policy_handle()")
+
+ pos, policy_handle['handle_type'] = unmarshall_int32(data, pos)
+ pos, policy_handle['uuid'] = unmarshall_guid(data, pos)
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_policy_handle()")
+ return pos, policy_handle
+end
+
+----------------------------------
+-- SECURITY
+-- (dependencies: MISC)
+----------------------------------
+
+---Unmarshall a dom_sid struct
+--
+--<code>
+-- 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;
+--</code>
+--
+--@param data The data being processed.
+--@param pos The position within <code>data</code>.
+--@return (pos, result) The new position in <code>data</code>, 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)
+ if #data - pos + 1 < 6 then
+ stdnse.debug1("MSRPC: ERROR: Ran off the end of a packet in unmarshall_dom_sid2(). Please report!")
+ return pos, nil
+ end
+ sid.authority, pos = string.unpack(">I6", data, pos)
+
+ 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 <code>dom_sid2</code> struct. See the <code>unmarshall_dom_sid2</code> function
+-- for more information.
+--
+--@param data The data being processed.
+--@param pos The position within <code>data</code>.
+--@return (pos, result) The new position in <code>data</code>, 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 dom_sid struct
+--
+--<code>
+-- 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;
+--</code>
+--
+--@return A string representing the marshalled data.
+function marshall_dom_sid2(sid)
+ local i
+ local pos_next
+ local sid_array = {}
+ local result = ""
+ stdnse.debug4("MSRPC: Entering marshall_dom_sid2()")
+
+
+ if(string.find(sid, "^S%-") == nil) then
+ stdnse.debug1("MSRPC: ERROR: Invalid SID encountered: %s\n", sid)
+ return nil
+ end
+ if(string.find(sid, "%-%d+$") == nil) then
+ stdnse.debug1("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 = tonumber(string.sub(sid, pos, pos_next - 1))
+
+ pos = pos_next + 1
+ pos_next = string.find(sid, "-", pos)
+ sid_array.authority = tonumber(string.sub(sid, pos, pos_next - 1))
+
+ 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] = tonumber(string.sub(sid, pos))
+ else
+ sid_array['sub_auths'][i] = tonumber(string.sub(sid, pos, pos_next - 1))
+ end
+ i = i + 1
+ until pos_next == nil
+ sid_array['num_auths'] = i - 1
+
+ result = {
+ -- TODO: Is the first 32-bit integer here supposed to be num_auths, or some
+ -- other count value?
+ string.pack("<I4BB>I6", sid_array.num_auths, sid_array.sid_rev_num, sid_array.num_auths, sid_array.authority),
+ }
+ for i = 1, sid_array['num_auths'], 1 do
+ result[#result+1] = string.pack("<I4", sid_array['sub_auths'][i])
+ end
+
+ stdnse.debug4("MSRPC: Leaving marshall_dom_sid2()")
+ return table.concat(result)
+end
+
+
+
+
+----------------------------------
+-- LSA
+-- (dependencies: SECURITY)
+----------------------------------
+
+
+---A <code>lsa_String</code> 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:
+--
+--<code>
+-- 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;
+--</code>
+--
+--@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.debug4("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 .. string.pack("<I2I2", length * 2, max_length * 2) .. marshall_ptr(HEAD, marshall_unicode, {str, do_null, max_length}, str)
+ end
+
+ if(location == BODY or location == ALL) then
+ result = result .. marshall_ptr(BODY, marshall_unicode, {str, do_null, max_length}, str)
+ end
+
+ stdnse.debug4("MSRPC: Leaving marshall_lsa_String_internal()")
+ return result
+end
+
+---Unmarshall a <code>lsa_String</code> value. See <code>marshall_lsa_String_internal</code> 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.debug4("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.debug4("MSRPC: Leaving unmarshall_lsa_String_internal()")
+ return pos, str
+end
+
+---Public version of <code>marshall_lsa_String_internal</code> -- see that function on that for more information.
+-- This version doesn't require a <code>location</code>, 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.debug4("MSRPC: Entering marshall_lsa_String()")
+
+ result = marshall_lsa_String_internal(ALL, str, max_length)
+
+ stdnse.debug4("MSRPC: Leaving marshall_lsa_String()")
+ return result
+end
+
+---Marshall an array of lsa_String objects. This is a perfect demonstration of how to use
+-- <code>marshall_array</code>.
+--
+--@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.debug4("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.debug4("MSRPC: Leaving marshall_lsa_String_array()")
+ return result
+end
+
+---Basically the same as <code>marshall_lsa_String_array</code>, 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
+ .. marshall_int32(0) -- Offset
+ .. 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 <code>lsa_SidType</code>. 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 <code>nil</code> if it wasn't
+-- found.
+function marshall_lsa_SidType(sid_type)
+ local result
+ stdnse.debug4("MSRPC: Entering marshall_lsa_SidType()")
+
+ result = marshall_Enum32(sid_type, lsa_SidType)
+
+ stdnse.debug4("MSRPC: Leaving marshall_lsa_SidType()")
+ return result
+end
+
+---Unmarshall a <code>lsa_SidType</code>. 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.debug4("MSRPC: Entering unmarshall_lsa_SidType()")
+
+ pos, str = unmarshall_Enum16(data, pos, lsa_SidType)
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_lsa_SidType()")
+ return pos, str
+end
+
+---Convert a <code>lsa_SidType</code> value to a string that can be shown to the user. This is
+-- based on the <code>_str</code> table.
+--
+--@param val The string value (returned by the <code>unmarshall_</code> function) to convert.
+--@return A string suitable for displaying to the user, or <code>nil</code> if it wasn't found.
+function lsa_SidType_tostr(val)
+ local result
+ stdnse.debug4("MSRPC: Entering lsa_SidType_tostr()")
+
+ result = lsa_SidType_str[val]
+
+ stdnse.debug4("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 <code>lsa_LookupNamesLevel</code>. 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 <code>nil</code> if it wasn't
+-- found.
+function marshall_lsa_LookupNamesLevel(names_level)
+ local result
+ stdnse.debug4("MSRPC: Entering marshall_lsa_LookupNamesLevel()")
+
+ result = marshall_Enum32(names_level, lsa_LookupNamesLevel)
+
+ stdnse.debug4("MSRPC: Leaving marshall_lsa_LookupNamesLevel()")
+ return result
+end
+
+---Unmarshall a <code>lsa_LookupNamesLevel</code>. 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.debug4("MSRPC: Entering unmarshall_lsa_LookupNamesLevel()")
+
+ pos, str = unmarshall_Enum32(data, pos, lsa_LookupNamesLevel)
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_lsa_LookupNamesLevel()")
+ return pos, str
+end
+
+---Convert a <code>lsa_LookupNamesLevel</code> value to a string that can be shown to the user. This is
+-- based on the <code>_str</code> table.
+--
+--@param val The string value (returned by the <code>unmarshall_</code> function) to convert.
+--@return A string suitable for displaying to the user, or <code>nil</code> if it wasn't found.
+function lsa_LookupNamesLevel_tostr(val)
+ local result
+ stdnse.debug4("MSRPC: Entering lsa_LookupNamesLevel_tostr()")
+
+ result = lsa_LookupNamesLevel_str[val]
+
+ stdnse.debug4("MSRPC: Leaving lsa_LookupNamesLevel_tostr()")
+ return result
+end
+
+---Marshall a lsa_TranslatedSid2 struct
+--
+--<code>
+-- typedef struct {
+-- lsa_SidType sid_type;
+-- uint32 rid;
+-- uint32 sid_index;
+-- uint32 unknown;
+-- } lsa_TranslatedSid2;
+--</code>
+--
+--@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 <code>sid_type</code> value (I don't know what this means)
+--@param rid The <code>rid</code> (a number representing the user)
+--@param sid_index The <code>sid_index</code> value (I don't know what this means, either)
+--@param unknown An unknown value (is normally 0).
+--@return A string representing the marshalled data.
+local function marshall_lsa_TranslatedSid2(location, sid_type, rid, sid_index, unknown)
+ local result = ""
+ stdnse.debug4("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 = marshall_lsa_SidType(sid_type)
+ .. marshall_int32(rid)
+ .. marshall_int32(sid_index)
+ .. marshall_int32(unknown)
+ end
+
+ if(location == BODY or location == ALL) then
+ end
+
+ stdnse.debug4("MSRPC: Leaving marshall_lsa_TranslatedSid2()")
+ return result
+end
+
+---Unmarshall a lsa_TranslatedSid2 struct
+--
+--<code>
+-- typedef struct {
+-- lsa_SidType sid_type;
+-- uint32 rid;
+-- uint32 sid_index;
+-- uint32 unknown;
+-- } lsa_TranslatedSid2;
+--</code>
+--
+--@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 <code>data</code>.
+--@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 <code>data</code>, 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 lsa_TranslatedName2 struct
+--
+--<code>
+-- typedef struct {
+-- lsa_SidType sid_type;
+-- lsa_String name;
+-- uint32 sid_index;
+-- uint32 unknown;
+-- } lsa_TranslatedName2;
+--</code>
+--
+--@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 <code>sid_type</code> 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.debug4("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 = marshall_lsa_SidType(sid_type)
+ .. marshall_lsa_String_internal(HEAD, name)
+ .. marshall_int32(sid_index)
+ .. marshall_int32(unknown)
+ end
+
+ if(location == BODY or location == ALL) then
+ result = result .. marshall_lsa_String_internal(BODY, name)
+ end
+
+ stdnse.debug4("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 <code>data</code>.
+--@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 <code>data</code>, and a table representing the datatype.
+local function unmarshall_lsa_TranslatedName2(location, data, pos, result)
+ stdnse.debug4("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.debug4("MSRPC: Leaving unmarshall_lsa_TranslatedName2()")
+ return pos, result
+end
+
+
+---Marshall a lsa_TransSidArray2 struct
+--
+--<code>
+-- typedef struct {
+-- [range(0,1000)] uint32 count;
+-- [size_is(count)] lsa_TranslatedSid2 *sids;
+-- } lsa_TransSidArray2;
+--</code>
+--
+--@param sids An array of SIDs to translate (as strings)
+--@return A string representing the marshalled data.
+function marshall_lsa_TransSidArray2(sids)
+ local array = {}
+ stdnse.debug4("MSRPC: Entering marshall_lsa_TransSidArray2()")
+
+
+ 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
+
+ local result = marshall_int32(#sids)
+ .. marshall_ptr(ALL, marshall_array, {array}, array)
+
+ stdnse.debug4("MSRPC: Leaving marshall_lsa_TransSidArray2()")
+ return result
+end
+
+---Marshall a lsa_StringLarge struct
+--
+--<code>
+-- 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;
+--</code>
+--
+--@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 <code>data</code>.
+--@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 <code>data</code>, and the string value.
+local function unmarshall_lsa_StringLarge(location, data, pos, result)
+ local length, size
+ local str
+ stdnse.debug4("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.debug4("MSRPC: Leaving unmarshall_lsa_StringLarge()")
+ return pos, str
+end
+
+---Unmarshall a lsa_DomainInfo struct
+--
+--<code>
+-- typedef struct {
+-- lsa_StringLarge name;
+-- dom_sid2 *sid;
+-- } lsa_DomainInfo;
+--</code>
+--
+--@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 <code>data</code>.
+--@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 <code>data</code>, and a table representing the datatype.
+local function unmarshall_lsa_DomainInfo(location, data, pos, result)
+ stdnse.debug4("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.debug4("MSRPC: Leaving unmarshall_lsa_DomainInfo()")
+ return pos, result
+end
+
+---Unmarshall a lsa_RefDomainList struct
+--
+--<code>
+-- typedef struct {
+-- [range(0,1000)] uint32 count;
+-- [size_is(count)] lsa_DomainInfo *domains;
+-- uint32 max_size;
+-- } lsa_RefDomainList;
+--</code>
+--
+--@param data The data being processed.
+--@param pos The position within <code>data</code>.
+--@return (pos, result) The new position in <code>data</code>, and a table representing the datatype.
+function unmarshall_lsa_RefDomainList(data, pos)
+ local result = {}
+ stdnse.debug4("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.debug4("MSRPC: Leaving unmarshall_lsa_RefDomainList()")
+ return pos, result
+end
+
+---Unmarshall a pointer to a <code>lsa_RefDomainList</code>. See the <code>unmarshall_lsa_RefDomainList</code> function
+-- for more information.
+--
+--@param data The data being processed.
+--@param pos The position within <code>data</code>.
+--@return (pos, result) The new position in <code>data</code>, and a table representing the datatype.
+function unmarshall_lsa_RefDomainList_ptr(data, pos)
+ local result
+ stdnse.debug4("MSRPC: Entering unmarshall_lsa_RefDomainList_ptr()")
+
+ pos, result = unmarshall_ptr(ALL, data, pos, unmarshall_lsa_RefDomainList, nil)
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_lsa_RefDomainList_ptr()")
+ return pos, result
+end
+
+---Unmarshall a lsa_TransSidArray2 struct
+--
+--<code>
+-- typedef struct {
+-- [range(0,1000)] uint32 count;
+-- [size_is(count)] lsa_TranslatedSid2 *sids;
+-- } lsa_TransSidArray2;
+--</code>
+--
+--@param data The data being processed.
+--@param pos The position within <code>data</code>.
+--@return (pos, result) The new position in <code>data</code>, and a table representing the datatype.
+function unmarshall_lsa_TransSidArray2(data, pos)
+ local result = {}
+ stdnse.debug4("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.debug4("MSRPC: Leaving unmarshall_lsa_TransSidArray2()")
+ return pos, result
+end
+
+---Marshall a lsa_QosInfo struct
+--
+--<code>
+-- typedef struct {
+-- uint32 len; /* ignored */
+-- uint16 impersonation_level;
+-- uint8 context_mode;
+-- uint8 effective_only;
+-- } lsa_QosInfo;
+--</code>
+--
+-- 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()
+ stdnse.debug4("MSRPC: Entering marshall_lsa_QosInfo()")
+
+ local result = marshall_int32(12)
+ .. marshall_int16(2, false)
+ .. marshall_int8(1, false)
+ .. marshall_int8(0, false)
+
+ stdnse.debug4("MSRPC: Leaving marshall_lsa_QosInfo()")
+ return result
+end
+
+---Marshall a lsa_ObjectAttribute struct
+--
+--<code>
+-- 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;
+--</code>
+--
+-- 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()
+ stdnse.debug4("MSRPC: Entering marshall_lsa_ObjectAttribute()")
+
+ local result = marshall_int32(24)
+ .. marshall_int32(0) -- Null'ing out these pointers for now. Maybe we'll need them in the future...
+ .. marshall_int32(0)
+ .. marshall_int32(0)
+ .. marshall_int32(0)
+ .. marshall_ptr(ALL, marshall_lsa_QosInfo, {})
+
+ stdnse.debug4("MSRPC: Leaving marshall_lsa_ObjectAttribute()")
+ return result
+end
+
+---Marshall a lsa_SidPtr struct
+--
+--<code>
+-- typedef struct {
+-- dom_sid2 *sid;
+-- } lsa_SidPtr;
+--</code>
+--
+--@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.debug4("MSRPC: Entering marshall_lsa_SidPtr()")
+
+ result = marshall_ptr(location, marshall_dom_sid2, {sid}, sid)
+
+ stdnse.debug4("MSRPC: Leaving marshall_lsa_SidPtr()")
+ return result
+end
+
+---Marshall a lsa_SidArray struct
+--
+--<code>
+-- typedef [public] struct {
+-- [range(0,1000)] uint32 num_sids;
+-- [size_is(num_sids)] lsa_SidPtr *sids;
+-- } lsa_SidArray;
+--</code>
+--
+--@param sids The array of SIDs to marshall (as strings).
+--@return A string representing the marshalled data.
+function marshall_lsa_SidArray(sids)
+ local array = {}
+
+ for i = 1, #sids, 1 do
+ array[i] = {}
+ array[i]['func'] = marshall_lsa_SidPtr
+ array[i]['args'] = {sids[i]}
+ end
+
+ local result = marshall_int32(#sids)
+ .. marshall_ptr(ALL, marshall_array, {array}, array)
+
+ return result
+end
+
+---Unmarshall a lsa_SidPtr struct
+--
+--<code>
+-- typedef struct {
+-- dom_sid2 *sid;
+-- } lsa_SidPtr;
+--</code>
+--
+--@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 <code>data</code>.
+--@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 <code>data</code>, 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 lsa_SidArray struct
+--
+-- 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 <code>data</code>.
+--@return (pos, result) The new position in <code>data</code>, 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 lsa_TransNameArray2 struct
+--
+--<code>
+-- typedef struct {
+-- [range(0,1000)] uint32 count;
+-- [size_is(count)] lsa_TranslatedName2 *names;
+-- } lsa_TransNameArray2;
+--</code>
+--
+--@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.debug4("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.debug4("MSRPC: Leaving marshall_lsa_TransNameArray2()")
+ return result
+end
+
+---Unmarshall a <code>lsa_TransNameArray2</code> structure. See the <code>marshall_lsa_TransNameArray2</code> for more
+-- information.
+--
+--@param data The data being processed.
+--@param pos The position within <code>data</code>.
+--@return (pos, result) The new position in <code>data</code>, and a table representing the datatype.
+function unmarshall_lsa_TransNameArray2(data, pos)
+ local result = {}
+ stdnse.debug4("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.debug4("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 <code>winreg_AccessMask</code>.
+--
+--@param accessmask The access mask as a string (see the <code>winreg_AccessMask</code>
+-- table)
+--@return A string representing the marshalled data.
+function marshall_winreg_AccessMask(accessmask)
+ local result
+ stdnse.debug4("MSRPC: Entering marshall_winreg_AccessMask()")
+
+ result = marshall_Enum32(accessmask, winreg_AccessMask)
+
+ stdnse.debug4("MSRPC: Leaving marshall_winreg_AccessMask()")
+ return result
+end
+
+---Unmarshall a <code>winreg_AccessMask</code>. 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.debug4("MSRPC: Entering unmarshall_winreg_AccessMask()")
+
+ pos, str = unmarshall_Enum32(data, pos, winreg_AccessMask)
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_winreg_AccessMask()")
+ return pos, str
+end
+
+---Convert a <code>winreg_AccessMask</code> value to a string that can be shown to the user. This is
+-- based on the <code>_str</code> table.
+--
+--@param val The string value (returned by the <code>unmarshall_</code> function) to convert.
+--@return A string suitable for displaying to the user, or <code>nil</code> if it wasn't found.
+function winreg_AccessMask_tostr(val)
+ local result
+ stdnse.debug4("MSRPC: Entering winreg_AccessMask_tostr()")
+
+ result = winreg_AccessMask_str[val]
+
+ stdnse.debug4("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 <code>winreg_Type</code>. 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 <code>nil</code> if it wasn't
+-- found.
+function marshall_winreg_Type(winregtype)
+ local result
+ stdnse.debug4("MSRPC: Entering marshall_winreg_Type()")
+
+ result = marshall_Enum32(winregtype, winreg_Type)
+
+ stdnse.debug4("MSRPC: Leaving marshall_winreg_Type()")
+ return result
+end
+
+---Unmarshall a <code>winreg_Type</code>. 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.debug4("MSRPC: Entering unmarshall_winreg_Type()")
+
+ pos, str = unmarshall_Enum32(data, pos, winreg_Type)
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_winreg_Type()")
+ return pos, str
+end
+
+---Marshall a pointer to a <code>winreg_Type</code>. 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 <code>nil</code> if it wasn't
+-- found.
+function marshall_winreg_Type_ptr(winreg_type)
+ local result
+ stdnse.debug4("MSRPC: Entering marshall_winreg_Type_ptr()")
+
+ result = marshall_ptr(ALL, marshall_winreg_Type, {winreg_type}, winreg_type)
+
+ stdnse.debug4("MSRPC: Leaving marshall_winreg_Type_ptr()")
+ return result
+end
+
+---Unmarshall a pointer to a <code>winreg_Type</code>. 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.debug4("MSRPC: Entering unmarshall_winreg_Type_ptr()")
+
+ pos, str = unmarshall_ptr(ALL, data, pos, unmarshall_winreg_Type, {})
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_winreg_Type_ptr()")
+ return pos, str
+end
+
+---Convert a <code>winreg_Type</code> value to a string that can be shown to the user. This is
+-- based on the <code>_str</code> table.
+--
+--@param val The string value (returned by the <code>unmarshall_</code> function) to convert.
+--@return A string suitable for displaying to the user, or <code>nil</code> if it wasn't found.
+function winreg_Type_tostr(val)
+ local result
+ stdnse.debug4("MSRPC: Entering winreg_Type_tostr()")
+
+ result = winreg_Type_str[val]
+
+ stdnse.debug4("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:
+--
+--<code>
+-- 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;
+--</code>
+--
+--@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.debug4("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 = string.pack("<I2I2", length * 2, max_length * 2) .. marshall_ptr(ALL, marshall_unicode, {name, false, max_length}, name)
+ else
+ if(name == nil) then
+ length = 0
+ else
+ length = #name + 1
+ end
+
+ result = string.pack("<I2I2", length * 2, max_length * 2) .. marshall_ptr(ALL, marshall_unicode, {name, true, max_length}, name)
+ end
+
+ stdnse.debug4("MSRPC: Leaving marshall_winreg_StringBuf()")
+ return result
+end
+
+---Unmarshall a winreg_StringBuf buffer.
+--
+--@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(data, pos)
+ local length, size
+ local str
+ stdnse.debug4("MSRPC: Entering unmarshall_winreg_StringBuf()")
+
+ pos, length = unmarshall_int16(data, pos, false)
+ pos, size = unmarshall_int16(data, pos, false)
+
+ pos, str = unmarshall_ptr(ALL, data, pos, unmarshall_unicode, {true})
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_winreg_StringBuf()")
+ return pos, str
+end
+
+---Marshall a winreg_StringBuffer pointer. Same as <code>marshall_winreg_StringBuf</code>, except
+-- the string can be <code>nil</code>.
+--
+--@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.debug4("MSRPC: Entering marshall_winreg_StringBuf_ptr()")
+
+ result = marshall_ptr(ALL, marshall_winreg_StringBuf, {table, max_length}, table)
+
+ stdnse.debug4("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.debug4("MSRPC: Entering unmarshall_winreg_StringBuf_ptr()")
+
+ pos, str = unmarshall_ptr(ALL, data, pos, unmarshall_winreg_StringBuf, {})
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_winreg_StringBuf_ptr()")
+ return pos, str
+end
+
+
+--- A winreg_String has the same makeup 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.debug4("MSRPC: Entering marshall_winreg_String()")
+
+ result = marshall_winreg_StringBuf(table, max_length)
+
+ stdnse.debug4("MSRPC: Leaving marshall_winreg_String()")
+ return result
+end
+
+---Unmarshall a winreg_String. Since it has the same makeup 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.debug4("MSRPC: Entering unmarshall_winreg_String()")
+
+ pos, str = unmarshall_winreg_StringBuf(data, pos)
+
+ stdnse.debug4("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 <code>srvsvc_ShareType</code>. 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 <code>nil</code> if it wasn't
+-- found.
+function marshall_srvsvc_ShareType(sharetype)
+ local result
+ stdnse.debug4("MSRPC: Entering marshall_srvsvc_ShareType()")
+
+ result = marshall_Enum32(sharetype, srvsvc_ShareType)
+
+ stdnse.debug4("MSRPC: Leaving marshall_srvsvc_ShareType()")
+ return result
+end
+
+---Unmarshall a <code>srvsvc_ShareType</code>. 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.debug4("MSRPC: Entering unmarshall_srvsvc_ShareType()")
+
+ pos, str = unmarshall_Enum32(data, pos, srvsvc_ShareType)
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_srvsvc_ShareType()")
+ return pos, str
+end
+
+---Convert a <code>srvsvc_ShareType</code> value to a string that can be shown to the user. This is
+-- based on the <code>_str</code> table.
+--
+--@param val The string value (returned by the <code>unmarshall_</code> function) to convert.
+--@return A string suitable for displaying to the user, or <code>nil</code> if it wasn't found.
+function srvsvc_ShareType_tostr(val)
+ local result
+ stdnse.debug4("MSRPC: Entering srvsvc_ShareType_tostr()")
+
+ result = srvsvc_ShareType_str[val]
+
+ stdnse.debug4("MSRPC: Leaving srvsvc_ShareType_tostr()")
+ return result
+end
+
+---Marshall a NetShareInfo type 0, which is just a name.
+--
+--<code>
+-- typedef struct {
+-- [string,charset(UTF16)] uint16 *name;
+-- } srvsvc_NetShareInfo0;
+--</code>
+--
+--@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.debug4("MSRPC: Entering marshall_srvsvc_NetShareInfo0()")
+
+ result = marshall_ptr(location, marshall_unicode, {name, true}, name)
+
+ stdnse.debug4("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 <code>data</code>, and a table representing the datatype.
+local function unmarshall_srvsvc_NetShareInfo0(location, data, pos, result)
+ stdnse.debug4("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.debug4("MSRPC: Leaving unmarshall_srvsvc_NetShareInfo0()")
+ return pos, result
+end
+
+---Marshall a NetShareInfo type 1, which is the name and a few other things.
+--
+--<code>
+-- typedef struct {
+-- [string,charset(UTF16)] uint16 *name;
+-- srvsvc_ShareType type;
+-- [string,charset(UTF16)] uint16 *comment;
+-- } srvsvc_NetShareInfo1;
+--</code>
+--
+--@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.debug4("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 = name .. sharetype .. comment
+
+ stdnse.debug4("MSRPC: Leaving marshall_srvsvc_NetShareInfo1()")
+ return result
+end
+
+---Unmarshall a NetShareInfo type 1, which is a name and a couple 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 <code>data</code>, and a table representing the datatype.
+local function unmarshall_srvsvc_NetShareInfo1(location, data, pos, result)
+ stdnse.debug4("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.debug4("MSRPC: Leaving unmarshall_srvsvc_NetShareInfo1()")
+ return pos, result
+end
+
+
+---Marshall a NetShareInfo type 2, which is the name and a few other things.
+--
+--<code>
+-- 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;
+--</code>
+--
+--@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.debug4("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.debug4("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 <code>data</code>, and a table representing the datatype.
+local function unmarshall_srvsvc_NetShareInfo2(location, data, pos, result)
+ stdnse.debug4("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.debug4("MSRPC: Leaving unmarshall_srvsvc_NetShareInfo2()")
+ return pos, result
+end
+
+---Marshall a NetShareCtr (container) type 0.
+--
+--It is a simple array with the following definition:
+--
+--<code>
+-- typedef struct {
+-- uint32 count;
+-- [size_is(count)] srvsvc_NetShareInfo0 *array;
+-- } srvsvc_NetShareCtr0;
+--</code>
+--
+--@param NetShareCtr0 A table representing the structure.
+--@return A string representing the marshalled data.
+function marshall_srvsvc_NetShareCtr0(NetShareCtr0)
+ local i
+ local result = {}
+ stdnse.debug4("MSRPC: Entering marshall_srvsvc_NetShareCtr0()")
+
+ if(NetShareCtr0 == nil) then
+ result[#result+1] = string.pack("<I4", 0)
+ else
+ local array = NetShareCtr0['array']
+ local marshall = nil
+
+ if(array == nil) then
+ result[#result+1] = string.pack("<I4", 0)
+ else
+ result[#result+1] = string.pack("<I4", #array) -- count
+
+ -- Build the array that we can marshall
+ marshall = {}
+ for i = 1, #array, 1 do
+ marshall[i] = {}
+ marshall[i]['func'] = marshall_srvsvc_NetShareInfo0
+ marshall[i]['args'] = {array[i]['name']}
+ end
+ end
+
+ result[#result+1] = marshall_ptr(ALL, marshall_array, {marshall}, marshall) -- array
+ end
+
+ stdnse.debug4("MSRPC: Leaving marshall_srvsvc_NetShareCtr0()")
+ return table.concat(result)
+end
+
+---Unmarshall a NetShareCtr (container) type 0. See the marshall function for the definition.
+--
+--@param data The data packet.
+--@param pos The position within the data.
+--@return (pos, result) The new position in <code>data</code>, and a table representing the datatype.
+function unmarshall_srvsvc_NetShareCtr0(data, pos)
+ local count
+ local result = {}
+ stdnse.debug4("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.debug4("MSRPC: Leaving unmarshall_srvsvc_NetShareCtr0()")
+ return pos, result
+end
+
+---Marshall a NetShareCtr (container) type 1.
+--
+--It is a simple array with the following definition:
+--
+--<code>
+-- typedef struct {
+-- uint32 count;
+-- [size_is(count)] srvsvc_NetShareInfo1 *array;
+-- } srvsvc_NetShareCtr1;
+--</code>
+--
+--@param NetShareCtr1 A table representing the structure.
+--@return A string representing the marshalled data.
+function marshall_srvsvc_NetShareCtr1(NetShareCtr1)
+ local i
+ local result = {}
+ stdnse.debug4("MSRPC: Entering marshall_srvsvc_NetShareCtr1()")
+
+ if(NetShareCtr1 == nil) then
+ result[#result+1] = string.pack("<I4", 0)
+ else
+ local array = NetShareCtr1['array']
+ local marshall = nil
+
+ if(array == nil) then
+ result[#result+1] = string.pack("<I4", 0)
+ else
+ result[#result+1] = string.pack("<I4", #array) -- count
+
+ -- Build the array that we can marshall
+ marshall = {}
+ for i = 1, #array, 1 do
+ marshall[i] = {}
+ marshall[i]['func'] = marshall_srvsvc_NetShareInfo1
+ marshall[i]['args'] = {array[i]['name'], array[i]['sharetype'], array[i]['comment']}
+ end
+ end
+
+ result[#result+1] = marshall_ptr(ALL, marshall_array, {marshall}, marshall) -- array
+ end
+
+ stdnse.debug4("MSRPC: Leaving marshall_srvsvc_NetShareCtr1()")
+ return table.concat(result)
+end
+
+
+---Marshall a NetShareCtr (container) type 2.
+--
+--It is a simple array with the following definition:
+--
+--<code>
+-- typedef struct {
+-- uint32 count;
+-- [size_is(count)] srvsvc_NetShareInfo2 *array;
+-- } srvsvc_NetShareCtr2;
+--</code>
+--
+--@param NetShareCtr2 A pointer to the structure.
+--@return A string representing the marshalled data.
+function marshall_srvsvc_NetShareCtr2(NetShareCtr2)
+ local i
+ local result = {}
+ stdnse.debug4("MSRPC: Entering marshall_srvsvc_NetShareCtr2()")
+
+ if(NetShareCtr2 == nil) then
+ result[#result+1] = string.pack("<I4", 0)
+ else
+ local array = NetShareCtr2['array']
+ local marshall = nil
+
+ if(array == nil) then
+ result[#result+1] = string.pack("<I4", 0)
+ else
+ result[#result+1] = string.pack("<I4", #array) -- count
+
+ -- Build the array that we can marshall
+ marshall = {}
+ for i = 1, #array, 1 do
+ marshall[i] = {}
+ marshall[i]['func'] = marshall_srvsvc_NetShareInfo2
+ marshall[i]['args'] = {array[i]['name'], array[i]['sharetype'], array[i]['comment'], array[i]['permissions'], array[i]['max_users'], array[i]['current_users'], array[i]['path'], array[i]['password']}
+ marshall[i]['args'] = {array[i]['name']}
+ end
+ end
+
+ result[#result+1] = marshall_ptr(ALL, marshall_array, {marshall}, marshall) -- array
+ end
+
+ stdnse.debug4("MSRPC: Leaving marshall_srvsvc_NetShareCtr2()")
+ return table.concat(result)
+end
+
+---Marshall the top-level NetShareCtr. This is a union of a bunch of different containers:
+--
+--<code>
+-- 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;
+--</code>
+--
+-- 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)
+ stdnse.debug4("MSRPC: Entering marshall_srvsvc_NetShareCtr()")
+
+ local marshaller
+ if(level == 0) then
+ marshaller = marshall_srvsvc_NetShareCtr0
+ elseif(level == 1) then
+ marshaller = marshall_srvsvc_NetShareCtr1
+ elseif(level == 2) then
+ marshaller = marshall_srvsvc_NetShareCtr2
+ else
+ stdnse.debug1("MSRPC: ERROR: Script requested an unknown level for srvsvc_NetShareCtr: %d", level)
+ return nil
+ end
+ local result = string.pack("<I4", level) .. marshall_ptr(ALL, marshaller, {data}, data)
+
+ stdnse.debug4("MSRPC: Leaving marshall_srvsvc_NetShareCtr()")
+ return result
+end
+
+---Unmarshall the top-level NetShareCtr. This is a union of a bunch of containers, see the equivalent
+-- marshall function for more information; at the time of this writing I've only implemented level = 0.
+--
+--@param data The data packet.
+--@param pos The position within the data.
+--@return (pos, result) The new position in <code>data</code>, and a table representing the datatype.
+-- The result may be <code>nil</code> if there's an error.
+function unmarshall_srvsvc_NetShareCtr(data, pos)
+ local level
+ local result
+ stdnse.debug4("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.debug1("MSRPC: ERROR: Server returned an unknown level for srvsvc_NetShareCtr: %d", level)
+ pos, result = nil, nil
+ end
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_srv_NetShareCtr()")
+ return pos, result
+end
+
+---Unmarshall the top-level NetShareInfo. This is a union of a bunch of different structs:
+--
+--<code>
+-- 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;
+--</code>
+--
+-- 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 <code>data</code>.
+--@return (pos, result) The new position in <code>data</code>, and a table representing the datatype. This may be
+-- <code>nil</code> if there was an error.
+function unmarshall_srvsvc_NetShareInfo(data, pos)
+ local level
+ local result
+ stdnse.debug4("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.debug1("MSRPC: ERROR: Invalid level returned by NetShareInfo: %d\n", level)
+ pos, result = nil, nil
+ end
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_srvsvc_NetShareInfo()")
+ return pos, result
+end
+
+---Marshall a NetSessInfo type 10.
+--
+--<code>
+-- typedef struct {
+-- [string,charset(UTF16)] uint16 *client;
+-- [string,charset(UTF16)] uint16 *user;
+-- uint32 time;
+-- uint32 idle_time;
+-- } srvsvc_NetSessInfo10;
+--</code>
+--
+--@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.debug4("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 = client .. user .. time .. idle_time
+
+ stdnse.debug4("MSRPC: Leaving marshall_srvsvc_NetShareInfo10()")
+ return result
+end
+
+---Unmarshall a NetSessInfo type 10. For more information, see the marshall function.
+--
+--@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 <code>data</code>, and a table representing the datatype.
+local function unmarshall_srvsvc_NetSessInfo10(location, data, pos, result)
+ stdnse.debug4("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.debug4("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:
+--
+--<code>
+-- typedef struct {
+-- uint32 count;
+-- [size_is(count)] srvsvc_NetSessInfo10 *array;
+-- } srvsvc_NetSessCtr10;
+--</code>
+--
+--@param NetSessCtr10 A table representing the structure.
+--@return A string representing the marshalled data.
+function marshall_srvsvc_NetSessCtr10(NetSessCtr10)
+ local i
+ local result = {}
+ stdnse.debug4("MSRPC: Entering marshall_srvsvc_NetSessCtr10()")
+
+ if(NetSessCtr10 == nil) then
+ result[#result+1] = string.pack("<I4", 0)
+ else
+ local array = NetSessCtr10['array']
+ local marshall = nil
+
+ if(array == nil) then
+ result[#result+1] = string.pack("<I4", 0)
+ else
+ result[#result+1] = string.pack("<I4", #array) -- count
+
+ -- Build the array that we can marshall
+ marshall = {}
+ for i = 1, #array, 1 do
+ marshall[i] = {}
+ marshall[i]['func'] = marshall_srvsvc_NetSessInfo10
+ marshall[i]['args'] = {array[i]['client'], array[i]['user'], array[i]['time'], array[i]['idle_time']}
+ end
+ end
+
+ result[#result+1] = marshall_ptr(ALL, marshall_array, {marshall}, marshall) -- array
+ end
+
+ stdnse.debug4("MSRPC: Leaving marshall_srvsvc_NetSessCtr10()")
+ return table.concat(result)
+end
+
+---Unmarshall a NetSessCtr (session container) type 10. See the marshall function for the definition.
+--
+--@param data The data packet.
+--@param pos The position within the data.
+--@return (pos, result) The new position in <code>data</code>, and a table representing the datatype.
+function unmarshall_srvsvc_NetSessCtr10(data, pos)
+ local count
+ local result = {}
+ stdnse.debug4("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.debug4("MSRPC: Leaving unmarshall_srvsvc_NetSessCtr10()")
+ return pos, result
+end
+
+---Marshall the top-level NetShareCtr. This is a union of a bunch of different containers:
+--
+--<code>
+-- 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;
+--</code>
+--
+-- 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.debug4("MSRPC: Entering marshall_srvsvc_NetShareCtr()")
+
+ if(level == 10) then
+ result = string.pack("<I4", level) .. marshall_ptr(ALL, marshall_srvsvc_NetSessCtr10, {data}, data)
+ else
+ stdnse.debug1("MSRPC: ERROR: Script requested an unknown level for srvsvc_NetSessCtr")
+ result = nil
+ end
+
+ stdnse.debug4("MSRPC: Leaving marshall_srvsvc_NetShareCtr()")
+ return result
+end
+
+---Unmarshall the top-level NetShareCtr. This is a union; see the marshall function for more information.
+--
+--@param data The data being processed.
+--@param pos The position within <code>data</code>
+--@return (pos, result) The new position in <code>data</code>, and a table representing the datatype. Can be
+-- <code>nil</code> if there's an error.
+function unmarshall_srvsvc_NetSessCtr(data, pos)
+ local level
+ local result
+ stdnse.debug4("MSRPC: Entering unmarshall_srvsvc_NetSessCtr()")
+
+ level, pos = string.unpack("<I4", data, pos)
+
+ if(level == 10) then
+ pos, result = unmarshall_ptr(ALL, data, pos, unmarshall_srvsvc_NetSessCtr10, {})
+ else
+ stdnse.debug1("MSRPC: ERROR: Invalid level returned by NetSessCtr: %d\n", level)
+ pos, result = nil, nil
+ end
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_srvsvc_NetSessCtr()")
+ return pos, result
+end
+
+
+---Unmarshall a <code>srvsvc_Statistics</code> packet. This is basically a great big struct:
+--
+--<code>
+-- 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;
+--</code>
+--
+-- 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 <code>data</code>
+--@return (pos, result) The new position in <code>data</code>, and a table representing the datatype.
+function unmarshall_srvsvc_Statistics(data, pos)
+ local response = {}
+ stdnse.debug4("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.debug4("MSRPC: Leaving unmarshall_srvsvc_Statistics()")
+ return pos, response
+end
+
+---Unmarshalls a <code>srvsvc_Statistics</code> as a pointer. Wireshark fails to do this, and ends
+-- up parsing the packet wrong, so take care when packetlogging.
+--
+-- See <code>unmarshall_srvsvc_Statistics</code> for more information.
+--
+--@param data The data being processed.
+--@param pos The position within <code>data</code>
+--@return (pos, result) The new position in <code>data</code>, and a table representing the datatype.
+function unmarshall_srvsvc_Statistics_ptr(data, pos)
+ local result
+ stdnse.debug4("MSRPC: Entering unmarshall_srvsvc_Statistics_ptr()")
+
+ pos, result = unmarshall_ptr(ALL, data, pos, unmarshall_srvsvc_Statistics, {})
+
+ stdnse.debug4("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 <code>samr_ConnectAccessMask</code>. 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 <code>nil</code> if it wasn't
+-- found.
+function marshall_samr_ConnectAccessMask(accessmask)
+ local result
+ stdnse.debug4("MSRPC: Entering marshall_samr_ConnectAccessMask()")
+
+ result = marshall_Enum32(accessmask, samr_ConnectAccessMask)
+
+ stdnse.debug4("MSRPC: Leaving marshall_samr_ConnectAccessMask()")
+ return result
+end
+
+---Unmarshall a <code>samr_ConnectAccessMask</code>. 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 <code>data</code>, and a table representing the datatype.
+function unmarshall_samr_ConnectAccessMask(data, pos)
+ local result
+ stdnse.debug4("MSRPC: Entering unmarshall_samr_ConnectAccessMask()")
+
+ pos, result = unmarshall_Enum32(data, pos, samr_ConnectAccessMask)
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_samr_ConnectAccessMask()")
+ return pos, result
+end
+
+---Convert a <code>samr_ConnectAccessMask</code> value to a string that can be shown to the user. This is
+-- based on the <code>_str</code> table.
+--
+--@param val The string value (returned by the <code>unmarshall_</code> function) to convert.
+--@return A string suitable for displaying to the user, or <code>nil</code> if it wasn't found.
+function samr_ConnectAccessMask_tostr(val)
+ local result
+ stdnse.debug4("MSRPC: Entering samr_ConnectAccessMask_tostr()")
+
+ result = samr_ConnectAccessMask_str[val]
+
+ stdnse.debug4("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 <code>samr_DomainAccessMask</code>. 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 <code>nil</code> if it wasn't
+-- found.
+function marshall_samr_DomainAccessMask(accessmask)
+ local result
+ stdnse.debug4("MSRPC: Entering marshall_samr_DomainAccessMask()")
+
+ result = marshall_Enum32(accessmask, samr_DomainAccessMask)
+
+ stdnse.debug4("MSRPC: Leaving marshall_samr_DomainAccessMask()")
+ return result
+end
+
+---Unmarshall a <code>samr_DomainAccessMask</code>. 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 <code>data</code>, and a table representing the datatype.
+function unmarshall_samr_DomainAccessMask(data, pos)
+ local result
+ stdnse.debug4("MSRPC: Entering unmarshall_samr_DomainAccessMask()")
+
+ pos, result = unmarshall_Enum32(data, pos, samr_DomainAccessMask)
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_samr_DomainAccessMask()")
+ return pos, result
+end
+
+---Convert a <code>samr_DomainAccessMask</code> value to a string that can be shown to the user. This is
+-- based on the <code>_str</code> table.
+--
+--@param val The string value (returned by the <code>unmarshall_</code> function) to convert.
+--@return A string suitable for displaying to the user, or <code>nil</code> if it wasn't found.
+function samr_DomainAccessMask_tostr(val)
+ local result
+ stdnse.debug4("MSRPC: Entering samr_DomainAccessMask_tostr()")
+
+ result = samr_DomainAccessMask_str[val]
+
+ stdnse.debug4("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 <code>samr_AcctFlags</code>. 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 <code>nil</code> if it wasn't
+-- found.
+function marshall_samr_AcctFlags(flags)
+ local result
+ stdnse.debug4("MSRPC: Entering marshall_samr_AcctFlags()")
+
+ result = marshall_Enum32(flags, samr_AcctFlags)
+
+ stdnse.debug4("MSRPC: Leaving marshall_samr_AcctFlags()")
+ return result
+end
+
+---Unmarshall a <code>samr_AcctFlags</code>. 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.debug4("MSRPC: Entering unmarshall_samr_AcctFlags()")
+
+ pos, str = unmarshall_Enum32_array(data, pos, samr_AcctFlags)
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_samr_AcctFlags()")
+ return pos, str
+end
+
+---Convert a <code>samr_AcctFlags</code> value to a string that can be shown to the user. This is
+-- based on the <code>_str</code> table.
+--
+--@param val The string value (returned by the <code>unmarshall_</code> function) to convert.
+--@return A string suitable for displaying to the user, or <code>nil</code> if it wasn't found.
+function samr_AcctFlags_tostr(val)
+ local result
+ stdnse.debug4("MSRPC: Entering samr_AcctFlags_tostr()")
+
+ result = samr_AcctFlags_str[val]
+
+ stdnse.debug4("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 <code>samr_PasswordProperties</code>. 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 <code>nil</code> if it wasn't
+-- found.
+function marshall_samr_PasswordProperties(properties)
+ local result
+ stdnse.debug4("MSRPC: Entering marshall_samr_PasswordProperties()")
+
+ result = marshall_Enum32(properties, samr_PasswordProperties)
+
+ stdnse.debug4("MSRPC: Leaving marshall_samr_PasswordProperties()")
+ return result
+end
+
+---Unmarshall a <code>samr_PasswordProperties</code>. 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.debug4("MSRPC: Entering unmarshall_samr_PasswordProperties()")
+
+ pos, str = unmarshall_Enum32_array(data, pos, samr_PasswordProperties)
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_samr_PasswordProperties()")
+ return pos, str
+end
+
+---Convert a <code>samr_PasswordProperties</code> value to a string that can be shown to the user. This is
+-- based on the <code>_str</code> table.
+--
+--@param val The string value (returned by the <code>unmarshall_</code> function) to convert.
+--@return A string suitable for displaying to the user, or <code>nil</code> if it wasn't found.
+function samr_PasswordProperties_tostr(val)
+ local result
+ stdnse.debug4("MSRPC: Entering samr_PasswordProperties_tostr()")
+
+ result = samr_PasswordProperties_str[val]
+
+ stdnse.debug4("MSRPC: Leaving samr_PasswordProperties_tostr()")
+ return result
+end
+
+
+---Unmarshall a samr_SamEntry struct
+--
+--<code>
+-- typedef struct {
+-- uint32 idx;
+-- lsa_String name;
+-- } samr_SamEntry;
+--</code>
+--
+--@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 <code>data</code>.
+--@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 <code>data</code>, and a table representing the datatype.
+local function unmarshall_samr_SamEntry(location, data, pos, result)
+ stdnse.debug4("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.debug4("MSRPC: Leaving unmarshall_samr_SamEntry()")
+ return pos, result
+end
+
+---Unmarshall a samr_SamArray struct
+--
+--<code>
+-- typedef struct {
+-- uint32 count;
+-- [size_is(count)] samr_SamEntry *entries;
+-- } samr_SamArray;
+--</code>
+--
+--@param data The data being processed.
+--@param pos The position within <code>data</code>.
+--@return (pos, result) The new position in <code>data</code>, and a table representing the datatype.
+function unmarshall_samr_SamArray(data, pos)
+ local result = {}
+ stdnse.debug4("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.debug4("MSRPC: Leaving unmarshall_samr_SamArray()")
+ return pos, result
+end
+
+---Unmarshall a pointer to a <code>samr_SamArray</code> type. See <code>unmarshall_samr_SamArray</code> for
+-- more information.
+--
+--@param data The data being processed.
+--@param pos The position within <code>data</code>.
+--@return (pos, result) The new position in <code>data</code>, and a table representing the datatype.
+function unmarshall_samr_SamArray_ptr(data, pos)
+ local result
+ stdnse.debug4("MSRPC: Entering unmarshall_samr_SamArray_ptr()")
+
+ pos, result = unmarshall_ptr(ALL, data, pos, unmarshall_samr_SamArray, {})
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_samr_SamArray_ptr()")
+ return pos, result
+end
+
+---Unmarshall a samr_DispEntryGeneral struct
+--
+--<code>
+-- typedef struct {
+-- uint32 idx;
+-- uint32 rid;
+-- samr_AcctFlags acct_flags;
+-- lsa_String account_name;
+-- lsa_String description;
+-- lsa_String full_name;
+-- } samr_DispEntryGeneral;
+--</code>
+--
+--@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 <code>data</code>.
+--@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 <code>data</code>, and a table representing the datatype.
+local function unmarshall_samr_DispEntryGeneral(location, data, pos, result)
+ stdnse.debug4("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.debug4("MSRPC: Leaving unmarshall_samr_DispEntryGeneral()")
+ return pos, result
+end
+
+---Unmarshall a samr_DispInfoGeneral struct
+--
+--<code>
+-- typedef struct {
+-- uint32 count;
+-- [size_is(count)] samr_DispEntryGeneral *entries;
+-- } samr_DispInfoGeneral;
+--</code>
+--
+--@param data The data being processed.
+--@param pos The position within <code>data</code>.
+--@return (pos, result) The new position in <code>data</code>, and a table representing the datatype.
+function unmarshall_samr_DispInfoGeneral(data, pos)
+ local result = {}
+ stdnse.debug4("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.debug4("MSRPC: Leaving unmarshall_samr_DispInfoGeneral()")
+ return pos, result
+end
+
+
+---Unmarshall a samr_DispInfo struct
+--
+--<code>
+-- 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;
+--</code>
+--
+--@param data The data being processed.
+--@param pos The position within <code>data</code>.
+--@return (pos, result) The new position in <code>data</code>, and a table representing the datatype. It may also return
+-- <code>nil</code>, if there was an error.
+function unmarshall_samr_DispInfo(data, pos)
+ local level
+ local result
+ stdnse.debug4("MSRPC: Entering unmarshall_samr_DispInfo()")
+
+ pos, level = unmarshall_int16(data, pos)
+
+ if(level == 1) then
+ pos, result = unmarshall_samr_DispInfoGeneral(data, pos)
+ else
+ stdnse.debug1("MSRPC: ERROR: Server returned an unknown level for samr_DispInfo: %d", level)
+ pos, result = nil, nil
+ end
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_samr_DispInfo()")
+ return pos, result
+end
+
+---Unmarshall a samr_DomInfo1 struct
+--
+--<code>
+-- 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;
+--</code>
+--
+--@param data The data being processed.
+--@param pos The position within <code>data</code>.
+--@return (pos, result) The new position in <code>data</code>, and a table representing the datatype.
+function unmarshall_samr_DomInfo1(data, pos)
+ local result = {}
+ stdnse.debug4("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.debug4("MSRPC: Leaving unmarshall_samr_DomInfo1()")
+ return pos, result
+end
+
+---Unmarshall a samr_DomInfo8 struct
+--
+--<code>
+-- typedef struct {
+-- hyper sequence_num;
+-- NTTIME domain_create_time;
+-- } samr_DomInfo8;
+--</code>
+--
+--@param data The data being processed.
+--@param pos The position within <code>data</code>.
+--@return (pos, result) The new position in <code>data</code>, and a table representing the datatype.
+function unmarshall_samr_DomInfo8(data, pos)
+ local result = {}
+ stdnse.debug4("MSRPC: Entering unmarshall_samr_DomInfo8()")
+
+ pos, result['sequence_num'] = unmarshall_hyper(data, pos)
+ pos, result['domain_create_time'] = unmarshall_NTTIME(data, pos)
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_samr_DomInfo8()")
+ return pos, result
+end
+
+---Unmarshall a samr_DomInfo12 struct
+--
+--<code>
+-- typedef struct {
+-- hyper lockout_duration;
+-- hyper lockout_window;
+-- uint16 lockout_threshold;
+-- } samr_DomInfo12;
+--</code>
+--
+--@param data The data being processed.
+--@param pos The position within <code>data</code>.
+--@return (pos, result) The new position in <code>data</code>, and a table representing the datatype.
+function unmarshall_samr_DomInfo12(data, pos)
+ local result = {}
+ stdnse.debug4("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.debug4("MSRPC: Leaving unmarshall_samr_DomInfo12()")
+ return pos, result
+end
+
+---Unmarshall a samr_DomainInfo union
+--
+--<code>
+-- 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;
+--</code>
+--
+--@param data The data being processed.
+--@param pos The position within <code>data</code>.
+--@return (pos, result) The new position in <code>data</code>, and a table representing the datatype. May return
+-- <code>nil</code> if there was an error.
+function unmarshall_samr_DomainInfo(data, pos)
+ local level
+ local result
+ stdnse.debug4("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.debug1("MSRPC: ERROR: Server returned an unknown level for samr_DomainInfo: %d", level)
+ pos, result = nil, nil
+ end
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_samr_DomainInfo()")
+ return pos, result
+end
+
+---Unmarshall a pointer to a <code>samr_DomainInfo</code>. See <code>unmarshall_samr_DomainInfo</code> for
+-- more information.
+--
+--@param data The data being processed.
+--@param pos The position within <code>data</code>.
+--@return (pos, result) The new position in <code>data</code>, and a table representing the datatype. May return
+-- <code>nil</code> if there was an error.
+function unmarshall_samr_DomainInfo_ptr(data, pos)
+ local result
+ stdnse.debug4("MSRPC: Entering unmarshall_samr_DomainInfo_ptr()")
+
+ pos, result = unmarshall_ptr(ALL, data, pos, unmarshall_samr_DomainInfo, {})
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_samr_DomainInfo_ptr()")
+ return pos, result
+end
+
+---Unmarshall a samr_Ids struct
+--
+--<code>
+-- typedef struct {
+-- [range(0,1024)] uint32 count;
+-- [size_is(count)] uint32 *ids;
+-- } samr_Ids;
+--</code>
+--
+--@param data The data being processed.
+--@param pos The position within <code>data</code>.
+--@return (pos, result) The new position in <code>data</code>, and a table representing the datatype. May return
+-- <code>nil</code> 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 <code>svcctl_ControlCode</code>. 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 <code>nil</code> if it wasn't
+-- found.
+function marshall_svcctl_ControlCode(flags)
+ local result
+ stdnse.debug4("MSRPC: Entering marshall_svcctl_ControlCode()")
+
+ result = marshall_Enum32(flags, svcctl_ControlCode)
+
+ stdnse.debug4("MSRPC: Leaving marshall_svcctl_ControlCode()")
+ return result
+end
+
+---Unmarshall a <code>svcctl_ControlCode</code>. 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.debug4("MSRPC: Entering unmarshall_svcctl_ControlCode()")
+
+ pos, str = unmarshall_Enum32_array(data, pos, svcctl_ControlCode)
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_svcctl_ControlCode()")
+ return pos, str
+end
+
+---Convert a <code>svcctl_ControlCode</code> value to a string that can be shown to the user. This is
+-- based on the <code>_str</code> table.
+--
+--@param val The string value (returned by the <code>unmarshall_</code> function) to convert.
+--@return A string suitable for displaying to the user, or <code>nil</code> if it wasn't found.
+function svcctl_ControlCode_tostr(val)
+ local result
+ stdnse.debug4("MSRPC: Entering svcctl_ControlCode_tostr()")
+
+ result = svcctl_ControlCode_str[val]
+
+ stdnse.debug4("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 <code>svcctl_Type</code>. 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 <code>nil</code> if it wasn't
+-- found.
+function marshall_svcctl_Type(flags)
+ local result
+ stdnse.debug4("MSRPC: Entering marshall_svcctl_Type()")
+
+ result = marshall_Enum32(flags, svcctl_Type)
+
+ stdnse.debug4("MSRPC: Leaving marshall_svcctl_Type()")
+ return result
+end
+
+---Unmarshall a <code>svcctl_Type</code>. 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.debug4("MSRPC: Entering unmarshall_svcctl_Type()")
+
+ pos, str = unmarshall_Enum32_array(data, pos, svcctl_Type)
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_svcctl_Type()")
+ return pos, str
+end
+
+--[[Convert a <code>svcctl_Type</code> value to a string that can be shown to the user. This is
+-- based on the <code>_str</code> table.
+--
+--@param val The string value (returned by the <code>unmarshall_</code> function) to convert.
+--@return A string suitable for displaying to the user, or <code>nil</code> if it wasn't found.
+function svcctl_Type_tostr(val)
+ local result
+ stdnse.debug4("MSRPC: Entering svcctl_Type_tostr()")
+
+ result = svcctl_Type_str[val]
+
+ stdnse.debug4("MSRPC: Leaving svcctl_Type_tostr()")
+ return result
+end]]--
+
+
+
+local svcctl_State =
+{
+ SERVICE_STOPPED = 0x01,
+ SERVICE_START_PENDING = 0x02,
+ SERVICE_STOP_PENDING = 0x03,
+ SERVICE_RUNNING = 0x04,
+ SERVICE_CONTINUE_PENDING = 0x05,
+ SERVICE_PAUSE_PENDING = 0x06,
+ SERVICE_PAUSED = 0x07,
+}
+
+---Marshall a <code>svcctl_State</code>. 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 <code>nil</code> if it wasn't
+-- found.
+function marshall_svcctl_State(flags)
+ local result
+ stdnse.debug4("MSRPC: Entering marshall_svcctl_State()")
+
+ result = marshall_Enum32(flags, svcctl_State)
+
+ stdnse.debug4("MSRPC: Leaving marshall_svcctl_State()")
+ return result
+end
+
+---Unmarshall a <code>svcctl_State</code>. 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.debug4("MSRPC: Entering unmarshall_svcctl_State()")
+
+ pos, str = unmarshall_Enum32_array(data, pos, svcctl_State)
+
+ stdnse.debug4("MSRPC: Leaving unmarshall_svcctl_State()")
+ return pos, str
+end
+
+--[[Convert a <code>svcctl_State</code> value to a string that can be shown to the user. This is
+-- based on the <code>_str</code> table.
+--
+--@param val The string value (returned by the <code>unmarshall_</code> function) to convert.
+--@return A string suitable for displaying to the user, or <code>nil</code> if it wasn't found.
+function svcctl_State_tostr(val)
+ local result
+ stdnse.debug4("MSRPC: Entering svcctl_State_tostr()")
+
+ result = svcctl_State_str[val]
+
+ stdnse.debug4("MSRPC: Leaving svcctl_State_tostr()")
+ return result
+end]]--
+
+
+---Unmarshall a SERVICE_STATUS struct, converting it to a table.
+--
+-- The structure is as follows:
+--
+-- <code>
+-- 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;
+-- </code>
+--
+--@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
+
+
+--- Unmarshalls a null-terminated Unicode string (LPTSTR datatype)
+-- @param w_str The data being processed
+-- @param startpos The current position within the data
+-- @return The new position
+-- @return The unmarshalled string
+function unmarshall_lptstr(w_str, startpos)
+
+ local _
+ local endpos = startpos
+
+ repeat
+ _, endpos = w_str:find("\0\0", endpos, true)
+ if not endpos then
+ return
+ end
+ until endpos % 2 == 0
+
+ return endpos + 1, w_str:sub(startpos, endpos)
+
+end
+
+local atsvc_DaysOfMonth =
+{
+ First = 0x00000001,
+ Second = 0x00000002,
+ Third = 0x00000004,
+ Fourth = 0x00000008,
+ Fifth = 0x00000010,
+ Sixth = 0x00000020,
+ Seventh = 0x00000040,
+ Eighth = 0x00000080,
+ Ninth = 0x00000100,
+ Tenth = 0x00000200,
+ Eleventh = 0x00000400,
+ Twelfth = 0x00000800,
+ Thirteenth = 0x00001000,
+ Fourteenth = 0x00002000,
+ Fifteenth = 0x00004000,
+ Sixteenth = 0x00008000,
+ Seventeenth = 0x00010000,
+ Eighteenth = 0x00020000,
+ Ninteenth = 0x00040000,
+ Twentieth = 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 <code>atsvc_DaysOfMonth</code>. 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 <code>nil</code> if it wasn't
+-- found.
+function marshall_atsvc_DaysOfMonth(flags)
+ local result
+ stdnse.debug4("MSRPC: Entering marshall_atsvc_DaysOfMonth()")
+
+ result = marshall_Enum32(flags, atsvc_DaysOfMonth)
+
+ stdnse.debug4("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 <code>atsvc_Flags</code>. 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 <code>nil</code> if it wasn't
+-- found.
+function marshall_atsvc_Flags(flags)
+ local result
+ stdnse.debug4("MSRPC: Entering marshall_atsvc_Flags()")
+
+ result = marshall_Enum8(flags, atsvc_Flags, false)
+
+ stdnse.debug4("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 <code>atsvc_DaysOfWeek</code>. 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 <code>nil</code> if it wasn't
+-- found.
+function marshall_atsvc_DaysOfWeek(flags)
+ local result
+ stdnse.debug4("MSRPC: Entering marshall_atsvc_DaysOfWeek()")
+
+ result = marshall_Enum8(flags, atsvc_DaysOfWeek, false)
+
+ stdnse.debug4("MSRPC: Leaving marshall_atsvc_DaysOfWeek()")
+ return result
+end
+
+---Marshall a JobInfo struct.
+--
+--The structure is as follows:
+--
+--<code>
+-- 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;
+--</code>
+--
+--@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 = marshall_int32(time) -- Job time
+ .. marshall_int32(0) -- Day of month
+ .. marshall_int8(0, false) -- Day of week
+ .. marshall_atsvc_Flags("JOB_NONINTERACTIVE") -- Flags
+ .. marshall_int16(0, false) -- Padding
+ .. marshall_unicode_ptr(command, true) -- Command
+
+ return result
+end
+
+
+
+
+return _ENV;