Blame mlogc/mlogc.c

Packit Service 384592
/*
Packit Service 384592
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
Packit Service 384592
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
Packit Service 384592
*
Packit Service 384592
* You may not use this file except in compliance with
Packit Service 384592
* the License.  You may obtain a copy of the License at
Packit Service 384592
*
Packit Service 384592
*     http://www.apache.org/licenses/LICENSE-2.0
Packit Service 384592
*
Packit Service 384592
* If any of the files related to licensing are missing or if you have any
Packit Service 384592
* other questions related to licensing please contact Trustwave Holdings, Inc.
Packit Service 384592
* directly using the email address security@modsecurity.org.
Packit Service 384592
*/
Packit Service 384592
Packit Service 384592
#include <apr.h>
Packit Service 384592
#include <apr_errno.h>
Packit Service 384592
#include <apr_general.h>
Packit Service 384592
#include <apr_file_io.h>
Packit Service 384592
#include <apr_file_info.h>
Packit Service 384592
#include <apr_hash.h>
Packit Service 384592
#include <apr_lib.h>
Packit Service 384592
#include <apr_strings.h>
Packit Service 384592
#include <apr_signal.h>
Packit Service 384592
#include <apr_thread_proc.h>
Packit Service 384592
#include <apr_global_mutex.h>
Packit Service 384592
#include <apr_getopt.h>
Packit Service 384592
#include <apr_version.h>
Packit Service 384592
#if APR_HAVE_UNISTD_H
Packit Service 384592
#include <unistd.h>         /* for getpid() */
Packit Service 384592
#endif
Packit Service 384592
#include <pcre.h>
Packit Service 384592
#include <curl/curl.h>
Packit Service 384592
#include <fcntl.h>
Packit Service 384592
#include <sys/stat.h>
Packit Service 384592
#include <sys/types.h>
Packit Service 384592
Packit Service 384592
#include "msc_release.h"
Packit Service 384592
Packit Service 384592
static void logc_shutdown(int rc);
Packit Service 384592
static void create_new_worker(int lock);
Packit Service 384592
static void error_log(int level, void *thread,
Packit Service 384592
                      const char *text, ...) PRINTF_ATTRIBUTE(3,4);
Packit Service 384592
Packit Service 384592
Packit Service 384592
/* -- Constants -- */
Packit Service 384592
Packit Service 384592
/* Error log levels. */
Packit Service 384592
#define LOG_ERROR           1
Packit Service 384592
#define LOG_WARNING         2
Packit Service 384592
#define LOG_NOTICE          3
Packit Service 384592
#define LOG_DEBUG           4
Packit Service 384592
#define LOG_DEBUG2          5
Packit Service 384592
Packit Service 384592
/* The management thread will wake up every five seconds. */
Packit Service 384592
#define MANAGER_SLEEP       5000000
Packit Service 384592
#define MANAGER_SUBSLEEP    10000
Packit Service 384592
Packit Service 384592
/* Hack to allow multiple mlogc with single delete */
Packit Service 384592
#define KEEP_ENTRIES_REMOVE_HACK   2600
Packit Service 384592
#define KEEP_ENTRIES_REMOVE_TIME   0l
Packit Service 384592
#ifdef TEST_HACK
Packit Service 384592
#define TEST_WITH_RAND_SLEEP(n) \
Packit Service 384592
do { \
Packit Service 384592
    int sec = rand()/(RAND_MAX/n); \
Packit Service 384592
    error_log(LOG_DEBUG2, NULL, "TEST_HACK: Sleeping for %ds", sec); \
Packit Service 384592
    apr_sleep(apr_time_from_sec(sec)); \
Packit Service 384592
} while(0)
Packit Service 384592
#else
Packit Service 384592
#define TEST_WITH_RAND_SLEEP(n)
Packit Service 384592
#endif
Packit Service 384592
Packit Service 384592
#define CAPTUREVECTORSIZE   60
Packit Service 384592
#define PIPE_BUF_SIZE       65536
Packit Service 384592
#define MEMALLOC_ERROR_MSG  "Memory allocation failed!"
Packit Service 384592
#define VERSION             MODSEC_VERSION
Packit Service 384592
Packit Service 384592
#define CMDLINE_OPTS        "fvh"
Packit Service 384592
Packit Service 384592
#define TXIN            0
Packit Service 384592
#define TXOUT           1
Packit Service 384592
Packit Service 384592
#define STATUSBUF_SIZE      256
Packit Service 384592
Packit Service 384592
#define ISHEXCHAR(X) (   ((X >= '0')&&(X <= '9')) \
Packit Service 384592
                      || ((X >= 'a')&&(X <= 'f')) \
Packit Service 384592
                      || ((X >= 'A')&&(X <= 'F')) )
Packit Service 384592
Packit Service 384592
/* -- Regex Patterns -- */
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * This regular expression is used to parse the entire
Packit Service 384592
 * log line we receive from Apache. The REQUEST_LINE is
Packit Service 384592
 * treated as a single parameter to allow for invalid
Packit Service 384592
 * requests.
Packit Service 384592
 */
Packit Service 384592
static const char logline_pattern[] =
Packit Service 384592
    "^(\\S+)"
Packit Service 384592
    "\\ (\\S+)\\ (\\S+)\\ (\\S+)"
Packit Service 384592
    "\\ \\[([^:]+):(\\d+:\\d+:\\d+)\\ ([^\\]]+)\\]"
Packit Service 384592
    "\\ \"(.*)\""
Packit Service 384592
    "\\ (\\d+)\\ (\\S+)"
Packit Service 384592
    "\\ \"(.*)\"\\ \"(.*)\""
Packit Service 384592
    "\\ (\\S+)\\ \"(.*)\""
Packit Service 384592
    "\\ /?(\\S+)\\ (\\d+)\\ (\\d+)"
Packit Service 384592
    "\\ (\\S+)"
Packit Service 384592
    "(.*)$";
Packit Service 384592
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * This regular expression can be used to parse
Packit Service 384592
 * a REQUEST_LINE field into method, URI, and
Packit Service 384592
 * protocol.
Packit Service 384592
 */
Packit Service 384592
static const char requestline_pattern[] =
Packit Service 384592
    "(\\S+)\\ (.*?)\\ (\\S+)";
Packit Service 384592
Packit Service 384592
Packit Service 384592
/* -- Structures -- */
Packit Service 384592
Packit Service 384592
typedef struct {
Packit Service 384592
    unsigned long int        id;
Packit Service 384592
    const char              *line;
Packit Service 384592
    apr_size_t               line_size;
Packit Service 384592
} entry_t;
Packit Service 384592
Packit Service 384592
Packit Service 384592
/* -- Global variables -- */
Packit Service 384592
Packit Service 384592
static pid_t                  logc_pid = 0;
Packit Service 384592
static const char            *conffile = NULL;
Packit Service 384592
static const char            *lockfile = NULL;
Packit Service 384592
static int                    have_read_data = 0;
Packit Service 384592
static int                    checkpoint_interval = 60;
Packit Service 384592
static apr_time_t             checkpoint_time_last = 0;
Packit Service 384592
static const char            *collector_root = NULL;
Packit Service 384592
static apr_table_t           *conf = NULL;
Packit Service 384592
static const char            *console_uri = NULL;
Packit Service 384592
static apr_array_header_t    *curl_handles = NULL;
Packit Service 384592
static int                    current_workers = 0;
Packit Service 384592
static int                    management_thread_active = 0;
Packit Service 384592
static unsigned long int      entry_counter = 1;
Packit Service 384592
static const char            *error_log_path = NULL;
Packit Service 384592
static apr_file_t            *error_log_fd = NULL;
Packit Service 384592
static int                    error_log_level = 2;
Packit Service 384592
static apr_hash_t            *in_progress = NULL;
Packit Service 384592
static int                    keep_alive = 150;           /* Not used yet. */
Packit Service 384592
static int                    keep_alive_timeout = 300;   /* Not used yet. */
Packit Service 384592
static int                    keep_entries = 0;
Packit Service 384592
static const char            *log_repository = NULL;
Packit Service 384592
static void                  *logline_regex = NULL;
Packit Service 384592
static int                    max_connections = 10;
Packit Service 384592
static int                    max_worker_requests = 1000;
Packit Service 384592
static apr_global_mutex_t    *gmutex = NULL;
Packit Service 384592
static apr_thread_mutex_t    *mutex = NULL;
Packit Service 384592
static apr_pool_t            *pool = NULL;
Packit Service 384592
static apr_pool_t            *thread_pool = NULL;
Packit Service 384592
static apr_pool_t            *recv_pool = NULL;
Packit Service 384592
static apr_array_header_t    *queue = NULL;
Packit Service 384592
static const char            *queue_path = NULL;
Packit Service 384592
static int                    ssl_validation = 0;
Packit Service 384592
static int                    tlsprotocol = 1;
Packit Service 384592
static curl_version_info_data* curlversion = NULL;
Packit Service 384592
/* static apr_time_t             queue_time = 0; */
Packit Service 384592
static void                  *requestline_regex = NULL;
Packit Service 384592
static int                    running = 0;
Packit Service 384592
static const char            *sensor_password = NULL;
Packit Service 384592
static const char            *sensor_username = NULL;
Packit Service 384592
static int                    server_error = 0;
Packit Service 384592
static apr_time_t             server_error_last_check_time = 0;
Packit Service 384592
static int                    server_error_timeout = 60;
Packit Service 384592
static int                    startup_delay = 100;
Packit Service 384592
static int                    transaction_delay = 100;
Packit Service 384592
static const char            *transaction_log_path = NULL;
Packit Service 384592
static apr_file_t            *transaction_log_fd = NULL;
Packit Service 384592
Packit Service 384592
Packit Service 384592
/* -- Commandline opts -- */
Packit Service 384592
static int                    opt_force = 0;
Packit Service 384592
Packit Service 384592
/* -- Code -- */
Packit Service 384592
Packit Service 384592
static char *_log_escape(apr_pool_t *mp, const char *input,
Packit Service 384592
                         apr_size_t input_len)
Packit Service 384592
{
Packit Service 384592
    static const char c2x_table[] = "0123456789abcdef";
Packit Service 384592
    unsigned char *d = NULL;
Packit Service 384592
    char *ret = NULL;
Packit Service 384592
    unsigned long int i;
Packit Service 384592
Packit Service 384592
    if (input == NULL) return NULL;
Packit Service 384592
Packit Service 384592
    ret = apr_palloc(mp, input_len * 4 + 1);
Packit Service 384592
    if (ret == NULL) return NULL;
Packit Service 384592
    d = (unsigned char *)ret;
Packit Service 384592
Packit Service 384592
    i = 0;
Packit Service 384592
    while(i < input_len) {
Packit Service 384592
        switch(input[i]) {
Packit Service 384592
            case '"' :
Packit Service 384592
                *d++ = '\\';
Packit Service 384592
                *d++ = '"';
Packit Service 384592
                break;
Packit Service 384592
            case '\b' :
Packit Service 384592
                *d++ = '\\';
Packit Service 384592
                *d++ = 'b';
Packit Service 384592
                break;
Packit Service 384592
            case '\n' :
Packit Service 384592
                *d++ = '\\';
Packit Service 384592
                *d++ = 'n';
Packit Service 384592
                break;
Packit Service 384592
            case '\r' :
Packit Service 384592
                *d++ = '\\';
Packit Service 384592
                *d++ = 'r';
Packit Service 384592
                break;
Packit Service 384592
            case '\t' :
Packit Service 384592
                *d++ = '\\';
Packit Service 384592
                *d++ = 't';
Packit Service 384592
                break;
Packit Service 384592
            case '\v' :
Packit Service 384592
                *d++ = '\\';
Packit Service 384592
                *d++ = 'v';
Packit Service 384592
                break;
Packit Service 384592
            case '\\' :
Packit Service 384592
                *d++ = '\\';
Packit Service 384592
                *d++ = '\\';
Packit Service 384592
                break;
Packit Service 384592
            default :
Packit Service 384592
                if ((input[i] <= 0x1f)||(input[i] >= 0x7f)) {
Packit Service 384592
                    *d++ = '\\';
Packit Service 384592
                    *d++ = 'x';
Packit Service 384592
                    *d++ = c2x_table[input[i] >> 4];
Packit Service 384592
                    *d++ = c2x_table[input[i] & 0x0f];
Packit Service 384592
                } else {
Packit Service 384592
                    *d++ = input[i];
Packit Service 384592
                }
Packit Service 384592
                break;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        i++;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    *d = 0;
Packit Service 384592
Packit Service 384592
    return ret;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Converts a byte given as its hexadecimal representation
Packit Service 384592
 * into a proper byte. Handles uppercase and lowercase letters
Packit Service 384592
 * but does not check for overflows.
Packit Service 384592
 */
Packit Service 384592
static unsigned char x2c(unsigned char *what) {
Packit Service 384592
    register unsigned char digit;
Packit Service 384592
Packit Service 384592
    digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
Packit Service 384592
    digit *= 16;
Packit Service 384592
    digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0'));
Packit Service 384592
Packit Service 384592
    return digit;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * URL Decodes a string in-place
Packit Service 384592
 */
Packit Service 384592
static int urldecode_inplace(unsigned char *input, apr_size_t input_len) {
Packit Service 384592
    unsigned char *d = (unsigned char *)input;
Packit Service 384592
    apr_size_t i;
Packit Service 384592
Packit Service 384592
    if (input == NULL) return 0;
Packit Service 384592
Packit Service 384592
    i = 0;
Packit Service 384592
    while (i < input_len) {
Packit Service 384592
        if (input[i] == '%') {
Packit Service 384592
            /* Character is a percent sign. */
Packit Service 384592
Packit Service 384592
            /* Are there enough bytes available? */
Packit Service 384592
            if (i + 2 < input_len) {
Packit Service 384592
                char c1 = input[i + 1];
Packit Service 384592
                char c2 = input[i + 2];
Packit Service 384592
Packit Service 384592
                if (ISHEXCHAR(c1) && ISHEXCHAR(c2)) {
Packit Service 384592
                    /* Valid encoding - decode it. */
Packit Service 384592
                    *d++ = x2c(&input[i + 1]);
Packit Service 384592
                    i += 3;
Packit Service 384592
                } else {
Packit Service 384592
                    /* Not a valid encoding, skip this % */
Packit Service 384592
                    *d++ = input[i++];
Packit Service 384592
                }
Packit Service 384592
            } else {
Packit Service 384592
                /* Not enough bytes available, copy the raw bytes. */
Packit Service 384592
                *d++ = input[i++];
Packit Service 384592
            }
Packit Service 384592
        } else {
Packit Service 384592
            /* Character is not a percent sign. */
Packit Service 384592
            if (input[i] == '+') {
Packit Service 384592
                *d++ = ' ';
Packit Service 384592
            } else {
Packit Service 384592
                *d++ = input[i];
Packit Service 384592
            }
Packit Service 384592
            i++;
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    *d = '\0';
Packit Service 384592
Packit Service 384592
    return 1;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Detect a relative path and merge it with the collector root
Packit Service 384592
 * path. Leave absolute paths as they are.
Packit Service 384592
 */
Packit Service 384592
static const char *file_path(const char *path)
Packit Service 384592
{
Packit Service 384592
    char *newpath = NULL;
Packit Service 384592
    apr_status_t rc;
Packit Service 384592
Packit Service 384592
    if (path == NULL) return NULL;
Packit Service 384592
Packit Service 384592
    rc = apr_filepath_merge(&newpath, collector_root,
Packit Service 384592
                            path, APR_FILEPATH_TRUENAME, pool);
Packit Service 384592
    if ((newpath != NULL) && (rc == APR_SUCCESS || APR_STATUS_IS_EPATHWILD(rc)
Packit Service 384592
        || APR_STATUS_IS_ENOENT(rc) || APR_STATUS_IS_ENOTDIR(rc)))
Packit Service 384592
    {
Packit Service 384592
        return newpath;
Packit Service 384592
    }
Packit Service 384592
    else {
Packit Service 384592
        return NULL;
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Returns the current datetime as a string.
Packit Service 384592
 */
Packit Service 384592
static char *current_logtime(char *dest, int dlen)
Packit Service 384592
{
Packit Service 384592
    apr_time_exp_t t;
Packit Service 384592
    apr_size_t len;
Packit Service 384592
Packit Service 384592
    apr_time_exp_lt(&t, apr_time_now());
Packit Service 384592
    apr_strftime(dest, &len, dlen, "%a %b %d %H:%M:%S %Y", &t);
Packit Service 384592
Packit Service 384592
    return dest;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Logs error to the error log (if available) or
Packit Service 384592
 * to the stderr.
Packit Service 384592
 */
Packit Service 384592
static void error_log(int level, void *thread, const char *text, ...)
Packit Service 384592
{
Packit Service 384592
    char msg1[4096] = "";
Packit Service 384592
    char msg2[4096] = "";
Packit Service 384592
    char datetime[100];
Packit Service 384592
    va_list ap;
Packit Service 384592
Packit Service 384592
    if (level > error_log_level) return;
Packit Service 384592
Packit Service 384592
    va_start(ap, text);
Packit Service 384592
Packit Service 384592
    apr_vsnprintf(msg1, sizeof(msg1), text, ap);
Packit Service 384592
    apr_snprintf(msg2, sizeof(msg2), "[%s] [%d] [%" APR_PID_T_FMT "/%pp] %s\n",
Packit Service 384592
                 current_logtime(datetime, sizeof(datetime)),
Packit Service 384592
                 level, logc_pid, (thread ? thread : 0), msg1);
Packit Service 384592
Packit Service 384592
    if (error_log_fd != NULL) {
Packit Service 384592
        apr_size_t nbytes_written;
Packit Service 384592
        apr_size_t nbytes = strlen(msg2);
Packit Service 384592
        apr_file_write_full(error_log_fd, msg2, nbytes, &nbytes_written);
Packit Service 384592
    }
Packit Service 384592
    else {
Packit Service 384592
        fprintf(stderr, "%s", msg2);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    va_end(ap);
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Adds one entry to the internal queue. It will (optionally) start
Packit Service 384592
 * a new thread to handle it.
Packit Service 384592
 */
Packit Service 384592
static void add_entry(const char *data, int start_worker)
Packit Service 384592
{
Packit Service 384592
    entry_t *entry = NULL;
Packit Service 384592
Packit Service 384592
    entry = (entry_t *)malloc(sizeof(entry_t));
Packit Service 384592
    entry->id = 0;
Packit Service 384592
    entry->line = strdup(data);
Packit Service 384592
    entry->line_size = strlen(entry->line);
Packit Service 384592
Packit Service 384592
    error_log(LOG_DEBUG, NULL, "Queue locking thread mutex.");
Packit Service 384592
    if (APR_STATUS_IS_EBUSY(apr_thread_mutex_trylock(mutex))) {
Packit Service 384592
        error_log(LOG_DEBUG, NULL, "Queue waiting on thread mutex.");
Packit Service 384592
        apr_thread_mutex_lock(mutex);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Assign unique ID to this log entry. */
Packit Service 384592
    entry->id = entry_counter++;
Packit Service 384592
Packit Service 384592
    /* Add the new audit log entry to the queue. */
Packit Service 384592
    *(entry_t **)apr_array_push(queue) = entry;
Packit Service 384592
Packit Service 384592
    /* Create a new worker if we can, but not if there is a
Packit Service 384592
     * known problem with the server.
Packit Service 384592
     */
Packit Service 384592
    if (   (start_worker != 0)
Packit Service 384592
        && (current_workers < max_connections)&&(server_error == 0))
Packit Service 384592
    {
Packit Service 384592
        create_new_worker(0);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    error_log(LOG_DEBUG, NULL, "Queue unlocking thread mutex.");
Packit Service 384592
    apr_thread_mutex_unlock(mutex);
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Read the queue entries.
Packit Service 384592
 */
Packit Service 384592
static int read_queue_entries(apr_file_t *fd, apr_time_t *queue_time)
Packit Service 384592
{
Packit Service 384592
    char linebuf[4100];
Packit Service 384592
    int line_count = -1;
Packit Service 384592
    int line_size = 0;
Packit Service 384592
    apr_status_t rc = 0;
Packit Service 384592
    char *p = NULL;
Packit Service 384592
Packit Service 384592
    for(;;) {
Packit Service 384592
        memset(linebuf, 0, 4100);
Packit Service 384592
        rc = apr_file_gets(linebuf, 4096, fd);
Packit Service 384592
Packit Service 384592
        if (rc == APR_EOF) break;
Packit Service 384592
        if (rc != APR_SUCCESS) {
Packit Service 384592
            error_log(LOG_ERROR, NULL, "Error reading from the queue file.");
Packit Service 384592
            logc_shutdown(1);
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        if (line_count < 0) {
Packit Service 384592
            /* First line contains the queue time. */
Packit Service 384592
            *queue_time = (apr_time_t)apr_atoi64(linebuf);
Packit Service 384592
            line_count = 0;
Packit Service 384592
            continue;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        p = &linebuf[0];
Packit Service 384592
        line_size = strlen(p);
Packit Service 384592
Packit Service 384592
        /* Remove the \n from the end of the line. */
Packit Service 384592
        while(*p != '\0' && line_size > 0) {
Packit Service 384592
            if (*p == '\n') {
Packit Service 384592
                *p = '\0';
Packit Service 384592
                break;
Packit Service 384592
            }
Packit Service 384592
            p++;
Packit Service 384592
            line_size--;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        if (linebuf[0] == '#') { /* Ignore comments. */
Packit Service 384592
            continue;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        add_entry((const char *)&linebuf, 0);
Packit Service 384592
Packit Service 384592
        line_count++;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    apr_file_close(fd);
Packit Service 384592
Packit Service 384592
    return line_count;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Initialise the transaction log. This code should be
Packit Service 384592
 * executed only once at startup.
Packit Service 384592
 */
Packit Service 384592
static void transaction_log_init(void)
Packit Service 384592
{
Packit Service 384592
    /* ENH: These big enough? */
Packit Service 384592
    char new_queue_path[256];
Packit Service 384592
    char old_queue_path[256];
Packit Service 384592
    apr_file_t *queue_fd = NULL;
Packit Service 384592
    apr_time_t queue_time;
Packit Service 384592
Packit Service 384592
    apr_snprintf(new_queue_path, sizeof(new_queue_path), "%s.new", queue_path);
Packit Service 384592
    apr_snprintf(old_queue_path, sizeof(old_queue_path), "%s.old", queue_path);
Packit Service 384592
Packit Service 384592
    /* Put a lock in place to ensure exclusivity. */
Packit Service 384592
    error_log(LOG_DEBUG, NULL,
Packit Service 384592
              "Transaction initialization locking global mutex.");
Packit Service 384592
    if (APR_STATUS_IS_EBUSY(apr_global_mutex_trylock(gmutex))) {
Packit Service 384592
        error_log(LOG_DEBUG, NULL,
Packit Service 384592
                  "Transaction initialization waiting on global mutex.");
Packit Service 384592
        apr_global_mutex_lock(gmutex);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    error_log(LOG_DEBUG, NULL, "Transaction initialization started.");
Packit Service 384592
Packit Service 384592
    /* Delete .new file if there is one. */
Packit Service 384592
    apr_file_remove(new_queue_path, pool);
Packit Service 384592
Packit Service 384592
    /* Read in the data from the queue. */
Packit Service 384592
    if (apr_file_open(&queue_fd, queue_path, APR_READ | APR_FILE_NOCLEANUP,
Packit Service 384592
        0, pool) == APR_SUCCESS)
Packit Service 384592
    {
Packit Service 384592
        int line_count = read_queue_entries(queue_fd, &queue_time);
Packit Service 384592
Packit Service 384592
        apr_file_close(queue_fd);
Packit Service 384592
Packit Service 384592
        if (line_count > 0) {
Packit Service 384592
            error_log(LOG_NOTICE, NULL,
Packit Service 384592
                      "Loaded %d entries from the queue file.", line_count);
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
    /* Try the old queue file. */
Packit Service 384592
    else if (apr_file_open(&queue_fd, old_queue_path,
Packit Service 384592
                           APR_READ | APR_FILE_NOCLEANUP,
Packit Service 384592
                           0, pool) == APR_SUCCESS)
Packit Service 384592
    {
Packit Service 384592
        int line_count = read_queue_entries(queue_fd, &queue_time);
Packit Service 384592
        apr_file_close(queue_fd);
Packit Service 384592
        error_log(LOG_NOTICE, NULL,
Packit Service 384592
                  "Loaded %d entries from the OLD queue file.", line_count);
Packit Service 384592
        apr_file_rename(old_queue_path, queue_path, pool);
Packit Service 384592
    }
Packit Service 384592
    else {
Packit Service 384592
        error_log(LOG_NOTICE, NULL,
Packit Service 384592
                  "Queue file not found. New one will be created.");
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Delete the old queue file. */
Packit Service 384592
    apr_file_remove(old_queue_path, pool);
Packit Service 384592
Packit Service 384592
    checkpoint_time_last = apr_time_now();
Packit Service 384592
Packit Service 384592
    /* Start fresh with the transaction log. Do note that
Packit Service 384592
     * we do not truncate the transaction log on purpose. Apache
Packit Service 384592
     * will start copies of piped logging binaries during configuration
Packit Service 384592
     * testing. Truncating would erase the log of a currently running
Packit Service 384592
     * instance.
Packit Service 384592
     */
Packit Service 384592
    if (apr_file_open(&transaction_log_fd, transaction_log_path,
Packit Service 384592
                      APR_WRITE | APR_CREATE | APR_APPEND | APR_XTHREAD,
Packit Service 384592
                      APR_OS_DEFAULT, pool) != APR_SUCCESS)
Packit Service 384592
    {
Packit Service 384592
        error_log(LOG_ERROR, NULL,
Packit Service 384592
                  "Failed to open the transaction log: %s\n",
Packit Service 384592
                  transaction_log_path);
Packit Service 384592
        error_log(LOG_DEBUG, NULL,
Packit Service 384592
                  "Transaction initialization unlocking global mutex.");
Packit Service 384592
        apr_global_mutex_unlock(gmutex);
Packit Service 384592
        logc_shutdown(1);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    error_log(LOG_DEBUG, NULL, "Transaction initialization completed.");
Packit Service 384592
Packit Service 384592
    /* Unlock */
Packit Service 384592
    error_log(LOG_DEBUG, NULL,
Packit Service 384592
              "Transaction initialization unlocking global mutex.");
Packit Service 384592
    apr_global_mutex_unlock(gmutex);
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Log entry event (incoming or outgoing) to the transaction log.
Packit Service 384592
 */
Packit Service 384592
static void transaction_log(int direction, const char *entry)
Packit Service 384592
{
Packit Service 384592
    apr_size_t nbytes, nbytes_written;
Packit Service 384592
    char msg[8196] = "";
Packit Service 384592
Packit Service 384592
    apr_snprintf(msg, sizeof(msg), "%u %s: %s\n",
Packit Service 384592
                 (unsigned int)apr_time_sec(apr_time_now()),
Packit Service 384592
        (direction == TXIN ? "IN" : "OUT"), entry);
Packit Service 384592
    nbytes = strlen(msg);
Packit Service 384592
    apr_file_write_full(transaction_log_fd, msg, nbytes, &nbytes_written);
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Executes a checkpoint, which causes the current queue to be
Packit Service 384592
 * written to a file and the transaction log to be truncated.
Packit Service 384592
 */
Packit Service 384592
static void transaction_checkpoint(void)
Packit Service 384592
{
Packit Service 384592
    /* ENH: These big enough? */
Packit Service 384592
    char new_queue_path[256];
Packit Service 384592
    char old_queue_path[256];
Packit Service 384592
    apr_file_t *queue_fd = NULL;
Packit Service 384592
    apr_hash_index_t *hi = NULL;
Packit Service 384592
    char msg[256];
Packit Service 384592
    int i;
Packit Service 384592
    apr_pool_t *cpool;
Packit Service 384592
Packit Service 384592
    apr_snprintf(new_queue_path, sizeof(new_queue_path), "%s.new", queue_path);
Packit Service 384592
    apr_snprintf(old_queue_path, sizeof(old_queue_path), "%s.old", queue_path);
Packit Service 384592
    apr_snprintf(msg, sizeof(msg), "%u\n",
Packit Service 384592
                 (unsigned int)apr_time_sec(apr_time_now()));
Packit Service 384592
Packit Service 384592
    if (! have_read_data) {
Packit Service 384592
        error_log(LOG_DEBUG, NULL, "Checkpoint not required.");
Packit Service 384592
        return;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Put a lock in place to ensure exclusivity. */
Packit Service 384592
    error_log(LOG_DEBUG, NULL, "Checkpoint locking global mutex.");
Packit Service 384592
    if (APR_STATUS_IS_EBUSY(apr_global_mutex_trylock(gmutex))) {
Packit Service 384592
        error_log(LOG_DEBUG, NULL, "Checkpoint waiting on global mutex.");
Packit Service 384592
        apr_global_mutex_lock(gmutex);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    error_log(LOG_DEBUG, NULL, "Checkpoint started.");
Packit Service 384592
Packit Service 384592
    apr_pool_create(&cpool, NULL);
Packit Service 384592
Packit Service 384592
    /* Dump active entries into a new queue file. */
Packit Service 384592
    if (apr_file_open(&queue_fd, new_queue_path,
Packit Service 384592
                      APR_WRITE | APR_CREATE | APR_EXCL |
Packit Service 384592
                      APR_TRUNCATE | APR_FILE_NOCLEANUP,
Packit Service 384592
                      APR_OS_DEFAULT, cpool) != APR_SUCCESS)
Packit Service 384592
    {
Packit Service 384592
        error_log(LOG_ERROR, NULL, "Failed to create file: %s", new_queue_path);
Packit Service 384592
        error_log(LOG_DEBUG, NULL, "Checkpoint unlocking global mutex.");
Packit Service 384592
        apr_pool_destroy(cpool);
Packit Service 384592
        apr_global_mutex_unlock(gmutex);
Packit Service 384592
        return;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Write the time first. */
Packit Service 384592
    apr_file_write_full(queue_fd, msg, strlen(msg), NULL);
Packit Service 384592
Packit Service 384592
    /* Dump the entries sitting in the queue first. */
Packit Service 384592
    for (i = 0; i < queue->nelts; i++) {
Packit Service 384592
        entry_t *entry = ((entry_t **)queue->elts)[i];
Packit Service 384592
        apr_file_write_full(queue_fd, entry->line, entry->line_size, NULL);
Packit Service 384592
        apr_file_write_full(queue_fd, &"\n", 1, NULL);
Packit Service 384592
    }
Packit Service 384592
    error_log(LOG_DEBUG2, NULL,
Packit Service 384592
              "Checkpoint wrote %d queued entries to new queue.", i);
Packit Service 384592
Packit Service 384592
    /* Then dump the ones that are currently being processed. */
Packit Service 384592
    i = 0;
Packit Service 384592
    for (hi = apr_hash_first(NULL, in_progress);
Packit Service 384592
         hi != NULL; hi = apr_hash_next(hi))\
Packit Service 384592
    {
Packit Service 384592
        void *e;
Packit Service 384592
        entry_t *entry = NULL;
Packit Service 384592
Packit Service 384592
        i++;
Packit Service 384592
        apr_hash_this(hi, NULL, NULL, &e);
Packit Service 384592
        entry = e; /* quiet type-punned warning */
Packit Service 384592
        apr_file_write_full(queue_fd, entry->line, entry->line_size, NULL);
Packit Service 384592
        apr_file_write_full(queue_fd, &"\n", 1, NULL);
Packit Service 384592
    }
Packit Service 384592
    error_log(LOG_DEBUG2, NULL,
Packit Service 384592
              "Checkpoint wrote %d additional entries to new queue.", i);
Packit Service 384592
Packit Service 384592
    apr_file_close(queue_fd);
Packit Service 384592
Packit Service 384592
    /* Switch the files and truncate the transaction log file. */
Packit Service 384592
    apr_file_remove(old_queue_path, cpool);
Packit Service 384592
    apr_file_rename(queue_path, old_queue_path, cpool);
Packit Service 384592
    apr_file_rename(new_queue_path, queue_path, cpool);
Packit Service 384592
    apr_file_remove(old_queue_path, cpool);
Packit Service 384592
    apr_file_trunc(transaction_log_fd, 0);
Packit Service 384592
Packit Service 384592
    error_log(LOG_DEBUG, NULL, "Checkpoint completed.");
Packit Service 384592
Packit Service 384592
    apr_pool_destroy(cpool);
Packit Service 384592
Packit Service 384592
    /* Unlock and exit. */
Packit Service 384592
    error_log(LOG_DEBUG, NULL, "Checkpoint unlocking global mutex.");
Packit Service 384592
    apr_global_mutex_unlock(gmutex);
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Parse one confguration line and add it to the
Packit Service 384592
 * configuration table.
Packit Service 384592
 */
Packit Service 384592
static void parse_configuration_line(const char *line, int line_count)
Packit Service 384592
{
Packit Service 384592
    char *start = NULL, *command = NULL;
Packit Service 384592
    char *p = NULL;
Packit Service 384592
Packit Service 384592
    /* Remove the trailing newline character. */
Packit Service 384592
    p = (char *)line;
Packit Service 384592
    while(*p != '\0') p++;
Packit Service 384592
    if ((p > start)&&(*(p - 1) == '\n')) *(p - 1) = '\0';
Packit Service 384592
Packit Service 384592
    p = (char *)line;
Packit Service 384592
    /* Ignore whitespace at the beginning of the line. */
Packit Service 384592
    while(apr_isspace(*p)) p++;
Packit Service 384592
Packit Service 384592
    /* Ignore empty lines and comments. */
Packit Service 384592
    if ((*p == '\0')||(*p == '#')) return;
Packit Service 384592
Packit Service 384592
    start = p;
Packit Service 384592
    while(!apr_isspace(*p)&&(*p != '\0')) p++;
Packit Service 384592
Packit Service 384592
    command = apr_pstrmemdup(pool, start, p - start);
Packit Service 384592
Packit Service 384592
    while(apr_isspace(*p)) p++;
Packit Service 384592
Packit Service 384592
    /* Remove whitespace at the end. */
Packit Service 384592
    start = p;
Packit Service 384592
    while(*p != '\0') p++;
Packit Service 384592
    if (p > start) {
Packit Service 384592
        p--;
Packit Service 384592
        while(apr_isspace(*p)) {
Packit Service 384592
            *p-- = '\0';
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Remove quotes, but only if we have matching */
Packit Service 384592
    if ((*start == '"') && (p > start) && (*p == '"')) {
Packit Service 384592
        start++;
Packit Service 384592
        *p-- = '\0';
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Take the last directive */
Packit Service 384592
    /* ENH: Error on dup directives? */
Packit Service 384592
    apr_table_set(conf, command, start);
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Reads configuration from a file.
Packit Service 384592
 */
Packit Service 384592
static void read_configuration(void)
Packit Service 384592
{
Packit Service 384592
    char linebuf[4096];
Packit Service 384592
    apr_status_t rc;
Packit Service 384592
    apr_file_t *fd;
Packit Service 384592
    int line_count;
Packit Service 384592
Packit Service 384592
    conf = apr_table_make(pool, 32);
Packit Service 384592
    if (conf == NULL) {
Packit Service 384592
        error_log(LOG_ERROR, NULL, MEMALLOC_ERROR_MSG);
Packit Service 384592
        logc_shutdown(1);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    rc = apr_file_open(&fd, conffile, APR_READ | APR_FILE_NOCLEANUP, 0, pool);
Packit Service 384592
    if (rc != APR_SUCCESS) {
Packit Service 384592
        error_log(LOG_ERROR, NULL,
Packit Service 384592
                  "Unable to open configuration file: %s", conffile);
Packit Service 384592
        logc_shutdown(1);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    line_count = 0;
Packit Service 384592
    for(;;) {
Packit Service 384592
        rc = apr_file_gets(linebuf, 4096, fd);
Packit Service 384592
        if (rc == APR_EOF) return;
Packit Service 384592
        if (rc != APR_SUCCESS) {
Packit Service 384592
            error_log(LOG_ERROR, NULL,
Packit Service 384592
                      "Error reading from the configuration file.");
Packit Service 384592
            logc_shutdown(1);
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        line_count++;
Packit Service 384592
        parse_configuration_line(linebuf, line_count);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    apr_file_close(fd);
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Initialize the configuration.
Packit Service 384592
 */
Packit Service 384592
static void init_configuration(void)
Packit Service 384592
{
Packit Service 384592
    char errstr[1024];
Packit Service 384592
    apr_status_t rc = 0;
Packit Service 384592
    const char *s = NULL;
Packit Service 384592
Packit Service 384592
    /* Other values may be based off the collector root. */
Packit Service 384592
    s = apr_table_get(conf, "CollectorRoot");
Packit Service 384592
    if (s != NULL) {
Packit Service 384592
        collector_root = s;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Error Log */
Packit Service 384592
    s = apr_table_get(conf, "ErrorLog");
Packit Service 384592
    if (s != NULL) {
Packit Service 384592
        error_log_path = file_path(s);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    s = apr_table_get(conf, "ErrorLogLevel");
Packit Service 384592
    if (s != NULL) {
Packit Service 384592
        error_log_level = atoi(s);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    if ((rc = apr_file_open(&error_log_fd, error_log_path,
Packit Service 384592
                            APR_WRITE | APR_CREATE | APR_APPEND,
Packit Service 384592
                            APR_OS_DEFAULT, pool)) != APR_SUCCESS)
Packit Service 384592
    {
Packit Service 384592
        error_log(LOG_ERROR, NULL, "Failed to open the error log %s: %s\n",
Packit Service 384592
            error_log_path, apr_strerror(rc, errstr, 1024));
Packit Service 384592
        logc_shutdown(1);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    error_log(LOG_NOTICE, NULL,
Packit Service 384592
              "Configuring ModSecurity Audit Log Collector %s.", VERSION);
Packit Service 384592
Packit Service 384592
    /* Startup Delay */
Packit Service 384592
    s = apr_table_get(conf, "StartupDelay");
Packit Service 384592
    if (s != NULL) {
Packit Service 384592
        startup_delay = atoi(s);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* TLS Protocol - TLSv1(0) TLSv1.1(1) TLSv1.2(2) (SSLv3 not supported) */
Packit Service 384592
    s = apr_table_get(conf, "TLSProtocol");
Packit Service 384592
    if (s != NULL) {
Packit Service 384592
    	int num = atoi(s);
Packit Service 384592
    	switch (num) {
Packit Service 384592
    	case 0:
Packit Service 384592
    		tlsprotocol = 0;
Packit Service 384592
    		break;
Packit Service 384592
    	case 1:
Packit Service 384592
    		tlsprotocol = 1;
Packit Service 384592
    		break;
Packit Service 384592
    	case 2:
Packit Service 384592
    		tlsprotocol = 2;
Packit Service 384592
    		break;
Packit Service 384592
    	default:
Packit Service 384592
    		tlsprotocol = 2; /* Default is TLSv1.2 */
Packit Service 384592
    	}
Packit Service 384592
    }
Packit Service 384592
    curlversion = curl_version_info(CURLVERSION_NOW);
Packit Service 384592
Packit Service 384592
    if ( startup_delay > 0 ) {
Packit Service 384592
        error_log(LOG_NOTICE, NULL,
Packit Service 384592
                  "Delaying execution for %dms.", startup_delay);
Packit Service 384592
        apr_sleep(startup_delay * 1000);
Packit Service 384592
        error_log(LOG_DEBUG, NULL,
Packit Service 384592
                  "Continuing execution after %dms delay.", startup_delay);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Remaining Configuration */
Packit Service 384592
Packit Service 384592
    error_log(LOG_DEBUG2, NULL, "CollectorRoot=%s", collector_root);
Packit Service 384592
    error_log(LOG_DEBUG2, NULL, "ErrorLog=%s", error_log_path);
Packit Service 384592
    error_log(LOG_DEBUG2, NULL, "ErrorLogLevel=%d", error_log_level);
Packit Service 384592
    error_log(LOG_DEBUG2, NULL, "StartupDelay=%d", startup_delay);
Packit Service 384592
    error_log(LOG_DEBUG2, NULL, "TLSProtocol=%d", tlsprotocol);
Packit Service 384592
    error_log(LOG_DEBUG2, NULL, "cURL version=%s",  curlversion->version);
Packit Service 384592
Packit Service 384592
    s = apr_table_get(conf, "CheckpointInterval");
Packit Service 384592
    if (s != NULL) {
Packit Service 384592
        checkpoint_interval = atoi(s);
Packit Service 384592
        error_log(LOG_DEBUG2, NULL,
Packit Service 384592
                  "CheckpointInterval=%d", checkpoint_interval);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    s = apr_table_get(conf, "InsecureNoCheckCert");
Packit Service 384592
    if (s != NULL) {
Packit Service 384592
        int num = atoi(s);
Packit Service 384592
        if (num)
Packit Service 384592
        {
Packit Service 384592
            ssl_validation = 0;
Packit Service 384592
        }
Packit Service 384592
        else
Packit Service 384592
        {
Packit Service 384592
            ssl_validation = 1;
Packit Service 384592
        }
Packit Service 384592
        error_log(LOG_DEBUG2, NULL, "InsecureNoCheckCert=%d", num);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    s = apr_table_get(conf, "QueuePath");
Packit Service 384592
    if (s != NULL) {
Packit Service 384592
        queue_path = file_path(s);
Packit Service 384592
        error_log(LOG_DEBUG2, NULL, "QueuePath=%s", queue_path);
Packit Service 384592
    }
Packit Service 384592
    else {
Packit Service 384592
        error_log(LOG_ERROR, NULL,
Packit Service 384592
                  "QueuePath not defined in the configuration file.");
Packit Service 384592
        logc_shutdown(1);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    s = apr_table_get(conf, "LockFile");
Packit Service 384592
    if (s != NULL) {
Packit Service 384592
        lockfile = file_path(s);
Packit Service 384592
        error_log(LOG_DEBUG2, NULL, "LockFile=%s", lockfile);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    s = apr_table_get(conf, "ServerErrorTimeout");
Packit Service 384592
    if (s != NULL) {
Packit Service 384592
        server_error_timeout = atoi(s);
Packit Service 384592
        error_log(LOG_DEBUG2, NULL,
Packit Service 384592
                  "ServerErrorTimeout=%d", server_error_timeout);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    s = apr_table_get(conf, "TransactionDelay");
Packit Service 384592
    if (s != NULL) {
Packit Service 384592
        transaction_delay = atoi(s);
Packit Service 384592
        error_log(LOG_DEBUG2, NULL, "TransactionDelay=%d", transaction_delay);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    s = apr_table_get(conf, "TransactionLog");
Packit Service 384592
    if (s != NULL) {
Packit Service 384592
        transaction_log_path = file_path(s);
Packit Service 384592
        error_log(LOG_DEBUG2, NULL, "TransactionLog=%s", transaction_log_path);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    s = apr_table_get(conf, "MaxConnections");
Packit Service 384592
    if (s != NULL) {
Packit Service 384592
        int v = atoi(s);
Packit Service 384592
        if (v >= 0) max_connections = v;
Packit Service 384592
        error_log(LOG_DEBUG2, NULL, "MaxConnections=%d", max_connections);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    s = apr_table_get(conf, "MaxWorkerRequests");
Packit Service 384592
    if (s != NULL) {
Packit Service 384592
        int v = atoi(s);
Packit Service 384592
        if (v >= 0) max_worker_requests = v;
Packit Service 384592
        error_log(LOG_DEBUG2, NULL,
Packit Service 384592
                  "MaxWorkerRequests=%d", max_worker_requests);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    s = apr_table_get(conf, "KeepAlive");
Packit Service 384592
    if (s != NULL) {
Packit Service 384592
        int v = atoi(s);
Packit Service 384592
        if (v >= 0) keep_alive = v;
Packit Service 384592
        error_log(LOG_DEBUG2, NULL, "KeepAlive=%d", keep_alive);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    s = apr_table_get(conf, "KeepAliveTimeout");
Packit Service 384592
    if (s != NULL) {
Packit Service 384592
        int v = atoi(s);
Packit Service 384592
        if (v >= 0) keep_alive_timeout = v;
Packit Service 384592
        error_log(LOG_DEBUG2, NULL, "KeepAliveTimeout=%d", keep_alive_timeout);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    s = apr_table_get(conf, "LogStorageDir");
Packit Service 384592
    if (s != NULL) {
Packit Service 384592
        log_repository = file_path(s);
Packit Service 384592
        error_log(LOG_DEBUG2, NULL, "LogStorageDir=%s", log_repository);
Packit Service 384592
    }
Packit Service 384592
    else {
Packit Service 384592
        error_log(LOG_ERROR, NULL,
Packit Service 384592
                  "Missing mandatory parameter LogStorageDir.\n");
Packit Service 384592
        logc_shutdown(1);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    s = apr_table_get(conf, "ConsoleURI");
Packit Service 384592
    if (s != NULL) {
Packit Service 384592
        console_uri = s;
Packit Service 384592
        error_log(LOG_DEBUG2, NULL, "ConsoleURI=%s", console_uri);
Packit Service 384592
    }
Packit Service 384592
    else {
Packit Service 384592
        error_log(LOG_ERROR, NULL, "Missing mandatory parameter ConsoleURI.\n");
Packit Service 384592
        logc_shutdown(1);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    s = apr_table_get(conf, "SensorUsername");
Packit Service 384592
    if (s != NULL) {
Packit Service 384592
        sensor_username = s;
Packit Service 384592
        error_log(LOG_DEBUG2, NULL, "SensorUsername=%s", sensor_username);
Packit Service 384592
    }
Packit Service 384592
    else {
Packit Service 384592
        error_log(LOG_ERROR, NULL,
Packit Service 384592
                  "Missing mandatory parameter SensorUsername.\n");
Packit Service 384592
        logc_shutdown(1);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    s = apr_table_get(conf, "SensorPassword");
Packit Service 384592
    if (s != NULL) {
Packit Service 384592
        sensor_password = s;
Packit Service 384592
        error_log(LOG_DEBUG2, NULL, "SensorPassword=%s", sensor_password);
Packit Service 384592
    }
Packit Service 384592
    else {
Packit Service 384592
        error_log(LOG_ERROR, NULL,
Packit Service 384592
                  "Missing mandatory parameter SensorPassword.\n");
Packit Service 384592
        logc_shutdown(1);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    s = apr_table_get(conf, "KeepEntries");
Packit Service 384592
    if (s != NULL) {
Packit Service 384592
        keep_entries = atoi(s);
Packit Service 384592
    }
Packit Service 384592
    else {
Packit Service 384592
        keep_entries = 0;
Packit Service 384592
    }
Packit Service 384592
    error_log(LOG_DEBUG2, NULL, "KeepEntries=%d", keep_entries);
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Clean-up resources before process shutdown.
Packit Service 384592
 */
Packit Service 384592
static void logc_cleanup(void)
Packit Service 384592
{
Packit Service 384592
    curl_global_cleanup();
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Shutdown the logger.
Packit Service 384592
 */
Packit Service 384592
static void logc_shutdown(int rc)
Packit Service 384592
{
Packit Service 384592
    /* Tell the threads to shut down. */
Packit Service 384592
    running = 0;
Packit Service 384592
Packit Service 384592
    error_log(LOG_DEBUG, NULL, "Shutting down");
Packit Service 384592
Packit Service 384592
    /* Wait for the management thread to stop */
Packit Service 384592
    /* ENH: Need a fixed timeout if this never happens */
Packit Service 384592
    while(management_thread_active != 0) {
Packit Service 384592
        apr_sleep(10 * 1000);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    if (rc == 0) {
Packit Service 384592
        error_log(LOG_NOTICE, NULL,
Packit Service 384592
                  "ModSecurity Audit Log Collector %s terminating normally.",
Packit Service 384592
                  VERSION);
Packit Service 384592
    }
Packit Service 384592
    else {
Packit Service 384592
        error_log(LOG_NOTICE, NULL,
Packit Service 384592
                  "ModSecurity Audit Log Collector %s "
Packit Service 384592
                  "terminating with error %d", VERSION, rc);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    if (error_log_fd != NULL) {
Packit Service 384592
        apr_file_flush(error_log_fd);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    exit(rc);
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Handle signals.
Packit Service 384592
 */
Packit Service 384592
static int handle_signals(int signum)
Packit Service 384592
{
Packit Service 384592
    switch (signum) {
Packit Service 384592
        case SIGINT:
Packit Service 384592
            error_log(LOG_NOTICE, NULL, "Caught SIGINT, shutting down.");
Packit Service 384592
            logc_shutdown(0);
Packit Service 384592
        case SIGTERM:
Packit Service 384592
            error_log(LOG_NOTICE, NULL, "Caught SIGTERM, shutting down.");
Packit Service 384592
            logc_shutdown(0);
Packit Service 384592
#ifndef WIN32
Packit Service 384592
        case SIGHUP:
Packit Service 384592
            error_log(LOG_NOTICE, NULL, "Caught SIGHUP, ignored.");
Packit Service 384592
            /* ENH: reload config? */
Packit Service 384592
            return 0;
Packit Service 384592
        case SIGALRM:
Packit Service 384592
            error_log(LOG_DEBUG, NULL, "Caught SIGALRM, ignored.");
Packit Service 384592
            return 0;
Packit Service 384592
        case SIGTSTP:
Packit Service 384592
            error_log(LOG_DEBUG, NULL, "Caught SIGTSTP, ignored.");
Packit Service 384592
            return 0;
Packit Service 384592
#endif /* WIN32 */
Packit Service 384592
    }
Packit Service 384592
#ifndef WIN32
Packit Service 384592
    error_log(LOG_NOTICE, NULL,
Packit Service 384592
              "Caught unexpected signal %d: %s",
Packit Service 384592
              signum, apr_signal_description_get(signum));
Packit Service 384592
#else
Packit Service 384592
    error_log(LOG_NOTICE, NULL, "Caught unexpected signal %d", signum);
Packit Service 384592
#endif /* WIN32 */
Packit Service 384592
    logc_shutdown(1);
Packit Service 384592
Packit Service 384592
    return 0; /* should never reach */
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
#ifdef WIN32
Packit Service 384592
/**
Packit Service 384592
 * This function is invoked by Curl to read the source file on Windows
Packit Service 384592
 */
Packit Service 384592
static size_t curl_readfunction(void *ptr, size_t size,
Packit Service 384592
                                 size_t nmemb, void *stream)
Packit Service 384592
{
Packit Service 384592
        return fread(ptr, size, nmemb, (FILE *)stream);
Packit Service 384592
}
Packit Service 384592
#endif
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * This function is invoked by Curl to read the response
Packit Service 384592
 * body. Since we don't care about the response body the function
Packit Service 384592
 * pretends it is retrieving data where it isn't.
Packit Service 384592
 */
Packit Service 384592
static size_t curl_writefunction(void *ptr, size_t size,
Packit Service 384592
                                 size_t nmemb, void *stream)
Packit Service 384592
{
Packit Service 384592
    unsigned char *data = (unsigned char *)ptr;
Packit Service 384592
    unsigned char *status = (unsigned char *)stream;
Packit Service 384592
Packit Service 384592
    /* Grab the status line text from the first line of output */
Packit Service 384592
    if ((status[0] == 0) && (status[1] == 1)) {
Packit Service 384592
        apr_size_t i, j;
Packit Service 384592
        int ismsg = 0;
Packit Service 384592
Packit Service 384592
        status[1] = 0; /* reset hidden init flag */
Packit Service 384592
Packit Service 384592
        for (i = 0, j = 0; i < STATUSBUF_SIZE; i++) {
Packit Service 384592
            /* We found a line ending so we are done */
Packit Service 384592
            if ( data[i] == '\r' ) {
Packit Service 384592
                break;
Packit Service 384592
            }
Packit Service 384592
            /* Skip to after the first space (where msg is) */
Packit Service 384592
            if (ismsg < 3) {
Packit Service 384592
                if ((ismsg == 1) && !isspace(data[i])) {
Packit Service 384592
                    ismsg++;
Packit Service 384592
                }
Packit Service 384592
                else if (isspace(data[i])) {
Packit Service 384592
                    ismsg++;
Packit Service 384592
                }
Packit Service 384592
                continue;
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            /* Copy data (msg) from data to status */
Packit Service 384592
            status[j++] = data[i];
Packit Service 384592
        }
Packit Service 384592
        status[j] = '\0';
Packit Service 384592
        urldecode_inplace(status, j);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* do nothing */
Packit Service 384592
    return (size * nmemb);
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * This function is invoked by Curl whenever it has something
Packit Service 384592
 * to say. We forward its messages to the error log at level
Packit Service 384592
 * DEBUG or DEBUG2 depending on the verbosity.
Packit Service 384592
 */
Packit Service 384592
static int curl_debugfunction(CURL *curl, curl_infotype infotype,
Packit Service 384592
                              char *data, size_t datalen, void *ourdata)
Packit Service 384592
{
Packit Service 384592
    apr_size_t i, effectivelen;
Packit Service 384592
    apr_thread_t *thread = (apr_thread_t *)ourdata;
Packit Service 384592
Packit Service 384592
    if (error_log_level < LOG_DEBUG) return 0;
Packit Service 384592
Packit Service 384592
    effectivelen = datalen;
Packit Service 384592
    for(i = 0; i < datalen; i++) {
Packit Service 384592
        if ((data[i] == 0x0a)||(data[i] == 0x0d)) {
Packit Service 384592
            effectivelen = i;
Packit Service 384592
            break;
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    switch (infotype) {
Packit Service 384592
        case CURLINFO_TEXT:
Packit Service 384592
            /* More verbose data starts with an indent */
Packit Service 384592
            if (apr_isspace(data[0])) {
Packit Service 384592
                char *dataptr = data + 1;
Packit Service 384592
                
Packit Service 384592
                /* Skip initial whitespace (indent) */
Packit Service 384592
                while (   ((size_t)(dataptr - data) > datalen)
Packit Service 384592
                       && apr_isspace(*dataptr)) dataptr++;
Packit Service 384592
                dataptr++;
Packit Service 384592
                error_log(LOG_DEBUG2, thread, "CURL: %s",
Packit Service 384592
                          _log_escape(apr_thread_pool_get(thread), dataptr,
Packit Service 384592
                                      effectivelen - (dataptr - data)));
Packit Service 384592
            }
Packit Service 384592
            else {
Packit Service 384592
                error_log(LOG_DEBUG, thread, "CURL: %s",
Packit Service 384592
                          _log_escape(apr_thread_pool_get(thread), data,
Packit Service 384592
                                      effectivelen));
Packit Service 384592
            }
Packit Service 384592
            break;
Packit Service 384592
        case CURLINFO_HEADER_IN:
Packit Service 384592
            error_log(LOG_DEBUG, thread, "CURL: HEADER_IN %s",
Packit Service 384592
                      _log_escape(apr_thread_pool_get(thread), data,
Packit Service 384592
                                  effectivelen));
Packit Service 384592
            break;
Packit Service 384592
        case CURLINFO_HEADER_OUT:
Packit Service 384592
            error_log(LOG_DEBUG, thread, "CURL: HEADER_OUT %s",
Packit Service 384592
                      _log_escape(apr_thread_pool_get(thread), data,
Packit Service 384592
                                  effectivelen));
Packit Service 384592
            break;
Packit Service 384592
        case CURLINFO_DATA_IN:
Packit Service 384592
            error_log(LOG_DEBUG2, thread, "CURL: DATA_IN %s",
Packit Service 384592
                      _log_escape(apr_thread_pool_get(thread), data,
Packit Service 384592
                                  effectivelen));
Packit Service 384592
            break;
Packit Service 384592
        case CURLINFO_DATA_OUT:
Packit Service 384592
            error_log(LOG_DEBUG2, thread, "CURL: DATA_OUT %s",
Packit Service 384592
                      _log_escape(apr_thread_pool_get(thread), data,
Packit Service 384592
                                  effectivelen));
Packit Service 384592
            break;
Packit Service 384592
        default:
Packit Service 384592
            /* Ignore anything else */
Packit Service 384592
            break;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    return 0;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Initialise the necessary resources and structures.
Packit Service 384592
 */
Packit Service 384592
static void logc_init(void)
Packit Service 384592
{
Packit Service 384592
    char errstr[1024];
Packit Service 384592
    apr_status_t rc = 0;
Packit Service 384592
    const char *errptr = NULL;
Packit Service 384592
    int i, erroffset;
Packit Service 384592
    /* cURL major, minor and patch version */
Packit Service 384592
    short cmaj, cmin, cpat = 0;
Packit Service 384592
Packit Service 384592
    queue = apr_array_make(pool, 64, sizeof(entry_t *));
Packit Service 384592
    if (queue == NULL) {
Packit Service 384592
        error_log(LOG_ERROR, NULL, MEMALLOC_ERROR_MSG);
Packit Service 384592
        logc_shutdown(1);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    in_progress = apr_hash_make(pool);
Packit Service 384592
    if (in_progress == NULL) {
Packit Service 384592
        error_log(LOG_ERROR, NULL, MEMALLOC_ERROR_MSG);
Packit Service 384592
        logc_shutdown(1);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    if ((rc = apr_global_mutex_create(&gmutex, lockfile,
Packit Service 384592
                                      APR_LOCK_DEFAULT, pool)) != APR_SUCCESS)
Packit Service 384592
    {
Packit Service 384592
        error_log(LOG_ERROR, NULL, "Failed to create global mutex: %s",
Packit Service 384592
            apr_strerror(rc, errstr, 1024));
Packit Service 384592
        logc_shutdown(1);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    if ((rc = apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_UNNESTED,
Packit Service 384592
                                      pool)) != APR_SUCCESS)
Packit Service 384592
    {
Packit Service 384592
        error_log(LOG_ERROR, NULL, "Failed to create thread mutex: %s",
Packit Service 384592
            apr_strerror(rc, errstr, 1024));
Packit Service 384592
        logc_shutdown(1);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    entry_counter = 1;
Packit Service 384592
Packit Service 384592
    curl_handles = apr_array_make(pool, max_connections, sizeof(CURL *));
Packit Service 384592
    if (curl_handles == NULL) {
Packit Service 384592
        error_log(LOG_ERROR, NULL, MEMALLOC_ERROR_MSG);
Packit Service 384592
        logc_shutdown(1);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Initialise a number of Curl handles. */
Packit Service 384592
    for(i = 0; i < max_connections; i++) {
Packit Service 384592
        CURL *curl = NULL;
Packit Service 384592
Packit Service 384592
        /* Create cURL handle. */
Packit Service 384592
        curl = curl_easy_init();
Packit Service 384592
Packit Service 384592
        /* Pre-configure the handle. */
Packit Service 384592
        curl_easy_setopt(curl, CURLOPT_UPLOAD, TRUE);
Packit Service 384592
        curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, (char *)NULL);
Packit Service 384592
        curl_easy_setopt(curl, CURLOPT_URL, console_uri);
Packit Service 384592
        curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
Packit Service 384592
Packit Service 384592
        if (ssl_validation)
Packit Service 384592
        {
Packit Service 384592
            curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1);
Packit Service 384592
            curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1);
Packit Service 384592
        }
Packit Service 384592
        else
Packit Service 384592
        {
Packit Service 384592
            curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
Packit Service 384592
            curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
Packit Service 384592
        /* Seems like CURL_SSLVERSION_TLSv1_2 is not supported on libcurl
Packit Service 384592
         * < v7.34.0
Packit Service 384592
         *
Packit Service 384592
         * version_num is a 24 bit number created like this:
Packit Service 384592
         * <8 bits major number> | <8 bits minor number> | <8 bits patch number>.
Packit Service 384592
         */
Packit Service 384592
        switch (tlsprotocol) {
Packit Service 384592
        case 0:
Packit Service 384592
        	curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_0);
Packit Service 384592
        	break;
Packit Service 384592
        case 1:
Packit Service 384592
        	curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_1);
Packit Service 384592
        	break;
Packit Service 384592
        case 2:
Packit Service 384592
        	curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
Packit Service 384592
        	break;
Packit Service 384592
        default:
Packit Service 384592
        	curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
Packit Service 384592
        	break;
Packit Service 384592
        }
Packit Service 384592
        cmaj = curlversion->version_num >> 16;
Packit Service 384592
        cmin = (curlversion->version_num & 0x00ff00) >> 8;
Packit Service 384592
        cpat = (curlversion->version_num & 0x0000ff);
Packit Service 384592
        /* If cURL version < v7.34.0, use TLS v1.x */
Packit Service 384592
        if (cmaj <= 7 && cmin < 34) {
Packit Service 384592
        	curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 15);
Packit Service 384592
        curl_easy_setopt(curl, CURLOPT_NOSIGNAL, TRUE);
Packit Service 384592
        curl_easy_setopt(curl, CURLOPT_HEADER, TRUE);
Packit Service 384592
Packit Service 384592
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_writefunction);
Packit Service 384592
Packit Service 384592
        *(CURL **)apr_array_push(curl_handles) = curl;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    if (cmaj <= 7 && cmin < 34) {
Packit Service 384592
    	error_log(LOG_DEBUG2, NULL, "TLSv1.2 is unsupported in cURL %d.%d.%d",  cmaj, cmin, cpat);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    logline_regex = pcre_compile(logline_pattern, PCRE_CASELESS,
Packit Service 384592
                                 &errptr, &erroffset, NULL);
Packit Service 384592
    if (logline_regex == NULL) {
Packit Service 384592
        error_log(LOG_ERROR, NULL,
Packit Service 384592
                  "Failed to compile pattern: %s\n", logline_pattern);
Packit Service 384592
        logc_shutdown(1);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    requestline_regex = pcre_compile(requestline_pattern,
Packit Service 384592
                                     PCRE_CASELESS, &errptr, &erroffset, NULL);
Packit Service 384592
    if (requestline_regex == NULL) {
Packit Service 384592
        error_log(LOG_ERROR, NULL,
Packit Service 384592
                  "Failed to compile pattern: %s\n", requestline_pattern);
Packit Service 384592
        logc_shutdown(1);
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * HACK: To allow two mlogcs running against a single dataset we use the
Packit Service 384592
 * mtime as a flag for deletion.
Packit Service 384592
 *
Packit Service 384592
 *  1) Check file date.
Packit Service 384592
 *  2) If it is KEEP_ENTRIES_REMOVE_TIME, then remove the file.
Packit Service 384592
 *  3) Otherwise set the date and let the other mlogc remove it.
Packit Service 384592
 */
Packit Service 384592
static void keep_entries_hack(apr_pool_t *mp,
Packit Service 384592
                              apr_thread_t *thread, const char *fn)
Packit Service 384592
{
Packit Service 384592
    apr_file_t *f = NULL;
Packit Service 384592
    apr_finfo_t finfo;
Packit Service 384592
    char errstr[1024];
Packit Service 384592
    apr_status_t rc;
Packit Service 384592
Packit Service 384592
    /* Opening for write as required for exclusive lock */
Packit Service 384592
    if ((rc = apr_file_open(&f, fn,
Packit Service 384592
                            APR_READ|APR_WRITE|APR_APPEND,
Packit Service 384592
                            APR_OS_DEFAULT, mp)) != APR_SUCCESS)
Packit Service 384592
    {
Packit Service 384592
        error_log(LOG_ERROR, thread,
Packit Service 384592
                  "Could not open \"%s\": %s",
Packit Service 384592
                  fn, apr_strerror(rc, errstr, 1024));
Packit Service 384592
        return;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    if ((rc = apr_file_lock(f,
Packit Service 384592
                  APR_FLOCK_EXCLUSIVE|APR_FLOCK_NONBLOCK)) != APR_SUCCESS)
Packit Service 384592
    {
Packit Service 384592
        error_log(LOG_DEBUG2, thread,
Packit Service 384592
                  "Waiting for lock on \"%s\": %s",
Packit Service 384592
                  fn, apr_strerror(rc, errstr, 1024));
Packit Service 384592
        if ((rc = apr_file_lock(f, APR_FLOCK_EXCLUSIVE)) != APR_SUCCESS) {
Packit Service 384592
            error_log(LOG_ERROR, thread,
Packit Service 384592
                      "Could not lock \"%s\": %s",
Packit Service 384592
                      fn, apr_strerror(rc, errstr, 1024));
Packit Service 384592
            apr_file_close(f);
Packit Service 384592
            return;
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
    error_log(LOG_DEBUG2, thread, "Locked: %s", fn);
Packit Service 384592
Packit Service 384592
    /* For testing only */
Packit Service 384592
    TEST_WITH_RAND_SLEEP(2);
Packit Service 384592
Packit Service 384592
    if ((rc = apr_stat(&finfo, fn, APR_FINFO_MIN, mp)) != APR_SUCCESS) {
Packit Service 384592
        error_log(LOG_ERROR, thread,
Packit Service 384592
                  "Could not stat \"%s\": %s",
Packit Service 384592
                  fn, apr_strerror(rc, errstr, 1024));
Packit Service 384592
        error_log(LOG_DEBUG2, thread, "Unlocked: %s", fn);
Packit Service 384592
        apr_file_close(f);
Packit Service 384592
        return;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    if (error_log_level >= LOG_DEBUG) {
Packit Service 384592
        error_log(LOG_DEBUG, thread,
Packit Service 384592
                  "STAT \"%s\" {"
Packit Service 384592
                  "uid=%d; gid=%d; size=%" APR_OFF_T_FMT "; "
Packit Service 384592
                  "csize=%" APR_OFF_T_FMT "; atime=%" APR_TIME_T_FMT "; "
Packit Service 384592
                  "ctime=%" APR_TIME_T_FMT "; mtime=%" APR_TIME_T_FMT
Packit Service 384592
                  "}",
Packit Service 384592
                  fn, finfo.user, finfo.group, finfo.size,
Packit Service 384592
                  finfo.csize, finfo.atime, finfo.ctime, finfo.mtime);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    if (finfo.mtime != KEEP_ENTRIES_REMOVE_TIME) {
Packit Service 384592
        error_log(LOG_DEBUG2, thread, "Set mtime: %s", fn);
Packit Service 384592
        if ((rc = apr_file_mtime_set(fn,
Packit Service 384592
                        (apr_time_t)KEEP_ENTRIES_REMOVE_TIME, mp))
Packit Service 384592
                  != APR_SUCCESS)
Packit Service 384592
        {
Packit Service 384592
            error_log(LOG_ERROR, thread,
Packit Service 384592
                      "Could not set mtime on \"%s\": %s",
Packit Service 384592
                      fn, apr_strerror(rc, errstr, 1024));
Packit Service 384592
        }
Packit Service 384592
        error_log(LOG_DEBUG2, thread, "Unlocked: %s", fn);
Packit Service 384592
        apr_file_close(f);
Packit Service 384592
        return;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
Packit Service 384592
    error_log(LOG_DEBUG, thread, "Removing: %s", fn);
Packit Service 384592
    error_log(LOG_DEBUG2, thread, "Unlocked: %s", fn);
Packit Service 384592
    apr_file_close(f);
Packit Service 384592
    apr_file_remove(fn, mp);
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Worker thread. Works in a loop, fetching jobs from the queue,
Packit Service 384592
 * until the queue is empty or it is otherwise told to quit.
Packit Service 384592
 */
Packit Service 384592
static void * APR_THREAD_FUNC thread_worker(apr_thread_t *thread, void *data)
Packit Service 384592
{
Packit Service 384592
    unsigned int loop_count = 0;
Packit Service 384592
    CURL *curl = (CURL *)data;
Packit Service 384592
    entry_t **entryptr = NULL;
Packit Service 384592
    entry_t *entry = NULL;
Packit Service 384592
    apr_status_t rc;
Packit Service 384592
    apr_finfo_t finfo;
Packit Service 384592
    int capturevector[CAPTUREVECTORSIZE];
Packit Service 384592
    int take_new = 1;
Packit Service 384592
    apr_pool_t *tpool;
Packit Service 384592
    struct curl_slist *headerlist = NULL;
Packit Service 384592
    char curl_error_buffer[CURL_ERROR_SIZE] = "";
Packit Service 384592
    int num_requests = 0;
Packit Service 384592
Packit Service 384592
    /* There is no need to do the sleep if this was an invalid entry
Packit Service 384592
     * as the sleep is just to protect flooding the console server
Packit Service 384592
     * with rapid requests.  With an invalid entry we never hit the
Packit Service 384592
     * server, so we should not delay processing the next event.
Packit Service 384592
     */
Packit Service 384592
    int nodelay = 0;
Packit Service 384592
Packit Service 384592
Packit Service 384592
    error_log(LOG_DEBUG, thread, "Worker thread starting.");
Packit Service 384592
Packit Service 384592
    /* Each worker uses its own pool to manage memory. To avoid
Packit Service 384592
     * memory leaks the pool is cleared after each processed
Packit Service 384592
     * entry.
Packit Service 384592
     */
Packit Service 384592
    apr_pool_create(&tpool, thread_pool);
Packit Service 384592
Packit Service 384592
    /* Process jobs in a queue until there are no more jobs to process. */
Packit Service 384592
    for(;;) {
Packit Service 384592
        nodelay = 0;
Packit Service 384592
Packit Service 384592
        /* Do we need to shut down? */
Packit Service 384592
        if (running == 0) {
Packit Service 384592
            error_log(LOG_DEBUG, thread, "We were told to shut down.");
Packit Service 384592
            goto THREAD_SHUTDOWN;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /* Is there a problem with the server? We need
Packit Service 384592
         * to shut down if there is. Except that we don't
Packit Service 384592
         * want to shut down if we were launched to investigate
Packit Service 384592
         * if the server came back online (loop_count will be
Packit Service 384592
         * zero in that case).
Packit Service 384592
         */
Packit Service 384592
        if ((server_error == 1)&&(loop_count != 0)) {
Packit Service 384592
            error_log(LOG_DEBUG, thread, "Shutting down due to server error.");
Packit Service 384592
            goto THREAD_SHUTDOWN;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        loop_count++;
Packit Service 384592
Packit Service 384592
        /* Get a new entry, but only if we need one. */
Packit Service 384592
        if (take_new) {
Packit Service 384592
            error_log(LOG_DEBUG, thread, "Worker fetch locking thread mutex.");
Packit Service 384592
            if (APR_STATUS_IS_EBUSY(apr_thread_mutex_trylock(mutex))) {
Packit Service 384592
                error_log(LOG_DEBUG, thread,
Packit Service 384592
                          "Worker fetch waiting on thread mutex.");
Packit Service 384592
                apr_thread_mutex_lock(mutex);
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            error_log(LOG_DEBUG, thread, "Worker fetch started.");
Packit Service 384592
Packit Service 384592
            /* Deal with the previous entry. */
Packit Service 384592
            if (entry != NULL) {
Packit Service 384592
                error_log(LOG_DEBUG, thread,
Packit Service 384592
                          "Removing previous entry from storage.");
Packit Service 384592
                transaction_log(TXOUT, entry->line);
Packit Service 384592
Packit Service 384592
                /* Remove previous entry from storage. */
Packit Service 384592
                apr_hash_set(in_progress, &entry->id, sizeof(entry->id), NULL);
Packit Service 384592
Packit Service 384592
                /* Release the memory it used to occupy. */
Packit Service 384592
                free((void *)entry->line);
Packit Service 384592
                free(entry);
Packit Service 384592
                entry = NULL;
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            error_log(LOG_DEBUG, thread, "Getting one entry from the queue.");
Packit Service 384592
Packit Service 384592
            /* Get one entry. */
Packit Service 384592
            entryptr = (entry_t **)apr_array_pop(queue);
Packit Service 384592
            if (entryptr == NULL) {
Packit Service 384592
                error_log(LOG_DEBUG, thread,
Packit Service 384592
                          "Worker fetch unlocking thread mutex.");
Packit Service 384592
                apr_thread_mutex_unlock(mutex);
Packit Service 384592
                error_log(LOG_DEBUG, thread,
Packit Service 384592
                          "No more work for this thread, exiting.");
Packit Service 384592
Packit Service 384592
                goto THREAD_SHUTDOWN;
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            entry = *entryptr;
Packit Service 384592
            apr_hash_set(in_progress, &entry->id, sizeof(entry->id), entry);
Packit Service 384592
Packit Service 384592
            error_log(LOG_DEBUG, thread, "Worker fetch completed.");
Packit Service 384592
Packit Service 384592
            error_log(LOG_DEBUG, thread,
Packit Service 384592
                      "Worker fetch unlocking thread mutex.");
Packit Service 384592
            apr_thread_mutex_unlock(mutex);
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /* Send one entry. */
Packit Service 384592
Packit Service 384592
        error_log(LOG_DEBUG, thread, "Processing entry.");
Packit Service 384592
        take_new = 0;
Packit Service 384592
Packit Service 384592
        /* Keep track of requests processed if we need to */
Packit Service 384592
        if (max_worker_requests > 0) {
Packit Service 384592
            num_requests++;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        rc = pcre_exec(logline_regex, NULL, entry->line, entry->line_size, 0, 0,
Packit Service 384592
            capturevector, CAPTUREVECTORSIZE);
Packit Service 384592
        if (rc == PCRE_ERROR_NOMATCH) { /* No match. */
Packit Service 384592
            error_log(LOG_WARNING, thread,
Packit Service 384592
                      "Invalid entry (failed to match regex): %s",
Packit Service 384592
                      _log_escape(tpool, entry->line, entry->line_size));
Packit Service 384592
            take_new = 1;
Packit Service 384592
            nodelay = 1;
Packit Service 384592
        }
Packit Service 384592
        else if (rc < 0) { /* Error condition. */
Packit Service 384592
            error_log(LOG_WARNING, thread,
Packit Service 384592
                      "Invalid entry (PCRE error %d): %s",
Packit Service 384592
                      rc, _log_escape(tpool, entry->line, entry->line_size));
Packit Service 384592
            take_new = 1;
Packit Service 384592
            nodelay = 1;
Packit Service 384592
        }
Packit Service 384592
        else { /* We have a match. */
Packit Service 384592
            char *uniqueid = NULL;
Packit Service 384592
            char *auditlogentry = NULL;
Packit Service 384592
            char *hash = NULL;
Packit Service 384592
            char *summary = NULL;
Packit Service 384592
            char *credentials = NULL;
Packit Service 384592
Packit Service 384592
            error_log(LOG_DEBUG, thread, "Regular expression matched.");
Packit Service 384592
Packit Service 384592
            /* For testing only */
Packit Service 384592
            TEST_WITH_RAND_SLEEP(2);
Packit Service 384592
Packit Service 384592
            uniqueid = apr_psprintf(tpool, "%.*s",
Packit Service 384592
                (capturevector[2*13+1] - capturevector[2*13]),
Packit Service 384592
                (entry->line + capturevector[2*13]));
Packit Service 384592
            auditlogentry = apr_psprintf(tpool, "%s/%.*s", log_repository,
Packit Service 384592
                (capturevector[2*15+1] - capturevector[2*15]),
Packit Service 384592
                (entry->line + capturevector[2*15]));
Packit Service 384592
            hash = apr_psprintf(tpool, "X-Content-Hash: %.*s",
Packit Service 384592
                (capturevector[2*18+1] - capturevector[2*15]),
Packit Service 384592
                (entry->line + capturevector[2*18]));
Packit Service 384592
            summary = apr_psprintf(tpool, "X-ForensicLog-Summary: %s",
Packit Service 384592
                    entry->line);
Packit Service 384592
            credentials = apr_psprintf(tpool, "%s:%s",
Packit Service 384592
                                       sensor_username, sensor_password);
Packit Service 384592
Packit Service 384592
            rc = apr_stat(&finfo, auditlogentry, APR_FINFO_SIZE, tpool);
Packit Service 384592
            if (rc == APR_SUCCESS) {
Packit Service 384592
                FILE *hd_src;
Packit Service 384592
                char response_buf[STATUSBUF_SIZE];
Packit Service 384592
                CURLcode res;
Packit Service 384592
Packit Service 384592
                if (error_log_level >= LOG_DEBUG) {
Packit Service 384592
                    error_log(LOG_DEBUG, thread,
Packit Service 384592
                              "STAT \"%s\" {"
Packit Service 384592
                              "uid=%d; gid=%d; size=%" APR_OFF_T_FMT "; "
Packit Service 384592
                              "csize=%" APR_OFF_T_FMT "; "
Packit Service 384592
                              "atime=%" APR_TIME_T_FMT "; "
Packit Service 384592
                              "ctime=%" APR_TIME_T_FMT "; "
Packit Service 384592
                              "mtime=%" APR_TIME_T_FMT
Packit Service 384592
                              "}",
Packit Service 384592
                              auditlogentry, finfo.user, finfo.group,
Packit Service 384592
                              finfo.size, finfo.csize, finfo.atime,
Packit Service 384592
                              finfo.ctime, finfo.mtime);
Packit Service 384592
                }
Packit Service 384592
Packit Service 384592
                /* Initialize the respone buffer with a hidden value */
Packit Service 384592
                response_buf[0] = 0;
Packit Service 384592
                response_buf[1] = 1;
Packit Service 384592
Packit Service 384592
                if (finfo.size == 0) {
Packit Service 384592
                    error_log(LOG_WARNING, thread,
Packit Service 384592
                              "File found (%" APR_OFF_T_FMT
Packit Service 384592
                              " bytes), skipping.", finfo.size);
Packit Service 384592
                    take_new = 1;
Packit Service 384592
                    nodelay = 1;
Packit Service 384592
                    goto THREAD_CLEANUP;
Packit Service 384592
                }
Packit Service 384592
                else {
Packit Service 384592
                    error_log(LOG_DEBUG, thread,
Packit Service 384592
                              "File found (%" APR_OFF_T_FMT
Packit Service 384592
                              " bytes), activating cURL.", finfo.size);
Packit Service 384592
                }
Packit Service 384592
Packit Service 384592
Packit Service 384592
                curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
Packit Service 384592
                curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
Packit Service 384592
                                 curl_debugfunction);
Packit Service 384592
                curl_easy_setopt(curl, CURLOPT_DEBUGDATA, thread);
Packit Service 384592
                curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_error_buffer);
Packit Service 384592
                curl_easy_setopt(curl, CURLOPT_USERPWD, credentials);
Packit Service 384592
                curl_easy_setopt(curl, CURLOPT_WRITEDATA, (char *)response_buf);
Packit Service 384592
Packit Service 384592
                headerlist = curl_slist_append(headerlist, "Expect:");
Packit Service 384592
                headerlist = curl_slist_append(headerlist, hash);
Packit Service 384592
                headerlist = curl_slist_append(headerlist, summary);
Packit Service 384592
                curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
Packit Service 384592
Packit Service 384592
                hd_src = fopen(auditlogentry, "rb");
Packit Service 384592
                if (hd_src == NULL) {
Packit Service 384592
                    error_log(LOG_WARNING, thread,
Packit Service 384592
                              "Invalid entry (failed to open file for "
Packit Service 384592
                              "reading): %s", auditlogentry);
Packit Service 384592
                    take_new = 1;
Packit Service 384592
                    nodelay = 1;
Packit Service 384592
                    goto THREAD_CLEANUP;
Packit Service 384592
                }
Packit Service 384592
Packit Service 384592
                curl_easy_setopt(curl, CURLOPT_READDATA, hd_src);
Packit Service 384592
                curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, finfo.size);
Packit Service 384592
Packit Service 384592
#ifdef WIN32
Packit Service 384592
                /* Mandatory on win32 */
Packit Service 384592
                curl_easy_setopt(curl, CURLOPT_READFUNCTION, curl_readfunction);
Packit Service 384592
#endif
Packit Service 384592
Packit Service 384592
                res = curl_easy_perform(curl);
Packit Service 384592
Packit Service 384592
                fclose(hd_src);
Packit Service 384592
Packit Service 384592
                if (res == 0) {
Packit Service 384592
                    long response_code = 0;
Packit Service 384592
Packit Service 384592
                    res = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE,
Packit Service 384592
                                            &response_code);
Packit Service 384592
                    error_log(LOG_DEBUG, thread,
Packit Service 384592
                              "Request returned with status \"%ld %s\": %s",
Packit Service 384592
                              response_code, response_buf, uniqueid);
Packit Service 384592
Packit Service 384592
Packit Service 384592
                    if (response_code == 0) {
Packit Service 384592
                        /* Assume problem with connection */
Packit Service 384592
                        error_log(LOG_WARNING, thread,
Packit Service 384592
                                  "Flagging server as errored after failure "
Packit Service 384592
                                  "to retrieve response code for entry %s "
Packit Service 384592
                                  "(cURL code %d): Possible SSL negotiation "
Packit Service 384592
                                  "error",
Packit Service 384592
                                  uniqueid, res);
Packit Service 384592
                        apr_sleep(1000 * 1000);
Packit Service 384592
                        take_new = 0;
Packit Service 384592
                        server_error = 1;
Packit Service 384592
                        server_error_last_check_time = apr_time_now();
Packit Service 384592
                    }
Packit Service 384592
                    else if (res != 0) {
Packit Service 384592
                        error_log(LOG_WARNING, thread,
Packit Service 384592
                                  "Flagging server as errored after failure "
Packit Service 384592
                                  "to retrieve response code for entry %s "
Packit Service 384592
                                  "(cURL code %d): %s",
Packit Service 384592
                                  uniqueid, res, curl_error_buffer);
Packit Service 384592
                        apr_sleep(1000 * 1000);
Packit Service 384592
                        take_new = 0;
Packit Service 384592
                        server_error = 1;
Packit Service 384592
                        server_error_last_check_time = apr_time_now();
Packit Service 384592
                    }
Packit Service 384592
                    else {
Packit Service 384592
                        if (response_code == 200) {
Packit Service 384592
                            double total_time, upload_size;
Packit Service 384592
Packit Service 384592
                            if (server_error == 1) {
Packit Service 384592
                                error_log(LOG_NOTICE, thread,
Packit Service 384592
                                          "Clearing the server error flag "
Packit Service 384592
                                          "after successful entry "
Packit Service 384592
                                          "submission: %s", uniqueid);
Packit Service 384592
                            }
Packit Service 384592
                            server_error = 0;
Packit Service 384592
                            server_error_last_check_time = 0;
Packit Service 384592
Packit Service 384592
                            curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME,
Packit Service 384592
                                              &total_time);
Packit Service 384592
                            curl_easy_getinfo(curl, CURLINFO_SIZE_UPLOAD,
Packit Service 384592
                                              &upload_size);
Packit Service 384592
Packit Service 384592
                            if (!keep_entries) {
Packit Service 384592
                                error_log(LOG_DEBUG, thread,
Packit Service 384592
                                          "Removing: %s", auditlogentry);
Packit Service 384592
                                apr_file_remove(auditlogentry, tpool);
Packit Service 384592
                            }
Packit Service 384592
                            else if (keep_entries == KEEP_ENTRIES_REMOVE_HACK)
Packit Service 384592
                            {
Packit Service 384592
                                keep_entries_hack(tpool, thread, auditlogentry);
Packit Service 384592
                            }
Packit Service 384592
Packit Service 384592
                            error_log(LOG_NOTICE, thread,
Packit Service 384592
                                      "Entry completed (%.3f seconds, %.0f "
Packit Service 384592
                                      "bytes): %s",
Packit Service 384592
                                      total_time, upload_size,
Packit Service 384592
                                      uniqueid);
Packit Service 384592
                            take_new = 1;
Packit Service 384592
                        }
Packit Service 384592
                        else if (response_code == 409) {
Packit Service 384592
                            /* Assume problem with audit log entry. */
Packit Service 384592
                            error_log(LOG_WARNING, thread,
Packit Service 384592
                                      "Failed to submit entry with "
Packit Service 384592
                                      "\"409 %s\": %s",
Packit Service 384592
                                      response_buf, uniqueid);
Packit Service 384592
                            take_new = 1;
Packit Service 384592
                        }
Packit Service 384592
                        else {
Packit Service 384592
                            /* Assume problem with server. */
Packit Service 384592
                            error_log(LOG_WARNING, thread,
Packit Service 384592
                                      "Flagging server as errored after "
Packit Service 384592
                                      "failure to submit entry %s with "
Packit Service 384592
                                      "HTTP response code %ld: %s",
Packit Service 384592
                                      uniqueid, response_code, response_buf);
Packit Service 384592
                            server_error = 1;
Packit Service 384592
                            server_error_last_check_time = apr_time_now();
Packit Service 384592
                            take_new = 0;
Packit Service 384592
                        }
Packit Service 384592
                    }
Packit Service 384592
                }
Packit Service 384592
                else { /* Something isn't right. */
Packit Service 384592
                    error_log(LOG_WARNING, thread,
Packit Service 384592
                              "Flagging server as errored after "
Packit Service 384592
                              "failure to submit entry %s "
Packit Service 384592
                              "(cURL code %d): %s",
Packit Service 384592
                              uniqueid, res, curl_error_buffer);
Packit Service 384592
                    server_error = 1;
Packit Service 384592
                    server_error_last_check_time = apr_time_now();
Packit Service 384592
                    take_new = 0;
Packit Service 384592
Packit Service 384592
                }
Packit Service 384592
            }
Packit Service 384592
            else {
Packit Service 384592
                error_log(LOG_WARNING, thread,
Packit Service 384592
                          "Invalid entry (file not found %d): %s",
Packit Service 384592
                          rc, auditlogentry);
Packit Service 384592
                take_new = 1;
Packit Service 384592
                nodelay = 1;
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            /* If we are tracking num_requests, then shutdown if we are
Packit Service 384592
             * over our threshold.
Packit Service 384592
             */
Packit Service 384592
            if (num_requests && (num_requests >= max_worker_requests)) {
Packit Service 384592
                error_log(LOG_NOTICE, thread,
Packit Service 384592
                          "Reached max requests (%d) for this worker, exiting.",
Packit Service 384592
                          max_worker_requests);
Packit Service 384592
Packit Service 384592
                goto THREAD_SHUTDOWN;
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        THREAD_CLEANUP:
Packit Service 384592
Packit Service 384592
        /* Sleep if we sent data to the server so we do not flood */
Packit Service 384592
        /* ENH: Need to sleep for 1ms in a loop checking for shutdown */
Packit Service 384592
        if ((nodelay == 0) && (transaction_delay > 0)) {
Packit Service 384592
            error_log(LOG_DEBUG, thread,
Packit Service 384592
                      "Sleeping for %d msec.", transaction_delay);
Packit Service 384592
            apr_sleep(transaction_delay * 1000);
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        if (headerlist != NULL) {
Packit Service 384592
            curl_slist_free_all(headerlist);
Packit Service 384592
            headerlist = NULL;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        apr_pool_clear(tpool);
Packit Service 384592
Packit Service 384592
        error_log(LOG_DEBUG, thread, "Worker processing completed.");
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    THREAD_SHUTDOWN:
Packit Service 384592
Packit Service 384592
    error_log(LOG_DEBUG, thread, "Worker shutdown locking thread mutex.");
Packit Service 384592
    if (APR_STATUS_IS_EBUSY(apr_thread_mutex_trylock(mutex))) {
Packit Service 384592
        error_log(LOG_DEBUG, thread,
Packit Service 384592
                  "Worker shutdown waiting on thread mutex.");
Packit Service 384592
        apr_thread_mutex_lock(mutex);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Deal with the previous entry, if any. */
Packit Service 384592
    if (entry != NULL) {
Packit Service 384592
        apr_hash_set(in_progress, &entry->id, sizeof(entry->id), NULL);
Packit Service 384592
Packit Service 384592
        if (take_new == 0) { /* Not done. */
Packit Service 384592
            *(entry_t **)apr_array_push(queue) = entry;
Packit Service 384592
        }
Packit Service 384592
        else {
Packit Service 384592
            transaction_log(TXOUT, entry->line);
Packit Service 384592
            free((void *)entry->line);
Packit Service 384592
            free(entry);
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        entry = NULL;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Return curl handle to the pool for reuse. */
Packit Service 384592
    *(CURL **)apr_array_push(curl_handles) = curl;
Packit Service 384592
Packit Service 384592
    /* No more work, exit. */
Packit Service 384592
    current_workers--;
Packit Service 384592
Packit Service 384592
    error_log(LOG_DEBUG, thread, "Worker shutdown unlocking thread mutex.");
Packit Service 384592
    apr_thread_mutex_unlock(mutex);
Packit Service 384592
Packit Service 384592
    apr_pool_destroy(tpool);
Packit Service 384592
Packit Service 384592
    error_log(LOG_DEBUG, thread, "Worker thread completed.");
Packit Service 384592
Packit Service 384592
    apr_thread_exit(thread, 0);
Packit Service 384592
Packit Service 384592
    return NULL;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Creates one new worker, giving it one of the available
Packit Service 384592
 * Curl handles to work with.
Packit Service 384592
 */
Packit Service 384592
static void create_new_worker(int lock)
Packit Service 384592
{
Packit Service 384592
    apr_thread_t *thread = NULL;
Packit Service 384592
    CURL **curlptr = NULL;
Packit Service 384592
Packit Service 384592
    if (lock) {
Packit Service 384592
        error_log(LOG_DEBUG, NULL, "Worker creation locking thread mutex.");
Packit Service 384592
        if (APR_STATUS_IS_EBUSY(apr_thread_mutex_trylock(mutex))) {
Packit Service 384592
            error_log(LOG_DEBUG, NULL,
Packit Service 384592
                      "Worker creation waiting on thread mutex.");
Packit Service 384592
            apr_thread_mutex_lock(mutex);
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    error_log(LOG_DEBUG, NULL, "Worker creation started.");
Packit Service 384592
Packit Service 384592
    /* A sanity check: this part executes under lock and
Packit Service 384592
     * we want to make *sure* we don't create more threads
Packit Service 384592
     * than we are allowed.
Packit Service 384592
     */
Packit Service 384592
    if (current_workers >= max_connections) {
Packit Service 384592
        if (lock) {
Packit Service 384592
            error_log(LOG_DEBUG, NULL,
Packit Service 384592
                      "Worker creation unlocking thread mutex.");
Packit Service 384592
            apr_thread_mutex_unlock(mutex);
Packit Service 384592
        }
Packit Service 384592
        return;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Cleanup thread pool when idle */
Packit Service 384592
    if (current_workers <= 0)  {
Packit Service 384592
        if (thread_pool != NULL) {
Packit Service 384592
            error_log(LOG_DEBUG, NULL, "Destroying thread_pool.");
Packit Service 384592
            apr_pool_destroy(thread_pool);
Packit Service 384592
            thread_pool = NULL;
Packit Service 384592
        }
Packit Service 384592
        error_log(LOG_DEBUG, NULL, "Creating thread_pool.");
Packit Service 384592
        apr_pool_create(&thread_pool, NULL);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    curlptr = (CURL **)apr_array_pop(curl_handles);
Packit Service 384592
    if (curlptr != NULL) {
Packit Service 384592
        apr_threadattr_t *thread_attrs;
Packit Service 384592
        apr_status_t rc;
Packit Service 384592
Packit Service 384592
        apr_threadattr_create(&thread_attrs, thread_pool);
Packit Service 384592
        apr_threadattr_detach_set(thread_attrs, 1);
Packit Service 384592
        apr_threadattr_stacksize_set(thread_attrs, 1024);
Packit Service 384592
Packit Service 384592
        rc = apr_thread_create(&thread, thread_attrs,
Packit Service 384592
                               thread_worker, *curlptr, thread_pool);
Packit Service 384592
        if (rc != APR_SUCCESS) {
Packit Service 384592
            if (lock) {
Packit Service 384592
                error_log(LOG_DEBUG, NULL,
Packit Service 384592
                          "Worker creation unlocking thread mutex.");
Packit Service 384592
                apr_thread_mutex_unlock(mutex);
Packit Service 384592
            }
Packit Service 384592
            error_log(LOG_ERROR, NULL,
Packit Service 384592
                      "Failed to create new worker thread: %d", rc);
Packit Service 384592
            logc_shutdown(1);
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        current_workers++;
Packit Service 384592
    }
Packit Service 384592
    else {
Packit Service 384592
        if (lock) {
Packit Service 384592
            error_log(LOG_DEBUG, NULL,
Packit Service 384592
                      "Worker creation unlocking thread mutex.");
Packit Service 384592
            apr_thread_mutex_unlock(mutex);
Packit Service 384592
        }
Packit Service 384592
        error_log(LOG_ERROR, NULL, "No more cURL handles (Internal Error).");
Packit Service 384592
        logc_shutdown(1);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    error_log(LOG_DEBUG, NULL, "Worker creation completed: %pp", thread);
Packit Service 384592
Packit Service 384592
    if (lock) {
Packit Service 384592
        error_log(LOG_DEBUG, NULL, "Worker creation unlocking thread mutex.");
Packit Service 384592
        apr_thread_mutex_unlock(mutex);
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * This function implements the management thread.
Packit Service 384592
 */
Packit Service 384592
static void * APR_THREAD_FUNC thread_manager(apr_thread_t *thread, void *data)
Packit Service 384592
{
Packit Service 384592
    apr_time_t last = 0;
Packit Service 384592
    apr_time_t now = 0;
Packit Service 384592
Packit Service 384592
    error_log(LOG_DEBUG, thread, "Management thread: Starting.");
Packit Service 384592
Packit Service 384592
    for(;;) {
Packit Service 384592
        now = apr_time_now();
Packit Service 384592
Packit Service 384592
        /* Should we stop running? */
Packit Service 384592
        if (running == 0) {
Packit Service 384592
            /* We need to be last */
Packit Service 384592
            error_log(LOG_DEBUG, thread,
Packit Service 384592
                      "Management thread: Waiting for worker "
Packit Service 384592
                      "threads to finish.");
Packit Service 384592
            while(current_workers > 0) {
Packit Service 384592
                apr_sleep(10 * 1000);
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            if (have_read_data) {
Packit Service 384592
                error_log(LOG_NOTICE, thread,
Packit Service 384592
                          "Running final transaction checkpoint.");
Packit Service 384592
                transaction_checkpoint();
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            error_log(LOG_DEBUG, thread, "Management thread: Exiting.");
Packit Service 384592
            management_thread_active = 0;
Packit Service 384592
            apr_thread_exit(thread, 0);
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /* Sleep for a while, but wake up often to check running status */
Packit Service 384592
        if ((last > 0) && ((now - last) < MANAGER_SLEEP)) {
Packit Service 384592
            apr_sleep(MANAGER_SUBSLEEP);
Packit Service 384592
            continue;
Packit Service 384592
        }
Packit Service 384592
        last = now;
Packit Service 384592
Packit Service 384592
        error_log(LOG_DEBUG2, thread, "Management thread: Processing");
Packit Service 384592
Packit Service 384592
        /* When the server is flagged errored we need to
Packit Service 384592
         * create a worker thread from time to time to
Packit Service 384592
         * investigate.
Packit Service 384592
         */
Packit Service 384592
        if (server_error) {
Packit Service 384592
            if ((current_workers == 0)&&
Packit Service 384592
                (apr_time_sec(now - server_error_last_check_time)
Packit Service 384592
                    > server_error_timeout))
Packit Service 384592
            {
Packit Service 384592
                server_error_last_check_time = now;
Packit Service 384592
                error_log(LOG_DEBUG, thread,
Packit Service 384592
                          "Management thread: Creating worker thread to "
Packit Service 384592
                          "investigate server.");
Packit Service 384592
                create_new_worker(1);
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
        else {
Packit Service 384592
            if (   (current_workers < max_connections)
Packit Service 384592
                && (queue->nelts > current_workers) )
Packit Service 384592
            {
Packit Service 384592
                error_log(LOG_DEBUG, thread,
Packit Service 384592
                          "Management thread: Creating worker thread to "
Packit Service 384592
                          "catch up with the queue.");
Packit Service 384592
                create_new_worker(1);
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /* Initiate a transaction log checkpoint if enough time passed
Packit Service 384592
         * since the last one.
Packit Service 384592
         */
Packit Service 384592
        if (apr_time_sec(now - checkpoint_time_last) > checkpoint_interval) {
Packit Service 384592
            error_log(LOG_DEBUG, thread,
Packit Service 384592
                      "Management thread: Initiating a checkpoint "
Packit Service 384592
                      "(previous was %" APR_TIME_T_FMT " seconds ago).",
Packit Service 384592
                      apr_time_sec(now - checkpoint_time_last));
Packit Service 384592
            checkpoint_time_last = now;
Packit Service 384592
            transaction_checkpoint();
Packit Service 384592
        }
Packit Service 384592
        else {
Packit Service 384592
            error_log(LOG_DEBUG2, thread,
Packit Service 384592
                      "Management thread: Last checkpoint was %" APR_TIME_T_FMT
Packit Service 384592
                      " seconds ago.",
Packit Service 384592
                      apr_time_sec(now - checkpoint_time_last));
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    return NULL;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
#ifndef WIN32
Packit Service 384592
/**
Packit Service 384592
 * Thread to handle all signals
Packit Service 384592
 */
Packit Service 384592
static void * APR_THREAD_FUNC thread_signals(apr_thread_t *thread, void *data)
Packit Service 384592
{
Packit Service 384592
    apr_status_t rc;
Packit Service 384592
Packit Service 384592
    error_log(LOG_DEBUG, thread, "Signal thread: Starting.");
Packit Service 384592
    rc = apr_signal_thread(handle_signals);
Packit Service 384592
    if (rc != APR_SUCCESS) {
Packit Service 384592
        error_log(LOG_DEBUG, thread, "Signal thread: Error %d", rc);
Packit Service 384592
        logc_shutdown(1);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    return NULL;
Packit Service 384592
}
Packit Service 384592
#endif /* WIN32 */
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * The main loop where we receive log entries from
Packit Service 384592
 * Apache and add them to the queue, sometimes creating
Packit Service 384592
 * new worker threads to handle them.
Packit Service 384592
 */
Packit Service 384592
static void receive_loop(void) {
Packit Service 384592
    apr_file_t *fd_stdin;
Packit Service 384592
    apr_size_t nbytes = PIPE_BUF_SIZE;
Packit Service 384592
    char *buf = apr_palloc(pool, PIPE_BUF_SIZE + 1);
Packit Service 384592
    char errstr[1024];
Packit Service 384592
    apr_size_t evnt = 0; /* Index in buf to first event char */
Packit Service 384592
    apr_size_t curr = 0; /* Index in buf to current processing char */
Packit Service 384592
    apr_size_t next = 0; /* Index in buf to next unused char */
Packit Service 384592
    int done = 0;
Packit Service 384592
    int drop_next = 0;
Packit Service 384592
    int buffered_events = 0;
Packit Service 384592
    int count = 0;
Packit Service 384592
    apr_pool_t *tmp_pool;
Packit Service 384592
Packit Service 384592
    /* Open stdin. */
Packit Service 384592
    if (apr_file_open_stdin(&fd_stdin, pool) != APR_SUCCESS) {
Packit Service 384592
        error_log(LOG_ERROR, NULL, "Unable to open stdin for reading");
Packit Service 384592
        logc_shutdown(1);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Always want this NUL terminated */
Packit Service 384592
    buf[PIPE_BUF_SIZE] = '\0';
Packit Service 384592
Packit Service 384592
    apr_pool_create(&tmp_pool, NULL);
Packit Service 384592
Packit Service 384592
    /* Loop forever receiving entries from stdin. */
Packit Service 384592
    while(!done || (curr < next)) {
Packit Service 384592
        apr_status_t rc;
Packit Service 384592
Packit Service 384592
        if (error_log_level >= LOG_DEBUG2) {
Packit Service 384592
            error_log(LOG_DEBUG2, NULL,
Packit Service 384592
                      "Internal state: "
Packit Service 384592
                      "[evnt \"%" APR_SIZE_T_FMT "\"]"
Packit Service 384592
                      "[curr \"%" APR_SIZE_T_FMT "\"]"
Packit Service 384592
                      "[next \"%" APR_SIZE_T_FMT "\"]"
Packit Service 384592
                      "[nbytes \"%" APR_SIZE_T_FMT "\"]",
Packit Service 384592
                      evnt, curr, next, nbytes);
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /* If we are not done and have the space, read more */
Packit Service 384592
        if (!done && (nbytes > 0)) {
Packit Service 384592
            buffered_events = 0;
Packit Service 384592
            nbytes = PIPE_BUF_SIZE - next;
Packit Service 384592
            rc = apr_file_read(fd_stdin, (buf + next), &nbytes);
Packit Service 384592
            if (rc != APR_SUCCESS) {
Packit Service 384592
                if (have_read_data) {
Packit Service 384592
                    error_log(LOG_NOTICE, NULL,
Packit Service 384592
                              "No more data to read, emptying buffer: %s",
Packit Service 384592
                              apr_strerror(rc, errstr, 1024));
Packit Service 384592
                }
Packit Service 384592
                done = 1;
Packit Service 384592
            }
Packit Service 384592
            else {
Packit Service 384592
                have_read_data = 1;
Packit Service 384592
                if (error_log_level == LOG_DEBUG) {
Packit Service 384592
                    error_log(LOG_DEBUG, NULL,
Packit Service 384592
                              "Read %" APR_SIZE_T_FMT " bytes from pipe",
Packit Service 384592
                              nbytes);
Packit Service 384592
                }
Packit Service 384592
                else {
Packit Service 384592
                    error_log(LOG_DEBUG2, NULL,
Packit Service 384592
                              "Read %" APR_SIZE_T_FMT " bytes from pipe: `%s'",
Packit Service 384592
                              nbytes,
Packit Service 384592
                              _log_escape(tmp_pool, (buf + next), nbytes));
Packit Service 384592
                }
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            next += nbytes;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /**
Packit Service 384592
         * Each chunk of data we receive can contain one or more lines for
Packit Service 384592
         * which we need to find the EOL marker and then queue the event
Packit Service 384592
         * up to that.  So, find/queue as many lines in the buffer as we
Packit Service 384592
         * can.  Any remaining data will get shifted back to the beginning
Packit Service 384592
         * of the buffer and the buffer size for the next read adjusted.
Packit Service 384592
         */
Packit Service 384592
        while(curr < next) {
Packit Service 384592
            /* Look for EOL so we can parse the event */
Packit Service 384592
            while((curr < next) && (buf[curr] != 0x0a)) {
Packit Service 384592
                curr++;
Packit Service 384592
            }
Packit Service 384592
            if (buf[curr] == 0x0a) {
Packit Service 384592
                buf[curr] = '\0';
Packit Service 384592
Packit Service 384592
                /* We may have to drop this one if it previously failed */
Packit Service 384592
                if (drop_next) {
Packit Service 384592
                    error_log(LOG_ERROR, NULL,
Packit Service 384592
                              "Dropping remaining portion of failed "
Packit Service 384592
                              "event: `%s'",
Packit Service 384592
                              _log_escape(tmp_pool,
Packit Service 384592
                                          (buf + evnt), (curr - evnt)));
Packit Service 384592
                    drop_next = 0;
Packit Service 384592
                }
Packit Service 384592
                else {
Packit Service 384592
                    transaction_log(TXIN, buf + evnt);
Packit Service 384592
                    error_log(LOG_DEBUG2, NULL,
Packit Service 384592
                              "Received audit log entry "
Packit Service 384592
                              "(count %lu queue %d workers %d): %s",
Packit Service 384592
                              entry_counter, queue->nelts,
Packit Service 384592
                              current_workers,
Packit Service 384592
                              _log_escape(tmp_pool,
Packit Service 384592
                                          (buf + evnt), strlen(buf + evnt)));
Packit Service 384592
                    add_entry(buf + evnt, 1);
Packit Service 384592
                    buffered_events++;
Packit Service 384592
                }
Packit Service 384592
Packit Service 384592
                /* Advance indexes to next event in buf */
Packit Service 384592
                evnt = curr = curr + 1;
Packit Service 384592
            }
Packit Service 384592
            else {
Packit Service 384592
                error_log(LOG_DEBUG2, NULL,
Packit Service 384592
                          "Event buffer contains partial event: `%s'",
Packit Service 384592
                          _log_escape(tmp_pool, (buf + evnt), (next - evnt)));
Packit Service 384592
                break;
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
Packit Service 384592
        if (buffered_events > 0) {
Packit Service 384592
            error_log(LOG_DEBUG, NULL,
Packit Service 384592
                      "Processed %d entries from buffer.", buffered_events);
Packit Service 384592
Packit Service 384592
            /* Move the unused portion of the buffer to the beginning */
Packit Service 384592
            next -= evnt;
Packit Service 384592
            curr -= evnt;
Packit Service 384592
            memmove(buf, (buf + evnt), next);
Packit Service 384592
Packit Service 384592
            error_log(LOG_DEBUG2, NULL,
Packit Service 384592
                      "Shifted buffer back %" APR_SIZE_T_FMT 
Packit Service 384592
                      " and offset %" APR_SIZE_T_FMT 
Packit Service 384592
                      " bytes for next read: `%s'",
Packit Service 384592
                      evnt, next, _log_escape(tmp_pool, buf, next));
Packit Service 384592
Packit Service 384592
            evnt = 0;
Packit Service 384592
        }
Packit Service 384592
        else if (next == PIPE_BUF_SIZE) {
Packit Service 384592
            /**
Packit Service 384592
             * There is a chance we could fill the buffer, but not have finished
Packit Service 384592
             * reading the event (no EOL yet), so we need to say so and drop
Packit Service 384592
             * all data until we find the end of the event that is too large.
Packit Service 384592
             */
Packit Service 384592
Packit Service 384592
            if (drop_next) {
Packit Service 384592
                error_log(LOG_ERROR, NULL,
Packit Service 384592
                          "Event continuation too large, "
Packit Service 384592
                          "dropping it as well: `%s'",
Packit Service 384592
                          _log_escape(tmp_pool, buf, PIPE_BUF_SIZE));
Packit Service 384592
            }
Packit Service 384592
            else {
Packit Service 384592
                error_log(LOG_ERROR, NULL,
Packit Service 384592
                          "Event too large, dropping event: `%s'",
Packit Service 384592
                          _log_escape(tmp_pool, buf, PIPE_BUF_SIZE));
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            /* Rewind buf and mark that we need to drop up to the next event */
Packit Service 384592
            evnt = curr = next = 0;
Packit Service 384592
            drop_next = 1;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        nbytes = PIPE_BUF_SIZE - next;
Packit Service 384592
Packit Service 384592
        if (count++ > 1000) {
Packit Service 384592
            count = 0;
Packit Service 384592
            error_log(LOG_DEBUG, NULL, "Recycling tmp_pool.");
Packit Service 384592
            apr_pool_destroy(tmp_pool);
Packit Service 384592
            apr_pool_create(&tmp_pool, NULL);
Packit Service 384592
        }
Packit Service 384592
        else {
Packit Service 384592
            apr_pool_clear(tmp_pool);
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Wait for queue to empty if specified */
Packit Service 384592
    if ((server_error == 0) && (opt_force != 0) && (queue->nelts > 0)) {
Packit Service 384592
        error_log(LOG_NOTICE, NULL,
Packit Service 384592
                  "Waiting for queue to empty (%d active).", queue->nelts);
Packit Service 384592
        while ((server_error == 0) && (opt_force != 0) && (queue->nelts > 0)) {
Packit Service 384592
            apr_sleep(10 * 1000);
Packit Service 384592
        }
Packit Service 384592
        if (queue->nelts > 0) {
Packit Service 384592
            error_log(LOG_ERROR, NULL,
Packit Service 384592
                      "Could not empty queue (%d active).", queue->nelts);
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Creates the management thread.
Packit Service 384592
 */
Packit Service 384592
static void start_management_thread(void)
Packit Service 384592
{
Packit Service 384592
    apr_thread_t *thread = NULL;
Packit Service 384592
    apr_threadattr_t *thread_attrs;
Packit Service 384592
    apr_status_t rc;
Packit Service 384592
Packit Service 384592
    apr_threadattr_create(&thread_attrs, pool);
Packit Service 384592
    apr_threadattr_detach_set(thread_attrs, 1);
Packit Service 384592
    apr_threadattr_stacksize_set(thread_attrs, 1024);
Packit Service 384592
Packit Service 384592
    management_thread_active = 1;
Packit Service 384592
Packit Service 384592
    rc = apr_thread_create(&thread, thread_attrs, thread_manager, NULL, pool);
Packit Service 384592
    if (rc != APR_SUCCESS) {
Packit Service 384592
        error_log(LOG_ERROR, NULL,
Packit Service 384592
                  "Failed to create new management thread: %d", rc);
Packit Service 384592
        management_thread_active = 0;
Packit Service 384592
        logc_shutdown(1);
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
#ifndef WIN32
Packit Service 384592
/**
Packit Service 384592
 * Creates a thread to handle all signals
Packit Service 384592
 */
Packit Service 384592
static void start_signal_thread(void)
Packit Service 384592
{
Packit Service 384592
    apr_thread_t *thread = NULL;
Packit Service 384592
    apr_threadattr_t *thread_attrs;
Packit Service 384592
    apr_status_t rc;
Packit Service 384592
Packit Service 384592
    apr_threadattr_create(&thread_attrs, pool);
Packit Service 384592
    apr_threadattr_detach_set(thread_attrs, 1);
Packit Service 384592
    apr_threadattr_stacksize_set(thread_attrs, 1024);
Packit Service 384592
Packit Service 384592
    rc = apr_thread_create(&thread, thread_attrs, thread_signals, NULL, pool);
Packit Service 384592
    if (rc != APR_SUCCESS) {
Packit Service 384592
        error_log(LOG_ERROR, NULL,
Packit Service 384592
                  "Failed to create new signal thread: %d", rc);
Packit Service 384592
        logc_shutdown(1);
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
#endif /* WIN32 */
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Usage text.
Packit Service 384592
 */
Packit Service 384592
static void usage(void) {
Packit Service 384592
    fprintf(stderr, "ModSecurity Log Collector (mlogc) v%s\n", VERSION);
Packit Service 384592
    fprintf(stderr, "  Usage: mlogc [options] /path/to/the/mlogc.conf\n");
Packit Service 384592
    fprintf(stderr, "\n");
Packit Service 384592
    fprintf(stderr, "  Options:\n");
Packit Service 384592
    fprintf(stderr, "    -f        Force depletion of queue on exit\n");
Packit Service 384592
    fprintf(stderr, "    -v        Version information\n");
Packit Service 384592
    fprintf(stderr, "    -h        This help\n\n");
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Version text.
Packit Service 384592
 */
Packit Service 384592
static void version(void) {
Packit Service 384592
    fprintf(stderr,
Packit Service 384592
            "ModSecurity Log Collector (mlogc) v%s\n", VERSION);
Packit Service 384592
    fprintf(stderr,
Packit Service 384592
            "   APR: compiled=\"%s\"; "
Packit Service 384592
            "loaded=\"%s\"\n", APR_VERSION_STRING, apr_version_string());
Packit Service 384592
    fprintf(stderr,
Packit Service 384592
            "  PCRE: compiled=\"%d.%d\"; "
Packit Service 384592
            "loaded=\"%s\"\n", PCRE_MAJOR, PCRE_MINOR, pcre_version());
Packit Service 384592
    fprintf(stderr,
Packit Service 384592
            "  cURL: compiled=\"%s\"; "
Packit Service 384592
            "loaded=\"%s\"\n", LIBCURL_VERSION, curl_version());
Packit Service 384592
    fprintf(stderr, "\n");
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * This is the main entry point.
Packit Service 384592
 */
Packit Service 384592
int main(int argc, const char * const argv[]) {
Packit Service 384592
    apr_getopt_t *opt;
Packit Service 384592
    apr_status_t rc;
Packit Service 384592
Packit Service 384592
    apr_app_initialize(&argc, &argv, NULL);
Packit Service 384592
    atexit(apr_terminate);
Packit Service 384592
Packit Service 384592
    curl_global_init(CURL_GLOBAL_ALL);
Packit Service 384592
    atexit(logc_cleanup);
Packit Service 384592
Packit Service 384592
    logc_pid = getpid();
Packit Service 384592
    apr_pool_create(&pool, NULL);
Packit Service 384592
    apr_pool_create(&recv_pool, NULL);
Packit Service 384592
	
Packit Service 384592
#ifndef WIN32
Packit Service 384592
    apr_setup_signal_thread();
Packit Service 384592
#else
Packit Service 384592
	apr_signal(SIGINT, handle_signals);
Packit Service 384592
	apr_signal(SIGTERM, handle_signals);
Packit Service 384592
#endif /* WIN32 */
Packit Service 384592
Packit Service 384592
    if (argc < 2) {
Packit Service 384592
        usage();
Packit Service 384592
        logc_shutdown(1);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Commandline opts */
Packit Service 384592
    rc = apr_getopt_init(&opt, pool, argc, argv);
Packit Service 384592
    if (rc != APR_SUCCESS) {
Packit Service 384592
        usage();
Packit Service 384592
        logc_shutdown(1);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    do {
Packit Service 384592
        char  ch;
Packit Service 384592
        const char *val;
Packit Service 384592
        rc = apr_getopt(opt, CMDLINE_OPTS, &ch, &val;;
Packit Service 384592
        switch (rc) {
Packit Service 384592
            case APR_SUCCESS:
Packit Service 384592
                switch (ch) {
Packit Service 384592
                    case 'f':
Packit Service 384592
                        opt_force = 1;
Packit Service 384592
                        break;
Packit Service 384592
                    case 'v':
Packit Service 384592
                        version();
Packit Service 384592
                        logc_shutdown(0);
Packit Service 384592
                    case 'h':
Packit Service 384592
                        usage();
Packit Service 384592
                        logc_shutdown(0);
Packit Service 384592
                }
Packit Service 384592
                break;
Packit Service 384592
            case APR_BADCH:
Packit Service 384592
            case APR_BADARG:
Packit Service 384592
                usage();
Packit Service 384592
                logc_shutdown(1);
Packit Service 384592
        }
Packit Service 384592
    } while (rc != APR_EOF);
Packit Service 384592
Packit Service 384592
    /* Conf file is last */
Packit Service 384592
    conffile = argv[argc - 1];
Packit Service 384592
Packit Service 384592
    read_configuration();
Packit Service 384592
    init_configuration();
Packit Service 384592
Packit Service 384592
    logc_init();
Packit Service 384592
    transaction_log_init();
Packit Service 384592
Packit Service 384592
    running = 1;
Packit Service 384592
    server_error = 0;
Packit Service 384592
Packit Service 384592
    start_management_thread();
Packit Service 384592
#ifndef WIN32
Packit Service 384592
    start_signal_thread();
Packit Service 384592
#endif /* WIN32 */
Packit Service 384592
Packit Service 384592
    /* Process stdin until EOF */
Packit Service 384592
    receive_loop();
Packit Service 384592
Packit Service 384592
    logc_shutdown(0);
Packit Service 384592
Packit Service 384592
    return 0;
Packit Service 384592
}