new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / logcollector / read_audit.c
diff --git a/src/logcollector/read_audit.c b/src/logcollector/read_audit.c
new file mode 100644 (file)
index 0000000..8673d70
--- /dev/null
@@ -0,0 +1,117 @@
+/* Copyright (C) 2009 Trend Micro Inc.
+ * All right reserved.
+ *
+ * This program is a free software; you can redistribute it
+ * and/or modify it under the terms of the GNU General Public
+ * License (version 2) as published by the FSF - Free Software
+ * Foundation
+ */
+
+#include "shared.h"
+#include "logcollector.h"
+
+#define MAX_CACHE 16
+#define MAX_HEADER 64
+
+/* Compile message from cache and send through queue */
+static void audit_send_msg(char **cache, int top, const char *file, int drop_it) {
+    int i;
+    size_t n = 0;
+    size_t z;
+    char message[OS_MAXSTR];
+
+    for (i = 0; i < top; i++) {
+        z = strlen(cache[i]);
+
+        if (n + z + 1 < OS_MAXSTR) {
+            if (n > 0)
+                message[n++] = ' ';
+            
+            strncpy(message + n, cache[i], z);
+        }
+
+        n += z;
+        free(cache[i]);
+    }
+
+    if (!drop_it) {
+        message[n] = '\0';
+
+        if (SendMSG(logr_queue, message, file, LOCALFILE_MQ) < 0) {
+            merror(QUEUE_SEND, ARGV0);
+
+            if ((logr_queue = StartMQ(DEFAULTQPATH, WRITE)) < 0) {
+                ErrorExit(QUEUE_FATAL, ARGV0, DEFAULTQPATH);
+            }
+        }
+    }
+}
+
+void *read_audit(int pos, int *rc, int drop_it) {
+    char *cache[MAX_CACHE];
+    char header[MAX_HEADER] = { '\0' };
+    int icache = 0;
+    char buffer[OS_MAXSTR];
+    char *id;
+    char *p;
+    size_t z;
+    long offset = ftell(logff[pos].fp);
+    
+    if (offset < 0) {
+        merror(FTELL_ERROR, ARGV0, logff[pos].file, errno, strerror(errno));
+        return NULL;
+    }
+
+    *rc = 0;
+
+    while (fgets(buffer, OS_MAXSTR, logff[pos].fp)) {
+        if ((p = strchr(buffer, '\n')))
+            *p = '\0';
+        else {
+            if (strlen(buffer) == OS_MAXSTR - 1) {
+                // Message too large, discard line
+                while (fgets(buffer, OS_MAXSTR, logff[pos].fp) && !strchr(buffer, '\n'));
+            } else {
+                debug1("%s: Message not complete. Trying again: '%s'", ARGV0, buffer);
+                
+                if (fseek(logff[pos].fp, offset, SEEK_SET) < 0) {
+                    merror(FSEEK_ERROR, ARGV0, logff[pos].file, errno, strerror(errno));
+                    break;
+                }
+            }
+
+            break;
+        }
+
+        // Extract header: "type=\.* msg=audit(\d+.\d+:\d+):"
+
+        if (strncmp(buffer, "type=", 5) || !((id = strstr(buffer + 5, "msg=audit(")) && (p = strstr(id += 10, "): ")))) {
+            merror("%s: ERROR: discarding audit message because of invalid syntax", ARGV0);
+            break;
+        }
+        
+        z = p - id;
+
+        if (strncmp(id, header, z)) {
+            // Current message belongs to another event: send cached messages
+            if (icache > 0)
+                audit_send_msg(cache, icache, logff[pos].file, drop_it);
+
+            // Store current event
+            *cache = strdup(buffer);
+            icache = 1;
+            strncpy(header, id, z < MAX_HEADER ? z : MAX_HEADER - 1);
+        } else {
+            // The header is the same: store
+            if (icache == MAX_CACHE)
+                merror("%s: ERROR: discarding audit message because cache is full", ARGV0);
+            else
+                cache[icache++] = strdup(buffer);
+        }
+    }
+
+    if (icache > 0)
+        audit_send_msg(cache, icache, logff[pos].file, drop_it);
+
+    return NULL;
+}