mirror of
https://github.com/riverar/messageanalyzer-archive
synced 2026-06-08 17:10:57 +00:00
537 lines
18 KiB
Plaintext
537 lines
18 KiB
Plaintext
// A common header for all Samba syslog messages. Other messages inherit from the header, add more fields and override mutiline log parsing
|
|
message samba_header with
|
|
//Regex: Pass QE Check 8/1/2013
|
|
EntryInfo { Regex = @"\[(?<ts>[ \d:\./]+),\s*(?<level>\d+)\]\s*(?<source_file>[- \w/_\d\.]+)\:(?<file_line>\d+)\((?<function>.*)\)", Multiline = parseContent } : LogEntry
|
|
{
|
|
DateTime ts with EntryFieldInfo { IsTimestamp = true, IsLocalTime = true };
|
|
ushort level;
|
|
string source_file;
|
|
uint file_line;
|
|
string function;
|
|
optional string content;
|
|
|
|
bool parseContent(string line, LineContext context)
|
|
{
|
|
if (context.IsInitialLine) return true;
|
|
|
|
// If a header cannot be decoded then we assume that it is some description text,
|
|
// which should go to the content property
|
|
if (CanDecode<samba_header>(line, context)) return false;
|
|
|
|
if (content == nothing)
|
|
{
|
|
content = line.Trim();
|
|
}
|
|
else
|
|
{
|
|
// Cannot attach text as multiple lines because UI shows only the first line in that case
|
|
content = (content as string) + " " + line.Trim();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// ------ SMB Command parsing ----- //
|
|
|
|
// Represents a logged Samba command. The type also provides a helper builder method for
|
|
// iterative parsing of the command fields.
|
|
type smbcmd
|
|
{
|
|
optional uint size;
|
|
optional uint smb_com;
|
|
optional uint smb_com2;
|
|
optional int smb_rcls;
|
|
optional int smb_reh;
|
|
optional int smb_err;
|
|
optional int smb_flg;
|
|
optional int smb_flg2;
|
|
optional uint smb_tid;
|
|
optional uint smb_pid;
|
|
optional uint smb_uid;
|
|
optional uint smb_mid;
|
|
optional uint smt_wct;
|
|
optional array<int> smb_vwv;
|
|
optional int smb_bcc;
|
|
|
|
// Parses name-value pairs into the command fields. Attaches a validation error to the specified
|
|
// message if a given name-value pair is unknown.
|
|
bool parse(string line, LineContext context, any message m)
|
|
{
|
|
line = line.Trim();
|
|
var nvp = Decode<name_value_pair>(line, context);
|
|
// Done parsing if the specified line is not in the name-value pair format
|
|
if (nvp == null) return false;
|
|
|
|
// Switch on the name and initialized a corresponding field with a parsed value
|
|
switch (nvp.n)
|
|
{
|
|
case "size" => size = (nvp.v as uint);
|
|
case "smb_com" => smb_com = (nvp.v as uint);
|
|
case "smb_com2" => smb_com = (nvp.v as uint);
|
|
case "smb_rcls" => smb_rcls = (nvp.v as int);
|
|
case "smb_reh" => smb_reh = (nvp.v as int);
|
|
case "smb_err" => smb_err = (nvp.v as int);
|
|
case "smb_flg" => smb_flg = (nvp.v as int);
|
|
case "smb_flg2" => smb_flg2 = (nvp.v as int);
|
|
case "smb_tid" => smb_tid = (nvp.v as uint);
|
|
case "smb_pid" => smb_pid = (nvp.v as uint);
|
|
case "smb_uid" => smb_uid = (nvp.v as uint);
|
|
case "smb_mid" => smb_mid = (nvp.v as uint);
|
|
case "smt_wct" => smt_wct = (nvp.v as uint);
|
|
case "smb_vwv" =>
|
|
{
|
|
if (smb_vwv == nothing) smb_vwv = [];
|
|
|
|
var smb_vwv_v = smb_vwv as array<int>;
|
|
smb_vwv_v += [(nvp.v as int)];
|
|
smb_vwv = smb_vwv_v;
|
|
}
|
|
case "smb_bcc" => smb_bcc = (nvp.v as int);
|
|
default => ValidationCheck(false, m, 2 /* warning */, "Unknown smb_command flag: " + nvp.n);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Parses name-value pairs in the following forms:
|
|
// 1. name=value
|
|
// 2. name[ 0]= value (0x10)
|
|
message name_value_pair with
|
|
//Regex: Not Pass QE Check 9/10/2013 Used lazy quantifiers(as-few-times-as-possible quantifiers) which SDL Regex Fuzzer does not support.
|
|
//Looks like the regular expression is safe.
|
|
EntryInfo { Regex = @"^(?<n>[\w\d_]+)(\[.*?\])?=\s*(?<v>[\d\w]+)" } : LogEntry
|
|
{
|
|
string n;
|
|
string v;
|
|
}
|
|
|
|
message smb_command with
|
|
//Regex: Pass QE Check 9/10/2013
|
|
EntryInfo { Tag = "show_msg", Regex = @" ?", Multiline = parseFields, Priority = 0 } : samba_header
|
|
{
|
|
optional smbcmd command;
|
|
|
|
bool parseFields(string line, LineContext context)
|
|
{
|
|
if (!context.IsInitialLine)
|
|
{
|
|
var cmd = command == nothing ? new smbcmd() : command as smbcmd;
|
|
if (!cmd.parse(line, context, this))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
command = cmd;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// ------ NTLMSSP Negotiation parsing ----- //
|
|
|
|
message ntlmssp_negotiation with
|
|
//Regex: Pass QE Check 9/10/2013
|
|
EntryInfo { Tag = "debug_ntlmssp_flags", Regex = @" ?", Multiline = parseFlags, Priority = 0 } : samba_header
|
|
{
|
|
ulong neg_flags with DisplayInfo{ToText = ToHex};
|
|
optional bool NTLMSSP_NEGOTIATE_UNICODE;
|
|
optional bool NTLMSSP_NEGOTIATE_OEM;
|
|
optional bool NTLMSSP_REQUEST_TARGET;
|
|
optional bool NTLMSSP_NEGOTIATE_SIGN;
|
|
optional bool NTLMSSP_NEGOTIATE_SEAL;
|
|
optional bool NTLMSSP_NEGOTIATE_DATAGRAM;
|
|
optional bool NTLMSSP_NEGOTIATE_LM_KEY;
|
|
optional bool NTLMSSP_NEGOTIATE_NETWARE;
|
|
optional bool NTLMSSP_NEGOTIATE_NTLM;
|
|
optional bool NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED;
|
|
optional bool NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED;
|
|
optional bool NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL;
|
|
optional bool NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
|
|
optional bool NTLMSSP_REQUEST_NON_NT_SESSION_KEY;
|
|
optional bool NTLMSSP_NEGOTIATE_NTLM2;
|
|
optional bool NTLMSSP_NEGOTIATE_TARGET_INFO;
|
|
optional bool NTLMSSP_NEGOTIATE_VERSION;
|
|
optional bool NTLMSSP_NEGOTIATE_128;
|
|
optional bool NTLMSSP_NEGOTIATE_KEY_EXCH;
|
|
optional bool NTLMSSP_NEGOTIATE_56;
|
|
|
|
bool parseFlags(string line, LineContext context)
|
|
{
|
|
if (!context.IsInitialLine)
|
|
{
|
|
// We assume that the first line after the initial line has a format similar to:
|
|
// Got NTLMSSP neg_flags=0xe2088215
|
|
if (!("neg_flags" in context.Data))
|
|
{
|
|
var flags_index = line.LastIndexOf("=");
|
|
if (flags_index != -1)
|
|
{
|
|
neg_flags = line.Segment(flags_index + "=".Count).Trim() as ulong;
|
|
context.Data["neg_flags"] = true;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
// Something is not as expected - terminate further parsing
|
|
return false;
|
|
}
|
|
}
|
|
|
|
var flag_name = line.Trim();
|
|
switch (flag_name)
|
|
{
|
|
case "NTLMSSP_NEGOTIATE_UNICODE" => NTLMSSP_NEGOTIATE_UNICODE = true;
|
|
case "NTLMSSP_NEGOTIATE_OEM" => NTLMSSP_NEGOTIATE_OEM = true;
|
|
case "NTLMSSP_REQUEST_TARGET" => NTLMSSP_REQUEST_TARGET = true;
|
|
case "NTLMSSP_NEGOTIATE_SIGN" => NTLMSSP_NEGOTIATE_SIGN = true;
|
|
case "NTLMSSP_NEGOTIATE_SEAL" => NTLMSSP_NEGOTIATE_SEAL = true;
|
|
case "NTLMSSP_NEGOTIATE_DATAGRAM" => NTLMSSP_NEGOTIATE_DATAGRAM = true;
|
|
case "NTLMSSP_NEGOTIATE_LM_KEY" => NTLMSSP_NEGOTIATE_LM_KEY = true;
|
|
case "NTLMSSP_NEGOTIATE_NETWARE" => NTLMSSP_NEGOTIATE_NETWARE = true;
|
|
case "NTLMSSP_NEGOTIATE_NTLM" => NTLMSSP_NEGOTIATE_NTLM = true;
|
|
case "NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED" => NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED = true;
|
|
case "NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED" => NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED = true;
|
|
case "NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL" => NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL = true;
|
|
case "NTLMSSP_NEGOTIATE_ALWAYS_SIGN" => NTLMSSP_NEGOTIATE_ALWAYS_SIGN = true;
|
|
case "NTLMSSP_REQUEST_NON_NT_SESSION_KEY" => NTLMSSP_REQUEST_NON_NT_SESSION_KEY = true;
|
|
case "NTLMSSP_NEGOTIATE_NTLM2" => NTLMSSP_NEGOTIATE_NTLM2 = true;
|
|
case "NTLMSSP_NEGOTIATE_TARGET_INFO" => NTLMSSP_NEGOTIATE_TARGET_INFO = true;
|
|
case "NTLMSSP_NEGOTIATE_VERSION" => NTLMSSP_NEGOTIATE_VERSION = true;
|
|
case "NTLMSSP_NEGOTIATE_128" => NTLMSSP_NEGOTIATE_128 = true;
|
|
case "NTLMSSP_NEGOTIATE_KEY_EXCH" => NTLMSSP_NEGOTIATE_KEY_EXCH = true;
|
|
case "NTLMSSP_NEGOTIATE_56" => NTLMSSP_NEGOTIATE_56 = true;
|
|
// Terminate parsing if we encountered some unknown value
|
|
default => return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// ------ Security Token parsing ----- //
|
|
|
|
message security_token with
|
|
//Regex: Pass QE Check 9/10/2013
|
|
EntryInfo { Tag = "security_token_debug", Regex = @" ?", Multiline = parseSecurity, Priority = 0 } : samba_header
|
|
{
|
|
optional array<string> sids;
|
|
optional ulong privileges_mask;
|
|
optional array<string> privileges;
|
|
optional ulong rights_mask;
|
|
optional array<string> rights;
|
|
|
|
bool parseSecurity(string line, LineContext context)
|
|
{
|
|
if (!context.IsInitialLine)
|
|
{
|
|
var trimmed = line.Trim();
|
|
if (trimmed.IndexOf("Security token") == 0)
|
|
{
|
|
// Security token line does not carry any additional information, so just skip it
|
|
}
|
|
else if (trimmed.IndexOf("SID") == 0)
|
|
{
|
|
parseSID(trimmed);
|
|
}
|
|
else if (trimmed.IndexOf("Privileges") == 0)
|
|
{
|
|
parsePrivilegesMask(trimmed);
|
|
}
|
|
else if (trimmed.IndexOf("Privilege") == 0)
|
|
{
|
|
parsePrivilege(trimmed);
|
|
}
|
|
else if (trimmed.IndexOf("Rights") == 0)
|
|
{
|
|
parseRightsMask(trimmed);
|
|
}
|
|
else if (trimmed.IndexOf("Right") == 0)
|
|
{
|
|
parseRight(trimmed);
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void parseSID(string line)
|
|
{
|
|
// The line of the following format is expected:
|
|
// SID[ 0]: S-1-5-21-695135575-2411905282-2776759044-1008
|
|
var sidIndex = line.LastIndexOf(":");
|
|
if (sidIndex != -1)
|
|
{
|
|
var sid = line.Segment(sidIndex + 1).Trim();
|
|
if (sids == nothing) sids = [];
|
|
|
|
var sids_v = sids as array<string>;
|
|
sids_v += [sid];
|
|
sids = sids_v;
|
|
}
|
|
else
|
|
{
|
|
ValidationCheck(false, this, 2 /* warning */, "SID has invalid format: " + line);
|
|
}
|
|
}
|
|
|
|
void parsePrivilegesMask(string line)
|
|
{
|
|
// The line of the following format is expected:
|
|
// Privileges (0x 1FFFFFF00):
|
|
var mask = parseMaskHeader(line, this, "Privileges");
|
|
if (mask != nothing) privileges_mask = mask;
|
|
}
|
|
|
|
void parsePrivilege(string line)
|
|
{
|
|
// The line of the following format is expected:
|
|
// Privilege[ 0]: SeTakeOwnershipPrivilege
|
|
var privilege = parseSecuritySetting(line, this, "Privilege");
|
|
if (privilege != null)
|
|
{
|
|
if (privileges == nothing) privileges = [];
|
|
|
|
var privileges_v = privileges as array<string>;
|
|
privileges_v += [privilege];
|
|
privileges = privileges_v;
|
|
}
|
|
}
|
|
|
|
void parseRightsMask(string line)
|
|
{
|
|
// The line of the following format is expected:
|
|
// Rights (0x 403):
|
|
var mask = parseMaskHeader(line, this, "Rights");
|
|
if (mask != nothing) rights_mask = mask;
|
|
}
|
|
|
|
void parseRight(string line)
|
|
{
|
|
// The line of the following format is expected:
|
|
// Right[ 0]: SeInteractiveLogonRight
|
|
var right = parseSecuritySetting(line, this, "Right");
|
|
if (right != null)
|
|
{
|
|
if (rights == nothing) rights = [];
|
|
|
|
var rights_v = rights as array<string>;
|
|
rights_v += [right];
|
|
rights = rights_v;
|
|
}
|
|
}
|
|
|
|
// Parses a mask header. The method attaches a validation error
|
|
// to a message if the specified payload cannot be parsed.
|
|
// Return: a parsed mask value; or nothing if the payload could not be parsed.
|
|
static optional ulong parseMaskHeader(string payload, any message m, string header)
|
|
{
|
|
var maskStartIndex = payload.IndexOf("0x");
|
|
var maskEndIndex = payload.LastIndexOf(")");
|
|
if (maskStartIndex != -1 && maskEndIndex != -1)
|
|
{
|
|
maskStartIndex += "0x".Count;
|
|
var mask = payload.Segment(maskStartIndex, maskEndIndex - maskStartIndex).Trim();
|
|
mask = "0x" + mask;
|
|
return (mask as ulong);
|
|
}
|
|
else
|
|
{
|
|
ValidationCheck(false, m, 2 /* warning */, header + " header has invalid format: " + payload);
|
|
return nothing;
|
|
}
|
|
}
|
|
|
|
// Parses a security setting line. The method attaches a validation error
|
|
// to a message if the specified payload cannot be parsed.
|
|
// Return: a parsed setting value; or null if the payload could not be parsed.
|
|
static string parseSecuritySetting(string payload, any message m, string header)
|
|
{
|
|
var setting = null;
|
|
|
|
var settingIndex = payload.LastIndexOf(":");
|
|
if (settingIndex != -1)
|
|
{
|
|
setting = payload.Segment(settingIndex + 1).Trim();
|
|
}
|
|
else
|
|
{
|
|
ValidationCheck(false, m, 2 /* warning */, header + " has invalid format: " + payload);
|
|
}
|
|
|
|
return setting;
|
|
}
|
|
}
|
|
|
|
// ------ SMB Set Time parsing ----- //
|
|
|
|
message smb_set_file_time with
|
|
//Regex: Pass QE Check 9/10/2013
|
|
EntryInfo { Tag = "smb_set_file_time", Regex = @" ?", Multiline = parseSetTime, Priority = 0 } : samba_header
|
|
{
|
|
string actime;
|
|
string modtime;
|
|
string ctime;
|
|
string createtime;
|
|
optional smbcmd command;
|
|
optional string text;
|
|
|
|
bool parseSetTime(string line, LineContext context)
|
|
{
|
|
if (context.IsInitialLine)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
var trimmed = line.Trim();
|
|
// Skip empty lines
|
|
if (trimmed.Count == 0) return true;
|
|
|
|
// First try to parse time values
|
|
if (parseTime(trimmed)) return true;
|
|
|
|
if (command == nothing && text == nothing)
|
|
{
|
|
var cmd = new smbcmd();
|
|
if (cmd.parse(trimmed, context, this))
|
|
{
|
|
command = cmd;
|
|
return true;
|
|
}
|
|
|
|
// If the line cannot be parsed as samba_header then we assume that it belongs to
|
|
// the current smb_set_file_time message
|
|
if (!CanDecode<samba_header>(line, context))
|
|
{
|
|
text = trimmed;
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (command != nothing)
|
|
{
|
|
return (command as smbcmd).parse(trimmed, context, this);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Parse set-time command time values. Return true if the parsing is successfull; otherwise false.
|
|
bool parseTime(string line)
|
|
{
|
|
if (actime == null)
|
|
{
|
|
var index = line.IndexOf(actimePrefix);
|
|
if (index != -1)
|
|
{
|
|
var time = line.Segment(index + actimePrefix.Count).Trim();
|
|
actime = time;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (modtime == null)
|
|
{
|
|
var index = line.IndexOf(modtimePrefix);
|
|
if (index != -1)
|
|
{
|
|
var time = line.Segment(index + modtimePrefix.Count).Trim();
|
|
modtime = time;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (ctime == null)
|
|
{
|
|
var index = line.IndexOf(ctimePrefix);
|
|
if (index != -1)
|
|
{
|
|
var time = line.Segment(index + ctimePrefix.Count).Trim();
|
|
ctime = time;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (createtime == null)
|
|
{
|
|
var index = line.IndexOf(createtimePrefix);
|
|
if (index != -1)
|
|
{
|
|
var time = line.Segment(index + createtimePrefix.Count).Trim();
|
|
createtime = time;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Cannot declare those fields within a message because UI still shows them
|
|
const string actimePrefix = "actime:";
|
|
const string modtimePrefix = "modtime:";
|
|
const string ctimePrefix = "ctime:";
|
|
const string createtimePrefix = "createtime:";
|
|
|
|
string ToHex(any data)
|
|
{
|
|
string text = "Cannot convert to hex";
|
|
ulong v = 0;
|
|
if (data is uint || data is ulong)
|
|
{
|
|
v = data as ulong;
|
|
text = null;
|
|
}
|
|
// Currently is-operator is not supported for optional types
|
|
//else if (data is optional ulong)
|
|
//{
|
|
// var o = data as optional ulong;
|
|
// if (o == nothing)
|
|
// {
|
|
// text = "nothing";
|
|
// }
|
|
// else
|
|
// {
|
|
// v = o;
|
|
// text = null;
|
|
// }
|
|
//}
|
|
|
|
return text == null ? UlongToHex(v) : text;
|
|
}
|
|
|
|
string UlongToHex(ulong val)
|
|
{
|
|
var text = "";
|
|
while (val >= 16)
|
|
{
|
|
var remainder = val % 16;
|
|
text = ToHexDigit(remainder) + text;
|
|
val = val >> 4;
|
|
}
|
|
|
|
text = "0x" + ToHexDigit(val) + text;
|
|
return text;
|
|
}
|
|
|
|
string ToHexDigit(ulong val)
|
|
{
|
|
if (val >= 16) return null;
|
|
if (val < 10) return val as string;
|
|
if (val == 10) return "A";
|
|
if (val == 11) return "B";
|
|
if (val == 12) return "C";
|
|
if (val == 13) return "D";
|
|
if (val == 14) return "E";
|
|
return "F";
|
|
}
|