prelude-lml/master: Ability to provides static IDMEF template from defined log format

[email protected] Thu, 16 Jul 2009 15:42:29 +0200 (CEST)
Newsgroups gmane.comp.security.ids.prelude.cvs
Message-ID <[email protected]>
commit 866f11f23991556cad40926d3aa2c84219ed39c0
Author: Yoann Vandoorselaere <[email protected]>
Date:   Wed Jul 15 16:50:14 2009 +0200

    Ability to provides static IDMEF template from defined log format
    
    Implement the 'idmef-alter' and 'idmef-alter-force' option, that can
    be used to put specific values in generated IDMEF events from a given
    log format.
    
    Example: idmef-alter = alert.analyzer(-1).node.location = My Location
    
    'idmef-alter' will not overwrite an IDMEF path that is already set.
    Use 'idmef-alter-force' if this is what you intend to do.


========================================

 prelude-lml.conf.in      |   50 ++++++++++++++++----------
 src/include/log-entry.h  |    2 +
 src/include/log-source.h |    4 ++
 src/lml-alert.c          |    3 ++
 src/lml-options.c        |   20 ++++++++++
 src/log-entry.c          |   12 ++++++-
 src/log-source.c         |   87 ++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 158 insertions(+), 20 deletions(-)

========================================

diff --git a/prelude-lml.conf.in b/prelude-lml.conf.in
index 7c1d0a5..b904f77 100644
--- a/prelude-lml.conf.in
+++ b/prelude-lml.conf.in
@@ -9,9 +9,9 @@ include = @LIBPRELUDE_CONFIG_PREFIX@/default/idmef-client.conf
 # if value is "127.0.0.1", the connection will occur throught
 # an UNIX socket.
 #
-# This entry is disabled. The default is to use the entry 
-# located in the Prelude system wide clients.conf. You may 
-# overwrite the default address for this sensor by uncommenting 
+# This entry is disabled. The default is to use the entry
+# located in the Prelude system wide clients.conf. You may
+# overwrite the default address for this sensor by uncommenting
 # this entry.
 #
 # [prelude]
@@ -21,8 +21,9 @@ include = @LIBPRELUDE_CONFIG_PREFIX@/default/idmef-client.conf
 #
 # Files to monitor
 #
-# You should define the log message prefix-regex and time-format within a
-# [format] section. If not specified, the default syslog format will be used.
+# You should define the log message prefix-regex and time-format within
+# a [format] section. If not specified, the default syslog format will
+# be used.
 #
 # The prefix-regex should contain PCRE named subpatterns to pick out the
 # information available in your syslog's prefix.
@@ -34,26 +35,37 @@ include = @LIBPRELUDE_CONFIG_PREFIX@/default/idmef-client.conf
 #   - timestamp
 #
 # Please see pcrepattern(3) manpage for help writing the prefix-regex
-# In order to set the time-format, please have a look at the strptime(3) manpage.
+# In order to set the time-format, please have a look at the strptime(3)
+# manpage.
 #
 # Example configuration for syslog output:
 #
 # Each [format] section might have several file entry.
 # Each [format] section might have several udp-server entry.
 #
-# The same file or udp-server entry might be duplicated accross
-# differents formats.
+# If a file or udp-server entry might is listed accross differents
+# formats, then the first matching format for a given log entry will be
+# used.
 #
-# Additionally, you can specify a pattern in a file entry. LML will then searches 
-# for all the pathnames matching pattern according to the rules used by the shell 
-# (see glob(7)).
+# Additionally, you can specify a pattern in a file entry. LML will then
+# searches for all the pathnames matching pattern according to the rules
+# used by the shell (see glob(7)).
 #
 # Example: file = /var/log/*/*.log
-
+#
+#
+# Within each format, you might use the 'idmef-alter' option to modify
+# generated events:
+#
+# Example: idmef-alter = alert.analyzer(-1).node.location = MyLocation;
+#
+# Note that 'idmef-alter' will never overwrite an IDMEF path that is
+# already set. Use 'idmef-alter-force' if this is what you intend to do.
+#
 
 
 [format=syslog]
-time-format = "%b %d %H:%M:%S" 
+time-format = "%b %d %H:%M:%S"
 prefix-regex = "^(?P<timestamp>.{15}) (?P<hostname>\S+) (?:(?P<process>\S+?)(?:\[(?P<pid>[0-9]+)\])?: )?"
 file = /var/log/messages
 # udp-server = 0.0.0.0
@@ -64,7 +76,7 @@ file = /var/log/messages
 #
 [format=metalog]
 prefix-regex = "^(?P<timestamp>.{15}) \[(?P<process>\S+)\] "
-time-format = "%b %d %H:%M:%S" 
+time-format = "%b %d %H:%M:%S"
 file = /var/log/everything/current
 # udp-server = 0.0.0.0
 
@@ -97,7 +109,7 @@ file = /var/log/apache2/error_log
 
 #
 # Specifies the maximum difference, in seconds, between
-# the interval of two logfiles' rotation. If this difference 
+# the interval of two logfiles' rotation. If this difference
 # is reached, a high severity alert will be emited
 #
 #max-rotation-size-offset = 1024
@@ -105,11 +117,11 @@ file = /var/log/apache2/error_log
 
 
 #
-# Maximum number of warning a given source should emit in case it can not
-# parse log entry with the provided prefix_regex and time_format. 
+# Maximum number of warning a given source should emit in case it can
+# not parse log entry with the provided prefix_regex and time_format.
 #
 # -1 == unlimited number of warning
-#  0 == no warning at all 
+#  0 == no warning at all
 #  X == print at most X warnings.
 #
 # warning-limit = -1
@@ -128,7 +140,7 @@ ruleset=@configdir@/ruleset/pcre.rules
 #
 # This plugin issue an alert for each packet.
 # Carefull to the loging activity it generate.
-# 
+#
 # Triger Report to the console.
 # stderr
 
diff --git a/src/include/log-entry.h b/src/include/log-entry.h
index d849d76..9bdaa1e 100644
--- a/src/include/log-entry.h
+++ b/src/include/log-entry.h
@@ -33,4 +33,6 @@ int lml_log_entry_set_log(lml_log_entry_t *lc, lml_log_source_t *ls, const char
 
 void lml_log_entry_destroy(lml_log_entry_t *lc);
 
+const lml_log_format_t *lml_log_entry_get_format(const lml_log_entry_t *log);
+
 #endif /* _LOG_ENTRY_H */
diff --git a/src/include/log-source.h b/src/include/log-source.h
index 624becf..4677abb 100644
--- a/src/include/log-source.h
+++ b/src/include/log-source.h
@@ -49,6 +49,10 @@ int lml_log_format_set_ts_fmt(lml_log_format_t *lf, const char *fmt);
 
 const char *lml_log_format_get_ts_fmt(const lml_log_format_t *ls);
 
+int lml_log_format_set_idmef(lml_log_format_t *format, const char *idmef_s, prelude_bool_t force);
+
+void lml_log_format_apply_idmef(const lml_log_format_t *format, idmef_message_t *idmef);
+
 /*
  *
  */
diff --git a/src/lml-alert.c b/src/lml-alert.c
index ed5fbdc..02ea661 100644
--- a/src/lml-alert.c
+++ b/src/lml-alert.c
@@ -319,6 +319,9 @@ int lml_alert_prepare(idmef_message_t *message, const lml_log_source_t *ls, cons
                         return -1;
         }
 
+        if ( lml_log_entry_get_format(log) )
+                lml_log_format_apply_idmef(lml_log_entry_get_format(log), message);
+
         return 0;
 }
 
diff --git a/src/lml-options.c b/src/lml-options.c
index dc6ab2e..d2992bf 100644
--- a/src/lml-options.c
+++ b/src/lml-options.c
@@ -486,6 +486,18 @@ static int set_format(prelude_option_t *opt, const char *arg, prelude_string_t *
 }
 
 
+static int set_idmef_alter_force(prelude_option_t *opt, const char *arg, prelude_string_t *err, void *context)
+{
+        return lml_log_format_set_idmef(context, arg, TRUE);
+}
+
+
+static int set_idmef_alter(prelude_option_t *opt, const char *arg, prelude_string_t *err, void *context)
+{
+        return lml_log_format_set_idmef(context, arg, FALSE);
+}
+
+
 
 #if !((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__)
 static int set_user(prelude_option_t *opt, const char *optarg, prelude_string_t *err, void *context)
@@ -658,6 +670,14 @@ int lml_options_init(prelude_option_t *ropt, int argc, char **argv)
                            "address:port pair to listen to syslog to UDP messages (default port 514)",
                            PRELUDE_OPTION_ARGUMENT_OPTIONAL, set_udp_server, NULL);
 
+        prelude_option_add(opt, NULL, PRELUDE_OPTION_TYPE_CLI|PRELUDE_OPTION_TYPE_CFG,
+                           0, "idmef-alter", "Assign specific IDMEF path/value to matching log entry",
+                           PRELUDE_OPTION_ARGUMENT_REQUIRED, set_idmef_alter, NULL);
+
+        prelude_option_add(opt, NULL, PRELUDE_OPTION_TYPE_CLI|PRELUDE_OPTION_TYPE_CFG,
+                           0, "idmef-alter-force", "Assign specific IDMEF path/value to matching log entry, even if path is already used",
+                           PRELUDE_OPTION_ARGUMENT_REQUIRED, set_idmef_alter_force, NULL);
+
         ret = prelude_option_read(ropt, &config_file, &argc, argv, &err, NULL);
         if ( ret < 0 ) {
                 if ( prelude_error_get_code(ret) == PRELUDE_ERROR_EOF )
diff --git a/src/log-entry.c b/src/log-entry.c
index c16d7a7..e37e056 100644
--- a/src/log-entry.c
+++ b/src/log-entry.c
@@ -58,6 +58,8 @@ struct lml_log_entry {
         char *target_hostname;
         char *target_process;
         char *target_process_pid;
+
+        lml_log_format_t *format;
 };
 
 
@@ -281,8 +283,10 @@ int lml_log_entry_set_log(lml_log_entry_t *log_entry, lml_log_source_t *ls, cons
                 fc = prelude_linked_object_get_object(tmp);
 
                 ret = parse_prefix(lml_log_format_container_get_format(fc), ls, log_entry);
-                if ( ret == 0 )
+                if ( ret == 0 ) {
+                        log_entry->format = lml_log_format_container_get_format(fc);
                         break;
+                }
 
                 lml_log_entry_destroy_substring(log_entry);
         }
@@ -311,3 +315,9 @@ void lml_log_entry_destroy(lml_log_entry_t *log_entry)
         free(log_entry);
 }
 
+
+
+const lml_log_format_t *lml_log_entry_get_format(const lml_log_entry_t *log_entry)
+{
+        return log_entry->format;
+}
diff --git a/src/log-source.c b/src/log-source.c
index d210254..000b20c 100644
--- a/src/log-source.c
+++ b/src/log-source.c
@@ -54,12 +54,22 @@
 
 
 
+typedef struct {
+        prelude_list_t list;
+        prelude_bool_t force;
+        idmef_path_t *path;
+        idmef_value_t *value;
+} lml_format_idmef_t;
+
+
 struct lml_log_format {
         int refcount;
         char *name;
         char *ts_fmt;
         pcre *prefix_regex;
         pcre_extra *prefix_regex_extra;
+
+        prelude_list_t idmef_list;
 };
 
 
@@ -140,6 +150,7 @@ lml_log_format_t *lml_log_format_new(const char *name)
                 return NULL;
         }
 
+        prelude_list_init(&new->idmef_list);
         return new;
 }
 
@@ -195,6 +206,81 @@ int lml_log_format_set_ts_fmt(lml_log_format_t *ls, const char *fmt)
 
 
 
+
+int lml_log_format_set_idmef(lml_log_format_t *format, const char *idmef_s, prelude_bool_t force)
+{
+        int ret;
+        size_t len;
+        char *idmef, tmp;
+        lml_format_idmef_t *entry;
+
+        len = strcspn(idmef_s, " =");
+        if ( len == 0 )
+                return -1;
+
+        idmef = strdup(idmef_s);
+        if ( ! idmef )
+                return -1;
+
+        entry = malloc(sizeof(*entry));
+        if ( ! entry ) {
+                free(idmef);
+                return -1;
+        }
+
+        entry->force = force;
+
+        tmp = idmef[len];
+        idmef[len] = 0;
+
+        ret = idmef_path_new_fast(&entry->path, idmef);
+        if ( ret < 0 ) {
+                free(idmef);
+                free(entry);
+                return ret;
+        }
+
+        idmef[len] = tmp;
+
+        ret = idmef_value_new_from_path(&entry->value, entry->path, idmef + len + strspn(idmef + len, " ="));
+        if ( ret < 0 ) {
+                free(idmef);
+                idmef_path_destroy(entry->path);
+                free(entry);
+                return ret;
+        }
+
+        free(idmef);
+        prelude_list_add_tail(&format->idmef_list, &entry->list);
+
+        return 0;
+}
+
+
+
+void lml_log_format_apply_idmef(const lml_log_format_t *format, idmef_message_t *idmef)
+{
+        int ret;
+        prelude_list_t *tmp;
+        idmef_value_t *value;
+        lml_format_idmef_t *entry;
+
+        prelude_list_for_each(&format->idmef_list, tmp) {
+                entry = prelude_list_entry(tmp, lml_format_idmef_t, list);
+
+                if ( ! entry->force ) {
+                        ret = idmef_path_get(entry->path, idmef, &value);
+                        if ( ret > 0 ) {
+                                idmef_value_destroy(value);
+                                continue;
+                        }
+                }
+
+                idmef_path_set(entry->path, idmef, entry->value);
+        }
+}
+
+
 const char *lml_log_format_get_ts_fmt(const lml_log_format_t *source)
 {
         return source->ts_fmt;
@@ -387,3 +473,4 @@ prelude_list_t *lml_log_source_get_format_list(lml_log_source_t *source)
 {
         return &source->format_list;
 }
+
_______________________________________________
Prelude-cvslog site list
[email protected]
http://lists.prelude-ids.org/mailman/listinfo/prelude-cvslog