Imported Upstream version 2.5.1
[ossec-hids.git] / src / analysisd / testrule.c
index db769f7..c36d8ec 100755 (executable)
@@ -1,11 +1,11 @@
-/* @(#) $Id: testrule.c,v 1.7 2009/08/25 11:30:57 dcid Exp $ */
+/* @(#) $Id$ */
 
 /* Copyright (C) 2009 Trend Micro Inc.
  * All rights reserved.
  *
  * This program is a free software; you can redistribute it
  * and/or modify it under the terms of the GNU General Public
- * License (version 3) as published by the FSF - Free Software
+ * License (version 2) as published by the FSF - Free Software
  * Foundation.
  *
  * License details at the LICENSE file included with OSSEC or 
@@ -27,6 +27,8 @@
    #define ARGV0 "ossec-testrule"
 #endif
 
+
+
 #include "shared.h"
 
 #include "alerts/alerts.h"
 #include "config.h"
 #include "rules.h"
 #include "stats.h"
+
 #include "eventinfo.h"
 #include "analysisd.h"
 
 
 
 /** Internal Functions **/
-void OS_ReadMSG(int m_queue);
+void OS_ReadMSG(int m_queue, char *ut_str);
 RuleInfo *OS_CheckIfRuleMatch(Eventinfo *lf, RuleNode *curr_node);
 
 
@@ -60,6 +63,7 @@ int GlobalConf(char * cfgfile);
 
 /* For rules */
 void Rules_OP_CreateRules();
+void Lists_OP_CreateLists();
 int Rules_OP_ReadRules(char * cfgfile);
 int _setlevels(RuleNode *node, int nnode);
 int AddHash_Rule(RuleNode *node);
@@ -94,7 +98,10 @@ int SetDecodeXML();
  */
 int main(int argc, char **argv)
 {
+    int t_config = 0;
     int c = 0, m_queue = 0;
+    char *ut_str = NULL; 
+
     char *dir = DEFAULTDIR;
     char *user = USER;
     char *group = GROUPGLOBAL;
@@ -108,20 +115,30 @@ int main(int argc, char **argv)
     today = 0;
     prev_year = 0;
     full_output = 0;
+    alert_only = 0;
+
     active_responses = NULL;
     memset(prev_month, '\0', 4);
 
-    while((c = getopt(argc, argv, "Vfdhu:g:D:c:")) != -1){
+    while((c = getopt(argc, argv, "VatfdhU:u:g:D:c:")) != -1){
         switch(c){
            case 'V':
                print_version();
                break;
+            case 't':
+                t_config = 1;
+                break;
             case 'h':
                 help(ARGV0);
                 break;
             case 'd':
                 nowDebug();
                 break;
+            case 'U':
+                if(!optarg)
+                    ErrorExit("%s: -U needs an argument",ARGV0);
+                ut_str = optarg;
+                break;
             case 'u':
                 if(!optarg)
                     ErrorExit("%s: -u needs an argument",ARGV0);
@@ -141,6 +158,9 @@ int main(int argc, char **argv)
                     ErrorExit("%s: -c needs an argument",ARGV0);
                 cfg = optarg;
                 break;
+            case 'a':
+                alert_only = 1;
+                break;    
             case 'f':
                 full_output = 1;    
                 break;
@@ -152,6 +172,8 @@ int main(int argc, char **argv)
     }
 
 
+
+
     /* Reading configuration file */
     if(GlobalConf(cfg) < 0)
     {
@@ -184,45 +206,106 @@ int main(int argc, char **argv)
         ErrorExit(CHROOT_ERROR,ARGV0,dir);
 
 
-
-    /* Reading decoders */
-    OS_CreateOSDecoderList();
-    if(!ReadDecodeXML("etc/decoder.xml"))
+    /*
+     * Anonymous Section: Load rules, decoders, and lists 
+     *
+     * As lists require two pass loading of rules that make use of list lookups
+     * are created with blank database structs, and need to be filled in after 
+     * completion of all rules and lists. 
+     */
     {
-        ErrorExit(CONFIG_ERROR, ARGV0,  XML_DECODER);
-    }
+        { /* Lad decders */
+            /* Initializing the decoders list */
+            OS_CreateOSDecoderList();
+
+            if(!Config.decoders) 
+            { /* Legacy loading */
+                /* Reading decoders */
+                if(!ReadDecodeXML("etc/decoder.xml"))
+                {
+                    ErrorExit(CONFIG_ERROR, ARGV0,  XML_DECODER);
+                }
 
-    c = ReadDecodeXML("etc/local_decoder.xml");
-    if(!c)
-    {
-        if((c != -2))
-            ErrorExit(CONFIG_ERROR, ARGV0,  XML_LDECODER);
-    }
-    SetDecodeXML();
+                /* Reading local ones. */
+                c = ReadDecodeXML("etc/local_decoder.xml");
+                if(!c)
+                {
+                    if((c != -2))
+                        ErrorExit(CONFIG_ERROR, ARGV0,  XML_LDECODER);
+                }
+                else
+                {
+                    verbose("%s: INFO: Reading local decoder file.", ARGV0);
+                }
+            }
+            else
+            { /* New loaded based on file speified in ossec.conf */
+                char **decodersfiles;
+                decodersfiles = Config.decoders;
+                while( decodersfiles && *decodersfiles)
+                {
 
-    
-    /* Creating the rules list */
-    Rules_OP_CreateRules();
+                    verbose("%s: INFO: Reading decoder file %s.", ARGV0, *decodersfiles);
+                    if(!ReadDecodeXML(*decodersfiles))
+                        ErrorExit(CONFIG_ERROR, ARGV0, *decodersfiles);
+                    
+                    free(*decodersfiles);    
+                    decodersfiles++;    
+                }
+            }
 
-   
-    /* Reading the rules */
-    {
-        char **rulesfiles;
-        rulesfiles = Config.includes;
-        while(rulesfiles && *rulesfiles)
-        {
-            debug1("%s: INFO: Reading rules file: '%s'", ARGV0, *rulesfiles);
-            if(Rules_OP_ReadRules(*rulesfiles) < 0)
-                ErrorExit(RULES_ERROR, ARGV0, *rulesfiles);
-                
-            free(*rulesfiles);    
-            rulesfiles++;    
+            /* Load decoders */
+            SetDecodeXML();
+        }
+        { /* Load Lists */
+            /* Initializing the lists of list struct */
+            Lists_OP_CreateLists(); 
+            /* Load each list into list struct */
+            {
+                char **listfiles;
+                listfiles = Config.lists;
+                while(listfiles && *listfiles)
+                {
+                    verbose("%s: INFO: Reading loading the lists file: '%s'", ARGV0, *listfiles);
+                    if(Lists_OP_LoadList(*listfiles) < 0)
+                        ErrorExit(LISTS_ERROR, ARGV0, *listfiles);
+                    free(*listfiles);
+                    listfiles++;
+                }
+                free(Config.lists);
+                Config.lists = NULL;
+            }
         }
+        { /* Load Rules */
+            /* Creating the rules list */
+            Rules_OP_CreateRules();
+
+            /* Reading the rules */
+            {
+                char **rulesfiles;
+                rulesfiles = Config.includes;
+                while(rulesfiles && *rulesfiles)
+                {
+                    debug1("%s: INFO: Reading rules file: '%s'", ARGV0, *rulesfiles);
+                    if(Rules_OP_ReadRules(*rulesfiles) < 0)
+                        ErrorExit(RULES_ERROR, ARGV0, *rulesfiles);
+                        
+                    free(*rulesfiles);    
+                    rulesfiles++;    
+                }
 
-        free(Config.includes);
-        Config.includes = NULL;
+                free(Config.includes);
+                Config.includes = NULL;
+            }
+            
+            /* Find all rules with that require list lookups and attache the
+             * the correct list struct to the rule.  This keeps rules from having to 
+             * search thought the list of lists for the correct file during rule evaluation.
+             */
+            OS_ListLoadRules();
+        }
     }
-    
+
     
     /* Fixing the levels/accuracy */
     {
@@ -246,13 +329,18 @@ int main(int argc, char **argv)
     }
 
 
+    if(t_config == 1)
+    {
+        exit(0);
+    }
+
     
     /* Start up message */
     verbose(STARTUP_MSG, ARGV0, getpid());
 
 
     /* Going to main loop */   
-    OS_ReadMSG(m_queue);
+    OS_ReadMSG(m_queue, ut_str);
 
 
     exit(0);
@@ -265,10 +353,44 @@ int main(int argc, char **argv)
  * Main function. Receives the messages(events)
  * and analyze them all.
  */
-void OS_ReadMSG(int m_queue)
+void OS_ReadMSG(int m_queue, char *ut_str)
 {
     int i;
     char msg[OS_MAXSTR +1];
+    int exit_code = 0;
+    char *ut_alertlevel = NULL;
+    char *ut_rulelevel = NULL;
+    char *ut_decoder_name = NULL; 
+
+    if(ut_str)
+    {
+        /* XXX Break apart string */
+        ut_rulelevel = ut_str; 
+        ut_alertlevel =  strchr(ut_rulelevel, ':');
+        if(!ut_alertlevel)
+        {
+            ErrorExit("%s: -U requires the matching format to be "
+                      "\"<rule_id>:<alert_level>:<decoder_name>\"", ARGV0);
+        }
+        else
+        {
+            *ut_alertlevel = '\0';
+            ut_alertlevel++; 
+        }
+        ut_decoder_name = strchr(ut_alertlevel, ':');
+        if(!ut_decoder_name)
+        {
+            ErrorExit("%s: -U requires the matching format to be "
+                      "\"<rule_id>:<alert_level>:<decoder_name>\"", ARGV0);
+        }
+        else
+        {
+            *ut_decoder_name = '\0';
+            ut_decoder_name++;
+        }
+    }
+
+    RuleInfoDetail *last_info_detail;
     Eventinfo *lf;
 
 
@@ -287,6 +409,8 @@ void OS_ReadMSG(int m_queue)
     }
                                 
 
+    __crt_ftell = 1;
+
 
     /* Getting currently time before starting */
     c_time = time(NULL);
@@ -296,6 +420,7 @@ void OS_ReadMSG(int m_queue)
     memset(msg, '\0', OS_MAXSTR +1);
     
 
+    if(!alert_only)
     print_out("%s: Type one log per line.\n", ARGV0);
     
     
@@ -312,12 +437,12 @@ void OS_ReadMSG(int m_queue)
 
 
         /* Fixing the msg. */
-        strncpy(msg, "1:a:", 5);
+        snprintf(msg, 15, "1:stdin:");
         
     
         
         /* Receive message from queue */
-        if(fgets(msg +4, OS_MAXSTR, stdin))
+        if(fgets(msg +8, OS_MAXSTR, stdin))
         {
             RuleNode *rulenode_pt;
 
@@ -331,13 +456,13 @@ void OS_ReadMSG(int m_queue)
 
 
             /* Make sure we ignore blank lines. */
-            if(strlen(msg) < 6)
+            if(strlen(msg) < 10)
             {
                 continue;
             }
             
             
-            print_out("\n");
+            if(!alert_only)print_out("\n");
             
 
             /* Default values for the log info */
@@ -379,7 +504,7 @@ void OS_ReadMSG(int m_queue)
 
             
             #ifdef TESTRULE
-            if(full_output)
+            if(full_output && !alert_only)
                 print_out("\n**Rule debugging:");
             #endif
 
@@ -413,10 +538,18 @@ void OS_ReadMSG(int m_queue)
                 }
 
                 #ifdef TESTRULE
+                if(!alert_only)
+                {
+                  char *(ruleinfodetail_text[])={"Text","Link","CVE","OSVDB","BUGTRACKID"};
                   print_out("\n**Phase 3: Completed filtering (rules).");
                   print_out("       Rule id: '%d'", currently_rule->sigid);
                   print_out("       Level: '%d'", currently_rule->level);
                   print_out("       Description: '%s'",currently_rule->comment);
+                  for (last_info_detail = currently_rule->info_details; last_info_detail != NULL; last_info_detail = last_info_detail->next) 
+                  {
+                      print_out("       Info - %s: '%s'", ruleinfodetail_text[last_info_detail->type], last_info_detail->data);
+                  }
+                }
                 #endif
                                             
 
@@ -472,7 +605,15 @@ void OS_ReadMSG(int m_queue)
                 /* Log the alert if configured to ... */
                 if(currently_rule->alert_opts & DO_LOGALERT)
                 {
-                    print_out("**Alert to be generated.\n\n");
+                    if(alert_only)
+                    {
+                        OS_LogOutput(lf);
+                        __crt_ftell++;
+                    }
+                    else
+                    {
+                        print_out("**Alert to be generated.\n\n");
+                    }
                 }
 
 
@@ -512,6 +653,29 @@ void OS_ReadMSG(int m_queue)
 
             }while((rulenode_pt = rulenode_pt->next) != NULL);
 
+            if(ut_str)
+            {
+                /*setup exit code if we are doing unit testing*/
+                char holder[1024];
+                holder[1] = '\0';
+                exit_code = 3;
+                if(strcasecmp(ut_decoder_name, lf->decoder_info->name) == 0)
+                {
+                    exit_code--;
+                    snprintf(holder, 1023, "%d", currently_rule->sigid);
+                    if(strcasecmp(ut_rulelevel, holder) == 0)
+                    {
+                        exit_code--;
+                        snprintf(holder, 1023, "%d", currently_rule->level);
+                        if(strcasecmp(ut_alertlevel, holder) == 0)
+                        {
+                            exit_code--;
+                            printf("%d\n",exit_code);
+                        }
+                    }
+                }
+            }
+
 
             /* Only clear the memory if the eventinfo was not
              * added to the stateful memory 
@@ -523,12 +687,14 @@ void OS_ReadMSG(int m_queue)
         }
         else
         {
-            exit(0);   
+            exit(exit_code);   
         }
     }
+    exit(exit_code);
     return;
 }
 
 
 
 /* EOF */
+