From 986d1c9ee647a83822718f83c255aba85c75a866 Mon Sep 17 00:00:00 2001
From: Victor Julien <victor@inliniac.net>
Date: Tue, 8 Nov 2011 17:54:58 +0100
Subject: [PATCH] Add -S commandline option that loads a rule file
 exclusively. Issue #338.

---
 src/detect.c     |   43 +++++++++++++++++++++++--------------------
 src/detect.h     |    2 +-
 src/suricata.c   |   20 +++++++++++++++++---
 src/util-error.c |    1 +
 src/util-error.h |    1 +
 5 files changed, 43 insertions(+), 24 deletions(-)

diff --git a/src/detect.c b/src/detect.c
index a6460c8..a02bf9e 100644
--- a/src/detect.c
+++ b/src/detect.c
@@ -513,9 +513,10 @@ int DetectLoadSigFile(DetectEngineCtx *de_ctx, char *sig_file, int *sigs_tot) {
  *  \brief Load signatures
  *  \param de_ctx Pointer to the detection engine context
  *  \param sig_file Filename holding signatures
+ *  \param sig_file_exclusive File passed in 'sig_file' should be loaded exclusively.
  *  \retval -1 on error
  */
-int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file)
+int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, int sig_file_exclusive)
 {
     SCEnter();
 
@@ -571,27 +572,29 @@ int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file)
     }
 
     /* ok, let's load signature files from the general config */
-    rule_files = ConfGetNode("rule-files");
-    if (rule_files != NULL) {
-        TAILQ_FOREACH(file, &rule_files->head, next) {
-            sfile = DetectLoadCompleteSigPath(file->val);
-            SCLogDebug("Loading rule file: %s", sfile);
-
-            r = DetectLoadSigFile(de_ctx, sfile, &sigtotal);
-            cntf++;
-            if (r > 0) {
-                cnt += r;
-            } else if (r == 0){
-                SCLogWarning(SC_ERR_NO_RULES, "No rules loaded from %s", sfile);
-                if (de_ctx->failure_fatal == 1) {
-                    exit(EXIT_FAILURE);
-                }
-            } else if (r < 0){
-                if (de_ctx->failure_fatal == 1) {
-                    exit(EXIT_FAILURE);
+    if (!(sig_file != NULL && sig_file_exclusive == TRUE)) {
+        rule_files = ConfGetNode("rule-files");
+        if (rule_files != NULL) {
+            TAILQ_FOREACH(file, &rule_files->head, next) {
+                sfile = DetectLoadCompleteSigPath(file->val);
+                SCLogDebug("Loading rule file: %s", sfile);
+
+                r = DetectLoadSigFile(de_ctx, sfile, &sigtotal);
+                cntf++;
+                if (r > 0) {
+                    cnt += r;
+                } else if (r == 0){
+                    SCLogWarning(SC_ERR_NO_RULES, "No rules loaded from %s", sfile);
+                    if (de_ctx->failure_fatal == 1) {
+                        exit(EXIT_FAILURE);
+                    }
+                } else if (r < 0){
+                    if (de_ctx->failure_fatal == 1) {
+                        exit(EXIT_FAILURE);
+                    }
                 }
+                SCFree(sfile);
             }
-            SCFree(sfile);
         }
     }
 
diff --git a/src/detect.h b/src/detect.h
index 2ecd9bb..0264524 100644
--- a/src/detect.h
+++ b/src/detect.h
@@ -1043,7 +1043,7 @@ int SigGroupBuild(DetectEngineCtx *);
 int SigGroupCleanup (DetectEngineCtx *de_ctx);
 void SigAddressPrepareBidirectionals (DetectEngineCtx *);
 
-int SigLoadSignatures (DetectEngineCtx *, char *);
+int SigLoadSignatures (DetectEngineCtx *, char *, int);
 void SigTableSetup(void);
 int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx,
                        DetectEngineThreadCtx *det_ctx, Packet *p);
diff --git a/src/suricata.c b/src/suricata.c
index 2d5648b..457f033 100644
--- a/src/suricata.c
+++ b/src/suricata.c
@@ -411,7 +411,8 @@ void usage(const char *progname)
 #ifdef IPFW
     printf("\t-d <divert port>             : run in inline ipfw divert mode\n");
 #endif /* IPFW */
-    printf("\t-s <path>                    : path to signature file (optional)\n");
+    printf("\t-s <path>                    : path to signature file loaded in addition to suricata.yaml settings (optional)\n");
+    printf("\t-S <path>                    : path to signature file loaded exclusively (optional)\n");
     printf("\t-l <dir>                     : default log directory\n");
 #ifndef OS_WIN32
     printf("\t-D                           : run as daemon\n");
@@ -576,6 +577,7 @@ int main(int argc, char **argv)
     int opt;
     char pcap_dev[128];
     char *sig_file = NULL;
+    int sig_file_exclusive = FALSE;
     char *conf_filename = NULL;
     char *pid_filename = NULL;
 #ifdef UNITTESTS
@@ -688,7 +690,7 @@ int main(int argc, char **argv)
     /* getopt_long stores the option index here. */
     int option_index = 0;
 
-    char short_opts[] = "c:Dhi:l:q:d:r:us:U:VF:";
+    char short_opts[] = "c:Dhi:l:q:d:r:us:S:U:VF:";
 
     while ((opt = getopt_long(argc, argv, short_opts, long_opts, &option_index)) != -1) {
         switch (opt) {
@@ -1016,7 +1018,19 @@ int main(int argc, char **argv)
             }
             break;
         case 's':
+            if (sig_file != NULL) {
+                SCLogError(SC_ERR_CMD_LINE, "can't have multiple -s options or mix -s and -S.");
+                exit(EXIT_FAILURE);
+            }
+            sig_file = optarg;
+            break;
+        case 'S':
+            if (sig_file != NULL) {
+                SCLogError(SC_ERR_CMD_LINE, "can't have multiple -S options or mix -s and -S.");
+                exit(EXIT_FAILURE);
+            }
             sig_file = optarg;
+            sig_file_exclusive = TRUE;
             break;
         case 'u':
 #ifdef UNITTESTS
@@ -1442,7 +1456,7 @@ int main(int argc, char **argv)
 
     ActionInitConfig();
 
-    if (SigLoadSignatures(de_ctx, sig_file) < 0) {
+    if (SigLoadSignatures(de_ctx, sig_file, sig_file_exclusive) < 0) {
         if (sig_file == NULL) {
             SCLogError(SC_ERR_OPENING_FILE, "Signature file has not been provided");
         } else {
diff --git a/src/util-error.c b/src/util-error.c
index c7edde4..dedd00e 100644
--- a/src/util-error.c
+++ b/src/util-error.c
@@ -209,6 +209,7 @@ const char * SCErrorToString(SCError err)
         CASE_CODE (SC_ERR_AFP_CREATE);
         CASE_CODE (SC_ERR_AFP_READ);
         CASE_CODE (SC_ERR_AFP_DISPATCH);
+        CASE_CODE (SC_ERR_CMD_LINE);
 
         default:
             return "UNKNOWN_ERROR";
diff --git a/src/util-error.h b/src/util-error.h
index e7d3d18..e8e8223 100644
--- a/src/util-error.h
+++ b/src/util-error.h
@@ -222,6 +222,7 @@ typedef enum {
     SC_ERR_AFP_DISPATCH,
     SC_ERR_NO_AF_PACKET,
     SC_ERR_PCAP_FILE_DELETE_FAILED,
+    SC_ERR_CMD_LINE,
 } SCError;
 
 const char *SCErrorToString(SCError);
-- 
1.7.5.4

