############################################################################
 ## I N T R O D U C T I O N ##

 All comments relate to the privateye.config file and Privateye's 
 ParserNormal parser.  If you write some other parser for some reason, 
 I'd suggest you write your own documentation for it.

 All commands are of the form
 <command> <args>
 The command itself is not case sensitive.  Anything between [] marks is
   optional to the command
 The names of all objects are now only alphanumeric characters and '_', as
   defined by PCRE's \w+.


############################################################################
 ## A L E R T   P A R S E R ##
 ALERTPARSER <name> <type> [<args>] 

 Creates an AlertParser, an object that takes input from Input objects
 and performs various actions on it.  The "ADDPATH" command is used with 
 AlertParsers to determine what is done with the alert after it has been
 parsed.  Types and arguments follow:

 ALERT <trigger> <regexp> (<field1>[, <field2>, ...])
   Creates an alert parser that will run its regular expression on the alert
   string.  If it does not match, the parser ignores that alert string.
   Otherwise, it populates the fields given with the groups from the regexp.
   Immediately after the alert is created, <trigger> is run on it.  If
   <trigger> fails, the alert passes no further.

 CONFIG <output>
   A special type of AlertParser, this treats each input line as a console
   configuration line and deals with it accordingly.  This allows for 
   on-the-fly configuration of the program.

 Example:
 ALERTPARSER alertparser1 ALERT trigger1 \
                                /^#(\w*)#(\w*)#(\w*)#\s*$/ (a, b, c)
   This parser takes in a string and creates an alert with fields 'a', 'b',
   and 'c', the three groups of alphanumeric chars between the first four
   '#' marks.  It ignores other syntaxes.  After creating the alert with
   these three fields, 'alertparser1' passes the alert through 'trigger1'.
   If it returns false, the alert stops there.

############################################################################
 ## U S E R   H A S H ##
 USERHASH <name> <trigger> "<string>"

 Creates a user hash (the value used to reference the current user state)
 by taking the string <string> and substituting all strings '${field}' with
 the corresponding field value in the alert.  <trigger> is checked before
 the hash string values are substituted, and if it returns false, the
 UserHash drops the current alert.

 Example:
 USERHASH userhash1 trigger1 "UNAME=${uname}"
   This UserHash checks 'trigger1', and if it returns true, substitutes
   the value of alert field 'uname' into the string and returns it.


############################################################################
 ## T R I G G E R ##
 TRIGGER <name> <type> [<args>]

 Creates a trigger of the type given.  Types of triggers and args needed
 are as follows:

## BOOLEAN TRIGGERS ##

 TRUE
   Always returns true

 FALSE
   Always returns false

 AND <trigger1> <trigger2> .. <triggerN>
   Performs a boolean AND on the return values of triggers 1 through N,
   returning that as its value

 OUTOF <num> <trigger1> <trigger2> .. <triggerN>
   Returns true if at least <num> number of triggers 1 to N return true.

 OR <trigger1> <trigger2> .. <triggerN>
   Performs a boolean OR on the return values of triggers 1 through N,
   returning that as its value

 NOT <trigger>
   Returns the opposite of <trigger>'s return value.

## MISC TRIGGERS ##

 OUTPUT <output> "<message>"
   Tries to output <message> to the output vector <output>.  On success,
   return true.  On failure, return false.  The message can contain any
   number of ${<field>} strings, where <field> is an alert field.  The actual
   values of these fields will be replaced into the message before it is
   sent.  The escape sequences \n, \t, \", and \\ work so far in <message>

 ACTION <field> <action>
   Performs <action>, and sets alert field <field> to <action>'s output.
   Always returns true.

 USERFLAG <userflag>
   Returns true if the user flag <userflag> is set and has not expired.
   See the USERFLAG action for more details.

## DATABASE TRIGGERS ## (see DICTIONARY SYNTAX below)

 DB_SQL <db_driver> <db_host> <db_name> <db_user> <db_passwd> \
        <db_sql> <db_input> <db_output>
   This trigger executes the user-defined SQL statement <db_sql> on the 
   database specified by the first five arguments.  Each '?' in the SQL
   is substituted with the value of the alert field in the corresponding
   position in <db_input> (an array like the array of fields used for
   AlertParser).  The values of the first record returned by the 
   SQL query are stored into the corresponding fields in <db_output>, 
   another field name array.  See the examples below for one use of
   this trigger.  It's recommended, by the way, that you postpend
   "LIMIT 1" to all SELECT SQL statements that you use in DB_SQL, as all
   information after the first record is thrown out anyway.  A quick
   note:  a returned value of NULL will result in the alert field being
   set to the empty string, not NULL.  For the moment, this just 
   seems to work better.

## LDAP TRIGGERS ##

 LDAP_SEARCH <ldap_host> <ldap_user> <ldap_passwd> "<base_dn>" "<filter>"
	<dict:ldap->alert> [dict:ldap_opt_name->opt_val]
   This trigger runs a search on an LDAP directory, on server <ldap_host>
   and authenticated with <ldap_user> and <ldap_passwd>.  <base_dn> and
   <filter>, both of which can contain alert fields, are used to search
   the directory.  <dict:ldap->alert> is used to specify the attributes
   to request (all of the 'ldap' entries) and their mappings to alert
   fields (the 'alert' entries).  See the Dictionary Syntax below.  If
   required, the last dictionary allows for the setting of LDAP options.
   See example below.

## FIELD TRIGGERS ##

 REGEXP <field> <regexp>
   Runs a regular expression on the given field of an alert, returns true
   on a match.

 SUBSTR <field> "<string>" [pos]
   Returns true if <string> is a substring of <field>.  If <pos> is given,
   this will only return true if <string> starts at position <pos> (zero
   indexed). 

 COPY <from> <to>
   Copy field <from> of the alert to field <to> of the alert.

 SET <field> "<string>"
   Set alert's field <field> to the constant string <string> (no substitutions
   made).

 FIELD <field>
   Returns true if the alert contains a field named <field>

## MATH TRIGGERS ## (see MATH SYNTAX below)

 MATH_SET <field> '<math>'
   Sets alert field <field> to the value returned by math expression <math>,
   returning true on success or false on error (divide by zero, etc.)

 MATH_EQ '<math_1>' '<math_2>'
   Returns true if <math_1>'s return value is equal to <math_2>'s return
   value.  As always, be careful with floating point integers.

 MATH_GT '<math_1>' '<math_2>'
   Returns true if <math_1> is greater than <math_2>, false if not or on
   error.

 MATH_LT '<math_1>' '<math_2>'
   Returns true if <math_1> is less than <math_2>, false if not or on
   error.


 Examples:
 TRIGGER trigger1 REGEXP a /badstuff/i
   Returns true if field 'a' of an alert contains the string 'badstuff',
   case insensitive because of the trailing 'i'
 TRIGGER trigger2 TRUE
   Always returns true
 TRIGGER trigger3 AND trigger2 trigger1
   Tries trigger2, if true then tries trigger1, if true then returns true
 TRIGGER trigger4 DB_SQL mysql dbhost dbname dbuser dbpass \
         "SELECT `val1`, `val2` FROM `tbl` WHERE `val3` > ? LIMIT 1" \
	 ( af3 ) ( af1, af2 )
   When this trigger is hit, it will connect through 'mysql' to the host
   'dbhost' with username 'dbname' and password 'dbpass'.  It will then
   execute the specified SQL statement, testing if `val3` is greater than
   alert field value 'af3'.  The alert fields 'af1' and 'af2' will be set
   to the first `val1` and `val2` values returned.
 TRIGGER trigger5 OUTPUT stdout "Field ABC has data \"${ABC}\""
   Creates a trigger that outputs the string 'Field ABC has data "<ABC>"',
   where <ABC> is the data in field 'abc' of the alert.
 TRIGGER trigger6 LDAP_SEARCH ldap.server ldap_uname ldap_passwd \
	 "DC=mydomain,DC=com" "samaccountname=${username}" \
         { [displayname]:[fullname] } \
	 { [LDAP_OPT_REFERRALS]:[0] [LDAP_OPT_PROTOCOL_VERSION]:[3] }
   This trigger runs an LDAP search in an Active Directory environment.
   Connects to LDAP server 'ldap.server', then binds with user name
   'ldap_uname' and password 'ldap_passwd'.  Using the given base DN,
   'DC=mydomain,DC=com' and the filter 'samaccountname=${username}',
   it asks for the LDAP attribute 'displayname' of the first returned
   entry.  It then takes that attribute's value and places it into
   the alert field 'fullname'.  Since Microsoft is stupid and Active
   Direcory is not just LDAP, but BROKEN LDAP, the options seen above
   must be set when using AD.  LDAP_OPT_REFERRALS must be 0, and
   LDAP_OPT_PROTOCOL_VERSION must be 3.  *sigh*


############################################################################
 ## D I C T I O N A R Y   S Y N T A X ##  

 Dictionary syntax works like this:
   The whole dictionary is surrounded by curly braces '{' and '}'
   Elements are seperated by whitespace.
   Each element's name/value pairs are seperated by a colon ':'
   Each element is surrounded by square braces '[' and ']'
   There can be no space between the ']' of the name, the ':' separator,
     and the '[' of the value.
   Spaces within element names are signifigant

 Example:
   { [a]:[1] [b]:[2] [c]:[froggy] }
 This is a dictionary that maps a->1, b->2, and c->froggy.

 When dictionaries are used as arguments, they will be signified as
 <dict:foo->bar>, where 'foo' describes the element names and 'bar'
 describes the element values.


############################################################################
 ## M A T H   S Y N T A X ##

 Math Triggers use mathematical functions to create math objects, which allow
 for simple computations to be done between alert fields and constant values.
 Math equations are written in prefix notation (reverse Polish), with the
 operator followed by its two operands.  Parentheses are never needed and are
 not recognized.  Operators currently supported include:
  +: Addition
  -: Subtraction
  *: Multiplication
  /: Division
  &: Bitwise AND
  |: Bitwise OR
  ^: Bitwise XOR
  ~: Bitwise NOT (unary operator)
 Numbers are of the form /-?\d*\.?\d+/.  The following are legal:
   2  -6  58  .03  -2.7   -0.89   .123  -.77
 The following are NOT legal:
   232.
 Any set of alphanumeric characters that is not a number will be considered
 the name of an alert field.
   abc   _qwerty_   etc
 An example equation:
   * 2 + abc 5.5  : Returns 2 * (alert['abc'] + 5.5)


############################################################################
 ## A C T I O N ##
 ACTION <name> <type> [<args>]

 Creates an action of the type given.  Types of actions and args needed
 are as follows:

 NULL
   Do absolutely nothing.

 SH <shellcommand>
   Runs the shell command given.  Within the shell command may be any number
   of strings ${<field>}, where <field> is the field name of an alert.  These
   strings will be substituted before the command is run.

 AND <action1> <action2> ... <actionN>
   Perform <action1>, then <action2>, etc. and return the concatination of 
   their outputs.

 BRANCH <trigger> <actionT> <actionF>
   Checks to see if <trigger> returns true or false.  If true, execute 
   the action <actionT>.  Otherwise, execute action <actionF>.

 USERFLAG <userflag> <lifetime>
   Sets a flag named <userflag> on the current user.  This flag will disappear
   after <lifetime> seconds.  In the meantime, it can be seen by the USERFLAG
   trigger.  Note that each new user flag with the same name will delete
   the previous and reset the lifetime timer to the current time plus its
   own lifetime.

 CLEARFLAGS <userflag1> <userflag2> .. <userflagN>
   Clear all specified user flags.

 TRIGGER <trigger>
   Perform a trigger check, then return either "<trigger-name> SUCCEEDED"
   or "<trigger-name> FAILED"

 RULELIST <rulelist>
   Run the user and alert through the rule list <rulelist>

 Example:
 ACTION action1 SH echo "Field 'a' says ${a}"
   Echos the value of field 'a' to standard output


############################################################################
 ## R U L E ##
 RULE <name> <trigger> <action> <threshold_num> <threshold_duration> [<time>]

 Creates a new rule.  Whenever the trigger returns true, the user (as returned
 by the User Hash above) will store that event, and if the frequency ever
 reaches <threshold_num> events per <threshold_duration> seconds, it will 
 perform <action>.  If <threshold_num> is 1, <threshold_duration>'s value
 doesn't matter.  It should still be put in, however.  The <time> argument is
 optional.  If set, the rule will only trigger at most once every <time>
 seconds.  <time> defaults to 0.

 Example:
 RULE rule1 trigger1 action1 2 60
   The action 'action1' will be performed by any user that triggers 'trigger1'
   two or more times in 60 seconds.


############################################################################
 ## R U L E   L I S T ##
 RULELIST <name>

 Rules will be ignored unless they are part of a rule list.  A rule list
 is a set of rules that can be run to examine an alert for a user.
 Rules are added to a rule list with the ADDRULE command, below.

 Example:
 RULELIST rulelist1
   Creates an empty rule list named 'rulelist1'


############################################################################
 ## A D D   R U L E ##
 ADDRULE <rulelist> <rule>

 Unlike other commands, this does not actually create any objects.  Instead,
 it adds the rule <rule> to the rule list <rulelist>.  Rules cannot be 
 examined unless they are part of a rule list.

 Example:
 ADDRULE rulelist1 rule1
   Adds the rule 'rule1' to the rule list 'rulelist1'


############################################################################
 ## I N P U T ##
 INPUT <name> <type> [<args>]

 Input objects allow for the creation of multiple input vectors.  While
 running, the first Input vector to have data will always be used.  If more
 than one input vector has data available at once, data will be taken from
 Inputs in the order they are specified in this file, I hope.  Input types
 and arguments are as follows.

 All INPUT objects have an argument called 'separator', which cannot be set
 when the object is created, but which can be changed once it is (see the
 ARGS command below).  'separator' is a regular expression which matches
 the last line of input for a single alert.  By default, it is "/\n$/",
 which will match every line.  For Snort logs, though, we want to capture
 all data up to an empty line, so we change it to "/^\n$/", which doesn't
 match until an empty line is seen.

 FILE <filename>
   Reads through filename from start to finish.  When the file no longer
   has data, it will no longer be a viable input, even if data is appended
   later on.

 TAIL <filename>
   Tails a file.  This runs the command "tail -f -n 0 <filename>", so any
   data already in the file will be ignored.

 STDIN
   Reads data from the program's standard input.

 Example:
 INPUT input1 TAIL /var/log/messages
   Tails the /var/log/messages file.  I have no idea why anyone would want
   to do this.


############################################################################
 ## O U T P U T ##
 OUTPUT <name> <type> [<args>]

 Output objects allow for data to be written to an external (to the program)
 source.  These can be used for logging, etc.  Output types and arguments
 needed are as follows:

 FILEA <filename>
   Opens file <filename> for appending.  Data currently in the file is not
   lost, and if <filename> does not exist, it will be created.

 FILEW <filename>
   Opens file <filename> for writing.  If <filename> exists, it will be lost,
   since this overwrites <filename> with a new, empty file when created.

 STDOUT
   Writes output to the program's standard output handle.

 STDERR
   Writes output to the program's standard error handle.

 NULL
   Throws away output.  Use like '>/dev/null'

 AND <output1> <output2>
   Send output to both outputs, return true only if both succeed.  This does
   not preempt, so even if <output1> output fails, the OutputAnd object will 
   attempt to send data to <output2>.

 Examples:
 OUTPUT local1 FILEA /var/log/privateye.log
   Append output to the file /var/log/privateye.log

############################################################################
 ## I N P U T - O U T P U T   O B J E C T S ##
 INPUTOUTPUT <name> <type> [<args>]

 Certain objects can act as both input and output.  When created, these
 objects take on three different names, "Input_${name}", "Output_${name}",
 and "InputOutput_${name}".  If an object exists beforehand with any of 
 these names, the creation of the object will fail.  Types and required 
 arguments are as follows:

 TCP_SERVER <port> [timeout]
   Creates a TCP server listening on port <port>.  When connected from the
   outside, two-way communication will commence.  Until a connection is made,
   input and output communication will fail.  The server will timeout each
   connection after <timeout> seconds.  THE DEFAULT IS 10.  To disable the
   timeout, use '0'.

 TCP_CLIENT <host> <port>
   Attempt to connect, via TCP, to <host> on port <port>.  Once connected,
   use this single stream for input and output until the connection is closed

 TCP_SERVER_PASSWD <port> <timeout> <passwd>
   Create a TCP server as above, but one that requires a password before it
   will accept any input.  This performs a fun bit of token-based authenti-
   cation that works like this:  Immediately when the client connects, the
   server sends a one-line query string.  The client appends the password
   to that string, then returns the MD5sum of that new string.  The server
   checks that MD5sum to the correct sum, and if they're not the same, it
   disconnects.

 TCP_SERVER_CRYPT <port> <timeout> <passwd>
   Creates an encrypted TCP server.  The initial authorization works just as
   with the TCP_SERVER_PASSWD (this part is not encrypted).  Then, it
   encrypts all remaining traffic in rijndael-256 encryption (base64 encoded)
   and will only accept input in this form as well.

############################################################################
 ## P A T H ##
 PATH <name> <type> [<args>]

 Creates an input path, that takes data from an input vector and deals with
 it in a specific manner.  Types and required arguments are as follows:

 ALERT
   The normal path type.  AlertParsers, UserHashes, and RuleLists must
   be added to any path for it to work.  Each AlertParser will parse
   every input passed to the path.  For each alert generated, each 
   UserHash will find the username of this user.  For each user found,
   The alert will be sent through each rule list of the path.

 CONFIG <output>
   The input is parsed as a configuration option and changes the internal
   environment of the program.  Each input string is sent back to the
   <output> vector, along with a string "SUCCEEDED" or "FAILED" to determine
   whether the specified change took place.  It is recommended that you
   only attach each CONFIG path to a single input, as interlaced configuration
   input could be detrimental.

 Examples:
 PATH path1 ALERT
   Create an alert path.  This will be used by the next three commands.
 PATH path2 CONFIG stdout
   All input attached to this path is parsed by the configuration parser,
   and output is sent to the output object named 'stdout'.


############################################################################
 ## A D D P A R S E R ##
 ADDPARSER <input> <alertparser>
 
 Adds an alert parser <alertparser> to the input <input>.  All data coming
 through <input> from here on out is passed to <alertparser> for parsing.
 Note that this may be done many times, and each input from <input> will 
 be passed to all <alertparser>s added to that input.


############################################################################
 ## A D D P A T H ##
 ADDPATH <alertparser> <path>

 Adds path <path> to the AlertParser <alertparser>.  From now on, whenever 
 an alert is generated by <alertparser>, it will be passed to <path> for 
 processing.  This  can be done any number of times to an AlertParser, and 
 alerts from that AlertParser will traverse all paths.


############################################################################
 ## D U M P A L L ##
 DUMPALL

 A debugging feature, this command does not actually affect the environment.
 Instead, it dumps all information it can about all named objects.  Named
 objects include any object that can be created in the config file.

 Example:
 DUMPALL
   Dumps named object information to standard output.


############################################################################
 ## D U M P ##
 DUMP <name>

 Another debugging feature, this command takes the name of any named object,
 along with its object prefix, and dumps its data to standard output.  Object
 prefixes include 'Trigger_', 'Rule_', 'RuleList_', 'UserHash_', 'Path_',
 etc.  You should probably be able to guess the rest.


############################################################################
 ## I N C L U D E ##
 INCLUDE <filename>

 This parses all of the file <filename> inline with the contents of this
 file.  The difference between this method and defining a config path to the
 file is that the config path does not start until the main engine starts,
 after the initial parsing of the initial config file.


############################################################################
 ## A R G ##
 ARG <name> <command> [<args>]

 The "ARG" command allows for dynamic switching of object arguments of the
 object <name>.  The various commands and their arguments are as follows:

 GETARGS
   Returns a list of all changable arguments of the current object.  Output
   will be of the form:
     [<argtype>] <arg> = <currval>
   where <argtype> is the type of the argument, <arg> is the argument name,
   and <currval> is the current value of the argument (IE: the name of the
   object that <arg> is currently set to).

 SETARG <arg> "<new>"
   Sets the argument <arg> of the current object to the new object named
   <new>.  Note that <new> must be a full name, including prefix.


############################################################################
 ## U S E R S ##
 USERS <BACKUP|RESTORE> <dbType> <dbHost> <dbName> \
	<dbUser> <dbPasswd> <dbTable> <userhash> <object>

 The USERS command is used to store the data about users normally kept in
 memory by Privateye into a database.  This data is either stored or read
 from the mysql fields <userhash> (probably should be VARCHAR(255)) and
 <object> (probably should be TEXT) which will contain the serialized 
 objects.

############################################################################
 Now you can write your own stuff!  Woot. 
############################################################################