Use the new queue implementation for persistence. This only attaches "struct queue" to the existing interface, with minimal interface changes. Refactoring will follow. Note that this does not expose the Q_SYNC flag to users, so some records may be lost upon a system crash. I'm ambivalent about this - on one hand it is desirable to be able to protect the data against a crash, on the other hand the audit record may be lost by a crash even before audisp-remote gets a chance to write it to disk, and perhaps it's better not to promise anything than to promise and not deliver. Index: audit/audisp/plugins/remote/audisp-remote.c =================================================================== --- audit.orig/audisp/plugins/remote/audisp-remote.c +++ audit/audisp/plugins/remote/audisp-remote.c @@ -293,6 +293,17 @@ static int generic_remote_warning_handle config.generic_warning_exe); } +/* Report and handle a queue error, using errno. */ +void queue_error(void) +{ + char *errno_str; + va_list ap; + + errno_str = strerror(errno); + do_action("queue error", errno_str, LOG_ERR, config.queue_error_action, + config.queue_error_exe); +} + static void send_heartbeat (void) { relay_event (NULL, 0); @@ -358,7 +369,10 @@ int main(int argc, char *argv[]) rc = init_transport(); if (rc == ET_PERMANENT) return 1; - init_queue(config.queue_depth); + if (init_queue(&config) != 0) { + syslog(LOG_ERR, "Error initializing audit record queue"); + return 1; + } #ifdef HAVE_LIBCAP_NG // Drop all capabilities @@ -437,7 +451,8 @@ int main(int argc, char *argv[]) strnlen(e->data, MAX_AUDIT_MESSAGE_LENGTH)); if (rc >= 0) { - dequeue(0); // delete it + free(e); + e = dequeue(0); // delete it free(e); } } Index: audit/audisp/plugins/remote/queue.c =================================================================== --- audit.orig/audisp/plugins/remote/queue.c +++ audit/audisp/plugins/remote/queue.c @@ -163,7 +163,7 @@ static int sync_fh_state (struct queue * return q_sync(q); } - /* Implementation */ + /* Queue implementation */ /* Open PATH for Q, update Q from it, and return 0. On error, return -1 and set errno; Q->fd may be set even on error. */ @@ -570,81 +570,84 @@ err_errno_q: return NULL; } - /* The old interface */ + /* audisp-remote interface */ -static volatile event_t **q; -static unsigned int q_next, q_last, q_depth; +/* MAX_AUDIT_MESSAGE_LENGTH, aligned to 4 KB so that an average q_append() only + writes to two disk disk blocks (1 aligned data block, 1 header block). */ +#define QUEUE_ENTRY_SIZE (3*4096) -int init_queue(unsigned int size) +extern void queue_error(void); /* This will go away in a few more patches. */ + +static struct queue *q; + +int init_queue(remote_conf_t *config) { - unsigned int i; + const char *path; + int q_flags; - q_next = 0; - q_last = 0; - q_depth = size; - q = malloc(q_depth * sizeof(event_t *)); + if (config->queue_file != NULL) + path = config->queue_file; + else + path = "/var/lib/auditd-remote/queue"; + q_flags = Q_IN_MEMORY; + if (config->mode == M_STORE_AND_FORWARD) + /* FIXME: let user control Q_SYNC? */ + q_flags |= Q_IN_FILE | Q_CREAT | Q_RESIZE; + verify(QUEUE_ENTRY_SIZE >= MAX_AUDIT_MESSAGE_LENGTH); + q = q_open(q_flags, path, config->queue_depth, QUEUE_ENTRY_SIZE); if (q == NULL) return -1; - - for (i=0; idata) == 0) + ret = 0; + else if (errno == ENOSPC) + ret = -1; + else { + queue_error(); + ret = 0; } + free(e); + return ret; } event_t *dequeue(int peek) { event_t *e; - unsigned int n; - - // OK, grab the next event - n = q_last%q_depth; - if (q[n] != NULL) { - e = (event_t *)q[n]; - if (peek == 0) { - q[n] = NULL; - q_last = (n+1) % q_depth; - } - } else - e = NULL; + int r; - // Process the event + e = malloc(sizeof(*e)); + if (e == NULL) + goto err; + r = q_peek(q, e->data, sizeof(e->data)); + if (r == 0) { + free(e); + return NULL; + } + if (r != 1) + goto err; + if (!peek && q_drop_head(q) != 0) + goto err; return e; + +err: + queue_error(); + free(e); + return NULL; } int queue_length(void) { - if (q_next == q_last) - return 0; - if (q_last > q_next) - return (q_depth + q_next) - q_last; - else - return q_next - q_last; + return q_queue_length(q); } void destroy_queue(void) { - unsigned int i; - - for (i=0; i #include "libaudit.h" +#include "remote-config.h" typedef struct event { @@ -33,7 +34,7 @@ typedef struct event } event_t; -int init_queue(unsigned int size); +int init_queue(remote_conf_t *config); int enqueue(event_t *e); event_t *dequeue(int peek); int queue_length(void); Index: audit/audisp/plugins/remote/test-queue.c =================================================================== --- audit.orig/audisp/plugins/remote/test-queue.c +++ audit/audisp/plugins/remote/test-queue.c @@ -72,6 +72,12 @@ err__(int line, const char *message, ... abort(); } +/* This will go away in a few patches. */ +void queue_error(void) +{ + err("Queue error"); +} + static void init_sample_entries(void) {