|
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 |
}
|