diff --git a/CHANGES b/CHANGES
index 0ffc25b2..de9e3909 100644
--- a/CHANGES
+++ b/CHANGES
@@ -2,6 +2,9 @@
?? ??? 2007 - trunk
-------------------
+ * Added SecAuditLog2 directive to allow redundent concurrent audit log
+ index files. This will allow sending audit data to two consoles, etc.
+
* Removed CGI style HTTP_* variables in favor of REQUEST_HEADERS:Header-Name.
* Store filename/line for each rule and display it and the ID (if available)
diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c
index 5c64b820..0642109b 100644
--- a/apache2/apache2_config.c
+++ b/apache2/apache2_config.c
@@ -58,7 +58,9 @@ void *create_directory_config(apr_pool_t *mp, char *path) {
dcfg->auditlog_flag = NOT_SET;
dcfg->auditlog_type = NOT_SET;
dcfg->auditlog_name = NOT_SET_P;
+ dcfg->auditlog2_name = NOT_SET_P;
dcfg->auditlog_fd = NOT_SET_P;
+ dcfg->auditlog2_fd = NOT_SET_P;
dcfg->auditlog_storage_dir = NOT_SET_P;
dcfg->auditlog_parts = NOT_SET_P;
dcfg->auditlog_relevant_regex = NOT_SET_P;
@@ -324,6 +326,13 @@ void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child) {
merged->auditlog_fd = parent->auditlog_fd;
merged->auditlog_name = parent->auditlog_name;
}
+ if (child->auditlog2_fd != NOT_SET_P) {
+ merged->auditlog2_fd = child->auditlog2_fd;
+ merged->auditlog2_name = child->auditlog2_name;
+ } else {
+ merged->auditlog2_fd = parent->auditlog2_fd;
+ merged->auditlog2_name = parent->auditlog2_name;
+ }
merged->auditlog_storage_dir = (child->auditlog_storage_dir == NOT_SET_P
? parent->auditlog_storage_dir : child->auditlog_storage_dir);
merged->auditlog_parts = (child->auditlog_parts == NOT_SET_P
@@ -389,7 +398,9 @@ void init_directory_config(directory_config *dcfg) {
if (dcfg->auditlog_flag == NOT_SET) dcfg->auditlog_flag = 0;
if (dcfg->auditlog_type == NOT_SET) dcfg->auditlog_type = AUDITLOG_SERIAL;
if (dcfg->auditlog_fd == NOT_SET_P) dcfg->auditlog_fd = NULL;
+ if (dcfg->auditlog2_fd == NOT_SET_P) dcfg->auditlog2_fd = NULL;
if (dcfg->auditlog_name == NOT_SET_P) dcfg->auditlog_name = NULL;
+ if (dcfg->auditlog2_name == NOT_SET_P) dcfg->auditlog2_name = NULL;
if (dcfg->auditlog_storage_dir == NOT_SET_P) dcfg->auditlog_storage_dir = NULL;
if (dcfg->auditlog_parts == NOT_SET_P) dcfg->auditlog_parts = "ABCFHZ";
if (dcfg->auditlog_relevant_regex == NOT_SET_P) dcfg->auditlog_relevant_regex = NULL;
@@ -566,6 +577,43 @@ static const char *cmd_audit_log(cmd_parms *cmd, void *_dcfg, const char *p1) {
return NULL;
}
+static const char *cmd_audit_log2(cmd_parms *cmd, void *_dcfg, const char *p1) {
+ directory_config *dcfg = _dcfg;
+
+ if (dcfg->auditlog_name == NOT_SET_P) {
+ return apr_psprintf(cmd->pool, "ModSecurity: Cannot configure a secondary audit log without a primary defined: %s", p1);
+ }
+
+ dcfg->auditlog2_name = (char *)p1;
+
+ if (dcfg->auditlog2_name[0] == '|') {
+ const char *pipe_name = ap_server_root_relative(cmd->pool, dcfg->auditlog2_name + 1);
+ piped_log *pipe_log;
+
+ pipe_log = ap_open_piped_log(cmd->pool, pipe_name);
+ if (pipe_log == NULL) {
+ return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the secondary audit log pipe: %s",
+ pipe_name);
+ }
+ dcfg->auditlog2_fd = ap_piped_log_write_fd(pipe_log);
+ }
+ else {
+ const char *file_name = ap_server_root_relative(cmd->pool, dcfg->auditlog2_name);
+ apr_status_t rc;
+
+ rc = apr_file_open(&dcfg->auditlog2_fd, file_name,
+ APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY,
+ CREATEMODE, cmd->pool);
+
+ if (rc != APR_SUCCESS) {
+ return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the secondary audit log file: %s",
+ file_name);
+ }
+ }
+
+ return NULL;
+}
+
static const char *cmd_audit_log_parts(cmd_parms *cmd, void *_dcfg, const char *p1) {
directory_config *dcfg = _dcfg;
@@ -1076,7 +1124,15 @@ const command_rec module_directives[] = {
cmd_audit_log,
NULL,
CMD_SCOPE_ANY,
- "The filename of the audit log file"
+ "The filename of the primary audit log file"
+ ),
+
+ AP_INIT_TAKE1 (
+ "SecAuditLog2",
+ cmd_audit_log2,
+ NULL,
+ CMD_SCOPE_ANY,
+ "The filename of the secondary audit log file"
),
AP_INIT_TAKE1 (
diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h
index 95f9c6a0..23bec806 100644
--- a/apache2/modsecurity.h
+++ b/apache2/modsecurity.h
@@ -349,9 +349,12 @@ struct directory_config {
* name of the index file (for the new audit log type)
*/
char *auditlog_name;
+ /* The name of the secondary index file */
+ char *auditlog2_name;
- /* The file descriptor for the file above */
+ /* The file descriptors for the files above */
apr_file_t *auditlog_fd;
+ apr_file_t *auditlog2_fd;
/* For the new-style audit log only, the path where
* audit log entries will be stored
diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c
index 55abb11b..abe5a2a6 100644
--- a/apache2/msc_logging.c
+++ b/apache2/msc_logging.c
@@ -886,5 +886,16 @@ void sec_audit_logger(modsec_rec *msr) {
if (text == NULL) return;
nbytes = strlen(text);
+ if (msr->txcfg->debuglog_level >= 9) {
+ msr_log(msr, 9, "Audit Log: Writing %d bytes to primary concurrent index", nbytes);
+ }
apr_file_write_full(msr->txcfg->auditlog_fd, text, nbytes, &nbytes_written);
+
+ /* Write to the secondary audit log if we have one */
+ if (msr->txcfg->auditlog2_fd != NULL) {
+ if (msr->txcfg->debuglog_level >= 9) {
+ msr_log(msr, 9, "Audit Log: Writing %d bytes to secondary concurrent index", nbytes);
+ }
+ apr_file_write_full(msr->txcfg->auditlog2_fd, text, nbytes, &nbytes_written);
+ }
}
diff --git a/doc/modsecurity2-apache-reference.xml b/doc/modsecurity2-apache-reference.xml
index 351abd44..2e608548 100644
--- a/doc/modsecurity2-apache-reference.xml
+++ b/doc/modsecurity2-apache-reference.xml
@@ -568,6 +568,34 @@ SecAuditLogStorageDir logs/audit
"|/path/modsec-auditlog-collector.pl /path/SecAuditLogDataDir /path/SecAuditLog"
+
+ SecAuditLog2
+
+ Description: Defines the path to
+ the secondary audit log index file when concurrent logging is enabled.
+ See SecAuditLog2 for more
+ details.
+
+ Syntax: SecAuditLog2 /path/to/auditlog2
+
+ Example Usage: SecAuditLog2
+ /usr/local/apache/logs/audit2.log
+
+ Processing Phase: N/A
+
+ Scope:
+ Any
+
+ Dependencies/Notes: A main audit
+ log must be defined via SecAuditLog
+ before this directive may be used. Additionally, this log is only used
+ for replicating the main audit log index file when concurrent audit
+ logging is used. It will not be used
+ for non-concurrent audit logging.
+
+