Main Page | Modules | Class List | Directories | File List | Class Members | File Members | Related Pages

parser.c

Go to the documentation of this file.
00001 /* $Id$ */
00002 /*
00003 ** Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
00004 ** Copyright (C) 2000,2001 Andrew R. Baker <andrewb@uab.edu>
00005 **
00006 ** This program is free software; you can redistribute it and/or modify
00007 ** it under the terms of the GNU General Public License as published by
00008 ** the Free Software Foundation; either version 2 of the License, or
00009 ** (at your option) any later version.
00010 **
00011 ** This program is distributed in the hope that it will be useful,
00012 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 ** GNU General Public License for more details.
00015 **
00016 ** You should have received a copy of the GNU General Public License
00017 ** along with this program; if not, write to the Free Software
00018 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00019 */
00020 
00021 #ifdef HAVE_CONFIG_H
00022 #include "config.h"
00023 #endif
00024 #include <sys/types.h>
00025 #include <sys/stat.h>
00026 #include <stdlib.h>
00027 #include <string.h>
00028 #ifdef HAVE_STRINGS_H
00029 #include <strings.h>
00030 #endif
00031 #include <errno.h>
00032 #include <ctype.h>
00033 #ifndef WIN32
00034 #include <netdb.h>
00035 #include <sys/socket.h>
00036 #include <netinet/in.h>
00037 #include <arpa/inet.h>
00038 #include <grp.h>
00039 #include <pwd.h>
00040 #endif /* !WIN32 */
00041 #include <unistd.h>
00042 
00043 #include "src/preprocessors/flow/flow_print.h"
00044 #include "rules.h"
00045 #include "parser.h"
00046 #include "plugbase.h"
00047 #include "debug.h"
00048 #include "util.h"
00049 #include "mstring.h"
00050 #include "detect.h"
00051 #include "fpcreate.h"
00052 #include "log.h"
00053 #include "generators.h"
00054 #include "tag.h"
00055 #include "signature.h"
00056 #include "sfthreshold.h"
00057 #include "sfutil/sfthd.h"
00058 #include "snort.h"
00059 #include "inline.h"
00060 #include "event_queue.h"
00061 #include "asn1.h"
00062 
00063 #define MAX_RULE_OPTIONS 256
00064 #define MAX_LINE_LENGTH 4096
00065 
00066 ListHead Alert;         /* Alert Block Header */
00067 ListHead Log;           /* Log Block Header */
00068 ListHead Pass;          /* Pass Block Header */
00069 ListHead Activation;    /* Activation Block Header */
00070 ListHead Dynamic;       /* Dynamic Block Header */
00071 ListHead Drop;
00072 ListHead SDrop;
00073 ListHead Reject;
00074 ListHead RejectBoth;
00075 ListHead RejectSrc;
00076 ListHead RejectDst;
00077 ListHead Reinject;
00078 
00079 RuleTreeNode *rtn_tmp;      /* temp data holder */
00080 OptTreeNode *otn_tmp;       /* OptTreeNode temp ptr */
00081 ListHead *head_tmp = NULL;  /* ListHead temp ptr */
00082 
00083 RuleListNode *RuleLists;
00084 
00085 struct VarEntry *VarHead = NULL;
00086 
00087 char *file_name;        /* current rules file being processed */
00088 int file_line;          /* current line being processed in the rules
00089                          * file */
00090 int rule_count;         /* number of rules generated */
00091 int head_count;         /* number of header blocks (chain heads?) */
00092 int opt_count;          /* number of chains */
00093 
00094 int dynamic_rules_present;
00095 int active_dynamic_nodes;
00096 
00097 extern unsigned int giFlowbitSize; /** size of flowbits tracking */
00098 
00099 extern SNORT_EVENT_QUEUE g_event_queue;
00100 
00101 extern KeywordXlateList *KeywordList;   /* detection/response plugin keywords */
00102 extern PreprocessKeywordList *PreprocessKeywords;   /* preprocessor plugin
00103                              * keywords */
00104 extern OutputFuncNode *AlertList;   /* Alert function list */
00105 extern OutputFuncNode *LogList; /* log function list */
00106 
00107 extern OutputFuncNode *DropList;
00108 #ifdef GIDS
00109 extern OutputFuncNode *SDropList;
00110 extern OutputFuncNode *RejectList;
00111 extern OutputFuncNode *RejectBothList;
00112 extern OutputFuncNode *RejectSrcList;
00113 extern OutputFuncNode *RejectDstList;
00114 #ifdef IPFW
00115 extern OutputFuncNode *ReinjectList;
00116 #endif /* IPFW */
00117 #endif /* GIDS */
00118 
00119 /* Local Function Declarations */
00120 void ProcessHeadNode(RuleTreeNode *, ListHead *, int);
00121 void ParseSID(char *, OptTreeNode *);
00122 void ParseRev(char *, OptTreeNode *);
00123 void XferHeader(RuleTreeNode *, RuleTreeNode *);
00124 void DumpChain(RuleTreeNode *, char *, char *);
00125 void IntegrityCheck(RuleTreeNode *, char *, char *);
00126 void SetLinks(RuleTreeNode *, RuleTreeNode *);
00127 int ProcessIP(char *, RuleTreeNode *, int );
00128 IpAddrSet *AllocAddrNode(RuleTreeNode *, int );
00129 int TestHeader(RuleTreeNode *, RuleTreeNode *);
00130 RuleTreeNode *GetDynamicRTN(int, RuleTreeNode *);
00131 OptTreeNode *GetDynamicOTN(int, RuleTreeNode *);
00132 void AddrToFunc(RuleTreeNode *, int);
00133 void PortToFunc(RuleTreeNode *, int, int, int);
00134 void SetupRTNFuncList(RuleTreeNode *);
00135 static void ParsePortList(char *args);
00136 
00137 
00138 /****************************************************************************
00139  *
00140  * Function: ParseRulesFile(char *, int)
00141  *
00142  * Purpose:  Read the rules file a line at a time and send each rule to
00143  *           the rule parser
00144  *
00145  * Arguments: file => rules file filename
00146  *            inclevel => nr of stacked "include"s
00147  *
00148  * Returns: void function
00149  *
00150  ***************************************************************************/
00151 void ParseRulesFile(char *file, int inclevel)
00152 {
00153     FILE *thefp;        /* file pointer for the rules file */
00154     char buf[MAX_LINE_LENGTH+1];  /* file read buffer */
00155     char *index;        /* buffer indexing pointer */
00156     char *stored_file_name = file_name;
00157     int stored_file_line = file_line;
00158     char *saved_line = NULL;
00159     int continuation = 0;
00160     char *new_line = NULL;
00161     struct stat file_stat; /* for include path testing */
00162 
00163     if(inclevel == 0)
00164     {
00165         if(!pv.quiet_flag)
00166         {
00167             LogMessage("\n+++++++++++++++++++++++++++++++++++++++++++++++++++\n");
00168             LogMessage("Initializing rule chains...\n");
00169         }
00170     }
00171 
00172     stored_file_line = file_line;
00173     stored_file_name = file_name;
00174     file_line = 0;
00175     
00176     /* Changed to
00177      *  stat the file relative to the  current directory
00178      *  if that fails - stat it relative to the directory
00179      *  that the configuration file was in
00180      */ 
00181 
00182     file_name = strdup(file);
00183     if(file_name == NULL)
00184     {
00185         FatalError("ParseRulesFile strdup failed: %s\n", 
00186                    strerror(errno));
00187     }
00188 
00189     /* Well the file isn't the one that we thought it was - lets
00190        try the file relative to the current directory
00191      */
00192     
00193     if(stat(file_name, &file_stat) < 0) 
00194     {
00195         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"ParseRulesFile: stat "
00196                                 "on %s failed - going to config_dir\n", file_name););
00197         
00198         free(file_name);
00199 
00200         file_name = calloc(strlen(file) + strlen(pv.config_dir) + 1, 
00201                 sizeof(char));
00202 
00203         if(file_name == NULL)
00204         {
00205             FatalError("ParseRulesFile calloc failed: %s\n", 
00206                        strerror(errno));
00207         }
00208 
00209         strlcpy(file_name, pv.config_dir, strlen(file) + 
00210                 strlen(pv.config_dir) + 1);
00211 
00212         strlcat(file_name, file, strlen(file) + strlen(pv.config_dir) + 1);
00213 
00214         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"ParseRulesFile: Opening "
00215                     "and parsing %s\n", file_name););
00216     }
00217 
00218     /* open the rules file */
00219     if((thefp = fopen(file_name, "r")) == NULL)
00220     {
00221         FatalError("Unable to open rules file: %s or %s\n", file, 
00222                    file_name);
00223     }
00224 
00225     /* clear the line buffer */
00226     bzero((char *) buf, MAX_LINE_LENGTH+1);
00227 
00228 
00229     /* loop thru each file line and send it to the rule parser */
00230     while((fgets(buf, MAX_LINE_LENGTH, thefp)) != NULL)
00231     {
00232         /*
00233          * inc the line counter so the error messages know which line to
00234          * bitch about
00235          */
00236         file_line++;
00237 
00238         index = buf;
00239 
00240 #ifdef DEBUG2
00241     LogMessage("Got line %s (%d): %s\n", file_name, file_line, buf);
00242 #endif
00243         /* advance through any whitespace at the beginning of the line */
00244         while(*index == ' ' || *index == '\t')
00245             index++;
00246 
00247         /* if it's not a comment or a <CR>, send it to the parser */
00248         if((*index != '#') && (*index != 0x0a) && (*index != ';') && 
00249                 (index != NULL))
00250         {
00251             if(continuation == 1)
00252             {
00253                 new_line = (char *) calloc((strlen(saved_line) + strlen(index)
00254                             +1), sizeof(char)); 
00255                 strncat(new_line, saved_line, strlen(saved_line));
00256                 strncat(new_line, index, strlen(index));
00257                 free(saved_line);
00258                 saved_line = NULL;
00259                 index = new_line;
00260 
00261                 if(strlen(index) > PARSERULE_SIZE)
00262                 {
00263                     FatalError("Please don't try to overflow the parser, "
00264                             "that's not very nice of you... (%d-byte "
00265                             "limit on rule size)\n", PARSERULE_SIZE);
00266                 }
00267 
00268                 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"concat rule: %s\n", 
00269                             new_line););
00270             }
00271 
00272             /* check for a '\' continuation character at the end of the line
00273              * if it's there we need to get the next line in the file
00274              */
00275             if(ContinuationCheck(index) == 0) 
00276             {
00277                 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,
00278                             "[*] Processing rule: %s\n", index););
00279 
00280                 ParseRule(thefp, index, inclevel);
00281 
00282                 if(new_line != NULL)
00283                 {
00284                     free(new_line);
00285                     new_line = NULL;
00286                     continuation = 0;
00287                 }
00288             }
00289             else
00290             {
00291                 /* save the current line */
00292                 saved_line = strdup(index);
00293 
00294                 /* set the flag to let us know the next line is 
00295                  * a continuation line
00296                  */ 
00297                 continuation = 1;
00298             }   
00299         }
00300 
00301         bzero((char *) buf, MAX_LINE_LENGTH+1);
00302     }
00303 
00304     if(file_name)
00305         free(file_name);
00306 
00307     file_name = stored_file_name;
00308     file_line = stored_file_line;
00309 
00310     if(inclevel == 0 && !pv.quiet_flag)
00311     {
00312     LogMessage("%d Snort rules read...\n", rule_count);
00313     LogMessage("%d Option Chains linked into %d Chain Headers\n", opt_count, 
00314                 head_count);
00315     LogMessage("%d Dynamic rules\n", dynamic_rules_present);
00316     LogMessage("+++++++++++++++++++++++++++++++++++++++++++++++++++\n\n");
00317     }
00318 
00319     fclose(thefp);
00320 
00321     /* plug all the dynamic rules together */
00322     if(dynamic_rules_present)
00323     {
00324         LinkDynamicRules();
00325     }
00326 
00327     if(inclevel == 0)
00328     {
00329 #ifdef DEBUG
00330         DumpRuleChains();
00331 #endif
00332 
00333         IntegrityCheckRules();
00334         /*FindMaxSegSize();*/
00335     }
00336 
00337     return;
00338 }
00339 
00340 
00341 
00342 int ContinuationCheck(char *rule)
00343 {
00344     char *idx;  /* indexing var for moving around on the string */
00345 
00346     idx = rule + strlen(rule) - 1;
00347 
00348     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"initial idx set to \'%c\'\n", 
00349                 *idx););
00350 
00351     while(isspace((int)*idx))
00352     {
00353         idx--;
00354     }
00355 
00356     if(*idx == '\\')
00357     {
00358         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Got continuation char, "
00359                     "clearing char and returning 1\n"););
00360 
00361         /* clear the '\' so there isn't a problem on the appended string */
00362         *idx = '\x0';
00363         return 1;
00364     }
00365 
00366     return 0;
00367 }
00368 
00369 
00370 int CheckRule(char *str)
00371 {
00372     int len;
00373     int got_paren = 0;
00374     int got_semi = 0;
00375     char *index;
00376 
00377     len = strlen(str);
00378 
00379     index = str + len - 1; /* go to the end of the string */
00380 
00381     while((isspace((int)*index)))
00382     {
00383         if(index > str)
00384             index--;
00385         else
00386             return 0;
00387     }
00388 
00389     /* the last non-whitspace character should be a ')' */
00390     if(*index == ')')
00391     {
00392         got_paren = 1;
00393         index--;
00394     }
00395 
00396     while((isspace((int)*index)))
00397     {
00398         if(index > str)
00399             index--;
00400         else
00401             return 0;
00402     }
00403 
00404     /* the next to last char should be a semicolon */
00405     if(*index == ';')
00406     {
00407         got_semi = 1;
00408     }
00409 
00410     if(got_semi && got_paren)
00411     {
00412         return 1;
00413     }
00414     else
00415     {
00416         /* check for a '(' to make sure that rule options are being used... */
00417         for(index = str; index < str+len; index++)
00418         {
00419             if(*index == '(')
00420             {
00421                 return 0;
00422             }
00423         }
00424 
00425         return 1;
00426     }
00427 
00428 }
00429 
00430 void DumpRuleChains()
00431 {
00432     RuleListNode *rule;
00433 
00434     rule = RuleLists;
00435 
00436     while(rule != NULL)
00437     {
00438         DumpChain(rule->RuleList->IpList, rule->name, "IP Chains");
00439         DumpChain(rule->RuleList->TcpList, rule->name, "TCP Chains");
00440         DumpChain(rule->RuleList->UdpList, rule->name, "UDP Chains");
00441         DumpChain(rule->RuleList->IcmpList, rule->name, "ICMP Chains");
00442         rule = rule->next;
00443     }
00444 }
00445 
00446 void IntegrityCheckRules()
00447 {
00448     RuleListNode *rule;
00449 
00450     rule = RuleLists;
00451 
00452     if(!pv.quiet_flag)
00453     {
00454         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Performing Rule "
00455                     "List Integrity Tests...\n"););
00456         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"----------------"
00457                     "-----------------------\n"););
00458     }
00459 
00460     while(rule != NULL)
00461     {
00462         IntegrityCheck(rule->RuleList->IpList, rule->name, "IP Chains");
00463         IntegrityCheck(rule->RuleList->TcpList, rule->name, "TCP Chains");
00464         IntegrityCheck(rule->RuleList->UdpList, rule->name, "UDP Chains");
00465         IntegrityCheck(rule->RuleList->IcmpList, rule->name, "ICMP Chains");
00466         rule = rule->next;
00467     }
00468 
00469     if(!pv.quiet_flag)
00470     {
00471         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,
00472                     "---------------------------------------\n\n"););
00473     }
00474 }
00475 
00476 /****************************************************************************
00477  *
00478  * Function: ParseRule(FILE*, char *, int)
00479  *
00480  * Purpose:  Process an individual rule and add it to the rule list
00481  *
00482  * Arguments: rule => rule string
00483  *            inclevel => nr of stacked "include"s
00484  *
00485  * Returns: void function
00486  *
00487  ***************************************************************************/
00488 void ParseRule(FILE *rule_file, char *prule, int inclevel)
00489 {
00490     char **toks;        /* dbl ptr for mSplit call, holds rule tokens */
00491     int num_toks;       /* holds number of tokens found by mSplit */
00492     int rule_type;      /* rule type enumeration variable */
00493     char rule[PARSERULE_SIZE];
00494     int protocol = 0;
00495     char *tmp;
00496     RuleTreeNode proto_node;
00497     RuleListNode *node = RuleLists;
00498 
00499     /* chop off the <CR/LF> from the string */
00500     strip(prule);
00501 
00502     /* expand all variables */
00503     bzero((void *)rule, sizeof(rule));
00504 
00505     strncpy(rule, ExpandVars(prule), PARSERULE_SIZE-1);
00506 
00507     /* break out the tokens from the rule string */
00508     toks = mSplit(rule, " ", 10, &num_toks, 0);
00509 
00510 
00511     /* clean house */
00512     bzero((char *) &proto_node, sizeof(RuleTreeNode));
00513 
00514     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"[*] Rule start\n"););
00515 
00516     /* figure out what we're looking at */
00517     rule_type = RuleType(toks[0]);
00518 
00519     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Rule type: "););
00520 
00521     /* handle non-rule entries */
00522     switch(rule_type)
00523     {
00524         case RULE_DROP:
00525             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Drop\n"););
00526 
00527             /* if we are not listening to iptables, let's ignore
00528              * any drop rules in the configuration file */
00529             if (!InlineMode())
00530             {
00531                 return;
00532             }
00533             break;
00534                 
00535 #ifdef GIDS
00536         case RULE_SDROP:
00537             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"SDrop\n"););
00538               
00539             /* if we are not listening to iptables, let's ignore
00540              * any sdrop rules in the configuration file */
00541             if (!InlineMode())
00542             {
00543                 return;
00544             }
00545             break;
00546                 
00547         case RULE_REJECT:
00548             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Reject\n"););
00549               
00550             /* if we are not listening to iptables, let's ignore
00551              * any reject rules in the configuration file */
00552             if (!InlineMode())
00553             {
00554                 return;
00555             }
00556             break;
00557  
00558         case RULE_REJECTBOTH:
00559             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"RejectBoth\n"););
00560 
00561             /* if we are not listening to iptables, let's ignore
00562              * any reject rules in the configuration file */
00563             if (!InlineMode())
00564             {
00565                 return;
00566             }
00567             break;
00568 
00569         case RULE_REJECTSRC:
00570             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"RejectSrc\n"););
00571 
00572             /* if we are not listening to iptables, let's ignore
00573              * any reject rules in the configuration file */
00574             if (!InlineMode())
00575             {
00576                 return;
00577             }
00578             break;
00579 
00580         case RULE_REJECTDST:
00581             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"RejectDst\n"););
00582 
00583             /* if we are not listening to iptables, let's ignore
00584              * any reject rules in the configuration file */
00585             if (!InlineMode())
00586             {
00587                 return;
00588             }
00589             break;
00590 
00591 #ifdef IPFW
00592         case RULE_REINJECT:
00593             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Reinject\n"););
00594               
00595             /* if we are not in inline mode, let's ignore
00596              * any reject rules in the configuration file */
00597             if (!InlineMode())
00598             {
00599                 return;
00600             }
00601             break;
00602 #endif /* IPFW */
00603 #endif /* GIDS */
00604                 
00605         case RULE_PASS:
00606             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Pass\n"););
00607             break;
00608 
00609         case RULE_LOG:
00610             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Log\n"););
00611             break;
00612 
00613         case RULE_ALERT:
00614             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Alert\n"););
00615             break;
00616 
00617         case RULE_INCLUDE:
00618             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Include\n"););
00619             if(*toks[1] == '$')
00620             {
00621                 if((tmp = VarGet(toks[1]+1)) == NULL)
00622                 {
00623                     FatalError("%s(%d) => Undefined variable %s\n", 
00624                                file_name, file_line, toks[1]);
00625                 }
00626             }
00627             else
00628             {
00629                 tmp = toks[1];
00630             }
00631 
00632             ParseRulesFile(tmp, inclevel + 1);
00633             mSplitFree(&toks, num_toks);
00634             return;
00635 
00636         case RULE_VAR:
00637             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Variable\n"););
00638             VarDefine(toks[1], toks[2]);
00639             mSplitFree(&toks, num_toks);
00640             return;
00641 
00642         case RULE_PREPROCESS:
00643             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Preprocessor\n"););
00644             ParsePreprocessor(rule);
00645             mSplitFree(&toks, num_toks);
00646             return;
00647 
00648         case RULE_OUTPUT:
00649             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Output Plugin\n"););
00650             ParseOutputPlugin(rule);
00651             mSplitFree(&toks, num_toks);
00652             return;
00653 
00654         case RULE_ACTIVATE:
00655             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Activation rule\n"););
00656             break;
00657 
00658         case RULE_DYNAMIC:
00659             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Dynamic rule\n"););
00660             break;
00661 
00662         case RULE_CONFIG:
00663             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Rule file config\n"););
00664             ParseConfig(rule);
00665             mSplitFree(&toks, num_toks);
00666             return;
00667 
00668         case RULE_DECLARE:
00669             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Rule type declaration\n"););
00670             ParseRuleTypeDeclaration(rule_file, rule);
00671             mSplitFree(&toks, num_toks);
00672             return;
00673  
00674         case RULE_THRESHOLD:
00675             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Threshold\n"););
00676             ParseSFThreshold(rule_file, rule);
00677             mSplitFree(&toks, num_toks);
00678             return;
00679         
00680     case RULE_SUPPRESS:
00681             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Suppress\n"););
00682             ParseSFSuppress(rule_file, rule);
00683             mSplitFree(&toks, num_toks);
00684             return;
00685  
00686         case RULE_UNKNOWN:
00687             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Unknown rule type, might be declared\n"););
00688 
00689             /* find out if this ruletype has been declared */
00690             while(node != NULL)
00691             {
00692                 if(!strcasecmp(node->name, toks[0]))
00693                     break;
00694                 node = node->next;
00695             }
00696 
00697             if(node == NULL)
00698             {
00699                  FatalError("%s(%d) => Unknown rule type: %s\n",
00700                             file_name, file_line, toks[0]);
00701             }
00702 
00703             break; 
00704 
00705         default:
00706             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Invalid input: %s\n", prule););
00707             mSplitFree(&toks, num_toks);
00708             return;
00709     }
00710 
00711     if(num_toks < 7)
00712     {
00713         FatalError("%s(%d): Bad rule in rules file\n", file_name, file_line);
00714     }
00715 
00716     if(!CheckRule(prule))
00717     {
00718         FatalError("Unterminated rule in file %s, line %d\n" 
00719                    "   (Snort rules must be contained on a single line or\n"
00720                    "    on multiple lines with a '\\' continuation character\n"
00721                    "    at the end of the line,  make sure there are no\n"
00722                    "    carriage returns before the end of this line)\n",
00723                    file_name, file_line);
00724         return;
00725     }
00726 
00727     if (rule_type == RULE_UNKNOWN)
00728         proto_node.type = node->mode;
00729     else
00730         proto_node.type = rule_type;
00731 
00732     /* set the rule protocol */
00733     protocol = WhichProto(toks[1]);
00734 
00735     /* Process the IP address and CIDR netmask */
00736     /* changed version 1.2.1 */
00737     /*
00738      * "any" IP's are now set to addr 0, netmask 0, and the normal rules are
00739      * applied instead of checking the flag
00740      */
00741     /*
00742      * if we see a "!<ip number>" we need to set a flag so that we can
00743      * properly deal with it when we are processing packets
00744      */
00745     /* we found a negated address */
00746     /* if( *toks[2] == '!' )    
00747        {
00748        proto_node.flags |= EXCEPT_SRC_IP;
00749        ProcessIP(&toks[2][1], &proto_node, SRC);
00750        }
00751        else
00752        {*/
00753     ProcessIP(toks[2], &proto_node, SRC);
00754     /*}*/
00755 
00756     /* check to make sure that the user entered port numbers */
00757     /* sometimes they forget/don't know that ICMP rules need them */
00758     if(!strcasecmp(toks[3], "->") ||
00759             !strcasecmp(toks[3], "<>"))
00760     {
00761         FatalError("%s:%d => Port value missing in rule!\n", 
00762                    file_name, file_line);
00763     }
00764 
00765     /* do the same for the port */
00766     if(ParsePort(toks[3], (u_short *) & proto_node.hsp,
00767                 (u_short *) & proto_node.lsp, toks[1],
00768                 (int *) &proto_node.not_sp_flag))
00769     {
00770         proto_node.flags |= ANY_SRC_PORT;
00771     }
00772 
00773     if(proto_node.not_sp_flag)
00774         proto_node.flags |= EXCEPT_SRC_PORT;
00775 
00776     /* New in version 1.3: support for bidirectional rules */
00777     /*
00778      * this checks the rule "direction" token and sets the bidirectional flag
00779      * if the token = '<>'
00780      */
00781     if(!strncmp("<>", toks[4], 2))
00782     {
00783         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Bidirectional rule!\n"););
00784         proto_node.flags |= BIDIRECTIONAL;
00785     }
00786 
00787     /* changed version 1.8.4
00788      * Die when someone has tried to define a rule character other than
00789        -> or <>
00790     */
00791     if(strcmp("->", toks[4]) && strcmp("<>", toks[4]))
00792     {
00793         FatalError("%s(%d): Illegal direction specifier: %s\n", file_name, 
00794                 file_line, toks[4]);
00795     }
00796 
00797 
00798     /* changed version 1.2.1 */
00799     /*
00800      * "any" IP's are now set to addr 0, netmask 0, and the normal rules are
00801      * applied instead of checking the flag
00802      */
00803     /*
00804      * if we see a "!<ip number>" we need to set a flag so that we can
00805      * properly deal with it when we are processing packets
00806      */
00807     /* we found a negated address */
00808     ProcessIP(toks[5], &proto_node, DST);
00809 
00810     if(ParsePort(toks[6], (u_short *) & proto_node.hdp,
00811                 (u_short *) & proto_node.ldp, toks[1],
00812                 (int *) &proto_node.not_dp_flag))
00813     {
00814         proto_node.flags |= ANY_DST_PORT;
00815     }
00816 
00817     /* if there is anything beyond the dst port, it must begin with "(" */
00818     if (num_toks > 7 && toks[7][0] != '(')
00819     {
00820         FatalError("%s(%d): The rule option section (starting with a '(') must "
00821                    "follow immediately after the destination port.  "
00822                    "This means port lists are not supported.\n",
00823                    file_name, file_line);
00824     }
00825 
00826     if(proto_node.not_dp_flag)
00827         proto_node.flags |= EXCEPT_DST_PORT;
00828 
00829     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"proto_node.flags = 0x%X\n", proto_node.flags););
00830     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Processing Head Node....\n"););
00831 
00832     switch(rule_type)
00833     {
00834         case RULE_DROP:
00835             if (InlineMode())
00836             {
00837                 ProcessHeadNode(&proto_node, &Drop, protocol);
00838             }
00839             break;
00840              
00841 #ifdef GIDS
00842         case RULE_SDROP:
00843             if (InlineMode())
00844             {
00845                 ProcessHeadNode(&proto_node, &SDrop, protocol);
00846             }
00847             break;
00848              
00849         case RULE_REJECT:
00850             if (InlineMode())
00851             {
00852                 ProcessHeadNode(&proto_node, &Reject, protocol);
00853             }
00854             break;
00855 
00856          case RULE_REJECTBOTH:
00857             if (InlineMode())
00858             {
00859                 ProcessHeadNode(&proto_node, &RejectBoth, protocol);
00860             }
00861             break;
00862 
00863          case RULE_REJECTSRC:
00864             if (InlineMode())
00865             {
00866                 ProcessHeadNode(&proto_node, &RejectSrc, protocol);
00867             }
00868             break;
00869 
00870          case RULE_REJECTDST:
00871             if (InlineMode())
00872             {
00873                 ProcessHeadNode(&proto_node, &RejectDst, protocol);
00874             }
00875             break;
00876 
00877 #ifdef IPFW
00878         case RULE_REINJECT:
00879             if (InlineMode())
00880             {
00881                 ProcessHeadNode(&proto_node, &Reinject, protocol);
00882             }
00883             break;
00884 #endif /* IPFW */
00885 #endif /* GIDS */         
00886          
00887         case RULE_ALERT:
00888             ProcessHeadNode(&proto_node, &Alert, protocol);
00889             break;
00890 
00891         case RULE_LOG:
00892             ProcessHeadNode(&proto_node, &Log, protocol);
00893             break;
00894 
00895         case RULE_PASS:
00896             ProcessHeadNode(&proto_node, &Pass, protocol);
00897             break;
00898 
00899         case RULE_ACTIVATE:
00900             ProcessHeadNode(&proto_node, &Activation, protocol);
00901             break;
00902 
00903         case RULE_DYNAMIC:
00904             ProcessHeadNode(&proto_node, &Dynamic, protocol);
00905             break;
00906 
00907         case RULE_UNKNOWN:
00908             ProcessHeadNode(&proto_node, node->RuleList, protocol);
00909             break;
00910 
00911         default:
00912             FatalError("Unable to determine rule type (%s) for processing, exiting!\n", toks[0]);
00913     }
00914 
00915     rule_count++;
00916 
00917     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Parsing Rule Options...\n"););
00918 
00919     if (rule_type == RULE_UNKNOWN)
00920         ParseRuleOptions(rule, node->mode, protocol);
00921     else
00922         ParseRuleOptions(rule, rule_type, protocol);
00923 
00924     mSplitFree(&toks, num_toks);
00925 
00926     return;
00927 }
00928 
00929 /****************************************************************************
00930  *
00931  * Function: ProcessHeadNode(RuleTreeNode *, ListHead *, int)
00932  *
00933  * Purpose:  Process the header block info and add to the block list if
00934  *           necessary
00935  *
00936  * Arguments: test_node => data generated by the rules parsers
00937  *            list => List Block Header refernece
00938  *            protocol => ip protocol
00939  *
00940  * Returns: void function
00941  *
00942  ***************************************************************************/
00943 void ProcessHeadNode(RuleTreeNode * test_node, ListHead * list, int protocol)
00944 {
00945     int match = 0;
00946     RuleTreeNode *rtn_idx;
00947     RuleTreeNode *rtn_prev;
00948     RuleTreeNode *rtn_head_ptr;
00949     int count = 0;
00950     int insert_complete = 0;
00951 #ifdef DEBUG
00952     int i;
00953 #endif
00954 
00955     /* select the proper protocol list to attach the current rule to */
00956     switch(protocol)
00957     {
00958         case IPPROTO_TCP:
00959             rtn_idx = list->TcpList;
00960             break;
00961 
00962         case IPPROTO_UDP:
00963             rtn_idx = list->UdpList;
00964             break;
00965 
00966         case IPPROTO_ICMP:
00967             rtn_idx = list->IcmpList;
00968             break;
00969 
00970         case ETHERNET_TYPE_IP:
00971             rtn_idx = list->IpList;
00972             break;
00973 
00974         default:
00975             rtn_idx = NULL;
00976             break;
00977     }
00978 
00979     /* 
00980      * save which list we're on in case we need to do an insertion
00981      * sort on a new node
00982      */
00983     rtn_head_ptr = rtn_idx;
00984 
00985     /*
00986      * if the list head is NULL (empty), make a new one and attach the
00987      * ListHead to it
00988      */
00989     if(rtn_idx == NULL)
00990     {
00991         head_count++;
00992 
00993         switch(protocol)
00994         {
00995             case IPPROTO_TCP:
00996                 list->TcpList = (RuleTreeNode *) calloc(sizeof(RuleTreeNode), 
00997                         sizeof(char));
00998                 rtn_tmp = list->TcpList;
00999                 break;
01000 
01001             case IPPROTO_UDP:
01002                 list->UdpList = (RuleTreeNode *) calloc(sizeof(RuleTreeNode), 
01003                         sizeof(char));
01004                 rtn_tmp = list->UdpList;
01005                 break;
01006 
01007             case IPPROTO_ICMP:
01008                 list->IcmpList = (RuleTreeNode *) calloc(sizeof(RuleTreeNode), 
01009                         sizeof(char));
01010                 rtn_tmp = list->IcmpList;
01011                 break;
01012 
01013             case ETHERNET_TYPE_IP:
01014                 list->IpList = (RuleTreeNode *) calloc(sizeof(RuleTreeNode), 
01015                         sizeof(char));
01016                 rtn_tmp = list->IpList;
01017                 break;
01018 
01019         }
01020 
01021         /* copy the prototype header data into the new node */
01022         XferHeader(test_node, rtn_tmp);
01023 
01024         rtn_tmp->head_node_number = head_count;
01025 
01026         /* null out the down (options) pointer */
01027         rtn_tmp->down = NULL;
01028 
01029         /* add the function list to the new rule */
01030         SetupRTNFuncList(rtn_tmp);
01031 
01032         /* add link to parent listhead */
01033         rtn_tmp->listhead = list;
01034 
01035         return;
01036     }
01037 
01038     /* see if this prototype node matches any of the existing header nodes */
01039     match = TestHeader(rtn_idx, test_node);
01040 
01041     while((rtn_idx->right != NULL) && !match)
01042     {
01043         count++;
01044         match = TestHeader(rtn_idx, test_node);
01045 
01046         if(!match)
01047             rtn_idx = rtn_idx->right;
01048         else
01049             break;
01050     }
01051 
01052     /*
01053      * have to check this twice since my loop above exits early, which sucks
01054      * but it's not performance critical
01055      */
01056     match = TestHeader(rtn_idx, test_node);
01057 
01058     /*
01059      * if it doesn't match any of the existing nodes, make a new node and
01060      * stick it at the end of the list
01061      */
01062     if(!match)
01063     {
01064         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Building New Chain head node\n"););
01065 
01066         head_count++;
01067 
01068         /* build a new node */
01069         //rtn_idx->right = (RuleTreeNode *) calloc(sizeof(RuleTreeNode), 
01070         rtn_tmp = (RuleTreeNode *) calloc(sizeof(RuleTreeNode), 
01071                 sizeof(char));
01072 
01073         /* set the global ptr so we can play with this from anywhere */
01074         //rtn_tmp = rtn_idx->right;
01075 
01076         /* uh oh */
01077         if(rtn_tmp == NULL)
01078         {
01079             FatalError("Unable to allocate Rule Head Node!!\n");
01080         }
01081 
01082         /* copy the prototype header info into the new header block */
01083         XferHeader(test_node, rtn_tmp);
01084 
01085         rtn_tmp->head_node_number = head_count;
01086         rtn_tmp->down = NULL;
01087 
01088         /* initialize the function list for the new RTN */
01089         SetupRTNFuncList(rtn_tmp);
01090 
01091         /* add link to parent listhead */
01092         rtn_tmp->listhead = list;
01093         
01094         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,
01095                 "New Chain head flags = 0x%X\n", rtn_tmp->flags););
01096 
01097         /* we do an insertion sort of new RTNs for TCP/UDP traffic */
01098         if(protocol == IPPROTO_TCP || protocol == IPPROTO_UDP)
01099         {
01100             /* 
01101              * insert the new node into the RTN chain, order by destination
01102              * port
01103              */
01104             rtn_idx = rtn_head_ptr;
01105             rtn_prev = NULL;
01106             insert_complete = 0;
01107 
01108             /* 
01109              * Loop thru the RTN list and check to see of the low dest port
01110              * of the new node is greater than the low dest port of the 
01111              * new node.  If it is, insert the new node ahead of (to the 
01112              * left) of the existing node.
01113              */
01114             if(rtn_tmp->flags & EXCEPT_DST_PORT)
01115             {
01116                 switch(protocol)
01117                 {
01118                     case IPPROTO_TCP:
01119                         rtn_tmp->right = list->TcpList;
01120                         list->TcpList = rtn_tmp;
01121                         break;
01122 
01123                     case IPPROTO_UDP:
01124                         rtn_tmp->right = list->UdpList;
01125                         list->UdpList = rtn_tmp;
01126                         break;
01127                 }
01128 
01129                 rtn_head_ptr = rtn_tmp;
01130                 insert_complete = 1;
01131             }
01132             else
01133             {
01134                 while(rtn_idx != NULL)
01135                 {
01136                     if(rtn_idx->flags & EXCEPT_DST_PORT || 
01137                        rtn_idx->ldp < rtn_tmp->ldp)
01138                     {
01139                         rtn_prev = rtn_idx;
01140                         rtn_idx = rtn_idx->right;
01141                     }
01142                     else if(rtn_idx->ldp == rtn_tmp->ldp)
01143                     {
01144                         rtn_tmp->right = rtn_idx->right;
01145                         rtn_idx->right = rtn_tmp;
01146                         insert_complete = 1;
01147                         break;
01148                     }
01149                     else
01150                     {
01151                         rtn_tmp->right = rtn_idx;
01152 
01153                         if(rtn_prev != NULL)
01154                         {
01155                             rtn_prev->right = rtn_tmp;
01156                         }
01157                         else 
01158                         {
01159                             switch(protocol)
01160                             {
01161                                 case IPPROTO_TCP:
01162                                     list->TcpList = rtn_tmp;
01163                                     break;
01164 
01165                                 case IPPROTO_UDP:
01166                                     list->UdpList = rtn_tmp;
01167                                     break;
01168                             }
01169 
01170                             rtn_head_ptr = rtn_tmp;
01171                         }
01172 
01173                         insert_complete = 1;
01174 
01175                         break;
01176                     }
01177                 } 
01178             }
01179 
01180             if(!insert_complete)
01181             {
01182                 rtn_prev->right = rtn_tmp;   
01183             }
01184             
01185             rtn_idx = rtn_head_ptr;
01186 
01187             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, 
01188                     "New %s node inserted, new order:\n", 
01189                     protocol == IPPROTO_TCP?"TCP":"UDP"););
01190             
01191 #ifdef DEBUG
01192             i = 0;
01193 
01194             while(rtn_idx != NULL)
01195             {
01196                 if(rtn_idx->flags & EXCEPT_DST_PORT)
01197                 {
01198                     LogMessage("!");
01199                 }
01200 
01201                 DebugMessage(DEBUG_CONFIGRULES, "%d ", rtn_idx->ldp);
01202                 rtn_idx = rtn_idx->right;
01203                 if(i++ == 10)
01204                 {
01205                     DebugMessage(DEBUG_CONFIGRULES, "\n");
01206                     i = 0;
01207                 }
01208             }
01209             DebugMessage(DEBUG_CONFIGRULES, "\n");
01210 #endif
01211         }
01212         else
01213         {
01214             rtn_idx->right = rtn_tmp;
01215         }
01216     }
01217     else
01218     {
01219         rtn_tmp = rtn_idx;
01220         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,
01221                 "Chain head %d  flags = 0x%X\n", count, rtn_tmp->flags););
01222 
01223         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,
01224                     "Adding options to chain head %d\n", count););
01225     }
01226 }
01227 
01228 
01229 /****************************************************************************
01230  *
01231  * Function: AddRuleFuncToList(int (*func)(), RuleTreeNode *)
01232  *
01233  * Purpose:  Adds RuleTreeNode associated detection functions to the
01234  *          current rule's function list
01235  *
01236  * Arguments: *func => function pointer to the detection function
01237  *            rtn   => pointer to the current rule
01238  *
01239  * Returns: void function
01240  *
01241  ***************************************************************************/
01242 void AddRuleFuncToList(int (*func) (Packet *, struct _RuleTreeNode *, struct _RuleFpList *), RuleTreeNode * rtn)
01243 {
01244     RuleFpList *idx;
01245 
01246     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Adding new rule to list\n"););
01247 
01248     idx = rtn->rule_func;
01249 
01250     if(idx == NULL)
01251     {
01252         rtn->rule_func = (RuleFpList *) calloc(sizeof(RuleFpList), sizeof(char));
01253 
01254         rtn->rule_func->RuleHeadFunc = func;
01255     }
01256     else
01257     {
01258         while(idx->next != NULL)
01259             idx = idx->next;
01260 
01261         idx->next = (RuleFpList *) calloc(sizeof(RuleFpList), sizeof(char));
01262 
01263         idx = idx->next;
01264         idx->RuleHeadFunc = func;
01265     }
01266 }
01267 
01268 
01269 /****************************************************************************
01270  *
01271  * Function: SetupRTNFuncList(RuleTreeNode *)
01272  *
01273  * Purpose: Configures the function list for the rule header detection
01274  *          functions (addrs and ports)
01275  *
01276  * Arguments: rtn => the pointer to the current rules list entry to attach to
01277  *
01278  * Returns: void function
01279  *
01280  ***************************************************************************/
01281 void SetupRTNFuncList(RuleTreeNode * rtn)
01282 {
01283     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Initializing RTN function list!\n"););
01284     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Functions: "););
01285 
01286     if(rtn->flags & BIDIRECTIONAL)
01287     {
01288         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"CheckBidirectional->\n"););
01289         AddRuleFuncToList(CheckBidirectional, rtn);
01290     }
01291     else
01292     {
01293         /* Attach the proper port checking function to the function list */
01294         /*
01295          * the in-line "if's" check to see if the "any" or "not" flags have
01296          * been set so the PortToFunc call can determine which port testing
01297          * function to attach to the list
01298          */
01299         PortToFunc(rtn, (rtn->flags & ANY_DST_PORT ? 1 : 0),
01300                    (rtn->flags & EXCEPT_DST_PORT ? 1 : 0), DST);
01301 
01302         /* as above */
01303         PortToFunc(rtn, (rtn->flags & ANY_SRC_PORT ? 1 : 0),
01304                    (rtn->flags & EXCEPT_SRC_PORT ? 1 : 0), SRC);
01305 
01306         /* link in the proper IP address detection function */
01307         AddrToFunc(rtn, SRC);
01308 
01309         /* last verse, same as the first (but for dest IP) ;) */
01310         AddrToFunc(rtn, DST);
01311     }
01312 
01313     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"RuleListEnd\n"););
01314 
01315     /* tack the end (success) function to the list */
01316     AddRuleFuncToList(RuleListEnd, rtn);
01317 }
01318 
01319 
01320 
01321 /****************************************************************************
01322  *
01323  * Function: AddrToFunc(RuleTreeNode *, u_long, u_long, int, int)
01324  *
01325  * Purpose: Links the proper IP address testing function to the current RTN
01326  *          based on the address, netmask, and addr flags
01327  *
01328  * Arguments: rtn => the pointer to the current rules list entry to attach to
01329  *            ip =>  IP address of the current rule
01330  *            mask => netmask of the current rule
01331  *            exception_flag => indicates that a "!" has been set for this
01332  *                              address
01333  *            mode => indicates whether this is a rule for the source
01334  *                    or destination IP for the rule
01335  *
01336  * Returns: void function
01337  *
01338  ***************************************************************************/
01339 void AddrToFunc(RuleTreeNode * rtn, int mode)
01340 {
01341     /*
01342      * if IP and mask are both 0, this is a "any" IP and we don't need to
01343      * check it
01344      */
01345     switch(mode)
01346     {
01347         case SRC:
01348             if((rtn->flags & ANY_SRC_IP) == 0)
01349             {
01350                 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"CheckSrcIP -> "););
01351                 AddRuleFuncToList(CheckSrcIP, rtn);
01352             }
01353 
01354             break;
01355 
01356         case DST:
01357             if((rtn->flags & ANY_DST_IP) == 0)
01358             {
01359                 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"CheckDstIP -> "););
01360                 AddRuleFuncToList(CheckDstIP, rtn);
01361             }
01362 
01363             break;
01364     }
01365 }
01366 
01367 
01368 
01369 /****************************************************************************
01370  *
01371  * Function: PortToFunc(RuleTreeNode *, int, int, int)
01372  *
01373  * Purpose: Links in the port analysis function for the current rule
01374  *
01375  * Arguments: rtn => the pointer to the current rules list entry to attach to
01376  *            any_flag =>  accept any port if set
01377  *            except_flag => indicates negation (logical NOT) of the test
01378  *            mode => indicates whether this is a rule for the source
01379  *                    or destination port for the rule
01380  *
01381  * Returns: void function
01382  *
01383  ***************************************************************************/
01384 void PortToFunc(RuleTreeNode * rtn, int any_flag, int except_flag, int mode)
01385 {
01386     /*
01387      * if the any flag is set we don't need to perform any test to match on
01388      * this port
01389      */
01390     if(any_flag)
01391         return;
01392 
01393     /* if the except_flag is up, test with the "NotEq" funcs */
01394     if(except_flag)
01395     {
01396         switch(mode)
01397         {
01398             case SRC:
01399                 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"CheckSrcPortNotEq -> "););
01400                 AddRuleFuncToList(CheckSrcPortNotEq, rtn);
01401                 break;
01402 
01403             case DST:
01404                 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"CheckDstPortNotEq -> "););
01405                 AddRuleFuncToList(CheckDstPortNotEq, rtn);
01406                 break;
01407         }
01408 
01409         return;
01410     }
01411     /* default to setting the straight test function */
01412     switch(mode)
01413     {
01414         case SRC:
01415             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"CheckSrcPortEqual -> "););
01416             AddRuleFuncToList(CheckSrcPortEqual, rtn);
01417             break;
01418 
01419         case DST:
01420             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"CheckDstPortEqual -> "););
01421             AddRuleFuncToList(CheckDstPortEqual, rtn);
01422             break;
01423     }
01424 
01425     return;
01426 }
01427 
01428 
01429 
01430 
01431 
01432 /****************************************************************************
01433  *
01434  * Function: ParsePreprocessor(char *)
01435  *
01436  * Purpose: Walks the preprocessor function list looking for the user provided
01437  *          keyword.  Once found, call the preprocessor's initialization
01438  *          function.
01439  *
01440  * Arguments: rule => the preprocessor initialization string from the rules file
01441  *
01442  * Returns: void function
01443  *
01444  ***************************************************************************/
01445 void ParsePreprocessor(char *rule)
01446 {
01447     char **toks;        /* pointer to the tokenized array parsed from
01448                          * the rules list */
01449     char **pp_head;     /* parsed keyword list, with preprocessor
01450                          * keyword being the 2nd element */
01451     char *funcname;     /* the ptr to the actual preprocessor keyword */
01452     char *pp_args = NULL;   /* parsed list of arguments to the
01453                              * preprocessor */
01454     int num_arg_toks;   /* number of argument tokens returned by the mSplit function */
01455     int num_head_toks;  /* number of head tokens returned by the mSplit function */
01456     int found = 0;      /* flag var */
01457     PreprocessKeywordList *pl_idx;  /* index into the preprocessor
01458                                      * keyword/func list */
01459 
01460     /* break out the arguments from the keywords */
01461     toks = mSplit(rule, ":", 2, &num_arg_toks, '\\');
01462 
01463     if(num_arg_toks > 1)
01464     {
01465         /*
01466         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"toks[1] = %s\n", toks[1]););
01467         */
01468         /* the args are everything after the ":" */
01469         pp_args = toks[1];
01470     }
01471 
01472     /* split the head section for the preprocessor keyword */
01473     pp_head = mSplit(toks[0], " ", 2, &num_head_toks, '\\');
01474 
01475     /* set a pointer to the actual keyword */
01476     funcname = pp_head[1];
01477 
01478     /* set the index to the head of the keyword list */
01479     pl_idx = PreprocessKeywords;
01480 
01481     /* walk the keyword list */
01482     while(pl_idx != NULL)
01483     {
01484         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,
01485                 "comparing: \"%s\" => \"%s\"\n",
01486                 funcname, pl_idx->entry.keyword););
01487         /* compare the keyword against the current list element's keyword */
01488         if(!strcasecmp(funcname, pl_idx->entry.keyword))
01489         {
01490             pl_idx->entry.func(pp_args);
01491             found = 1;
01492         }
01493         if(!found)
01494         {
01495             pl_idx = pl_idx->next;
01496         }
01497         else
01498             break;
01499     }
01500 
01501     if(!found)
01502     {
01503         FatalError(" unknown preprocessor \"%s\"\n",
01504                    funcname);
01505     }
01506 
01507     mSplitFree(&toks, num_arg_toks);
01508     mSplitFree(&pp_head, num_head_toks);
01509 }
01510 
01511 
01512 void ParseOutputPlugin(char *rule)
01513 {
01514     char **toks;
01515     char **pp_head;
01516     char *plugin_name = NULL;
01517     char *pp_args = NULL;
01518     int num_arg_toks;
01519     int num_head_toks;
01520     OutputKeywordNode *plugin;
01521 
01522     toks = mSplit(rule, ":", 2, &num_arg_toks, '\\');
01523 
01524     if(num_arg_toks > 1)
01525     {
01526         pp_args = toks[1];
01527     }
01528     pp_head = mSplit(toks[0], " ", 2, &num_head_toks, '\\');
01529 
01530     plugin_name = pp_head[1];
01531 
01532     if(plugin_name == NULL)
01533     {
01534         FatalError("%s (%d): Output directive missing output plugin name!\n", 
01535                 file_name, file_line);
01536     }
01537 
01538     plugin = GetOutputPlugin(plugin_name);
01539     if( plugin != NULL )
01540     {
01541         switch(plugin->node_type)
01542         {
01543             case NT_OUTPUT_SPECIAL:
01544                 if(pv.alert_cmd_override)
01545                     ErrorMessage("command line overrides rules file alert "
01546                             "plugin!\n");
01547                 if(pv.log_cmd_override)
01548                     ErrorMessage("command line overrides rules file login "
01549                             "plugin!\n");
01550                 plugin->func(pp_args);
01551                 break;
01552 
01553             case NT_OUTPUT_ALERT:
01554                 if(!pv.alert_cmd_override)
01555                 {
01556                     /* call the configuration function for the plugin */
01557                     plugin->func(pp_args);
01558                 }
01559                 else
01560                 {
01561                     ErrorMessage("command line overrides rules file alert "
01562                             "plugin!\n");
01563                 }
01564 
01565                 break;
01566 
01567             case NT_OUTPUT_LOG:
01568                 if(!pv.log_cmd_override)
01569                 {
01570                     /* call the configuration function for the plugin */
01571                     plugin->func(pp_args);
01572                 }
01573                 else
01574                 {
01575                     ErrorMessage("command line overrides rules file logging "
01576                             "plugin!\n");
01577                 }
01578 
01579                 break;
01580         }
01581 
01582     }
01583 
01584     mSplitFree(&toks, num_arg_toks);
01585     mSplitFree(&pp_head, num_head_toks);
01586 }
01587 
01588 
01589 
01590 /****************************************************************************
01591  *
01592  * Function: ParseRuleOptions(char *, int)
01593  *
01594  * Purpose:  Process an individual rule's options and add it to the
01595  *           appropriate rule chain
01596  *
01597  * Arguments: rule => rule string
01598  *            rule_type => enumerated rule type (alert, pass, log)
01599  *
01600  * Returns: void function
01601  *
01602  ***************************************************************************/
01603 void ParseRuleOptions(char *rule, int rule_type, int protocol)
01604 {
01605     char **toks = NULL;
01606     char **opts = NULL;
01607     char *idx;
01608     char *aux;
01609     int num_toks, original_num_toks=0;
01610     int i;
01611     int num_opts;
01612     int found = 0;
01613     OptTreeNode *otn_idx;
01614     KeywordXlateList *kw_idx;
01615     THDX_STRUCT thdx;
01616     int one_threshold = 0;
01617     
01618 
01619     /* set the OTN to the beginning of the list */
01620     otn_idx = rtn_tmp->down;
01621 
01622     /*
01623      * make a new one and stick it either at the end of the list or hang it
01624      * off the RTN pointer
01625      */
01626     if(otn_idx != NULL)
01627     {
01628         /* loop to the end of the list */
01629         while(otn_idx->next != NULL)
01630         {
01631             otn_idx = otn_idx->next;
01632         }
01633 
01634         /* setup the new node */
01635         otn_idx->next = (OptTreeNode *) calloc(sizeof(OptTreeNode), 
01636                                                sizeof(char));
01637 
01638         /* set the global temp ptr */
01639         otn_tmp = otn_idx->next;
01640 
01641         if(otn_tmp == NULL)
01642         {
01643             FatalError("Unable to alloc OTN: %s", strerror(errno));
01644         }
01645 
01646         otn_tmp->next = NULL;
01647         opt_count++;
01648 
01649     }
01650     else
01651     {
01652         /* first entry on the chain, make a new node and attach it */
01653         otn_idx = (OptTreeNode *) calloc(sizeof(OptTreeNode), sizeof(char));
01654 
01655         bzero((char *) otn_idx, sizeof(OptTreeNode));
01656 
01657         otn_tmp = otn_idx;
01658 
01659         if(otn_tmp == NULL)
01660         {
01661             FatalError("Unable to alloc OTN!\n");
01662         }
01663         otn_tmp->next = NULL;
01664         rtn_tmp->down = otn_tmp;
01665         opt_count++;
01666     }
01667 
01668     otn_tmp->chain_node_number = opt_count;
01669     otn_tmp->type = rule_type;
01670     otn_tmp->proto_node = rtn_tmp;
01671     otn_tmp->event_data.sig_generator = GENERATOR_SNORT_ENGINE;
01672 
01673     /* add link to parent RuleTreeNode */
01674     otn_tmp->rtn = rtn_tmp;
01675 
01676     /* find the start of the options block */
01677     idx = index(rule, '(');
01678     i = 0;
01679 
01680     if(idx != NULL)
01681     {
01682         int one_msg = 0;
01683         int one_logto = 0;
01684         int one_activates = 0;
01685         int one_activated_by = 0;
01686         int one_count = 0;
01687         int one_tag = 0;
01688         int one_sid = 0;
01689         int one_rev = 0;
01690         int one_priority = 0;
01691         int one_classtype = 0;
01692         int one_stateless = 0;
01693         
01694         idx++;
01695 
01696         /* find the end of the options block */
01697         aux = strrchr(idx, ')');
01698 
01699         /* get rid of the trailing ")" */
01700         if(aux == NULL)
01701         {
01702             FatalError("%s(%d): Missing trailing ')' in rule: %s.\n",
01703                        file_name, file_line, rule);
01704         }
01705         *aux = 0;
01706 
01707 
01708         /* seperate all the options out, the seperation token is a semicolon */
01709         /*
01710          * NOTE: if you want to include a semicolon in the content of your
01711          * rule, it must be preceeded with a '\'
01712          */
01713         /* Ask for max + 1.  If we get that many back, scream and jump
01714          * up and down. */
01715         toks = mSplit(idx, ";", MAX_RULE_OPTIONS+1, &num_toks, '\\');
01716         if (num_toks > MAX_RULE_OPTIONS)
01717         {
01718             /* don't allow more than MAX_RULE_OPTIONS */
01719             FatalError("%s(%d): More than %d options in rule: %s.\n",
01720                        file_name, file_line, MAX_RULE_OPTIONS, rule);
01721         }
01722         original_num_toks = num_toks;  /* so we can properly deallocate toks later */
01723 
01724         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"   Got %d tokens\n", num_toks););
01725         /* decrement the number of toks */
01726         num_toks--;
01727 
01728         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Parsing options list: "););
01729 
01730     
01731         while(num_toks)        
01732         {
01733             char* option_name = NULL;
01734             char* option_args = NULL;
01735 
01736             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"   option: %s\n", toks[i]););
01737 
01738             /* break out the option name from its data */
01739             opts = mSplit(toks[i], ":", 4, &num_opts, '\\');
01740 
01741             /* can't free opts[0] later if it has been incremented, so
01742              * must use another variable here */
01743             option_name = opts[0];
01744             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"   option name: %s\n", option_name););
01745             if (num_opts > 1)
01746             {
01747                 option_args = opts[1];
01748                 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"   option args: %s\n", option_args););
01749             }
01750 
01751             /* advance to the beginning of the data (past the whitespace) */
01752             while(isspace((int) *option_name))
01753                 option_name++;
01754         
01755             /* figure out which option tag we're looking at */
01756             if(!strcasecmp(option_name, "msg"))
01757             {
01758                 ONE_CHECK (one_msg, option_name);
01759                 if(num_opts == 2)
01760                 {
01761                     ParseMessage(option_args);
01762                 }
01763                 else
01764                 {
01765                     FatalError("\n%s(%d) => No argument passed to "
01766                             "keyword \"%s\"\nMake sure you didn't forget a ':' "
01767                             "or the argument to this keyword!\n", file_name, 
01768                             file_line, option_name);
01769                 }
01770             }
01771             else if(!strcasecmp(option_name, "logto"))
01772             {
01773                 ONE_CHECK (one_logto, option_name);
01774                 if(num_opts == 2)
01775                 {
01776                     ParseLogto(option_args);
01777                 }
01778                 else
01779                 {
01780                     FatalError("\n%s(%d) => No argument passed to "
01781                             "keyword \"%s\"\nMake sure you didn't forget a ':' "
01782                             "or the argument to this keyword!\n", file_name, 
01783                             file_line, option_name);
01784                 }
01785             }
01786             else if(!strcasecmp(option_name, "activates"))
01787             {
01788                 ONE_CHECK (one_activates, option_name);
01789                 if(num_opts == 2)
01790                 {
01791                     ParseActivates(option_args);
01792                     dynamic_rules_present++;
01793                 }
01794                 else
01795                 {
01796                     FatalError("\n%s(%d) => No argument passed to "
01797                             "keyword \"%s\"\nMake sure you didn't forget a ':' "
01798                             "or the argument to this keyword!\n", file_name, 
01799                             file_line, option_name);
01800                 }
01801             }
01802             else if(!strcasecmp(option_name, "activated_by"))
01803             {
01804                 ONE_CHECK (one_activated_by, option_name);
01805                 if(num_opts == 2)
01806                 {
01807                     ParseActivatedBy(option_args);
01808                     dynamic_rules_present++;
01809                 }
01810                 else
01811                 {
01812                     FatalError("\n%s(%d) => No argument passed to "
01813                             "keyword \"%s\"\nMake sure you didn't forget a ':' "
01814                             "or the argument to this keyword!\n", file_name, 
01815                             file_line, opts[0]);
01816                 }
01817             }
01818             else if(!strcasecmp(option_name, "count"))
01819             {
01820                 ONE_CHECK (one_count, option_name);
01821                 if(num_opts == 2)
01822                 {
01823                     if(otn_tmp->type != RULE_DYNAMIC)
01824                         FatalError("The \"count\" option may only be used with "
01825                                 "the dynamic rule type!\n");
01826                     ParseCount(opts[1]);
01827                 }
01828                 else
01829                 {
01830                     FatalError("\n%s(%d) => No argument passed to "
01831                             "keyword \"%s\"\nMake sure you didn't forget a ':' "
01832                             "or the argument to this keyword!\n", file_name, 
01833                             file_line, opts[0]);
01834                 }
01835             }
01836             else if(!strcasecmp(option_name, "tag"))
01837             {
01838                 ONE_CHECK (one_tag, opts[0]);
01839                 if(num_opts == 2)
01840                 {
01841                     ParseTag(opts[1], otn_tmp);
01842                 }
01843                 else
01844                 {
01845                     FatalError("\n%s(%d) => No argument passed to "
01846                             "keyword \"%s\"\nMake sure you didn't forget a ':' "
01847                             "or the argument to this keyword!\n", file_name, 
01848                             file_line, opts[0]);
01849                 }
01850             }
01851             else if(!strcasecmp(option_name, "threshold"))
01852             {
01853                 ONE_CHECK (one_threshold, opts[0]);
01854                 if(num_opts == 2)
01855                 {
01856                     ParseThreshold2(&thdx, opts[1]);
01857                 }
01858                 else
01859                 {
01860                     FatalError("\n%s(%d) => No argument passed to "
01861                             "keyword \"%s\"\nMake sure you didn't forget a ':' "
01862                             "or the argument to this keyword!\n", file_name, 
01863                             file_line, opts[0]);
01864                 }
01865             }
01866             else if(!strcasecmp(option_name, "sid"))
01867             {
01868                 ONE_CHECK (one_sid, opts[0]);
01869                 if(num_opts == 2)
01870                 {
01871                     ParseSID(opts[1], otn_tmp);
01872                 }
01873                 else
01874                 {
01875                     FatalError("\n%s(%d) => No argument passed to "
01876                             "keyword \"%s\"\nMake sure you didn't forget a ':' "
01877                             "or the argument to this keyword!\n", file_name, 
01878                             file_line, opts[0]);
01879                 }
01880             }
01881             else if(!strcasecmp(option_name, "rev"))
01882             {
01883                 ONE_CHECK (one_rev, opts[0]);
01884                 if(num_opts == 2)
01885                 {
01886                     ParseRev(opts[1], otn_tmp);
01887                 }
01888                 else
01889                 {
01890                     FatalError("\n%s(%d) => No argument passed to "
01891                             "keyword \"%s\"\nMake sure you didn't forget a ':' "
01892                             "or the argument to this keyword!\n", file_name, 
01893                             file_line, opts[0]);
01894                 }
01895             }
01896             else if(!strcasecmp(option_name, "reference"))
01897             {
01898                 if(num_opts == 2)
01899                 {
01900                     ParseReference(opts[1], otn_tmp);
01901                 }
01902                 else
01903                 {
01904                     FatalError("\n%s(%d) => No argument passed to "
01905                             "keyword \"%s\"\nMake sure you didn't forget a ':' "
01906                             "or the argument to this keyword!\n", file_name, 
01907                             file_line, opts[0]);
01908                 }
01909             }
01910             else if(!strcasecmp(option_name, "priority"))
01911             {
01912                 ONE_CHECK (one_priority, opts[0]);
01913                 if(num_opts == 2)
01914                 {
01915                     ParsePriority(opts[1], otn_tmp);
01916                 }
01917                 else
01918                 {
01919                     FatalError("\n%s(%d) => No argument passed to "
01920                             "keyword \"%s\"\nMake sure you didn't forget a ':' "
01921                             "or the argument to this keyword!\n", file_name, 
01922                             file_line, opts[0]);
01923                 }
01924             }
01925             else if(!strcasecmp(option_name, "classtype"))
01926             {
01927                 ONE_CHECK (one_classtype, opts[0]);
01928                 if(num_opts == 2)
01929                 {
01930                     ParseClassType(opts[1], otn_tmp);
01931                 }
01932                 else
01933                 {
01934                     FatalError("\n%s(%d) => No argument passed to "
01935                             "keyword \"%s\"\nMake sure you didn't forget a ':' "
01936                             "or the argument to this keyword!\n", file_name, 
01937                             file_line, option_name);
01938                 }
01939             }
01940             else if(!strcasecmp(option_name, "stateless"))
01941             {
01942                 ONE_CHECK (one_stateless, opts[0]);
01943                 otn_tmp->stateless = 1;
01944             }
01945             else
01946             {
01947                 kw_idx = KeywordList;
01948                 found = 0;
01949 
01950                 while(kw_idx != NULL)
01951                 {
01952                     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "comparing: \"%s\" => \"%s\"\n", 
01953                         option_name, kw_idx->entry.keyword););
01954 
01955                     if(!strcasecmp(option_name, kw_idx->entry.keyword))
01956                     {
01957                         if(num_opts == 2) 
01958                         {
01959                             kw_idx->entry.func(option_args, otn_tmp, protocol);
01960                         } 
01961                         else 
01962                         {
01963                             kw_idx->entry.func(NULL, otn_tmp, protocol);
01964                         }
01965                         DEBUG_WRAP(DebugMessage(DEBUG_INIT, "%s->", kw_idx->entry.keyword););
01966                         found = 1;
01967                         break;
01968                     }
01969                     kw_idx = kw_idx->next;
01970                 }
01971 
01972                 if(!found)
01973                 {
01974                     /* Unrecognized rule option, complain */
01975                     FatalError("Warning: %s(%d) => Unknown keyword '%s' in "
01976                                "rule!\n", file_name, file_line, opts[0]);
01977                 }
01978             }
01979 
01980             mSplitFree(&opts,num_opts);
01981 
01982             --num_toks;
01983             i++;
01984         }
01985 
01986         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"OptListEnd\n"););
01987         AddOptFuncToList(OptListEnd, otn_tmp);
01988     }
01989     else
01990     {
01991         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"OptListEnd\n"););
01992         AddOptFuncToList(OptListEnd, otn_tmp);
01993     }
01994 
01995    if( one_threshold )
01996    {
01997        int rstat;
01998        thdx.sig_id = otn_tmp->sigInfo.id;
01999        thdx.gen_id = GENERATOR_SNORT_ENGINE;
02000        if( (rstat=sfthreshold_create( &thdx )) )
02001        {
02002               if( rstat == THD_TOO_MANY_THDOBJ )
02003           {
02004             FatalError("Rule-Threshold-Parse: could not create a threshold object -- only one per sid, sid = %u\n",thdx.sig_id);
02005           }
02006           else
02007           {
02008             FatalError("Unable to add Threshold object for Rule-sid =  %u\n",thdx.sig_id);
02009           }
02010        }
02011    }
02012    
02013     if(idx != NULL)
02014        mSplitFree(&toks,original_num_toks);
02015 }
02016 
02017 
02018 /****************************************************************************
02019  *
02020  * Function: RuleType(char *)
02021  *
02022  * Purpose:  Determine what type of rule is being processed and return its
02023  *           equivalent value
02024  *
02025  * Arguments: func => string containing the rule type
02026  *
02027  * Returns: The rule type designation
02028  *
02029  ***************************************************************************/
02030 int RuleType(char *func)
02031 {
02032     if(func == NULL)
02033     {
02034         FatalError("%s(%d) => NULL rule type\n", file_name, file_line);
02035     }
02036    
02037     if (!strcasecmp(func, "drop"))
02038         return RULE_DROP;
02039      
02040 #ifdef GIDS
02041     if (!strcasecmp(func, "sdrop"))
02042         return RULE_SDROP;
02043      
02044     if (!strcasecmp(func, "reject"))
02045         return RULE_REJECT;
02046 
02047     if (!strcasecmp(func, "rejectboth"))
02048         return RULE_REJECTBOTH;
02049 
02050     if (!strcasecmp(func, "rejectsrc"))
02051         return RULE_REJECTSRC;
02052 
02053     if (!strcasecmp(func, "rejectdst"))
02054         return RULE_REJECTDST;
02055 
02056 #ifdef IPFW
02057     if (!strcasecmp(func, "reinject"))
02058         return RULE_REINJECT;
02059 #endif /* IPFW */
02060 #endif /* GIDS */ 
02061      
02062     if(!strcasecmp(func, "log"))
02063         return RULE_LOG;
02064 
02065     if(!strcasecmp(func, "alert"))
02066         return RULE_ALERT;
02067 
02068     if(!strcasecmp(func, "pass"))
02069         return RULE_PASS;
02070 
02071     if(!strcasecmp(func, "var"))
02072         return RULE_VAR;
02073 
02074     if(!strcasecmp(func, "include"))
02075         return RULE_INCLUDE;
02076 
02077     if(!strcasecmp(func, "preprocessor"))
02078         return RULE_PREPROCESS;
02079 
02080     if(!strcasecmp(func, "output"))
02081         return RULE_OUTPUT;
02082 
02083     if(!strcasecmp(func, "activate"))
02084         return RULE_ACTIVATE;
02085 
02086     if(!strcasecmp(func, "dynamic"))
02087         return RULE_DYNAMIC;
02088 
02089     if(!strcasecmp(func, "config"))
02090         return RULE_CONFIG;
02091 
02092     if(!strcasecmp(func, "ruletype"))
02093         return RULE_DECLARE;
02094     
02095     if(!strcasecmp(func, "threshold"))
02096         return RULE_THRESHOLD;
02097     
02098     if(!strcasecmp(func, "suppress"))
02099         return RULE_SUPPRESS;
02100 
02101     return RULE_UNKNOWN;
02102 }
02103 
02104 
02105 
02106 /****************************************************************************
02107  *
02108  * Function: WhichProto(char *)
02109  *
02110  * Purpose: Figure out which protocol the current rule is talking about
02111  *
02112  * Arguments: proto_str => the protocol string
02113  *
02114  * Returns: The integer value of the protocol
02115  *
02116  ***************************************************************************/
02117 int WhichProto(char *proto_str)
02118 {
02119     if(!strcasecmp(proto_str, "tcp"))
02120         return IPPROTO_TCP;
02121 
02122     if(!strcasecmp(proto_str, "udp"))
02123         return IPPROTO_UDP;
02124 
02125     if(!strcasecmp(proto_str, "icmp"))
02126         return IPPROTO_ICMP;
02127 
02128     if(!strcasecmp(proto_str, "ip"))
02129         return ETHERNET_TYPE_IP;
02130 
02131     if(!strcasecmp(proto_str, "arp"))
02132         return ETHERNET_TYPE_ARP;
02133 
02134     /*
02135      * if we've gotten here, we have a protocol string we din't recognize and
02136      * should exit
02137      */
02138     FatalError("%s(%d) => Bad protocol: %s\n", file_name, file_line, proto_str);
02139 
02140     return 0;
02141 }
02142 
02143 
02144 
02145 int ProcessIP(char *addr, RuleTreeNode *rtn, int mode)
02146 {
02147     char **toks = NULL;
02148     int num_toks;
02149     int i;
02150     IpAddrSet *tmp_addr;
02151     char *tmp;
02152     char *enbracket;
02153 
02154     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Got address string: %s\n", 
02155                 addr););
02156 
02157     if(*addr == '!')
02158     {
02159         switch(mode)
02160         {
02161             case SRC:
02162                 rtn->flags |= EXCEPT_SRC_IP;
02163                 break;
02164 
02165             case DST:
02166                 rtn->flags |= EXCEPT_DST_IP;
02167                 break;
02168         }
02169 
02170         addr++;
02171     }
02172 
02173     if(*addr == '$')
02174     {
02175         if((tmp = VarGet(addr + 1)) == NULL)
02176         {
02177             FatalError("%s(%d) => Undefined variable %s\n", file_name, 
02178                     file_line, addr);
02179         }
02180     }
02181     else
02182     {
02183         tmp = addr;
02184     }
02185 
02186     /* check to see if the first char is a 
02187      * bracket, which signifies a list 
02188      */
02189     if(*tmp == '[')
02190     {
02191         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Found IP list!\n"););
02192 
02193         /* *(tmp+strlen(tmp)) = ' ';*/
02194         enbracket = strrchr(tmp, (int)']'); /* null out the en-bracket */
02195         if(enbracket) 
02196             *enbracket = '\x0';
02197         else
02198             FatalError("%s(%d) => Unterminated IP List\n", file_name, file_line);
02199 
02200         toks = mSplit(tmp+1, ",", 128, &num_toks, 0);
02201 
02202         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"mSplit got %d tokens...\n", 
02203                     num_toks););
02204 
02205         for(i=0; i< num_toks; i++)
02206         {
02207             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"adding %s to IP "
02208                         "address list\n", toks[i]););
02209             tmp = toks[i];
02210             while (isspace((int)*tmp)||*tmp=='[') tmp++;
02211             enbracket = strrchr(tmp, (int)']'); /* null out the en-bracket */
02212             if(enbracket) 
02213                 *enbracket = '\x0';
02214 
02215             if (strlen(tmp) == 0)
02216                 continue;
02217                 
02218             tmp_addr = AllocAddrNode(rtn, mode); 
02219             ParseIP(tmp, tmp_addr);
02220             if(tmp_addr->ip_addr == 0 && tmp_addr->netmask == 0)
02221             {
02222                 switch(mode)
02223                 {
02224                     case SRC:
02225                         rtn->flags |= ANY_SRC_IP;
02226                         break;
02227 
02228                     case DST:
02229                         rtn->flags |= ANY_DST_IP;
02230                         break;
02231                 }
02232             }
02233         }
02234 
02235         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "Freeing %d tokens...\n", 
02236                     num_toks););
02237 
02238         mSplitFree(&toks, num_toks);
02239     }
02240     else
02241     {
02242         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,
02243                     "regular IP address, processing...\n"););
02244         tmp_addr = AllocAddrNode(rtn, mode);
02245         ParseIP(tmp, tmp_addr);
02246         if(tmp_addr->ip_addr == 0 && tmp_addr->netmask == 0)
02247         {
02248             switch(mode)
02249             {
02250                 case SRC:
02251                     rtn->flags |= ANY_SRC_IP;
02252                     break;
02253 
02254                 case DST:
02255                     rtn->flags |= ANY_DST_IP;
02256                     break;
02257             }
02258         }
02259     }
02260 
02261     return 0;
02262 }
02263 
02264 
02265 
02266 IpAddrSet *AllocAddrNode(RuleTreeNode *rtn, int mode)
02267 {
02268     IpAddrSet *idx; /* indexing pointer */
02269 
02270     switch(mode)
02271     {
02272         case SRC:
02273             if(rtn->sip == NULL)
02274             {
02275                 rtn->sip = (IpAddrSet *)calloc(sizeof(IpAddrSet), sizeof(char));
02276                 if(rtn->sip == NULL)
02277                 {
02278                     FatalError(" Unable to allocate node for IP list\n");
02279                 }
02280                 return rtn->sip;
02281             }
02282             else
02283             {
02284                 idx = rtn->sip;
02285 
02286                 while(idx->next != NULL)
02287                 {
02288                     idx = idx->next;
02289                 }
02290 
02291                 idx->next = (IpAddrSet *)calloc(sizeof(IpAddrSet), sizeof(char));
02292                 if(idx->next == NULL)
02293                 {
02294                     FatalError(" Unable to allocate node for IP list\n");
02295                 }
02296                 return idx->next;
02297             }
02298 
02299 
02300         case DST:
02301             if(rtn->dip == NULL)
02302             {
02303                 rtn->dip = (IpAddrSet *)calloc(sizeof(IpAddrSet), sizeof(char));
02304                 if(rtn->dip == NULL)
02305                 {
02306                     FatalError(" Unable to allocate node for IP list\n");
02307                 }
02308                 return rtn->dip;
02309             }
02310             else
02311             {
02312                 idx = rtn->dip;
02313 
02314                 while(idx->next)
02315                 {
02316                     idx = idx->next;
02317                 }
02318 
02319                 idx->next = (IpAddrSet *)calloc(sizeof(IpAddrSet), sizeof(char));
02320                 if(idx->next == NULL)
02321                 {
02322                     FatalError(" Unable to allocate node for IP list\n");
02323                 }
02324                 return idx->next;
02325             }
02326     }
02327 
02328     return NULL;
02329 }
02330 
02331 /****************************************************************************
02332  *
02333  * Function: ParsePort(char *, u_short *)
02334  *
02335  * Purpose:  Convert the port string over to an integer value
02336  *
02337  * Arguments: prule_port => port rule string
02338  *            port => converted integer value of the port
02339  *
02340  * Returns: 0 for a normal port number, 1 for an "any" port
02341  *
02342  ***************************************************************************/
02343 int ParsePort(char *prule_port, u_short * hi_port, u_short * lo_port, char *proto, int *not_flag)
02344 {
02345     char **toks;        /* token dbl buffer */
02346     int num_toks;       /* number of tokens found by mSplit() */
02347     char *rule_port;    /* port string */
02348 
02349     *not_flag = 0;
02350 
02351     /* check for variable */
02352     if(!strncmp(prule_port, "$", 1))
02353     {
02354         if((rule_port = VarGet(prule_port + 1)) == NULL)
02355         {
02356             FatalError("%s(%d) => Undefined variable %s\n", file_name, file_line, prule_port);
02357         }
02358     }
02359     else
02360         rule_port = prule_port;
02361 
02362     if(rule_port[0] == '(')
02363     {
02364         /* user forgot to put a port number in for this rule */
02365         FatalError("%s(%d) => Bad port number: \"%s\"\n", 
02366                    file_name, file_line, rule_port);
02367     }
02368 
02369 
02370     /* check for wildcards */
02371     if(!strcasecmp(rule_port, "any"))
02372     {
02373         *hi_port = 0;
02374         *lo_port = 0;
02375         return 1;
02376     }
02377 
02378     if(rule_port[0] == '!')
02379     {
02380         *not_flag = 1;
02381         rule_port++;
02382     }
02383 
02384     if(rule_port[0] == ':')
02385     {
02386         *lo_port = 0;
02387     }
02388 
02389     toks = mSplit(rule_port, ":", 2, &num_toks, 0);
02390 
02391     switch(num_toks)
02392     {
02393         case 1:
02394             *hi_port = ConvPort(toks[0], proto);
02395 
02396             if(rule_port[0] == ':')
02397             {
02398                 *lo_port = 0;
02399             }
02400             else
02401             {
02402                 *lo_port = *hi_port;
02403 
02404                 if(index(rule_port, ':') != NULL)
02405                 {
02406                     *hi_port = 65535;
02407                 }
02408             }
02409 
02410             break;
02411 
02412         case 2:
02413             *lo_port = ConvPort(toks[0], proto);
02414 
02415             if(toks[1][0] == 0)
02416                 *hi_port = 65535;
02417             else
02418                 *hi_port = ConvPort(toks[1], proto);
02419 
02420             break;
02421 
02422         default:
02423             FatalError("%s(%d) => port conversion failed on \"%s\"\n",
02424                        file_name, file_line, rule_port);
02425     }
02426 
02427     mSplitFree(&toks, num_toks);
02428 
02429     return 0;
02430 }
02431 
02432 
02433 /****************************************************************************
02434  *
02435  * Function: ConvPort(char *, char *)
02436  *
02437  * Purpose:  Convert the port string over to an integer value
02438  *
02439  * Arguments: port => port string
02440  *            proto => converted integer value of the port
02441  *
02442  * Returns:  the port number
02443  *
02444  ***************************************************************************/
02445 int ConvPort(char *port, char *proto)
02446 {
02447     int conv;           /* storage for the converted number */
02448     char *digit;      /* used to check for a number */
02449     struct servent *service_info;
02450 
02451     /*
02452      * convert a "word port" (http, ftp, imap, whatever) to its corresponding
02453      * numeric port value
02454      */
02455     if(isalpha((int) port[0]) != 0)
02456     {
02457         service_info = getservbyname(port, proto);
02458 
02459         if(service_info != NULL)
02460         {
02461             conv = ntohs(service_info->s_port);
02462             return conv;
02463         }
02464         else
02465         {
02466             FatalError("%s(%d) => getservbyname() failed on \"%s\"\n",
02467                        file_name, file_line, port);
02468         }
02469     }
02470     digit = port;
02471     while (*digit) {
02472 
02473         if(!isdigit((int) *digit))
02474         {
02475             FatalError("%s(%d) => Invalid port: %s\n", file_name,
02476                        file_line, port);
02477         }
02478         digit++;
02479     }
02480     /* convert the value */
02481     conv = atoi(port);
02482 
02483     /* make sure it's in bounds */
02484     if((conv >= 0) && (conv < 65536))
02485     {
02486         return conv;
02487     }
02488     else
02489     {
02490         FatalError("%s(%d) => bad port number: %s\n", file_name,
02491                    file_line, port);
02492     }
02493 
02494     return 0;
02495 }
02496 
02497 
02498 
02499 /****************************************************************************
02500  *
02501  * Function: ParseMessage(char *)
02502  *
02503  * Purpose: Stuff the alert message onto the rule
02504  *
02505  * Arguments: msg => the msg string
02506  *
02507  * Returns: void function
02508  *
02509  ***************************************************************************/
02510 void ParseMessage(char *msg)
02511 {
02512     char *ptr;
02513     char *end;
02514     int size;
02515     int count = 0;
02516     char *read;
02517     char *write;
02518 
02519     /* figure out where the message starts */
02520     ptr = index(msg, '"');
02521 
02522     if(ptr == NULL)
02523     {
02524         ptr = msg;
02525     }
02526     else
02527         ptr++;
02528 
02529     end = index(ptr, '"');
02530 
02531     if(end != NULL)
02532         *end = 0;
02533 
02534     while(isspace((int) *ptr))
02535         ptr++;
02536 
02537 
02538     read = write = ptr;
02539 
02540     while(read < end)
02541     {
02542         if(*read == '\\')
02543         {
02544             read++;
02545             count++;
02546 
02547             if(read >= end)
02548             {
02549                 break;
02550             }
02551         }
02552 
02553         *write++ = *read++;
02554     }
02555 
02556     if(end)
02557     {
02558         *(end - count) = '\x0';
02559     }
02560 
02561     /* find the end of the alert string */
02562     size = strlen(msg) + 1;
02563     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "Message: %s\n", msg););
02564 
02565     /* alloc space for the string and put it in the rule */
02566     if(size > 0)
02567     {
02568         otn_tmp->sigInfo.message = strdup(ptr);
02569 
02570         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "Rule message set to: %s\n", 
02571                 otn_tmp->sigInfo.message););
02572 
02573     }
02574     else
02575     {
02576         ErrorMessage("%s(%d): bad alert message size %d\n", file_name, 
02577                      file_line, size);
02578     }
02579 
02580     return;
02581 }
02582 
02583 
02584 
02585 /****************************************************************************
02586  *
02587  * Function: ParseLogto(char *)
02588  *
02589  * Purpose: stuff the special log filename onto the proper rule option
02590  *
02591  * Arguments: filename => the file name
02592  *
02593  * Returns: void function
02594  *
02595  ***************************************************************************/
02596 void ParseLogto(char *filename)
02597 {
02598     char *sptr;
02599     char *eptr;
02600 
02601     /* grab everything between the starting " and the end one */
02602     sptr = index(filename, '"');
02603     eptr = strrchr(filename, '"');
02604 
02605     if(sptr != NULL && eptr != NULL)
02606     {
02607         /* increment past the first quote */
02608         sptr++;
02609 
02610         /* zero out the second one */
02611         *eptr = 0;
02612     }
02613     else
02614     {
02615         sptr = filename;
02616     }
02617 
02618     /* malloc up a nice shiny clean buffer */
02619     otn_tmp->logto = (char *) calloc(strlen(sptr) + 1, sizeof(char));
02620 
02621     bzero((char *) otn_tmp->logto, strlen(sptr) + 1);
02622 
02623     strncpy(otn_tmp->logto, sptr, strlen(sptr)+1);
02624 
02625     return;
02626 }
02627 
02628 
02629 
02630 
02631 /****************************************************************************
02632  *
02633  * Function: ParseActivates(char *)
02634  *
02635  * Purpose: Set an activation link record
02636  *
02637  * Arguments: act_num => rule number to be activated
02638  *
02639  * Returns: void function
02640  *
02641  ****************************************************************************/
02642 void ParseActivates(char *act_num)
02643 {
02644     /*
02645      * allocate a new node on the RTN get rid of whitespace at the front of
02646      * the list
02647      */
02648     while(!isdigit((int) *act_num))
02649         act_num++;
02650 
02651     otn_tmp->activates = atoi(act_num);
02652 
02653     return;
02654 }
02655 
02656 
02657 
02658 
02659 /****************************************************************************
02660  *
02661  * Function: ParseActivatedBy(char *)
02662  *
02663  * Purpose: Set an activation link record
02664  *
02665  * Arguments: act_by => rule number to be activated
02666  *
02667  * Returns: void function
02668  *
02669  ****************************************************************************/
02670 void ParseActivatedBy(char *act_by)
02671 {
02672     ActivateList *al_ptr;
02673 
02674     al_ptr = rtn_tmp->activate_list;
02675 
02676     if(al_ptr == NULL)
02677     {
02678         rtn_tmp->activate_list = (ActivateList *) calloc(sizeof(ActivateList), sizeof(char));
02679 
02680         if(rtn_tmp->activate_list == NULL)
02681         {
02682             FatalError("ParseActivatedBy() calloc failed: %s\n", strerror(errno));
02683         }
02684 
02685         al_ptr = rtn_tmp->activate_list;
02686     }
02687     else
02688     {
02689         while(al_ptr->next != NULL)
02690         {
02691             al_ptr = al_ptr->next;
02692         }
02693 
02694         al_ptr->next = (ActivateList *) calloc(sizeof(ActivateList), sizeof(char));
02695 
02696         al_ptr = al_ptr->next;
02697 
02698         if(al_ptr == NULL)
02699         {
02700             FatalError("ParseActivatedBy() calloc failed: %s\n", strerror(errno));
02701         }
02702     }
02703 
02704     /* get rid of whitespace at the front of the list */
02705     while(!isdigit((int) *act_by))
02706         act_by++;
02707 
02708     /* set the RTN list node number */
02709     al_ptr->activated_by = atoi(act_by);
02710 
02711     /* set the OTN list node number */
02712     otn_tmp->activated_by = atoi(act_by);
02713 
02714     return;
02715 }
02716 
02717 
02718 
02719 void ParseCount(char *num)
02720 {
02721     while(!isdigit((int) *num))
02722         num++;
02723 
02724     otn_tmp->activation_counter = atoi(num);
02725 
02726     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Set activation counter to %d\n", otn_tmp->activation_counter););
02727 
02728     return;
02729 }
02730 
02731 
02732 
02733 
02734 /****************************************************************************
02735  *
02736  * Function: XferHeader(RuleTreeNode *, RuleTreeNode *)
02737  *
02738  * Purpose: Transfer the rule block header data from point A to point B
02739  *
02740  * Arguments: rule => the place to xfer from
02741  *            rtn => the place to xfer to
02742  *
02743  * Returns: void function
02744  *
02745  ***************************************************************************/
02746 void XferHeader(RuleTreeNode * rule, RuleTreeNode * rtn)
02747 {
02748     rtn->type = rule->type;
02749     rtn->sip = rule->sip;
02750     rtn->dip = rule->dip;
02751     rtn->hsp = rule->hsp;
02752     rtn->lsp = rule->lsp;
02753     rtn->hdp = rule->hdp;
02754     rtn->ldp = rule->ldp;
02755     rtn->flags = rule->flags;
02756     rtn->not_sp_flag = rule->not_sp_flag;
02757     rtn->not_dp_flag = rule->not_dp_flag;
02758 }
02759 
02760 
02761 
02762 /****************************************************************************
02763  *
02764  * Function: TestHeader(RuleTreeNode *, RuleTreeNode *)
02765  *
02766  * Purpose: Check to see if the two header blocks are identical
02767  *
02768  * Arguments: rule => uh
02769  *            rtn  => uuuuhhhhh....
02770  *
02771  * Returns: 1 if they match, 0 if they don't
02772  *
02773  ***************************************************************************/
02774 int TestHeader(RuleTreeNode * rule, RuleTreeNode * rtn)
02775 {
02776     IpAddrSet *rule_idx;  /* ip struct indexer */
02777     IpAddrSet *rtn_idx;   /* ip struct indexer */
02778 
02779     rtn_idx = rtn->sip;
02780     for(rule_idx = rule->sip; rule_idx != NULL; rule_idx = rule_idx->next)
02781     {
02782         if(rtn_idx && (rtn_idx->ip_addr == rule_idx->ip_addr) &&
02783                 (rtn_idx->netmask == rule_idx->netmask) &&
02784                 (rtn_idx->addr_flags == rule_idx->addr_flags))
02785         {
02786             rtn_idx = rtn_idx->next;
02787         }
02788         else
02789         {
02790             return 0;
02791         }
02792     }
02793 
02794     rtn_idx = rtn->dip;
02795     for(rule_idx = rule->dip ; rule_idx != NULL; rule_idx = rule_idx->next)
02796     {
02797         if(rtn_idx && (rtn_idx->ip_addr == rule_idx->ip_addr) &&
02798                 (rtn_idx->netmask == rule_idx->netmask) &&
02799                 (rtn_idx->addr_flags == rule_idx->addr_flags))
02800         {
02801             rtn_idx = rtn_idx->next;
02802         }
02803         else
02804         {
02805             return 0;
02806         }
02807     }
02808 
02809     if(rtn->hsp == rule->hsp)
02810     {
02811         if(rtn->lsp == rule->lsp)
02812         {
02813             if(rtn->hdp == rule->hdp)
02814             {
02815                 if(rtn->ldp == rule->ldp)
02816                 {
02817                     if(rtn->flags == rule->flags)
02818                     {
02819                         return 1;
02820                     }
02821                 }
02822             }
02823         }
02824     }
02825     return 0;
02826 }
02827 
02828 
02829 /****************************************************************************
02830  *
02831  * Function: VarAlloc()
02832  *
02833  * Purpose: allocates memory for a variable
02834  *
02835  * Arguments: none
02836  *
02837  * Returns: pointer to new VarEntry
02838  *
02839  ***************************************************************************/
02840 struct VarEntry *VarAlloc()
02841 {
02842     struct VarEntry *new;
02843 
02844     if((new = (struct VarEntry *) calloc(sizeof(struct VarEntry), sizeof(char))) == NULL)
02845     {
02846         FatalError("cannot allocate memory for VarEntry.");
02847     }
02848 
02849     return(new);
02850 }
02851 
02852 /****************************************************************************
02853  *
02854  * Function: VarDefine(char *, char *)
02855  *
02856  * Purpose: define the contents of a variable
02857  *
02858  * Arguments: name => the name of the variable
02859  *            value => the contents of the variable
02860  *
02861  * Returns: void function
02862  *
02863  ***************************************************************************/
02864 struct VarEntry *VarDefine(char *name, char *value)
02865 {
02866     struct VarEntry *p;
02867 
02868     if(value == NULL)
02869     {
02870         FatalError("%s(%d):  Bad value in variable definition!\n"
02871                    "Make sure you don't have a \"$\" in the var name\n",
02872                    file_name, file_line);
02873     }
02874 
02875     if(!VarHead)
02876     {
02877         p = VarAlloc();
02878         p->name = strdup(name);
02879         p->value = strdup(value);
02880         p->prev = p;
02881         p->next = p;
02882 
02883         VarHead = p;
02884 
02885         return p;
02886     }
02887     p = VarHead;
02888 
02889     do
02890     {
02891         if(strcasecmp(p->name, name) == 0)
02892         {
02893         if (!(p->flags & VAR_STATIC))
02894             {
02895                 if( p->value )
02896                     free(p->value);
02897                 
02898                 p->value = strdup(value);
02899             }
02900         return (p);
02901         }
02902         p = p->next;
02903 
02904     } while(p != VarHead);
02905 
02906     p = VarAlloc();
02907     p->name = strdup(name);
02908     p->value = strdup(value);
02909     p->prev = VarHead;
02910     p->next = VarHead->next;
02911     p->next->prev = p;
02912     VarHead->next = p;
02913     
02914     return p;
02915 }
02916 
02917 
02918 /****************************************************************************
02919  *
02920  * Function: VarDelete(char *)
02921  *
02922  * Purpose: deletes a defined variable
02923  *
02924  * Arguments: name => the name of the variable
02925  *
02926  * Returns: void function
02927  *
02928  ***************************************************************************/
02929 void VarDelete(char *name)
02930 {
02931     struct VarEntry *p;
02932 
02933 
02934     if(!VarHead)
02935         return;
02936 
02937     p = VarHead;
02938 
02939     do
02940     {
02941         if(strcasecmp(p->name, name) == 0)
02942         {
02943             p->prev->next = p->next;
02944             p->next->prev = p->prev;
02945 
02946             if(VarHead == p)
02947                 if((VarHead = p->next) == p)
02948                     VarHead = NULL;
02949 
02950             if(p->name)
02951                 free(p->name);
02952 
02953             if(p->value)
02954                 free(p->value);
02955 
02956             free(p);
02957 
02958             return;
02959         }
02960         p = p->next;
02961 
02962     } while(p != VarHead);
02963 }
02964 
02965 
02966 /****************************************************************************
02967  *
02968  * Function: VarGet(char *)
02969  *
02970  * Purpose: get the contents of a variable
02971  *
02972  * Arguments: name => the name of the variable
02973  *
02974  * Returns: char * to contents of variable or FatalErrors on an
02975  *          undefined variable name
02976  *
02977  ***************************************************************************/
02978 char *VarGet(char *name)
02979 {
02980     struct VarEntry *p;
02981 
02982 
02983     if(VarHead)
02984     {
02985         p = VarHead;
02986 
02987         do
02988         {
02989             if(strcasecmp(p->name, name) == 0)
02990                 return(p->value);
02991 
02992             p = p->next;
02993 
02994         } while(p != VarHead);
02995     }
02996 
02997     FatalError("Undefined variable name: (%s:%d): %s\n", 
02998                file_name, file_line, name);
02999     
03000     
03001     return NULL;
03002 }
03003 
03004 /****************************************************************************
03005  *
03006  * Function: ExpandVars(char *)
03007  *
03008  * Purpose: expand all variables in a string
03009  *
03010  * Arguments: string => the name of the variable
03011  *
03012  * Returns: char * to the expanded string
03013  *
03014  ***************************************************************************/
03015 char *ExpandVars(char *string)
03016 {
03017     static char estring[PARSERULE_SIZE];
03018     char rawvarname[128], varname[128], varaux[128], varbuffer[128], varmodifier, *varcontents;
03019     int varname_completed, c, i, j, iv, jv, l_string, name_only;
03020     int quote_toggle = 0;
03021 
03022     if(!string || !*string || !strchr(string, '$'))
03023         return(string);
03024 
03025     bzero((char *) estring, sizeof(estring));
03026 
03027     i = j = 0;
03028     l_string = strlen(string);
03029     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "ExpandVars, Before: %s\n", string););
03030 
03031     while(i < l_string && j < sizeof(estring) - 1)
03032     {
03033         c = string[i++];
03034         
03035         if(c == '"')
03036         {
03037             /* added checks to make sure that we are inside a quoted string
03038              */
03039             quote_toggle ^= 1;
03040         }
03041 
03042         if(c == '$' && !quote_toggle)
03043         {
03044             bzero((char *) rawvarname, sizeof(rawvarname));
03045             varname_completed = 0;
03046             name_only = 1;
03047             iv = i;
03048             jv = 0;
03049 
03050             if(string[i] == '(')
03051             {
03052                 name_only = 0;
03053                 iv = i + 1;
03054             }
03055 
03056             while(!varname_completed
03057                   && iv < l_string
03058                   && jv < sizeof(rawvarname) - 1)
03059             {
03060                 c = string[iv++];
03061 
03062                 if((name_only && !(isalnum(c) || c == '_'))
03063                    || (!name_only && c == ')'))
03064                 {
03065                     varname_completed = 1;
03066 
03067                     if(name_only)
03068                         iv--;
03069                 }
03070                 else
03071                 {
03072                     rawvarname[jv++] = c;
03073                 }
03074             }
03075 
03076             if(varname_completed || iv == l_string)
03077             {
03078                 char *p;
03079 
03080                 i = iv;
03081 
03082                 varcontents = NULL;
03083 
03084                 bzero((char *) varname, sizeof(varname));
03085                 bzero((char *) varaux, sizeof(varaux));
03086                 varmodifier = ' ';
03087 
03088                 if((p = strchr(rawvarname, ':')))
03089                 {
03090                     strncpy(varname, rawvarname, p - rawvarname);
03091 
03092                     if(strlen(p) >= 2)
03093                     {
03094                         varmodifier = *(p + 1);
03095                         strcpy(varaux, p + 2);
03096                     }
03097                 }
03098                 else
03099                     strcpy(varname, rawvarname);
03100 
03101                 bzero((char *) varbuffer, sizeof(varbuffer));
03102 
03103                 varcontents = VarGet(varname);
03104 
03105                 switch(varmodifier)
03106                 {
03107                     case '-':
03108                         if(!varcontents || !strlen(varcontents))
03109                             varcontents = varaux;
03110                         break;
03111 
03112                     case '?':
03113                         if(!varcontents || !strlen(varcontents))
03114                         {
03115                             ErrorMessage("%s(%d): ", file_name, file_line);
03116 
03117                             if(strlen(varaux))
03118                                 FatalError("%s\n", varaux);
03119                             else
03120                                 FatalError("Undefined variable \"%s\"\n", varname);
03121                         }
03122                         break;
03123                 }
03124 
03125                 if(varcontents)
03126                 {
03127                     int l_varcontents = strlen(varcontents);
03128 
03129                     iv = 0;
03130 
03131                     while(iv < l_varcontents && j < sizeof(estring) - 1)
03132                         estring[j++] = varcontents[iv++];
03133                 }
03134             }
03135             else
03136             {
03137                 estring[j++] = '$';
03138             }
03139         }
03140         else
03141         {
03142             estring[j++] = c;
03143         }
03144     }
03145 
03146     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "ExpandVars, After: %s\n", estring););
03147 
03148     return(estring);
03149 }
03150 
03151 
03152 
03153 /******************************************************************
03154  *
03155  * Function: LinkDynamicRules()
03156  *
03157  * Purpose: Move through the activation and dynamic lists and link
03158  *          the activation rules to the rules that they activate.
03159  *
03160  * Arguments: None
03161  *
03162  * Returns: void function
03163  *
03164  ******************************************************************/
03165 void LinkDynamicRules()
03166 {
03167     SetLinks(Activation.TcpList, Dynamic.TcpList);
03168     SetLinks(Activation.UdpList, Dynamic.UdpList);
03169     SetLinks(Activation.IcmpList, Dynamic.IcmpList);
03170 }
03171 
03172 
03173 
03174 
03175 /******************************************************************
03176  *
03177  * Function: SetLinks()
03178  *
03179  * Purpose: Move through the activation and dynamic lists and link
03180  *          the activation rules to the rules that they activate.
03181  *
03182  * Arguments: activator => the activation rules
03183  *            activatee => the rules being activated
03184  *
03185  * Returns: void function
03186  *
03187  ******************************************************************/
03188 void SetLinks(RuleTreeNode * activator, RuleTreeNode * activated_by)
03189 {
03190     RuleTreeNode *act_idx;
03191     RuleTreeNode *dyn_idx;
03192     OptTreeNode *act_otn_idx;
03193 
03194     act_idx = activator;
03195     dyn_idx = activated_by;
03196 
03197     /* walk thru the RTN list */
03198     while(act_idx != NULL)
03199     {
03200         if(act_idx->down != NULL)
03201         {
03202             act_otn_idx = act_idx->down;
03203 
03204             while(act_otn_idx != NULL)
03205             {
03206                 act_otn_idx->RTN_activation_ptr = GetDynamicRTN(act_otn_idx->activates, dyn_idx);
03207 
03208                 if(act_otn_idx->RTN_activation_ptr != NULL)
03209                 {
03210                     act_otn_idx->OTN_activation_ptr = GetDynamicOTN(act_otn_idx->activates, act_otn_idx->RTN_activation_ptr);
03211                 }
03212                 act_otn_idx = act_otn_idx->next;
03213             }
03214         }
03215         act_idx = act_idx->right;
03216     }
03217 }
03218 
03219 
03220 
03221 RuleTreeNode *GetDynamicRTN(int link_number, RuleTreeNode * dynamic_rule_tree)
03222 {
03223     RuleTreeNode *rtn_idx;
03224     ActivateList *act_list;
03225 
03226     rtn_idx = dynamic_rule_tree;
03227 
03228     while(rtn_idx != NULL)
03229     {
03230         act_list = rtn_idx->activate_list;
03231 
03232         while(act_list != NULL)
03233         {
03234             if(act_list->activated_by == link_number)
03235             {
03236                 return rtn_idx;
03237             }
03238             act_list = act_list->next;
03239         }
03240 
03241         rtn_idx = rtn_idx->right;
03242     }
03243 
03244     return NULL;
03245 }
03246 
03247 
03248 
03249 
03250 OptTreeNode *GetDynamicOTN(int link_number, RuleTreeNode * dynamic_rule_tree)
03251 {
03252     OptTreeNode *otn_idx;
03253 
03254     otn_idx = dynamic_rule_tree->down;
03255 
03256     while(otn_idx != NULL)
03257     {
03258         if(otn_idx->activated_by == link_number)
03259         {
03260             return otn_idx;
03261         }
03262         otn_idx = otn_idx->next;
03263     }
03264 
03265     return NULL;
03266 }
03267 
03268 
03269 /****************************************************************************
03270  *
03271  * Function: ProcessAlertFileOption(char *)
03272  *
03273  * Purpose: define the alert file
03274  *
03275  * Arguments: filespec => the file specification
03276  *
03277  * Returns: void function
03278  *
03279  ***************************************************************************/
03280 void ProcessAlertFileOption(char *filespec)
03281 {
03282     pv.alert_filename = ProcessFileOption(filespec);
03283 
03284     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"alertfile set to: %s\n", 
03285                 pv.alert_filename););
03286     return;
03287 }
03288 
03289 char *ProcessFileOption(char *filespec)
03290 {
03291     char *filename;
03292     char buffer[STD_BUF];
03293 
03294     if(filespec == NULL)
03295     {
03296         FatalError("no arguement in this file option, remove extra ':' at the end of the alert option\n");
03297     }
03298 
03299     /* look for ".." in the string and complain and exit if it is found */
03300     if(strstr(filespec, "..") != NULL)
03301     {
03302         FatalError("file definition contains \"..\".  Do not do that!\n");
03303     }
03304 
03305     if(filespec[0] == '/')
03306     {
03307         /* absolute filespecs are saved as is */
03308         filename = strdup(filespec);
03309     }
03310     else
03311     {
03312         /* relative filespec is considered relative to the log directory */
03313         /* or /var/log if the log directory has not been set */
03314         if(pv.log_dir)
03315         {
03316             strlcpy(buffer, pv.log_dir, STD_BUF);
03317         }
03318         else
03319         {
03320             strlcpy(buffer, "/var/log/snort", STD_BUF);
03321         }
03322 
03323         strlcat(buffer, "/", STD_BUF - strlen(buffer));
03324         strlcat(buffer, filespec, STD_BUF - strlen(buffer));
03325         filename = strdup(buffer);
03326     }
03327 
03328     if(!pv.quiet_flag)
03329         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"ProcessFileOption: %s\n", filename););
03330 
03331     return filename;
03332 }
03333 
03334 void ProcessFlowbitsSize(char **args, int nargs)
03335 {
03336     int i;
03337     char *pcEnd;
03338 
03339     if(nargs)
03340     {
03341         i = strtol(args[0], &pcEnd, 10);
03342         if(*pcEnd || i < 0 || i > 256)
03343         {
03344             FatalError("%s(%d) => Invalid argument to 'flowbits_size'.  "  
03345                        "Must be a positive integer and less than 256.\n",
03346                        file_name, file_line);
03347         }
03348         
03349         giFlowbitSize = (unsigned int)i;
03350     }
03351 
03352     return;
03353 }
03354 
03355 void ProcessEventQueue(char **args, int nargs)
03356 {
03357     int iCtr;
03358 
03359     for(iCtr = 0; iCtr < nargs; iCtr++)
03360     {
03361         if(!strcasecmp("max_queue", args[iCtr]))
03362         {
03363             iCtr++;
03364             if(iCtr < nargs)
03365             {
03366                 g_event_queue.max_events = atoi(args[iCtr]);
03367                 if(g_event_queue.max_events <= 0)
03368                 {
03369                     FatalError("%s(%d) => Invalid argument to 'max_queue'.  "
03370                                "Must be a positive integer.\n", file_name,
03371                                file_line);
03372                 }
03373             }
03374             else
03375             {
03376                 FatalError("%s(%d) => No argument to 'max_queue'.  "
03377                            "Argument must be a positive integer.\n",
03378                            file_name, file_line);
03379             }
03380         }
03381         else if(!strcasecmp("log", args[iCtr]))
03382         {
03383             iCtr++;
03384             if(iCtr < nargs)
03385             {
03386                 g_event_queue.log_events = atoi(args[iCtr]);
03387                 if(g_event_queue.log_events <= 0)
03388                 {
03389                     FatalError("%s(%d) => Invalid argument to 'log'.  "
03390                                "Must be a positive integer.\n", file_name,
03391                                file_line);
03392                 }
03393             }
03394             else
03395             {
03396                 FatalError("%s(%d) => No argument to 'log'.  "
03397                            "Argument must be a positive integer.\n",
03398                            file_name, file_line);
03399             }
03400         }
03401         else if(!strcasecmp("order_events", args[iCtr]))
03402         {
03403             iCtr++;
03404             if(iCtr < nargs)
03405             {
03406                 if(!strcasecmp("priority", args[iCtr]))
03407                 {
03408                     g_event_queue.order = SNORT_EVENTQ_PRIORITY;
03409                 }
03410                 else if(!strcasecmp("content_length", args[iCtr]))
03411                 {
03412                     g_event_queue.order = SNORT_EVENTQ_CONTENT_LEN;
03413                 }
03414             }
03415             else
03416             {
03417                 FatalError("%s(%d) => No argument to 'order_events'.  "
03418                            "Arguments may be either 'priority' or "
03419                            "content_length.\n",
03420                            file_name, file_line);
03421             }
03422         }
03423         else
03424         {
03425             FatalError("%s(%d) => Invalid argument to 'event_queue'.  "
03426                        "To configure event_queue, the options 'max_queue', "
03427                        "'log', and 'order_events' must be configured.\n",
03428                        file_name, file_line);
03429         }
03430     }
03431     
03432     return;
03433 }
03434 
03435 void ProcessDetectionOptions( char ** args, int nargs )
03436 {
03437     int i;
03438     
03439     for(i=0;i<nargs;i++)
03440     {
03441        if( !strcasecmp(args[i],"search-method") )
03442        {
03443            i++;
03444            if( i < nargs ) 
03445            {
03446                if(fpSetDetectSearchMethod(args[i]))
03447                {
03448                    FatalError("%s (%d)=> Invalid argument to 'search-method'"
03449                               ".  Must be either 'mwm' or 'ac'.\n",
03450                               file_name, file_line);
03451                }
03452            }
03453            else
03454            {
03455                FatalError("%s (%d)=> No argument to 'search-method'. "
03456                           "Must be either 'mwm' or 'ac'.\n",
03457                           file_name, file_line);
03458            }
03459        }
03460        else if(!strcasecmp(args[i], "debug"))
03461        {
03462            fpSetDebugMode();
03463        }
03464        else if(!strcasecmp(args[i], "no_stream_inserts"))
03465        {
03466            fpSetStreamInsert();
03467        }
03468        else if(!strcasecmp(args[i], "max_queue_events"))
03469        {
03470            i++;
03471            if(i < nargs)
03472            {
03473                if(fpSetMaxQueueEvents(atoi(args[i])))
03474                {
03475                    FatalError("%s (%d)=> Invalid argument to "
03476                               "'max_queue_events'.  Argument must "
03477                               "be greater than 0.\n",
03478                               file_name, file_line);
03479                }
03480            }
03481        }
03482        else
03483        {
03484            FatalError("%s (%d)=> '%s' is an invalid option to the "
03485                       "'config detection:' configuration.\n", 
03486                       file_name, file_line, args[i]);
03487        }
03488     }
03489 }
03490 
03491 void ProcessResetMac(char ** args, int nargs)
03492 {
03493 #ifdef GIDS
03494 #ifndef IPFW
03495 
03496     int i = 0;
03497     int num_macargs=nargs; 
03498     char **macargs;
03499 
03500     macargs = mSplit(args[0], ":", 6, &num_macargs, '\\');
03501 
03502     if(num_macargs != 6)
03503     {
03504     FatalError("%s (%d)=> '%s' is not a valid macaddress "
03505                "for layer2resets\n",
03506            file_name, file_line, args[0]);
03507     }
03508 
03509     for(i = 0; i < num_macargs; i++)
03510         pv.enet_src[i] = (u_int8_t) strtoul(macargs[i], NULL, 16);
03511 
03512 #endif /* IPFW */
03513 #endif /* GIDS */
03514 
03515     return;
03516 } 
03517 
03518 void ParseConfig(char *rule)
03519 {
03520     char ** toks;
03521     char **rule_toks = NULL;
03522     char **config_decl = NULL;
03523     char *args = NULL;
03524     char *config;
03525     int num_rule_toks = 0, num_config_decl_toks = 0, num_toks=0;
03526 
03527     rule_toks = mSplit(rule, ":", 2, &num_rule_toks, 0);
03528     if(num_rule_toks > 1)
03529     {
03530         args = rule_toks[1];
03531     }
03532 
03533     config_decl = mSplit(rule_toks[0], " ", 2, &num_config_decl_toks, '\\');
03534     if(num_config_decl_toks != 2)
03535     {
03536         FatalError("unable to parse config: %s\n", rule);
03537     }
03538 
03539     config = config_decl[1];
03540 
03541     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Config: %s\n", config););
03542     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Args: %s\n", args););
03543 
03544     if(!strcasecmp(config, "order"))
03545     {
03546         if(!pv.rules_order_flag)
03547             OrderRuleLists(args);
03548         else
03549         LogMessage("Commandline option overiding rule file config\n");
03550 
03551         mSplitFree(&rule_toks,num_rule_toks);
03552         mSplitFree(&config_decl,num_config_decl_toks);
03553     
03554         return;
03555     }
03556     else if(!strcasecmp(config, "alertfile"))
03557     {
03558         toks = mSplit(args, " ", 1, &num_toks, 0);
03559 
03560         ProcessAlertFileOption(toks[0]);
03561     
03562         mSplitFree( &toks, num_toks );
03563         mSplitFree(&rule_toks,num_rule_toks);
03564         mSplitFree(&config_decl,num_config_decl_toks);
03565         return;
03566     }
03567     else if(!strcasecmp(config, "classification"))
03568     {
03569         ParseClassificationConfig(args);
03570     
03571         mSplitFree(&rule_toks,num_rule_toks);
03572         mSplitFree(&config_decl,num_config_decl_toks);
03573         return;
03574     }
03575     else if(!strcasecmp(config, "detection"))
03576     {
03577         toks = mSplit(args, ", ",20, &num_toks, 0);
03578         ProcessDetectionOptions(toks,num_toks);
03579         mSplitFree( &toks, num_toks );
03580         mSplitFree(&rule_toks,num_rule_toks);
03581         mSplitFree(&config_decl,num_config_decl_toks);
03582         return;
03583     }
03584     else if(!strcasecmp(config, "flowbits_size"))
03585     {
03586         toks = mSplit(args, ", ",20, &num_toks, 0);
03587         ProcessFlowbitsSize(toks, num_toks);
03588         mSplitFree( &toks, num_toks );
03589         mSplitFree(&rule_toks,num_rule_toks);
03590         mSplitFree(&config_decl,num_config_decl_toks);
03591         return;
03592     }
03593     else if(!strcasecmp(config, "event_queue"))
03594     {
03595         toks = mSplit(args, ", ", 20, &num_toks, 0);
03596         ProcessEventQueue(toks, num_toks);
03597         mSplitFree( &toks, num_toks );
03598         mSplitFree(&rule_toks,num_rule_toks);
03599         mSplitFree(&config_decl,num_config_decl_toks);
03600         return;
03601     }
03602     else if(!strcasecmp(config, "layer2resets"))
03603     {   
03604         if(args)
03605         {
03606             toks = mSplit(args, " ", 1, &num_toks, 0);
03607             ProcessResetMac(toks, num_toks);
03608 
03609             mSplitFree( &toks, num_toks );
03610         }
03611 
03612 #ifdef GIDS
03613 #ifndef IPFW
03614 
03615         pv.layer2_resets = 1;
03616 
03617 #endif
03618 #endif
03619 
03620         mSplitFree(&rule_toks,num_rule_toks);
03621         mSplitFree(&config_decl,num_config_decl_toks);
03622 
03623         return;
03624         
03625     }
03626     else if(!strcasecmp(config, "ipfw_reinject_rule"))
03627     {   
03628         if(args)
03629         {
03630             toks = mSplit(args, " ", 1, &num_toks, 0);
03631 #ifdef GIDS
03632 #ifdef IPFW
03633 
03634             pv.ipfw_reinject_rule = atoi(toks[0]) - 1;
03635 
03636 #endif
03637 #endif
03638 
03639             mSplitFree( &toks, num_toks );
03640         }
03641 
03642         mSplitFree(&rule_toks,num_rule_toks);
03643         mSplitFree(&config_decl,num_config_decl_toks);
03644 
03645         return;
03646         
03647     }
03648     else if(!strcasecmp(config, "asn1"))
03649     {
03650         toks = mSplit(args, ", ", 20, &num_toks, 0);
03651 
03652         if(num_toks > 0)
03653         {
03654             if(asn1_init_mem(atoi(toks[0])))
03655             {
03656                 FatalError("%s(%d) => Invalid argument to 'asn1' "
03657                            "configuration.  Must be a positive integer.\n", 
03658                            file_name, file_line);
03659             }
03660         }
03661         mSplitFree( &toks, num_toks );
03662         mSplitFree(&rule_toks,num_rule_toks);
03663         mSplitFree(&config_decl,num_config_decl_toks);
03664         return;
03665     }
03666     else if(!strcasecmp(config, "dump_chars_only"))
03667     {
03668         /* dump the application layer as text only */
03669         DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Character payload dump set\n"););
03670         pv.char_data_flag = 1;
03671     
03672         mSplitFree(&rule_toks,num_rule_toks);
03673         mSplitFree(&config_decl,num_config_decl_toks);
03674         return;
03675     }
03676     else if(!strcasecmp(config, "dump_payload"))
03677     {
03678         /* dump the application layer */
03679         DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Payload dump set\n"););
03680         pv.data_flag = 1;
03681     
03682         mSplitFree(&rule_toks,num_rule_toks);
03683         mSplitFree(&config_decl,num_config_decl_toks);
03684         return;
03685     }
03686     else if(!strcasecmp(config, "disable_decode_alerts"))
03687     {
03688         /* dump the application layer */
03689         DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the decoder alerts\n"););
03690         pv.decoder_flags.decode_alerts = 0;
03691     
03692         mSplitFree(&rule_toks,num_rule_toks);
03693         mSplitFree(&config_decl,num_config_decl_toks);
03694         return;
03695     }
03696     else if(!strcasecmp(config, "disable_decode_drops"))
03697     {
03698         DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the drop of decoder alerts\n"););
03699         pv.decoder_flags.drop_alerts = 0;
03700     
03701         mSplitFree(&rule_toks,num_rule_toks);
03702         mSplitFree(&config_decl,num_config_decl_toks);
03703         return;
03704     }
03705     else if(!strcasecmp(config, "disable_tcpopt_experimental_alerts"))
03706     {
03707         /* dump the application layer */
03708         DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the tcpopt experimental alerts\n"););
03709         pv.decoder_flags.tcpopt_experiment = 0;
03710     
03711         mSplitFree(&rule_toks,num_rule_toks);
03712         mSplitFree(&config_decl,num_config_decl_toks);
03713         return;
03714     }
03715     else if(!strcasecmp(config, "disable_tcpopt_experimental_drops"))
03716     {
03717         DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the drop of tcpopt exprimental alerts\n"););
03718         pv.decoder_flags.drop_tcpopt_experiment = 0;
03719    
03720         mSplitFree(&rule_toks,num_rule_toks);
03721         mSplitFree(&config_decl,num_config_decl_toks);
03722         return;
03723     }              
03724 
03725     else if(!strcasecmp(config, "disable_tcpopt_obsolete_alerts"))
03726     {
03727         /* dump the application layer */
03728         DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the tcpopt obsolete alerts\n"););
03729         pv.decoder_flags.tcpopt_obsolete = 0;
03730     
03731         mSplitFree(&rule_toks,num_rule_toks);
03732         mSplitFree(&config_decl,num_config_decl_toks);
03733         return;
03734     }
03735     else if(!strcasecmp(config, "disable_tcpopt_obsolete_drops"))
03736     {
03737         DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the drop of tcpopt obsolete alerts\n"););
03738         pv.decoder_flags.drop_tcpopt_obsolete = 0;
03739    
03740         mSplitFree(&rule_toks,num_rule_toks);
03741         mSplitFree(&config_decl,num_config_decl_toks);
03742         return;
03743     }              
03744 
03745     else if(!strcasecmp(config, "disable_ttcp_alerts") ||
03746             !strcasecmp(config, "disable_tcpopt_ttcp_alerts"))
03747     {
03748         /* dump the application layer */
03749         DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the ttcp alerts\n"););
03750         pv.decoder_flags.tcpopt_ttcp = 0;
03751     
03752         mSplitFree(&rule_toks,num_rule_toks);
03753         mSplitFree(&config_decl,num_config_decl_toks);
03754         return;
03755     }
03756     else if(!strcasecmp(config, "disable_ttcp_drops"))
03757     {
03758         DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the drop of ttcp alerts\n"););
03759         pv.decoder_flags.drop_tcpopt_ttcp = 0;
03760    
03761         mSplitFree(&rule_toks,num_rule_toks);
03762         mSplitFree(&config_decl,num_config_decl_toks);
03763         return;
03764     }              
03765 
03766     else if(!strcasecmp(config, "disable_tcpopt_alerts"))
03767     {
03768         /* dump the application layer */
03769         DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the all the other tcpopt alerts\n"););
03770         pv.decoder_flags.tcpopt_decode = 0;
03771     
03772         mSplitFree(&rule_toks,num_rule_toks);
03773         mSplitFree(&config_decl,num_config_decl_toks);
03774         return;
03775     }
03776     else if(!strcasecmp(config, "disable_tcpopt_drops"))
03777     {
03778         DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the drop of all other tcpopt alerts\n"););
03779         pv.decoder_flags.drop_tcpopt_decode = 0;
03780    
03781         mSplitFree(&rule_toks,num_rule_toks);
03782         mSplitFree(&config_decl,num_config_decl_toks);
03783         return;
03784     }              
03785 
03786     else if(!strcasecmp(config, "disable_ipopt_alerts"))
03787     {
03788         /* dump the application layer */
03789         DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the all the ipopt alerts\n"););
03790         pv.decoder_flags.ipopt_decode = 0;
03791     
03792         mSplitFree(&rule_toks,num_rule_toks);
03793         mSplitFree(&config_decl,num_config_decl_toks);
03794         return;
03795     }
03796     else if(!strcasecmp(config, "disable_ipopt_drops"))
03797     {
03798         DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the drop of all the ipopt alerts\n"););
03799         pv.decoder_flags.drop_ipopt_decode = 0;
03800    
03801         mSplitFree(&rule_toks,num_rule_toks);
03802         mSplitFree(&config_decl,num_config_decl_toks);
03803         return;
03804     }              
03805 
03806     else if(!strcasecmp(config, "decode_data_link"))
03807     {
03808         /* dump the data link layer as text only */
03809         DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Decode DLL set\n"););
03810         pv.show2hdr_flag = 1;
03811     
03812         mSplitFree(&rule_toks,num_rule_toks);
03813         mSplitFree(&config_decl,num_config_decl_toks);
03814         return;
03815     }
03816     else if(!strcasecmp(config, "bpf_file"))
03817     {
03818         /* Read BPF filters from a file */
03819         DEBUG_WRAP(DebugMessage(DEBUG_INIT, "BPF file set\n"););
03820         /* suck 'em in */
03821         pv.pcap_cmd = read_infile(args);
03822         mSplitFree(&rule_toks,num_rule_toks);
03823         mSplitFree(&config_decl,num_config_decl_toks);
03824         return;
03825     }
03826     else if(!strcasecmp(config, "set_gid"))
03827     {
03828 #ifdef WIN32
03829         FatalError(" Setting the group id is not supported in the WIN32 port of snort!\n");
03830 #else
03831         if((groupname = calloc(strlen(args) + 1, 1)) == NULL)
03832             FatalPrintError("calloc");
03833 
03834         bcopy(args, groupname, strlen(args));
03835 
03836         if((groupid = atoi(groupname)) == 0)
03837         {
03838             gr = getgrnam(groupname);
03839 
03840             if(gr == NULL)
03841             {
03842                 ErrorMessage("%s(%d) => Group \"%s\" unknown\n", 
03843                              file_name, file_line, groupname);
03844             }
03845 
03846             groupid = gr->gr_gid;
03847         }
03848 #endif
03849         mSplitFree(&rule_toks,num_rule_toks);
03850         mSplitFree(&config_decl,num_config_decl_toks);
03851 
03852         return;
03853     }
03854     else if(!strcasecmp(config, "daemon"))
03855     {
03856         DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Daemon mode flag set\n"););
03857         pv.daemon_flag = 1;
03858         flow_set_daemon();
03859         pv.quiet_flag = 1;
03860     
03861         mSplitFree(&rule_toks,num_rule_toks);
03862         mSplitFree(&config_decl,num_config_decl_toks);
03863         return;
03864 
03865     }
03866     else if(!strcasecmp(config, "reference_net"))
03867     {
03868         GenHomenet(args);
03869         mSplitFree(&rule_toks,num_rule_toks);
03870         mSplitFree(&config_decl,num_config_decl_toks);
03871         return;
03872     }
03873     else if(!strcasecmp(config, "threshold"))
03874     {
03875         ProcessThresholdOptions(args);
03876         mSplitFree(&rule_toks,num_rule_toks);
03877         mSplitFree(&config_decl,num_config_decl_toks);
03878         return;
03879     }
03880     else if(!strcasecmp(config, "interface"))
03881     {
03882         pv.interface = (char *) malloc(strlen(args) + 1);   /* XXX OOM check */
03883         strlcpy(pv.interface, args, strlen(args)+1);
03884         DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Interface = %s\n", 
03885                     PRINT_INTERFACE(pv.interface)););
03886 
03887         if(!pv.readmode_flag)
03888         {
03889             if(pd != NULL)
03890             {
03891                 pcap_close(pd);
03892             }
03893 
03894             DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Opening interface: %s\n", 
03895                         PRINT_INTERFACE(pv.interface)););
03896             /* open up our libpcap packet capture interface */
03897             OpenPcap();
03898         }
03899         mSplitFree(&rule_toks,num_rule_toks);
03900         mSplitFree(&config_decl,num_config_decl_toks);
03901         return;
03902     }
03903     else if(!strcasecmp(config, "alert_with_interface_name"))
03904     {
03905         pv.alert_interface_flag = 1;
03906         mSplitFree(&rule_toks,num_rule_toks);
03907         mSplitFree(&config_decl,num_config_decl_toks);
03908         return;
03909     }
03910     else if(!strcasecmp(config, "logdir"))
03911     {
03912         LogMessage("Found logdir config directive (%s)\n", args);
03913         if(!(pv.log_dir = strdup(args)))
03914             FatalError("Out of memory setting log dir from config file\n");
03915         DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Log directory = %s\n", 
03916                     pv.log_dir););
03917         mSplitFree(&rule_toks,num_rule_toks);
03918         mSplitFree(&config_decl,num_config_decl_toks);
03919         return;
03920     }
03921     else if(!strcasecmp(config, "chroot"))
03922     {
03923         LogMessage("Found chroot config directive (%s)\n", args);
03924         if(!(pv.chroot_dir = strdup(args)))
03925             FatalError("Out of memory setting chroot dir from config file\n");
03926         DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Chroot directory = %s\n",
03927                     pv.chroot_dir););
03928         mSplitFree(&rule_toks,num_rule_toks);
03929         mSplitFree(&config_decl,num_config_decl_toks);
03930         return;
03931     }
03932     else if(!strcasecmp(config, "umask"))
03933     {
03934         char *p;
03935         long val = 0;
03936         int umaskchange = 1;
03937         int defumask = 0;
03938 
03939         umaskchange = 0;
03940 
03941         val = strtol(args, &p, 8);
03942         if (*p != '\0' || val < 0 || (val & ~FILEACCESSBITS))
03943         {
03944             FatalError("bad umask %s\n", args);
03945         }
03946         else
03947         {
03948             defumask = val;
03949         }
03950 
03951         /* if the umask arg happened, set umask */
03952         if (umaskchange)
03953         {
03954             umask(077);           /* set default to be sane */
03955         }
03956         else
03957         {
03958             umask(defumask);
03959         }
03960         mSplitFree(&rule_toks,num_rule_toks);
03961         mSplitFree(&config_decl,num_config_decl_toks);
03962         return;
03963     }
03964     else if(!strcasecmp(config, "pkt_count"))
03965     {
03966         pv.pkt_cnt = atoi(args);
03967         DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Exiting after %d packets\n", pv.pkt_cnt););
03968         mSplitFree(&rule_toks,num_rule_toks);
03969         mSplitFree(&config_decl,num_config_decl_toks);
03970         return;
03971     }
03972     else if(!strcasecmp(config, "nolog"))
03973     {
03974         pv.log_mode = LOG_NONE;
03975         pv.log_cmd_override = 1;    /* XXX this is a funky way to do things */
03976         mSplitFree(&rule_toks,num_rule_toks);
03977         mSplitFree(&config_decl,num_config_decl_toks);
03978         return;
03979     }
03980     else if(!strcasecmp(config, "obfuscate"))
03981     {
03982         pv.obfuscation_flag = 1;
03983         mSplitFree(&rule_toks,num_rule_toks);
03984         mSplitFree(&config_decl,num_config_decl_toks);
03985         return;
03986     }
03987     else if(!strcasecmp(config, "no_promisc"))
03988     {
03989         pv.promisc_flag = 0;
03990         DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Promiscuous mode disabled!\n"););
03991         mSplitFree(&rule_toks,num_rule_toks);
03992         mSplitFree(&config_decl,num_config_decl_toks);
03993         return;
03994     }
03995     else if(!strcasecmp(config, "snaplen"))
03996     {
03997         pv.pkt_snaplen = atoi(args);
03998         DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Snaplength of Packets set to: %d\n", 
03999                     pv.pkt_snaplen););
04000         mSplitFree(&rule_toks,num_rule_toks);
04001         mSplitFree(&config_decl,num_config_decl_toks);
04002         return;
04003     }
04004     else if(!strcasecmp(config, "quiet"))
04005     {
04006         pv.quiet_flag = 1;
04007         mSplitFree(&rule_toks,num_rule_toks);
04008         mSplitFree(&config_decl,num_config_decl_toks);
04009         return;
04010     }
04011     else if(!strcasecmp(config, "read_bin_file"))
04012     {
04013         strlcpy(pv.readfile, args, STD_BUF);
04014         pv.readmode_flag = 1;
04015         DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Opening file: %s\n", pv.readfile););
04016 
04017         /* open the packet file for readback */
04018         OpenPcap();
04019         mSplitFree(&rule_toks,num_rule_toks);
04020         mSplitFree(&config_decl,num_config_decl_toks);
04021         return;
04022     }
04023     else if(!strcasecmp(config, "checksum_mode"))
04024     {
04025         int num_atoks,i;
04026         char **atoks;
04027 
04028         atoks  = mSplit(args, " ",10 , &num_atoks, 0);
04029     
04030         for(i=0;i<num_atoks;i++)
04031         {
04032             args=atoks[i];
04033 
04034         if(args == NULL || !strcasecmp(args, "all"))
04035         {
04036             pv.checksums_mode = DO_IP_CHECKSUMS | DO_TCP_CHECKSUMS |
04037                 DO_UDP_CHECKSUMS | DO_ICMP_CHECKSUMS;
04038         }
04039         else if(!strcasecmp(args, "none"))
04040         {
04041             pv.checksums_mode = 0;
04042         }
04043 
04044         else if(!strcasecmp(args, "noip")) 
04045         {
04046             pv.checksums_mode ^= DO_IP_CHECKSUMS;
04047         }
04048         else if(!strcasecmp(args, "notcp"))
04049         {
04050             pv.checksums_mode ^= DO_TCP_CHECKSUMS;
04051         }
04052         else if(!strcasecmp(args, "noudp"))
04053         {
04054             pv.checksums_mode ^= DO_UDP_CHECKSUMS;
04055         }
04056         else if(!strcasecmp(args, "noicmp"))
04057         {
04058             pv.checksums_mode ^= DO_ICMP_CHECKSUMS;
04059         }
04060 
04061         else if(!strcasecmp(args, "ip")) 
04062         {
04063             pv.checksums_mode |= DO_IP_CHECKSUMS;
04064         }
04065         else if(!strcasecmp(args, "tcp"))
04066         {
04067             pv.checksums_mode |= DO_TCP_CHECKSUMS;
04068         }
04069         else if(!strcasecmp(args, "udp"))
04070         {
04071             pv.checksums_mode |= DO_UDP_CHECKSUMS;
04072         }
04073         else if(!strcasecmp(args, "icmp"))
04074         {
04075             pv.checksums_mode |= DO_ICMP_CHECKSUMS;
04076         }
04077     
04078     }
04079     
04080     mSplitFree(&atoks,num_atoks);
04081     mSplitFree(&rule_toks,num_rule_toks);
04082         mSplitFree(&config_decl,num_config_decl_toks);
04083         return;
04084     }
04085     else if(!strcasecmp(config, "set_uid"))
04086     {
04087 #ifdef WIN32
04088         FatalError("Setting the user id is not supported in the WIN32 port of snort!\n");
04089 #else
04090         if((username = calloc(strlen(args) + 1, 1)) == NULL)
04091             FatalPrintError("malloc");
04092 
04093         bcopy(args, username, strlen(args));
04094 
04095         if((userid = atoi(username)) == 0)
04096         {
04097             pw = getpwnam(username);
04098             if(pw == NULL)
04099                 FatalError("User \"%s\" unknown\n", username);
04100 
04101             userid = pw->pw_uid;
04102         }
04103         else
04104         {
04105             pw = getpwuid(userid);
04106             if(pw == NULL)
04107                 FatalError(
04108                         "Can not obtain username for uid: %lu\n",
04109                         (u_long) userid);
04110         }
04111 
04112         if(groupname == NULL)
04113         {
04114             char name[256];
04115 
04116             snprintf(name, 255, "%lu", (u_long) pw->pw_gid);
04117 
04118             if((groupname = calloc(strlen(name) + 1, 1)) == NULL)
04119             {
04120                 FatalPrintError("malloc");
04121             }
04122             groupid = pw->pw_gid;
04123         }
04124 
04125         DEBUG_WRAP(DebugMessage(DEBUG_INIT, "UserID: %lu GroupID: %lu\n",
04126                     (unsigned long) userid, (unsigned long) groupid););
04127 #endif
04128         mSplitFree(&rule_toks,num_rule_toks);
04129         mSplitFree(&config_decl,num_config_decl_toks);
04130         return;
04131     }
04132     else if(!strcasecmp(config, "utc"))
04133     {
04134         pv.use_utc = 1;
04135         mSplitFree(&rule_toks,num_rule_toks);
04136         mSplitFree(&config_decl,num_config_decl_toks);
04137         return;
04138     }
04139     else if(!strcasecmp(config, "verbose"))
04140     {
04141         pv.verbose_flag = 1;
04142         DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Verbose Flag active\n"););
04143         mSplitFree(&rule_toks,num_rule_toks);
04144         mSplitFree(&config_decl,num_config_decl_toks);
04145         return;
04146     }
04147     else if(!strcasecmp(config, "dump_payload_verbose"))
04148     {
04149         DEBUG_WRAP(DebugMessage(DEBUG_INIT, 
04150                     "Verbose packet bytecode dumps enabled\n"););
04151 
04152         pv.verbose_bytedump_flag = 1;
04153         mSplitFree(&rule_toks,num_rule_toks);
04154         mSplitFree(&config_decl,num_config_decl_toks);
04155         return;
04156     }
04157     else if(!strcasecmp(config, "show_year"))
04158     {
04159         pv.include_year = 1;
04160         DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Enabled year in timestamp\n"););
04161         mSplitFree(&rule_toks,num_rule_toks);
04162         mSplitFree(&config_decl,num_config_decl_toks);
04163         return;
04164     }
04165     else if(!strcasecmp(config, "stateful")) /* this one's for Johnny! */
04166     {
04167         pv.assurance_mode = ASSURE_EST;
04168         mSplitFree(&rule_toks,num_rule_toks);
04169         mSplitFree(&config_decl,num_config_decl_toks);
04170         return;
04171     }
04172     else if(!strcasecmp(config, "min_ttl"))
04173     {
04174         if(args)
04175         {
04176             pv.min_ttl = atoi(args);
04177         }
04178         else 
04179         {
04180             FatalError("config min_ttl requires an argument\n");
04181         }
04182         mSplitFree(&rule_toks,num_rule_toks);
04183         mSplitFree(&config_decl,num_config_decl_toks);
04184         return;
04185     }
04186     else if(!strcasecmp(config, "reference"))
04187     {
04188         if(args)
04189         {
04190             ParseReferenceSystemConfig(args);
04191         }
04192         else
04193         {
04194             ErrorMessage("%s(%d) => Reference config without "
04195                          "arguments\n", file_name, file_line);
04196         }
04197         mSplitFree(&rule_toks,num_rule_toks);
04198         mSplitFree(&config_decl,num_config_decl_toks);
04199         return;
04200     }
04201     else if (!strcasecmp(config, "ignore_ports"))
04202     {
04203         LogMessage("Found ignore_ports config directive (%s)\n", args);
04204         ParsePortList(args);        
04205         mSplitFree(&rule_toks,num_rule_toks);
04206         mSplitFree(&config_decl,num_config_decl_toks);
04207         return;
04208     }
04209     
04210     FatalError("Unknown config directive: %s\n", rule);
04211     
04212 
04213     return;
04214 }
04215 
04216 
04217  /****************************************************************************
04218  *
04219  * Purpose: Parses a protocol plus a list of ports.
04220  *          The protocol should be "udp" or "tcp".
04221  *          The ports list should be a list of numbers or pairs of numbers.
04222  *          Each element of the list is separated by a space character.
04223  *          Each pair of numbers is separated by a colon character.
04224  *          So the string passed in is e.g. "tcp 443 578 6667:6681 13456"
04225  *          The numbers do not have to be in numerical order.
04226  *
04227  * Arguments: args => string containing protocol plus list of ports
04228  *
04229  * Returns: void function
04230  *
04231  *****************************************************************************/
04232 void ParsePortList(char *args)
04233 {
04234     char ** toks;
04235     int     num_toks = 0;
04236     int     i, p;
04237     u_short hi_port, lo_port;
04238     int     protocol;
04239     int     not_flag;
04240 
04241     toks = mSplit(args, " ", 65535, &num_toks, 0);
04242 
04243     if ( !num_toks )
04244     {
04245         FatalError("%s(%d) => config ignore_ports: Empty port list.\n", 
04246                     file_name, file_line);
04247     }
04248 
04249     protocol = WhichProto(toks[0]);
04250 
04251     if ( !(protocol == IPPROTO_TCP || protocol == IPPROTO_UDP) )
04252     {
04253         FatalError("%s(%d) => Invalid protocol: %s\n", file_name, file_line, toks[0]);
04254     }
04255 
04256     for ( i = 1; i < num_toks; i++ )
04257     {  
04258         /*  Re-use function from rules processing  */
04259         ParsePort(toks[i], &hi_port, &lo_port, toks[0], &not_flag);      
04260            
04261         for ( p = lo_port; p <= hi_port; p++ )
04262             pv.ignore_ports[p] = protocol;
04263     }
04264     
04265     mSplitFree(&toks, num_toks);
04266 }
04267 
04268 
04269 /* verify that we are not reusing some other keyword */
04270 int checkKeyword(char *keyword)
04271 {
04272     RuleListNode *node = RuleLists;
04273 
04274     if(RuleType(keyword) != RULE_UNKNOWN)
04275     {
04276         return 1;
04277     }
04278 
04279     /* check the declared ruletypes now */
04280     while(node != NULL)
04281     {
04282         if(!strcasecmp(node->name, keyword))
04283         {
04284             return 1;
04285         }
04286 
04287         node = node->next;
04288     }
04289 
04290     return 0;
04291 }
04292 
04293 void ParseRuleTypeDeclaration(FILE* rule_file, char *rule)
04294 {
04295     char *input;
04296     char *keyword;
04297     char **toks;
04298     int num_toks;
04299     int type;
04300     int rval = 1;
04301     ListHead *listhead = NULL;
04302 
04303     toks = mSplit(rule, " ", 10, &num_toks, 0);
04304     keyword = strdup(toks[1]);
04305 
04306     /* Verify keyword is unique */
04307     if(checkKeyword(keyword))
04308     {
04309         FatalError("%s(%d): Duplicate keyword: %s\n",
04310                    file_name, file_line, keyword);
04311     }
04312 
04313     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Declaring new rule type: %s\n", keyword););
04314 
04315     if(num_toks > 2)
04316     {
04317         if(strcasecmp("{", toks[2]) != 0)
04318         {
04319             FatalError("%s(%d): Syntax error: %s\n",
04320                        file_name, file_line, rule);
04321         }
04322     }
04323     else
04324     {
04325         input = ReadLine(rule_file);
04326         free(input);
04327     }
04328 
04329     input = ReadLine(rule_file);
04330 
04331     mSplitFree(&toks, num_toks);
04332 
04333     toks = mSplit(input, " ", 10, &num_toks, 0);
04334 
04335     /* read the type field */
04336     if(!strcasecmp("type", toks[0]))
04337     {
04338         type = RuleType(toks[1]);
04339         /* verify it is a valid ruletype */
04340         if((type != RULE_LOG) && (type != RULE_PASS) && (type != RULE_ALERT) &&
04341            (type != RULE_ACTIVATE) && (type != RULE_DYNAMIC))
04342         {
04343             FatalError("%s(%d): Invalid type for rule type declaration: %s\n", file_name, file_line, toks[1]);
04344         }
04345 
04346         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"\ttype(%i): %s\n", type, toks[1]););
04347 
04348         if(type == RULE_PASS)
04349         {
04350             rval = 0;
04351         }
04352 
04353         listhead = CreateRuleType(keyword, type, rval, NULL);
04354     }
04355     else
04356     {
04357         FatalError("%s(%d): Type not defined for rule file declaration: %s\n", file_name, file_line, keyword);
04358     }
04359 
04360     free(input);
04361     input = ReadLine(rule_file);
04362     
04363     mSplitFree(&toks, num_toks);
04364 
04365 
04366     toks = mSplit(input, " ", 2, &num_toks, 0);
04367 
04368     while(strcasecmp("}", toks[0]) != 0)
04369     {
04370         if(RuleType(toks[0]) != RULE_OUTPUT)
04371         {
04372             FatalError("%s(%d): Not an output plugin declaration: %s\n", file_name, file_line, keyword);
04373         }
04374 
04375         head_tmp = listhead;
04376         ParseOutputPlugin(input);
04377         head_tmp = NULL;
04378         free(input);
04379         input = ReadLine(rule_file);
04380 
04381         mSplitFree(&toks, num_toks);
04382         toks = mSplit(input, " ", 2, &num_toks, 0);
04383     }
04384 
04385     mSplitFree(&toks, num_toks);
04386 
04387     pv.num_rule_types++;
04388 
04389     return;
04390 }
04391 
04392 /* adapted from ParseRuleFile in rules.c */
04393 char *ReadLine(FILE * file)
04394 {
04395     char buf[MAX_LINE_LENGTH+1];
04396     char *index;
04397 
04398     bzero((char *) buf, MAX_LINE_LENGTH+1);
04399 
04400     /*
04401      * Read a line from file and return it. Skip over lines beginning with #,
04402      * ;, or a newline
04403      */
04404     while((fgets(buf, MAX_LINE_LENGTH, file)) != NULL)
04405     {
04406         file_line++;
04407         index = buf;
04408 
04409 #ifdef DEBUG2
04410         LogMessage("Got line %s (%d): %s\n", file_name, file_line, buf);
04411 #endif
04412         /* if it's not a comment or a <CR>, we return it */
04413         if((*index != '#') && (*index != 0x0a) && (*index != ';')
04414            && (index != NULL))
04415         {
04416             /* advance through any whitespace at the beginning of ther line */
04417             while(isspace((int) *index))
04418                 ++index;
04419 
04420             /* return a copy of the line */
04421             return strdup(index);
04422         }
04423     }
04424 
04425     return NULL;
04426 }
04427 
04428 /*
04429  * Same as VarGet - but this does not Fatal out if a var is not found
04430  */
04431 char *VarSearch(char *name)
04432 {
04433     struct VarEntry *p;
04434     if(VarHead)
04435     {
04436         p = VarHead;
04437         do
04438         {
04439             if(strcasecmp(p->name, name) == 0)
04440                 return p->value;
04441             p = p->next;
04442         } while(p != VarHead);
04443     }
04444 
04445     return NULL;
04446 }

Generated on Sun May 14 14:51:14 2006 by  doxygen 1.4.2