* [PATCH] Add auditd listener and remote audit protocol
@ 2008-08-14 21:43 DJ Delorie
2008-08-14 21:58 ` LC Bruzenak
2008-08-15 0:23 ` Steve Grubb
0 siblings, 2 replies; 25+ messages in thread
From: DJ Delorie @ 2008-08-14 21:43 UTC (permalink / raw)
To: linux-audit
Second in a series, a bit bigger than the first one.
(http://www.redhat.com/archives/linux-audit/2008-August/msg00070.html)
The goal of this patch is to add the server side of the remote logging
feature. To this end, a new auditd-listener.c is added which listens
on a TCP port for connections from other systems' audisp-remote
plugins. A new (private) protocol is added which prepends each
message with a header, giving length, status, version, and sequence
information. Each message begets a reply from the server, so we can
pass along status like "disk full" or "ok". Currently, these call a
set of stub functions, as the details of performing appropriate
actions from the plugin are yet to be decided.
The remote plugin has a new option "format" for "ascii" or "managed"
to choose between the old protocol (ascii strings) and the new one
(the header with ACK, default).
The listener will accept either format. It has new options for the
listen port, accept queue size, and acceptable client-side ports.
Comments?
DJ
Proposed ChangeLog entry:
- Add TCP listener and managed remote protocol features.
diff -N -U 3 -x .svn -r pristine/audisp/plugins/remote/audisp-remote.c trunk/audisp/plugins/remote/audisp-remote.c
--- pristine/audisp/plugins/remote/audisp-remote.c 2008-08-04 12:47:28.000000000 -0400
+++ trunk/audisp/plugins/remote/audisp-remote.c 2008-08-14 14:10:48.000000000 -0400
@@ -30,7 +30,11 @@
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
#include "libaudit.h"
+#include "private.h"
#include "remote-config.h"
#define CONFIG_FILE "/etc/audisp/audisp-remote.conf"
@@ -68,6 +72,56 @@
hup = 0;
}
+/*
+ * Handlers for various events coming back from the remote server.
+ * Return -1 if the remote dispatcher should exit.
+ */
+
+/* Loss of sync - got an invalid response. */
+static int sync_error_handler (const char *why)
+{
+ /* "why" has human-readable details on why we've lost (or will
+ be losing) sync. */
+ syslog (LOG_ERR, "lost/losing sync, %s", why);
+ return -1;
+}
+
+static int remote_disk_low_handler (const char *message)
+{
+ syslog (LOG_WARNING, "remote disk low, %s", message);
+ return 0;
+}
+
+static int remote_disk_full_handler (const char *message)
+{
+ syslog (LOG_ERR, "remote disk full, %s", message);
+ return -1;
+}
+
+static int remote_disk_error_handler (const char *message)
+{
+ syslog (LOG_ERR, "remote disk error, %s", message);
+ return -1;
+}
+
+static int remote_server_ending_handler (const char *message)
+{
+ syslog (LOG_INFO, "remote server ending, %s", message);
+ return -1;
+}
+
+static int generic_remote_error_handler (const char *message)
+{
+ stop = 1;
+ syslog(LOG_INFO, "audisp-remote: remote error: %s", message);
+ return -1;
+}
+static int generic_remote_warning_handler (const char *message)
+{
+ syslog(LOG_INFO, "audisp-remote: remote warning: %s", message);
+ return 0;
+}
+
int main(int argc, char *argv[])
{
@@ -122,6 +176,7 @@
struct addrinfo *ai;
struct addrinfo hints;
char remote[BUF_SIZE];
+ int one=1;
memset(&hints, '\0', sizeof(hints));
hints.ai_flags = AI_ADDRCONFIG|AI_NUMERICSERV;
@@ -140,12 +195,35 @@
freeaddrinfo(ai);
return -1;
}
+
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof (int));
+
+ if (config.local_port != 0) {
+ struct sockaddr_in address;
+
+ memset (&address, 0, sizeof(address));
+ address.sin_family = htons(AF_INET);
+ address.sin_port = htons(config.local_port);
+ address.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ if ( bind ( sock, (struct sockaddr *)&address, sizeof(address)) ) {
+ syslog(LOG_ERR, "Cannot bind local socket to port %d - exiting",
+ config.local_port);
+ close(sock);
+ return -1;
+ }
+
+ }
if (connect(sock, ai->ai_addr, ai->ai_addrlen)) {
syslog(LOG_ERR, "Error connecting to %s: %s - exiting",
config.remote_server, strerror(errno));
freeaddrinfo(ai);
return -1;
}
+
+ setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&one, sizeof (int));
+ setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof (int));
+
freeaddrinfo(ai);
return 0;
}
@@ -166,16 +244,143 @@
return rc;
}
-static int relay_sock(const char *s, size_t len)
+static int ar_write (int sock, const void *buf, int len)
{
int rc;
-
do {
- rc = write(sock, s, len);
+ rc = write(sock, buf, len);
} while (rc < 0 && errno == EINTR);
- if (rc > 0)
- return 0;
- return -1;
+ return rc;
+}
+
+static int ar_read (int sock, void *buf, int len)
+{
+ unsigned char *obuf = buf;
+ int rc = 0, r;
+ while (len > 0) {
+ do {
+ r = read(sock, buf, len);
+ } while (r < 0 && errno == EINTR);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+ rc += r;
+ buf = (void *)((char *)buf + r);
+ len -= r;
+ }
+ return rc;
+}
+
+static int relay_sock_ascii(const char *s, size_t len)
+{
+ int rc;
+
+ rc = ar_write(sock, s, len);
+ if (rc <= 0) {
+ stop = 1;
+ syslog(LOG_ERR, "connection to %s closed unexpectedly - exiting",
+ config.remote_server);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int relay_sock_managed(const char *s, size_t len)
+{
+ static int sequence_id = 1;
+ int rc;
+ unsigned char header[AUDIT_RMW_HEADER_SIZE];
+ int hver, mver;
+ uint32_t magic, type, rlen, seq;
+ char msg[MAX_AUDIT_MESSAGE_LENGTH+1];
+
+ sequence_id ++;
+ AUDIT_RMW_PACK_HEADER (header, 0, 0, len, sequence_id);
+ rc = ar_write(sock, header, AUDIT_RMW_HEADER_SIZE);
+ if (rc <= 0) {
+ stop = 1;
+ syslog(LOG_ERR, "connection to %s closed unexpectedly - exiting",
+ config.remote_server);
+ return -1;
+ }
+
+ rc = ar_write(sock, s, len);
+ if (rc <= 0) {
+ stop = 1;
+ syslog(LOG_ERR, "connection to %s closed unexpectedly - exiting",
+ config.remote_server);
+ return -1;
+ }
+
+ rc = ar_read (sock, header, AUDIT_RMW_HEADER_SIZE);
+ if (rc < 16) {
+ stop = 1;
+ syslog(LOG_ERR, "connection to %s closed unexpectedly - exiting",
+ config.remote_server);
+ return -1;
+ }
+
+
+ if (! AUDIT_RMW_IS_MAGIC (header, AUDIT_RMW_HEADER_SIZE))
+ /* FIXME: the right thing to do here is close the socket and start a new one. */
+ return sync_error_handler ("bad magic number");
+
+ AUDIT_RMW_UNPACK_HEADER (header, hver, mver, type, rlen, seq);
+
+ if (rlen > MAX_AUDIT_MESSAGE_LENGTH)
+ return sync_error_handler ("message too long");
+
+ if (rlen > 0
+ && ar_read (sock, msg, rlen) < rlen)
+ return sync_error_handler ("ran out of data reading reply");
+ msg[rlen] = 0;
+
+ if (seq != sequence_id)
+ /* FIXME: should we read another header and
+ see if it matches? If so, we need to deal
+ with timeouts. */
+ return sync_error_handler ("mismatched response");
+
+ /* Specific errors we know how to deal with. */
+
+ if (type == AUDIT_RMW_TYPE_ENDING)
+ return remote_server_ending_handler (msg);
+ if (type == AUDIT_RMW_TYPE_DISKLOW)
+ return remote_disk_low_handler (msg);
+ if (type == AUDIT_RMW_TYPE_DISKFULL)
+ return remote_disk_full_handler (msg);
+ if (type == AUDIT_RMW_TYPE_DISKERROR)
+ return remote_disk_error_handler (msg);
+
+ /* Generic errors. */
+ if (type & AUDIT_RMW_TYPE_FATALMASK)
+ return generic_remote_error_handler (msg);
+ if (type & AUDIT_RMW_TYPE_WARNMASK)
+ return generic_remote_warning_handler (msg);
+
+ return 0;
+}
+
+static int relay_sock(const char *s, size_t len)
+{
+ int rc;
+
+ switch (config.format)
+ {
+ case F_MANAGED:
+ rc = relay_sock_managed (s, len);
+ break;
+ case F_ASCII:
+ rc = relay_sock_ascii (s, len);
+ break;
+ default:
+ rc = -1;
+ break;
+ }
+
+ return rc;
}
static int relay_event(const char *s, size_t len)
diff -N -U 3 -x .svn -r pristine/audisp/plugins/remote/audisp-remote.conf trunk/audisp/plugins/remote/audisp-remote.conf
--- pristine/audisp/plugins/remote/audisp-remote.conf 2008-08-04 12:47:28.000000000 -0400
+++ trunk/audisp/plugins/remote/audisp-remote.conf 2008-08-14 15:11:23.000000000 -0400
@@ -5,8 +5,9 @@
remote_server =
port = 60
+#local_port =
transport = tcp
mode = immediate
queue_depth = 20
fail_action = SYSLOG
-
+format = managed
diff -N -U 3 -x .svn -r pristine/audisp/plugins/remote/audisp-remote.conf.5 trunk/audisp/plugins/remote/audisp-remote.conf.5
--- pristine/audisp/plugins/remote/audisp-remote.conf.5 2008-08-04 12:47:28.000000000 -0400
+++ trunk/audisp/plugins/remote/audisp-remote.conf.5 2008-08-14 15:36:53.000000000 -0400
@@ -11,6 +11,13 @@
.I port
This option is an unsigned integer that indicates what port to connect to on the remote machine.
.TP
+.I local_port
+This option is an unsigned integer that indicates what local port to
+connect from on the local machine. If unspecified (the default) or
+set to the word
+.I any
+then any available unpriviledged port is used.
+.TP
.I transport
This parameter tells the remote logging app how to send events to the remote system. Valid values are
.IR tcp ", and " ssl ".
@@ -55,7 +62,22 @@
option will cause the remote logging app to put the computer system in single user mode.
.I halt
option will cause the remote logging app to shutdown the computer system.
+.TP
+.I format
+This parameter tells the remote logging app what data format will be
+used for the messages sent over the network. The default is
+.I managed
+which adds some overhead to ensure each message is properly handled on
+the remote end, and to receive status messages from the remote server.
+If
+.I ascii
+is given instead, each message is a simple ASCII text line with no
+overhead at all.
+.SH "NOTES"
+Specifying a local port may make it difficult to restart the audit
+subsystem due to the previous connection being in a TIME_WAIT state,
+if you're reconnecting to and from the same hosts and ports as before.
.SH "SEE ALSO"
.BR audispd (8),
.BR audisp-remote(8).
diff -N -U 3 -x .svn -r pristine/audisp/plugins/remote/remote-config.c trunk/audisp/plugins/remote/remote-config.c
--- pristine/audisp/plugins/remote/remote-config.c 2008-08-04 12:47:28.000000000 -0400
+++ trunk/audisp/plugins/remote/remote-config.c 2008-08-13 22:19:31.000000000 -0400
@@ -62,6 +62,8 @@
remote_conf_t *config);
static int port_parser(struct nv_pair *nv, int line,
remote_conf_t *config);
+static int local_port_parser(struct nv_pair *nv, int line,
+ remote_conf_t *config);
static int transport_parser(struct nv_pair *nv, int line,
remote_conf_t *config);
static int mode_parser(struct nv_pair *nv, int line,
@@ -70,16 +72,20 @@
remote_conf_t *config);
static int fail_action_parser(struct nv_pair *nv, int line,
remote_conf_t *config);
+static int format_parser(struct nv_pair *nv, int line,
+ remote_conf_t *config);
static int sanity_check(remote_conf_t *config, const char *file);
static const struct kw_pair keywords[] =
{
{"remote_server", server_parser, 0 },
{"port", port_parser, 0 },
+ {"local_port", local_port_parser, 0 },
{"transport", transport_parser, 0 },
{"mode", mode_parser, 0 },
{"queue_depth", depth_parser, 0 },
{"fail_action", fail_action_parser, 0 },
+ {"format", format_parser, 0 },
{ NULL, NULL }
};
@@ -107,6 +113,13 @@
{ NULL, 0 }
};
+static const struct nv_list format_words[] =
+{
+ {"ascii", F_ASCII },
+ {"managed", F_MANAGED },
+ { NULL, 0 }
+};
+
/*
* Set everything to its default value
*/
@@ -114,11 +127,13 @@
{
config->remote_server = NULL;
config->port = 60;
+ config->local_port = 0;
config->port = T_TCP;
config->mode = M_IMMEDIATE;
config->queue_depth = 20;
config->fail_action = F_SYSLOG;
config->fail_exe = NULL;
+ config->format = F_MANAGED;
}
int load_config(remote_conf_t *config, const char *file)
@@ -392,6 +407,46 @@
return 0;
}
+static int local_port_parser(struct nv_pair *nv, int line, remote_conf_t *config)
+{
+ const char *ptr = nv->value;
+ int i;
+
+ if (strcasecmp (ptr, "any") == 0) {
+ config->local_port = 0;
+ return 0;
+ }
+
+ /* check that all chars are numbers */
+ for (i=0; ptr[i]; i++) {
+ if (!isdigit(ptr[i])) {
+ syslog(LOG_ERR,
+ "Value %s should only be numbers - line %d",
+ nv->value, line);
+ return 1;
+ }
+ }
+
+ /* convert to unsigned int */
+ errno = 0;
+ i = strtoul(nv->value, NULL, 10);
+ if (errno) {
+ syslog(LOG_ERR,
+ "Error converting string to a number (%s) - line %d",
+ strerror(errno), line);
+ return 1;
+ }
+ /* Check its range */
+ if (i > INT_MAX) {
+ syslog(LOG_ERR,
+ "Error - converted number (%s) is too large - line %d",
+ nv->value, line);
+ return 1;
+ }
+ config->local_port = (unsigned int)i;
+ return 0;
+}
+
static int transport_parser(struct nv_pair *nv, int line, remote_conf_t *config)
{
int i;
@@ -477,6 +532,20 @@
return 1;
}
+static int format_parser(struct nv_pair *nv, int line,
+ remote_conf_t *config)
+{
+ int i;
+ for (i=0; format_words[i].name != NULL; i++) {
+ if (strcasecmp(nv->value, format_words[i].name) == 0) {
+ config->format = format_words[i].option;
+ return 0;
+ }
+ }
+ syslog(LOG_ERR, "Option %s not found - line %d", nv->value, line);
+ return 1;
+}
+
/*
* This function is where we do the integrated check of the audispd config
* options. At this point, all fields have been read. Returns 0 if no
diff -N -U 3 -x .svn -r pristine/audisp/plugins/remote/remote-config.h trunk/audisp/plugins/remote/remote-config.h
--- pristine/audisp/plugins/remote/remote-config.h 2008-08-04 12:47:28.000000000 -0400
+++ trunk/audisp/plugins/remote/remote-config.h 2008-08-13 22:17:19.000000000 -0400
@@ -27,16 +27,19 @@
typedef enum { M_IMMEDIATE, M_STORE_AND_FORWARD } mode_t;
typedef enum { T_TCP, T_SSL, T_GSSAPI, T_LABELED } transport_t;
typedef enum { F_IGNORE, F_SYSLOG, F_EXEC, F_SUSPEND, F_SINGLE, F_HALT } fail_t;
+typedef enum { F_ASCII, F_MANAGED } format_t;
typedef struct remote_conf
{
const char *remote_server;
unsigned int port;
+ unsigned int local_port;
transport_t transport;
mode_t mode;
unsigned int queue_depth;
fail_t fail_action;
const char *fail_exe;
+ format_t format;
} remote_conf_t;
void clear_config(remote_conf_t *config);
diff -N -U 3 -x .svn -r pristine/docs/auditd.conf.5 trunk/docs/auditd.conf.5
--- pristine/docs/auditd.conf.5 2008-08-04 12:47:31.000000000 -0400
+++ trunk/docs/auditd.conf.5 2008-08-14 15:35:29.000000000 -0400
@@ -212,6 +212,26 @@
option will cause the audit daemon to put the computer system in single user mode.
.I halt
option will cause the audit daemon to shutdown the computer system.
+.TP
+.I tcp_listen_port
+This is a numeric value in the range 1..65535 which, if specified,
+causes auditd to listen on the corresponding TCP port for audit
+records from remote systems.
+.TP
+.I tcp_listen_queue
+This is a numeric value which indicates how many pending (requested
+but unaccepted) connections are allowed. The default is 5. Setting
+this too small may cause connections to be rejected if too many hosts
+start up at exactly the same time, such as after a power failure.
+.TP
+.I tcp_client_ports
+This parameter may be a single numeric value or two values separated
+by a dash (no spaces allowed). It indicates which client ports are
+allowed for incoming connections. If not specified, any port is
+allowed. Allowed values are 1..65535. For example, to require the
+client use a priviledged port, specify
+.I 1-1023
+for this parameter.
.SH NOTES
In a CAPP environment, the audit trail is considered so important that access to system resources must be denied if an audit trail cannot be created. In this environment, it would be suggested that /var/log/audit be on its own partition. This is to ensure that space detection is accurate and that no other process comes along and consumes part of it.
@@ -227,6 +247,11 @@
The disk_full_action is triggered when no more room exists on the partition. All access should be terminated since no more audit capability exists. This can be set to either single or halt.
.PP
The disk_error_action should be set to syslog, single, or halt depending on your local policies regarding handling of hardware malfunctions.
+.PP
+Specifying a single allowed client port may make it difficult for the
+client to restart their audit subsystem, as it will be unable to
+recreate a connection with the same host addresses and ports until the
+connection closure TIME_WAIT state times out.
.SH FILES
.TP
diff -N -U 3 -x .svn -r pristine/init.d/auditd.conf trunk/init.d/auditd.conf
--- pristine/init.d/auditd.conf 2008-08-04 12:47:28.000000000 -0400
+++ trunk/init.d/auditd.conf 2008-08-14 15:22:08.000000000 -0400
@@ -22,4 +22,6 @@
admin_space_left_action = SUSPEND
disk_full_action = SUSPEND
disk_error_action = SUSPEND
-
+#tcp_listen_port =
+#tcp_listen_queue = 5
+#tcp_client_ports = 1024-65535
diff -N -U 3 -x .svn -r pristine/lib/libaudit.h trunk/lib/libaudit.h
--- pristine/lib/libaudit.h 2008-08-04 12:47:34.000000000 -0400
+++ trunk/lib/libaudit.h 2008-08-14 10:58:46.000000000 -0400
@@ -413,10 +413,6 @@
};
};
-struct auditd_reply_list {
- struct audit_reply reply;
- struct auditd_reply_list *next;
-};
//
// End of ABI control
//////////////////////////////////////////////////////
diff -N -U 3 -x .svn -r pristine/lib/private.h trunk/lib/private.h
--- pristine/lib/private.h 2008-08-04 12:47:34.000000000 -0400
+++ trunk/lib/private.h 2008-08-14 10:58:46.000000000 -0400
@@ -55,6 +55,83 @@
;
#endif
+/* This structure is for protocol reference only. All fields are
+ packed and in network order (LSB first). */
+struct auditd_remote_message_wrapper {
+ /* The magic number shall never have LF (0x0a) as one of its bytes. */
+ uint32_t magic;
+ /* Bumped when the layout of this structure changes. */
+ uint8_t header_version;
+ /* The minimum support needed to understand this message type.
+ * Normally zero. */
+ uint8_t message_version;
+ /* Upper 8 bits are generic type, see below. */
+ uint32_t type;
+ /* Number of bytes that follow this header Must be 0..MAX_AUDIT_MESSAGE_LENGTH. */
+ uint16_t length;
+ /* Copied from message to its reply. */
+ uint32_t sequence_id;
+ /* The message follows for LENGTH bytes. */
+};
+
+#define AUDIT_RMW_HEADER_SIZE 16
+/* The magic number shall never have LF (0x0a) as one of its bytes. */
+#define AUDIT_RMW_MAGIC 0xff0000feUL
+
+#define AUDIT_RMW_HEADER_VERSION 0
+
+/* If set, this is a reply. */
+#define AUDIT_RMW_TYPE_REPLYMASK 0x40000000
+/* If set, this reply indicates a fatal error of some sort. */
+#define AUDIT_RMW_TYPE_FATALMASK 0x20000000
+/* If set, this reply indicates success but with some warnings. */
+#define AUDIT_RMW_TYPE_WARNMASK 0x10000000
+/* This part of the message type is the details for the above. */
+#define AUDIT_RMW_TYPE_DETAILMASK 0x0fffffff
+
+/* Version 0 messages. */
+#define AUDIT_RMW_TYPE_MESSAGE 0x00000000
+#define AUDIT_RMW_TYPE_ACK 0x40000000
+#define AUDIT_RMW_TYPE_ENDING 0x40000001
+#define AUDIT_RMW_TYPE_DISKLOW 0x50000001
+#define AUDIT_RMW_TYPE_DISKFULL 0x60000001
+#define AUDIT_RMW_TYPE_DISKERROR 0x60000002
+
+/* These next four should not be called directly. */
+#define _AUDIT_RMW_PUTN32(header,i,v) \
+ header[i] = v & 0xff; \
+ header[i+1] = (v>>8) & 0xff; \
+ header[i+2] = (v>>16) & 0xff; \
+ header[i+3] = (v>>24) & 0xff;
+#define _AUDIT_RMW_PUTN16(header,i,v) \
+ header[i] = v & 0xff; \
+ header[i+1] = (v>>8) & 0xff;
+#define _AUDIT_RMW_GETN32(header,i) \
+ (header[i] | (header[i+1]<<8) | (header[i+2]<<16) | (header[i+3]<<24))
+#define _AUDIT_RMW_GETN16(header,i) \
+ (header[i] | (header[i+1]<<8))
+
+/* For these, HEADER must by of type "unsigned char *" or "unsigned
+ char []" */
+
+#define AUDIT_RMW_PACK_HEADER(header,mver,type,len,seq) \
+ _AUDIT_RMW_PUTN32 (header,0, AUDIT_RMW_MAGIC); \
+ header[4] = AUDIT_RMW_HEADER_VERSION; \
+ header[5] = mver; \
+ _AUDIT_RMW_PUTN32 (header,6, type); \
+ _AUDIT_RMW_PUTN16 (header,10, len); \
+ _AUDIT_RMW_PUTN32 (header,12, seq);
+
+#define AUDIT_RMW_IS_MAGIC(header,length) \
+ (length >= 4 && _AUDIT_RMW_GETN32 (header,0) == AUDIT_RMW_MAGIC)
+
+#define AUDIT_RMW_UNPACK_HEADER(header,hver,mver,type,len,seq) \
+ hver = header[4]; \
+ mver = header[5]; \
+ type = _AUDIT_RMW_GETN32 (header,6); \
+ len = _AUDIT_RMW_GETN16 (header,10); \
+ seq = _AUDIT_RMW_GETN32 (header,12);
+
/* General */
extern int audit_send(int fd, int type, const void *data, unsigned int size)
hidden;
diff -N -U 3 -x .svn -r pristine/src/Makefile.am trunk/src/Makefile.am
--- pristine/src/Makefile.am 2008-08-07 21:18:16.000000000 -0400
+++ trunk/src/Makefile.am 2008-08-08 16:41:07.000000000 -0400
@@ -27,9 +27,9 @@
LIBS = -Lmt -lauditmt -Llibev -lev -lrt -lm
LDADD = -lpthread
AM_CFLAGS = -D_REENTRANT -D_GNU_SOURCE
-noinst_HEADERS = auditd-config.h auditd-event.h ausearch-llist.h ausearch-options.h auditctl-llist.h aureport-options.h ausearch-parse.h aureport-scan.h ausearch-lookup.h ausearch-int.h auditd-dispatch.h ausearch-string.h ausearch-nvpair.h ausearch-common.h ausearch-avc.h ausearch-time.h
+noinst_HEADERS = auditd-config.h auditd-event.h auditd-listen.h ausearch-llist.h ausearch-options.h auditctl-llist.h aureport-options.h ausearch-parse.h aureport-scan.h ausearch-lookup.h ausearch-int.h auditd-dispatch.h ausearch-string.h ausearch-nvpair.h ausearch-common.h ausearch-avc.h ausearch-time.h
-auditd_SOURCES = auditd.c auditd-event.c auditd-config.c auditd-reconfig.c auditd-sendmail.c auditd-dispatch.c
+auditd_SOURCES = auditd.c auditd-event.c auditd-config.c auditd-reconfig.c auditd-sendmail.c auditd-dispatch.c auditd-listen.c
auditd_CFLAGS = -fPIE -DPIE -g -D_REENTRANT -D_GNU_SOURCE
auditd_LDFLAGS = -pie -Wl,-z,relro
auditd_DEPENDENCIES = mt/libauditmt.a libev/libev.a
diff -N -U 3 -x .svn -r pristine/src/auditd-config.c trunk/src/auditd-config.c
--- pristine/src/auditd-config.c 2008-08-07 17:32:20.000000000 -0400
+++ trunk/src/auditd-config.c 2008-08-08 15:56:13.000000000 -0400
@@ -39,6 +39,8 @@
#include "libaudit.h"
#include "private.h"
+#define TCP_PORT_MAX 65535
+
/* Local prototypes */
struct nv_pair
{
@@ -103,6 +105,12 @@
struct daemon_conf *config);
static int priority_boost_parser(struct nv_pair *nv, int line,
struct daemon_conf *config);
+static int tcp_listen_port_parser(struct nv_pair *nv, int line,
+ struct daemon_conf *config);
+static int tcp_listen_queue_parser(struct nv_pair *nv, int line,
+ struct daemon_conf *config);
+static int tcp_client_ports_parser(struct nv_pair *nv, int line,
+ struct daemon_conf *config);
static int sanity_check(struct daemon_conf *config);
static const struct kw_pair keywords[] =
@@ -127,6 +135,9 @@
{"disk_full_action", disk_full_action_parser, 1 },
{"disk_error_action", disk_error_action_parser, 1 },
{"priority_boost", priority_boost_parser, 0 },
+ {"tcp_listen_port", tcp_listen_port_parser, 0 },
+ {"tcp_listen_queue", tcp_listen_queue_parser, 0 },
+ {"tcp_client_ports", tcp_client_ports_parser, 0 },
{ NULL, NULL }
};
@@ -227,6 +238,10 @@
config->disk_full_exe = NULL;
config->disk_error_action = FA_SYSLOG;
config->disk_error_exe = NULL;
+ config->tcp_listen_port = 0;
+ config->tcp_listen_queue = 5;
+ config->tcp_client_min_port = 0;
+ config->tcp_client_max_port = TCP_PORT_MAX;
}
static log_test_t log_test = TEST_AUDITD;
@@ -1109,6 +1124,172 @@
return 0;
}
+static int tcp_listen_port_parser(struct nv_pair *nv, int line,
+ struct daemon_conf *config)
+{
+ const char *ptr = nv->value;
+ unsigned long i;
+
+ audit_msg(LOG_DEBUG, "tcp_listen_port_parser called with: %s",
+ nv->value);
+
+ /* check that all chars are numbers */
+ for (i=0; ptr[i]; i++) {
+ if (!isdigit(ptr[i])) {
+ audit_msg(LOG_ERR,
+ "Value %s should only be numbers - line %d",
+ nv->value, line);
+ return 1;
+ }
+ }
+
+ /* convert to unsigned int */
+ errno = 0;
+ i = strtoul(nv->value, NULL, 10);
+ if (errno) {
+ audit_msg(LOG_ERR,
+ "Error converting string to a number (%s) - line %d",
+ strerror(errno), line);
+ return 1;
+ }
+ /* Check its range */
+ if (i > TCP_PORT_MAX) {
+ audit_msg(LOG_ERR,
+ "Error - converted number (%s) is too large - line %d",
+ nv->value, line);
+ return 1;
+ }
+ if (i < 1) {
+ audit_msg(LOG_ERR,
+ "Error - converted number (%s) is too small - line %d",
+ nv->value, line);
+ return 1;
+ }
+ config->tcp_listen_port = (unsigned int)i;
+ return 0;
+}
+
+static int tcp_listen_queue_parser(struct nv_pair *nv, int line,
+ struct daemon_conf *config)
+{
+ const char *ptr = nv->value;
+ unsigned long i;
+
+ audit_msg(LOG_DEBUG, "tcp_listen_queue_parser called with: %s",
+ nv->value);
+
+ /* check that all chars are numbers */
+ for (i=0; ptr[i]; i++) {
+ if (!isdigit(ptr[i])) {
+ audit_msg(LOG_ERR,
+ "Value %s should only be numbers - line %d",
+ nv->value, line);
+ return 1;
+ }
+ }
+
+ /* convert to unsigned int */
+ errno = 0;
+ i = strtoul(nv->value, NULL, 10);
+ if (errno) {
+ audit_msg(LOG_ERR,
+ "Error converting string to a number (%s) - line %d",
+ strerror(errno), line);
+ return 1;
+ }
+ /* Check its range. While this value is technically
+ unlimited, it's limited by the kernel, and we limit it here
+ for sanity. */
+ if (i > TCP_PORT_MAX) {
+ audit_msg(LOG_ERR,
+ "Error - converted number (%s) is too large - line %d",
+ nv->value, line);
+ return 1;
+ }
+ if (i < 1) {
+ audit_msg(LOG_ERR,
+ "Error - converted number (%s) is too small - line %d",
+ nv->value, line);
+ return 1;
+ }
+ config->tcp_listen_queue = (unsigned int)i;
+ return 0;
+}
+
+static int tcp_client_ports_parser(struct nv_pair *nv, int line,
+ struct daemon_conf *config)
+{
+ const char *ptr = nv->value;
+ unsigned long i, minv, maxv;
+ const char *saw_dash = NULL;
+
+ audit_msg(LOG_DEBUG, "tcp_listen_queue_parser called with: %s",
+ nv->value);
+
+ /* check that all chars are numbers, with an optional inclusive '-'. */
+ for (i=0; ptr[i]; i++) {
+ if (i > 0 && ptr[i] == '-' && ptr[i+1] != '\0') {
+ saw_dash = ptr + i;
+ continue;
+ }
+ if (!isdigit(ptr[i])) {
+ audit_msg(LOG_ERR,
+ "Value %s should only be numbers, or two numbers separated by a dash - line %d",
+ nv->value, line);
+ return 1;
+ }
+ }
+ for (; ptr[i]; i++) {
+ if (!isdigit(ptr[i])) {
+ audit_msg(LOG_ERR,
+ "Value %s should only be numbers, or two numbers separated by a dash - line %d",
+ nv->value, line);
+ return 1;
+ }
+ }
+
+ /* convert to unsigned int */
+ errno = 0;
+ maxv = minv = strtoul(nv->value, NULL, 10);
+ if (errno) {
+ audit_msg(LOG_ERR,
+ "Error converting string to a number (%s) - line %d",
+ strerror(errno), line);
+ return 1;
+ }
+ if (saw_dash) {
+ maxv = strtoul(saw_dash + 1, NULL, 10);
+ if (errno) {
+ audit_msg(LOG_ERR,
+ "Error converting string to a number (%s) - line %d",
+ strerror(errno), line);
+ return 1;
+ }
+ }
+ /* Check their ranges. */
+ if (minv > TCP_PORT_MAX) {
+ audit_msg(LOG_ERR,
+ "Error - converted number (%d) is too large - line %d",
+ minv, line);
+ return 1;
+ }
+ if (maxv > TCP_PORT_MAX) {
+ audit_msg(LOG_ERR,
+ "Error - converted number (%d) is too large - line %d",
+ maxv, line);
+ return 1;
+ }
+ if (minv > maxv) {
+ audit_msg(LOG_ERR,
+ "Error - converted range (%d-%d) is reversed - line %d",
+ minv, maxv, line);
+ return 1;
+ }
+ config->tcp_client_min_port = (unsigned int)minv;
+ config->tcp_client_max_port = (unsigned int)maxv;
+ return 0;
+}
+
/*
* This function is where we do the integrated check of the audit config
* options. At this point, all fields have been read. Returns 0 if no
diff -N -U 3 -x .svn -r pristine/src/auditd-config.h trunk/src/auditd-config.h
--- pristine/src/auditd-config.h 2008-08-04 12:47:30.000000000 -0400
+++ trunk/src/auditd-config.h 2008-08-14 15:33:28.000000000 -0400
@@ -70,6 +70,10 @@
const char *disk_full_exe;
failure_action_t disk_error_action;
const char *disk_error_exe;
+ unsigned long tcp_listen_port;
+ unsigned long tcp_listen_queue;
+ unsigned long tcp_client_min_port;
+ unsigned long tcp_client_max_port;
};
void set_allow_links(int allow);
@@ -80,7 +84,9 @@
int resolve_node(struct daemon_conf *config);
void init_config_manager(void);
+#ifdef AUDITD_EVENT_H
int start_config_manager(struct auditd_reply_list *rep);
+#endif
void shutdown_config(void);
void free_config(struct daemon_conf *config);
diff -N -U 3 -x .svn -r pristine/src/auditd-event.c trunk/src/auditd-event.c
--- pristine/src/auditd-event.c 2008-08-04 12:47:30.000000000 -0400
+++ trunk/src/auditd-event.c 2008-08-13 21:56:24.000000000 -0400
@@ -148,6 +148,36 @@
dequeue'r is responsible for freeing the memory. */
void enqueue_event(struct auditd_reply_list *rep)
{
+ char *buf;
+ int len;
+
+ rep->ack_socket = 0;
+ rep->sequence_id = 0;
+
+ switch (consumer_data.config->log_format)
+ {
+ case LF_RAW:
+ buf = format_raw(&rep->reply, consumer_data.config);
+ break;
+ case LF_NOLOG:
+ return;
+ default:
+ audit_msg(LOG_ERR,
+ "Illegal log format detected %d",
+ consumer_data.config->log_format);
+ return;
+ }
+
+ len = strlen (buf);
+ if (len < MAX_AUDIT_MESSAGE_LENGTH - 1)
+ memcpy (rep->reply.msg.data, buf, len+1);
+ else
+ {
+ /* FIXME: is truncation the right thing to do? */
+ memcpy (rep->reply.msg.data, buf, MAX_AUDIT_MESSAGE_LENGTH-1);
+ rep->reply.msg.data[MAX_AUDIT_MESSAGE_LENGTH-1] = 0;
+ }
+
rep->next = NULL; /* new packet goes at end - so zero this */
pthread_mutex_lock(&consumer_data.queue_lock);
@@ -164,6 +194,45 @@
pthread_mutex_unlock(&consumer_data.queue_lock);
}
+/* This function takes a preformatted message and places it on the
+ queue. The dequeue'r is responsible for freeing the memory. */
+void enqueue_formatted_event(char *msg, int ack_socket, uint32_t sequence_id)
+{
+ int len;
+ struct auditd_reply_list *rep;
+
+ rep = (struct auditd_reply_list *) calloc (1, sizeof (*rep));
+ if (rep == NULL) {
+ audit_msg(LOG_ERR, "Cannot allocate audit reply");
+ return;
+ }
+
+ rep->ack_socket = ack_socket;
+ rep->sequence_id = sequence_id;
+
+ len = strlen (msg);
+ if (len < MAX_AUDIT_MESSAGE_LENGTH - 1)
+ memcpy (rep->reply.msg.data, msg, len+1);
+ else {
+ /* FIXME: is truncation the right thing to do? */
+ memcpy (rep->reply.msg.data, msg, MAX_AUDIT_MESSAGE_LENGTH-1);
+ rep->reply.msg.data[MAX_AUDIT_MESSAGE_LENGTH-1] = 0;
+ }
+
+ pthread_mutex_lock(&consumer_data.queue_lock);
+ if (consumer_data.head == NULL) {
+ consumer_data.head = consumer_data.tail = rep;
+ pthread_cond_signal(&consumer_data.queue_nonempty);
+ } else {
+ /* FIXME: wait for room on the queue */
+
+ /* OK there's room...add it in */
+ consumer_data.tail->next = rep; /* link in at end */
+ consumer_data.tail = rep; /* move end to newest */
+ }
+ pthread_mutex_unlock(&consumer_data.queue_lock);
+}
+
void resume_logging(void)
{
logging_suspended = 0;
@@ -233,30 +302,8 @@
rotate_logs_now(data);
}
if (!logging_suspended) {
- char *buf = NULL;
-
- switch (data->config->log_format)
- {
- case LF_RAW:
- buf = format_raw(&data->head->reply,
- data->config);
- break;
- case LF_NOLOG:
- return;
- default:
- audit_msg(LOG_ERR,
- "Illegal log format detected %d",
- data->config->log_format);
- break;
- }
- /* The only way buf is NULL is if there is an
- * unidentified format...which is impossible since
- * start up would have failed. */
- if (buf) {
- write_to_log(buf, data);
- buf[0] = 0;
- }
+ write_to_log(data->head->reply.msg.data, data);
/* See if we need to flush to disk manually */
if (data->config->flush == FT_INCREMENTAL) {
@@ -289,12 +336,32 @@
}
}
+static int ar_write (int sock, const void *buf, int len)
+{
+ int rc = 0, w;
+ while (len > 0) {
+ do {
+ w = write(sock, buf, len);
+ } while (w < 0 && errno == EINTR);
+ if (w < 0)
+ return w;
+ if (w == 0)
+ break;
+ rc += w;
+ len -= w;
+ buf = (const void *)((const char *)buf + w);
+ }
+ return rc;
+}
+
/* This function writes the given buf to the current log file */
static void write_to_log(const char *buf, struct auditd_consumer_data *data)
{
int rc;
FILE *f = data->log_file;
struct daemon_conf *config = data->config;
+ int ack_type = AUDIT_RMW_TYPE_ACK;
+ const char *msg = "";
/* write it to disk */
rc = fprintf(f, "%s\n", buf);
@@ -307,20 +374,35 @@
if (saved_errno == ENOSPC && fs_space_left == 1) {
fs_space_left = 0;
do_disk_full_action(config);
- } else
+ ack_type = AUDIT_RMW_TYPE_DISKFULL;
+ msg = "disk full";
+ } else {
do_disk_error_action("write", config);
+ ack_type = AUDIT_RMW_TYPE_DISKERROR;
+ msg = "disk write error";
+ }
+
+ } else {
- return;
+ /* check log file size & space left on partition */
+ if (config->daemonize == D_BACKGROUND) {
+ // If either of these fail, I consider it an inconvenience
+ // as opposed to something that is actionable. There may be
+ // some temporary condition that the system recovers from.
+ // The real error occurs on write.
+ check_log_file_size(data->log_fd, data);
+ check_space_left(data->log_fd, config);
+ }
}
- /* check log file size & space left on partition */
- if (config->daemonize == D_BACKGROUND) {
- // If either of these fail, I consider it an inconvenience
- // as opposed to something that is actionable. There may be
- // some temporary condition that the system recovers from.
- // The real error occurs on write.
- check_log_file_size(data->log_fd, data);
- check_space_left(data->log_fd, config);
+ if (data->head->ack_socket) {
+ unsigned char header[AUDIT_RMW_HEADER_SIZE];
+
+ AUDIT_RMW_PACK_HEADER (header, 0, ack_type, strlen(msg), data->head->sequence_id);
+
+ ar_write (data->head->ack_socket, header, AUDIT_RMW_HEADER_SIZE);
+ if (msg[0])
+ ar_write (data->head->ack_socket, msg, strlen(msg));
}
}
diff -N -U 3 -x .svn -r pristine/src/auditd-event.h trunk/src/auditd-event.h
--- pristine/src/auditd-event.h 2008-08-04 12:47:30.000000000 -0400
+++ trunk/src/auditd-event.h 2008-08-13 20:41:41.000000000 -0400
@@ -25,12 +25,21 @@
#define AUDITD_EVENT_H
#include "libaudit.h"
+
+struct auditd_reply_list {
+ struct audit_reply reply;
+ struct auditd_reply_list *next;
+ int ack_socket;
+ unsigned long sequence_id;
+};
+
#include "auditd-config.h"
void shutdown_events(void);
int init_event(struct daemon_conf *config);
void resume_logging(void);
void enqueue_event(struct auditd_reply_list *rep);
+void enqueue_formatted_event(char *msg, int ack_socket, uint32_t sequence_id);
void *consumer_thread_main(void *arg);
#endif
diff -N -U 3 -x .svn -r pristine/src/auditd-listen.c trunk/src/auditd-listen.c
--- pristine/src/auditd-listen.c 1969-12-31 19:00:00.000000000 -0500
+++ trunk/src/auditd-listen.c 2008-08-13 22:29:22.000000000 -0400
@@ -0,0 +1,335 @@
+/* auditd-listen.c --
+ * Copyright 2008 Red Hat Inc., Durham, North Carolina.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Authors:
+ * DJ Delorie <dj@redhat.com>
+ *
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <fcntl.h> /* O_NOFOLLOW needs gnu defined */
+#include <libgen.h>
+#include <arpa/inet.h>
+#include <limits.h> /* INT_MAX */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include "libaudit.h"
+#include "auditd-event.h"
+#include "auditd-config.h"
+#include "private.h"
+
+#include "ev.h"
+
+extern volatile int stop;
+
+typedef struct ev_tcp {
+ struct ev_io io;
+ struct sockaddr_in addr;
+ struct ev_tcp *next, *prev;
+ int bufptr;
+ unsigned char buffer [MAX_AUDIT_MESSAGE_LENGTH + 17];
+} ev_tcp;
+
+static int listen_socket;
+static struct ev_io tcp_listen_watcher;
+static int min_port, max_port;
+
+static struct ev_tcp *client_chain = 0;
+
+static char *sockaddr_to_ip (struct sockaddr_in *addr)
+{
+ unsigned char *uaddr = (unsigned char *)&(addr->sin_addr);
+ static char buf[40];
+
+ sprintf (buf, "%d.%d.%d.%d:%d",
+ uaddr[0], uaddr[1], uaddr[2], uaddr[3], ntohs (addr->sin_port));
+ return buf;
+}
+
+static void set_close_on_exec (int fd)
+{
+ int flags = fcntl (fd, F_GETFD);
+ if (flags == -1)
+ flags = 0;
+ flags |= FD_CLOEXEC;
+ fcntl (fd, F_SETFD, flags);
+}
+
+static void close_client (struct ev_tcp *client)
+{
+ close (client->io.fd);
+ if (client_chain == client)
+ client_chain = client->next;
+ if (client->next)
+ client->next->prev = client->prev;
+ if (client->prev)
+ client->prev->next = client->next;
+ free (client);
+}
+
+static void client_message (struct ev_tcp *io, unsigned int length, unsigned char *header)
+{
+ unsigned char ch;
+ uint32_t magic, type, mlen, seq;
+ int hver, mver;
+ int i;
+
+ if (AUDIT_RMW_IS_MAGIC (header, length)) {
+ AUDIT_RMW_UNPACK_HEADER (header, hver, mver, type, mlen, seq)
+
+ ch = header[length];
+ header[length] = 0;
+ if (length > 1 && header[length-1] == '\n')
+ header[length-1] = 0;
+ enqueue_formatted_event (header+AUDIT_RMW_HEADER_SIZE, io->io.fd, seq);
+ header[length] = ch;
+ } else {
+ header[length] = 0;
+ if (length > 1 && header[length-1] == '\n')
+ header[length-1] = 0;
+ enqueue_formatted_event (header, 0, 0);
+ }
+}
+
+static void auditd_tcp_client_handler( struct ev_loop *loop, struct ev_io *_io, int revents )
+{
+ struct ev_tcp *io = (struct ev_tcp *) _io;
+ int i, r;
+ int total_this_call = 0;
+
+ /* The socket is non-blocking, but we have a limited buffer
+ size. In the event that we get a packet that's bigger than
+ our buffer, we need to read it in multiple parts. Thus, we
+ keep reading/parsing/processing until we run out of ready
+ data. */
+read_more:
+ r = read (io->io.fd,
+ io->buffer + io->bufptr,
+ MAX_AUDIT_MESSAGE_LENGTH - io->bufptr);
+
+ if (r < 0 && errno == EAGAIN)
+ r = 0;
+
+ /* We need to keep track of the difference between "no data
+ * because it's closed" and "no data because we've read it
+ * all". */
+ if (r == 0 && total_this_call > 0) {
+ return;
+ }
+
+ /* If the connection is gracefully closed, the first read we
+ try will return zero. If the connection times out or
+ otherwise fails, the read will return -1. */
+ if (r <= 0) {
+ if (r < 0)
+ audit_msg (LOG_WARNING, "client %s socket closed unexpectedly",
+ sockaddr_to_ip (&io->addr));
+
+ /* There may have been a final message without a LF. */
+ if (io->bufptr) {
+ client_message (io, io->bufptr, io->buffer);
+
+ }
+
+ ev_io_stop (loop, _io);
+ close_client (io);
+ return;
+ }
+
+ total_this_call += r;
+
+more_messages:
+ if (AUDIT_RMW_IS_MAGIC (io->buffer, io->bufptr+r)) {
+ uint32_t type, len, seq;
+ int hver, mver;
+ unsigned char *header = (unsigned char *)io->buffer;
+
+ io->bufptr += r;
+
+ if (io->bufptr < AUDIT_RMW_HEADER_SIZE)
+ return;
+
+ AUDIT_RMW_UNPACK_HEADER (header, hver, mver, type, len, seq);
+
+ i = len;
+ i += AUDIT_RMW_HEADER_SIZE;
+
+ /* See if we have enough bytes to extract the whole message. */
+ if (io->bufptr < i)
+ return;
+
+ } else {
+ /* At this point, the buffer has IO->BUFPTR+R bytes in it.
+ The first IO->BUFPTR bytes do not have a LF in them (we've
+ already checked), we must check the R new bytes. */
+
+ for (i = io->bufptr; i < io->bufptr + r; i ++)
+ if (io->buffer [i] == '\n')
+ break;
+
+ io->bufptr += r;
+
+ /* Check for a partial message, with no LF yet. */
+ if (i == io->bufptr)
+ return;
+
+ i ++;
+ }
+
+ /* We have an I-byte message in buffer. */
+ client_message (io, i, io->buffer);
+
+ /* Now copy any remaining bytes to the beginning of the
+ buffer. */
+ memmove (io->buffer, io->buffer + i, io->bufptr);
+ io->bufptr -= i;
+
+ /* See if this packet had more than one message in it. */
+ if (io->bufptr > 0) {
+ r = io->bufptr;
+ io->bufptr = 0;
+ goto more_messages;
+ }
+
+ /* Go back and see if there's more data to read. */
+ goto read_more;
+}
+
+static void auditd_tcp_listen_handler( struct ev_loop *loop, struct ev_io *_io, int revents )
+{
+ int one=1;
+ int afd;
+ socklen_t aaddrlen;
+ struct sockaddr_in aaddr;
+ struct linger li;
+ struct ev_tcp *client;
+ unsigned char *uaddr;
+
+ /* Accept the connection and see where it's coming from. */
+ aaddrlen = sizeof(aaddr);
+ afd = accept (listen_socket, (struct sockaddr *)&aaddr, &aaddrlen);
+ if (afd == -1) {
+ audit_msg(LOG_ERR, "Unable to accept TCP connection");
+ return;
+ }
+
+ uaddr = (unsigned char *)&aaddr.sin_addr;
+
+ /* Verify it's coming from an authorized port. We assume the firewall will
+ block attempts from unauthorized machines. */
+ if (min_port > ntohs (aaddr.sin_port) || ntohs (aaddr.sin_port) > max_port) {
+ audit_msg(LOG_ERR, "TCP connection from %s rejected", sockaddr_to_ip (&aaddr));
+ close (afd);
+ return;
+ }
+
+ setsockopt(afd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof (int));
+ setsockopt(afd, SOL_SOCKET, SO_KEEPALIVE, (char *)&one, sizeof (int));
+ setsockopt(afd, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof (int));
+ fcntl(afd, F_SETFL, O_NONBLOCK | O_NDELAY);
+ set_close_on_exec (afd);
+
+ client = (struct ev_tcp *) malloc (sizeof (struct ev_tcp));
+ if (client == NULL) {
+ audit_msg(LOG_CRIT, "Unable to allocate TCP client data");
+ close (afd);
+ return;
+ }
+
+ memset (client, 0, sizeof (struct ev_tcp));
+
+ ev_io_init (&(client->io), auditd_tcp_client_handler, afd, EV_READ | EV_ERROR);
+ ev_io_start (loop, &(client->io));
+
+ memcpy (&client->addr, &aaddr, sizeof (struct sockaddr_in));
+
+ /* Keep a linked list of active clients. */
+ client->next = client_chain;
+ if (client->next)
+ client->next->prev = client;
+ client_chain = client;
+}
+
+int auditd_tcp_listen_init ( struct ev_loop *loop, struct daemon_conf *config )
+{
+ struct sockaddr_in address;
+ int one = 1;
+ int flags;
+
+ /* If the port is not set, that means we aren't going to
+ listen for connections. */
+ if (config->tcp_listen_port == 0)
+ return;
+
+ listen_socket = socket (AF_INET, SOCK_STREAM, 0);
+ if (listen_socket == 0) {
+ audit_msg(LOG_ERR, "Cannot create tcp listener socket");
+ return 1;
+ }
+
+ set_close_on_exec (listen_socket);
+ setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof (int));
+
+ memset (&address, 0, sizeof(address));
+ address.sin_family = htons(AF_INET);
+ address.sin_port = htons(config->tcp_listen_port);
+ address.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ /* This avoids problems if auditd needs to be restarted. */
+ setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof (int));
+
+ if ( bind ( listen_socket, (struct sockaddr *)&address, sizeof(address)) ) {
+ audit_msg(LOG_ERR, "Cannot bind tcp listener socket to port %d",
+ config->tcp_listen_port);
+ close(listen_socket);
+ return 1;
+ }
+
+ listen(listen_socket, config->tcp_listen_queue);
+
+ audit_msg(LOG_DEBUG, "Listening on TCP port %d", config->tcp_listen_port);
+
+ ev_io_init (&tcp_listen_watcher, auditd_tcp_listen_handler, listen_socket, EV_READ);
+ ev_io_start (loop, &tcp_listen_watcher);
+
+ min_port = config->tcp_client_min_port;
+ max_port = config->tcp_client_max_port;
+
+ return 0;
+}
+
+void auditd_tcp_listen_uninit ( struct ev_loop *loop )
+{
+ ev_io_stop ( loop, &tcp_listen_watcher );
+ close ( listen_socket );
+
+ while (client_chain) {
+ close_client (client_chain);
+ }
+}
diff -N -U 3 -x .svn -r pristine/src/auditd-listen.h trunk/src/auditd-listen.h
--- pristine/src/auditd-listen.h 1969-12-31 19:00:00.000000000 -0500
+++ trunk/src/auditd-listen.h 2008-08-08 17:01:37.000000000 -0400
@@ -0,0 +1,30 @@
+/* auditd-config.h --
+ * Copyright 2004-2007 Red Hat Inc., Durham, North Carolina.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Authors:
+ * DJ Delorie <dj@redhat.com>
+ *
+ */
+
+#ifndef AUDITD_LISTEN_H
+#define AUDITD_LISTEN_H
+
+int auditd_tcp_listen_init ( struct ev_loop *loop, struct daemon_conf *config );
+void auditd_tcp_listen_uninit ( struct ev_loop *loop );
+
+#endif
diff -N -U 3 -x .svn -r pristine/src/auditd-reconfig.c trunk/src/auditd-reconfig.c
--- pristine/src/auditd-reconfig.c 2008-08-04 12:47:30.000000000 -0400
+++ trunk/src/auditd-reconfig.c 2008-08-12 18:54:20.000000000 -0400
@@ -28,9 +28,9 @@
#include <unistd.h>
#include <string.h>
#include <stdio.h>
-#include "auditd-config.h"
-#include "auditd-event.h"
#include "libaudit.h"
+#include "auditd-event.h"
+#include "auditd-config.h"
#include "private.h"
/* This is the configuration manager code */
diff -N -U 3 -x .svn -r pristine/src/auditd.c trunk/src/auditd.c
--- pristine/src/auditd.c 2008-08-08 14:36:19.000000000 -0400
+++ trunk/src/auditd.c 2008-08-13 20:51:35.000000000 -0400
@@ -40,8 +40,8 @@
#include <getopt.h>
#include "libaudit.h"
-#include "auditd-config.h"
#include "auditd-event.h"
+#include "auditd-config.h"
#include "auditd-dispatch.h"
#include "private.h"
@@ -670,7 +670,15 @@
ev_signal_init (&sigchld_watcher, child_handler, SIGCHLD);
ev_signal_start (loop, &sigchld_watcher);
- ev_loop (loop, 0);
+ if (auditd_tcp_listen_init (loop, &config)) {
+ tell_parent (FAILURE);
+ stop = 1;
+ }
+
+ if (!stop)
+ ev_loop (loop, 0);
+
+ auditd_tcp_listen_uninit (loop);
/* Write message to log that we are going down */
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Add auditd listener and remote audit protocol
2008-08-14 21:43 [PATCH] Add auditd listener and remote audit protocol DJ Delorie
@ 2008-08-14 21:58 ` LC Bruzenak
2008-08-14 22:16 ` DJ Delorie
2008-08-15 0:23 ` Steve Grubb
1 sibling, 1 reply; 25+ messages in thread
From: LC Bruzenak @ 2008-08-14 21:58 UTC (permalink / raw)
To: DJ Delorie; +Cc: linux-audit
On Thu, 2008-08-14 at 17:43 -0400, DJ Delorie wrote:
> Second in a series, a bit bigger than the first one.
> (http://www.redhat.com/archives/linux-audit/2008-August/msg00070.html)
>
> The goal of this patch is to add the server side of the remote logging
> feature. To this end, a new auditd-listener.c is added which listens
> on a TCP port for connections from other systems' audisp-remote
> plugins. A new (private) protocol is added which prepends each
> message with a header, giving length, status, version, and sequence
> information. Each message begets a reply from the server, so we can
> pass along status like "disk full" or "ok". Currently, these call a
> set of stub functions, as the details of performing appropriate
> actions from the plugin are yet to be decided.
>
> The remote plugin has a new option "format" for "ascii" or "managed"
> to choose between the old protocol (ascii strings) and the new one
> (the header with ACK, default).
>
> The listener will accept either format. It has new options for the
> listen port, accept queue size, and acceptable client-side ports.
>
> Comments?
>
> DJ
Sorry to be dense, but if it isn't too much trouble would you mind
supplying an example use-case for this new capability? I went back and
read the supplied link but it isn't clear to me how to take advantage of
this, and I suspect it is important.
What I'm getting is that in addition to kernel-generated local events
the auditd would also receive signals as well as tcp-based events from
other sources. Would this be the way of implementing multi-source audit
aggregation or is it something different?
Thx,
LCB.
--
LC (Lenny) Bruzenak
lenny@magitekltd.com
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Add auditd listener and remote audit protocol
2008-08-14 21:58 ` LC Bruzenak
@ 2008-08-14 22:16 ` DJ Delorie
2008-08-14 23:00 ` John Dennis
2008-08-14 23:26 ` LC Bruzenak
0 siblings, 2 replies; 25+ messages in thread
From: DJ Delorie @ 2008-08-14 22:16 UTC (permalink / raw)
To: LC Bruzenak; +Cc: linux-audit
> What I'm getting is that in addition to kernel-generated local events
> the auditd would also receive signals as well as tcp-based events from
> other sources. Would this be the way of implementing multi-source audit
> aggregation or is it something different?
The net result is to aggregate audit logs from many systems onto one
central audit server. Remote audit messages have the new "node=" tag
on them so you know where they came from.
I.e. you configure audisp-remote.conf like this:
remote_server = 10.2.3.4
port = 1237
And the central server (10.2.3.4 in this example) like this:
tcp_listen_port = 1237
And then the client sends all audit messages to the server, where
they're logged to disk.
This is similar to centralized syslog logging.
The event loop change I linked to is a neccessary design change
prerequisite to this one, since the listener adds (potentially) many
descriptors which will need to be serviced. The loop now services
four types of events: local signals, local netlink, the listen socket
(for new connections), and client sockets (for incoming audit
messages).
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Add auditd listener and remote audit protocol
2008-08-14 22:16 ` DJ Delorie
@ 2008-08-14 23:00 ` John Dennis
2008-08-14 23:02 ` LC Bruzenak
2008-08-14 23:16 ` DJ Delorie
2008-08-14 23:26 ` LC Bruzenak
1 sibling, 2 replies; 25+ messages in thread
From: John Dennis @ 2008-08-14 23:00 UTC (permalink / raw)
To: DJ Delorie; +Cc: linux-audit
DJ Delorie wrote:
> The net result is to aggregate audit logs from many systems onto one
> central audit server. Remote audit messages have the new "node=" tag
> on them so you know where they came from.
>
The field name was "host", is the "node=" a typo or did the field name
change?
--
John Dennis <jdennis@redhat.com>
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Add auditd listener and remote audit protocol
2008-08-14 23:00 ` John Dennis
@ 2008-08-14 23:02 ` LC Bruzenak
2008-08-14 23:16 ` John Dennis
2008-08-14 23:16 ` DJ Delorie
1 sibling, 1 reply; 25+ messages in thread
From: LC Bruzenak @ 2008-08-14 23:02 UTC (permalink / raw)
To: John Dennis; +Cc: linux-audit
On Thu, 2008-08-14 at 19:00 -0400, John Dennis wrote:
> DJ Delorie wrote:
> > The net result is to aggregate audit logs from many systems onto one
> > central audit server. Remote audit messages have the new "node=" tag
> > on them so you know where they came from.
> >
> The field name was "host", is the "node=" a typo or did the field name
> change?
>
Mine say "node=".
LCB.
--
LC (Lenny) Bruzenak
lenny@magitekltd.com
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Add auditd listener and remote audit protocol
2008-08-14 23:02 ` LC Bruzenak
@ 2008-08-14 23:16 ` John Dennis
2008-08-14 23:55 ` Steve Grubb
0 siblings, 1 reply; 25+ messages in thread
From: John Dennis @ 2008-08-14 23:16 UTC (permalink / raw)
To: LC Bruzenak; +Cc: linux-audit
[-- Attachment #1.1: Type: text/plain, Size: 703 bytes --]
LC Bruzenak wrote:
> On Thu, 2008-08-14 at 19:00 -0400, John Dennis wrote:
>
>> DJ Delorie wrote:
>>
>>> The net result is to aggregate audit logs from many systems onto one
>>> central audit server. Remote audit messages have the new "node=" tag
>>> on them so you know where they came from.
>>>
>>>
>> The field name was "host", is the "node=" a typo or did the field name
>> change?
>>
>>
>
> Mine say "node=".
>
The "host" field was added to audit records almost a year ago, although
if memory serves me correctly you have to enable it as a configuration
option. Is the node field redundant with host or did node supercede host?
--
John Dennis <jdennis@redhat.com>
[-- Attachment #1.2: Type: text/html, Size: 1312 bytes --]
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Add auditd listener and remote audit protocol
2008-08-14 23:00 ` John Dennis
2008-08-14 23:02 ` LC Bruzenak
@ 2008-08-14 23:16 ` DJ Delorie
1 sibling, 0 replies; 25+ messages in thread
From: DJ Delorie @ 2008-08-14 23:16 UTC (permalink / raw)
To: John Dennis; +Cc: linux-audit
> The field name was "host", is the "node=" a typo or did the field name
> change?
Don't know, mine have always said node=
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Add auditd listener and remote audit protocol
2008-08-14 22:16 ` DJ Delorie
2008-08-14 23:00 ` John Dennis
@ 2008-08-14 23:26 ` LC Bruzenak
2008-08-14 23:37 ` John Dennis
` (2 more replies)
1 sibling, 3 replies; 25+ messages in thread
From: LC Bruzenak @ 2008-08-14 23:26 UTC (permalink / raw)
To: DJ Delorie; +Cc: linux-audit
On Thu, 2008-08-14 at 18:16 -0400, DJ Delorie wrote:
> > What I'm getting is that in addition to kernel-generated local events
> > the auditd would also receive signals as well as tcp-based events from
> > other sources. Would this be the way of implementing multi-source audit
> > aggregation or is it something different?
>
> The net result is to aggregate audit logs from many systems onto one
> central audit server. Remote audit messages have the new "node=" tag
> on them so you know where they came from.
>
> I.e. you configure audisp-remote.conf like this:
>
> remote_server = 10.2.3.4
> port = 1237
>
> And the central server (10.2.3.4 in this example) like this:
>
> tcp_listen_port = 1237
>
> And then the client sends all audit messages to the server, where
> they're logged to disk.
>
> This is similar to centralized syslog logging.
Maybe in theory...but a couple of differences matter a bit:
1: Yesterday I saved 95MB of audit data. The past 3 days' syslog is so
far under 3.5MB. I believe my audit data will grow more as my system
matures and gets tested. I don't know if those numbers are anywhere
close to representative or not though.
2: If I lose a portion of syslog data it doesn't hurt me too much
usually; not the case if I rely on my audit data to be complete and
accurate.
>
> The event loop change I linked to is a neccessary design change
> prerequisite to this one, since the listener adds (potentially) many
> descriptors which will need to be serviced. The loop now services
> four types of events: local signals, local netlink, the listen socket
> (for new connections), and client sockets (for incoming audit
> messages).
Thank you; I get it now.
This is about to get interesting! :)
Not certain why I didn't get it the first time, but for some reason I
had not considered sending the events into the auditd loop.
I was thinking of just aggregating the logfiles. Now it makes sense.
My one auditd machine gets very busy occasionally - I sometimes drop
events (rather than abort for a development machine) even after
ratcheting up my event queue to 8K. Often this is due to an error I've
introduced with too-general rules, so this is also not definitive.
Now the question is what happens if the network hiccups and I cannot
send the events from a client? I could still write the events to the
local disk, but them getting them onto the intended aggregator is now
tricky right? Will the sender keep track of the last event sent and
recover once the connection is restored?
I'm not disputing the approach, just trying to look down the road
knowing problems I've experienced myself. There are some definite
benefits to this approach I see also - the log files now are "blended"
and you don't have to do any special directory hierarchy to accommodate
the other events, for one.
OK, so - thanks again for the explanation and I look forward to testing
this out soon!
Thx,
LCB.
--
LC (Lenny) Bruzenak
lenny@magitekltd.com
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Add auditd listener and remote audit protocol
2008-08-14 23:26 ` LC Bruzenak
@ 2008-08-14 23:37 ` John Dennis
2008-08-14 23:50 ` LC Bruzenak
2008-08-15 0:04 ` Steve Grubb
2008-08-15 0:19 ` DJ Delorie
2 siblings, 1 reply; 25+ messages in thread
From: John Dennis @ 2008-08-14 23:37 UTC (permalink / raw)
To: LC Bruzenak; +Cc: linux-audit
LC Bruzenak wrote:
> Thank you; I get it now.
> This is about to get interesting! :)
>
> Not certain why I didn't get it the first time, but for some reason I
> had not considered sending the events into the auditd loop.
> I was thinking of just aggregating the logfiles. Now it makes sense.
>
> My one auditd machine gets very busy occasionally - I sometimes drop
> events (rather than abort for a development machine) even after
> ratcheting up my event queue to 8K. Often this is due to an error I've
> introduced with too-general rules, so this is also not definitive.
>
> Now the question is what happens if the network hiccups and I cannot
> send the events from a client? I could still write the events to the
> local disk, but them getting them onto the intended aggregator is now
> tricky right? Will the sender keep track of the last event sent and
> recover once the connection is restored?
>
> I'm not disputing the approach, just trying to look down the road
> knowing problems I've experienced myself. There are some definite
> benefits to this approach I see also - the log files now are "blended"
> and you don't have to do any special directory hierarchy to accommodate
> the other events, for one.
>
This is why the IPA project has selected AMQP (www.amqp.org) as the
transport for centralized loggiing (included audit logs). AMQP will
queue in persistent storage messages which do not reach their
destination until delivery is assured. The thinking was AMQP was too
heavy weight a dependency for a simple centralized audit log but makes
sense in an enterprise deployment such as IPA.
--
John Dennis <jdennis@redhat.com>
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Add auditd listener and remote audit protocol
2008-08-14 23:37 ` John Dennis
@ 2008-08-14 23:50 ` LC Bruzenak
2008-08-15 0:07 ` Steve Grubb
2008-08-15 0:23 ` DJ Delorie
0 siblings, 2 replies; 25+ messages in thread
From: LC Bruzenak @ 2008-08-14 23:50 UTC (permalink / raw)
To: John Dennis; +Cc: linux-audit
On Thu, 2008-08-14 at 19:37 -0400, John Dennis wrote:
> This is why the IPA project has selected AMQP (www.amqp.org) as the
> transport for centralized loggiing (included audit logs). AMQP will
> queue in persistent storage messages which do not reach their
> destination until delivery is assured. The thinking was AMQP was too
> heavy weight a dependency for a simple centralized audit log but makes
> sense in an enterprise deployment such as IPA.
>
I see; thanks for the info John.
Steve did mention this previously to me but I didn't get all the
implications I guess (dense!).
I do require centralized auditing and I also require (more importantly)
not losing any.
I cannot speak for other end-users...but my guess is that if they are
using audit and aggregating they probably care about not dropping it,
whereas others can just syslog the events if the auditd isn't enabled
and then use centralized syslog, right?
AMQP may be heavyweight, however if you start down the road of trying to
not lose networked audit data you probably end up somewhere near there
anyway...
Thx,
LCB.
--
LC (Lenny) Bruzenak
lenny@magitekltd.com
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Add auditd listener and remote audit protocol
2008-08-14 23:16 ` John Dennis
@ 2008-08-14 23:55 ` Steve Grubb
0 siblings, 0 replies; 25+ messages in thread
From: Steve Grubb @ 2008-08-14 23:55 UTC (permalink / raw)
To: linux-audit
On Thursday 14 August 2008 19:16:54 John Dennis wrote:
> The "host" field was added to audit records almost a year ago,
No, that was "node". "Host" has always been a field filled in by pam when
someone is logging in.
-Steve
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Add auditd listener and remote audit protocol
2008-08-14 23:26 ` LC Bruzenak
2008-08-14 23:37 ` John Dennis
@ 2008-08-15 0:04 ` Steve Grubb
2008-08-15 0:19 ` DJ Delorie
2 siblings, 0 replies; 25+ messages in thread
From: Steve Grubb @ 2008-08-15 0:04 UTC (permalink / raw)
To: linux-audit
On Thursday 14 August 2008 19:26:49 LC Bruzenak wrote:
> My one auditd machine gets very busy occasionally - I sometimes drop
> events (rather than abort for a development machine) even after
> ratcheting up my event queue to 8K.
I believe that this is a problem in the audit code. The scheduler changed
sometimes around 2.6.25 and I started seeing it when I hadn't previously. I
have a real strong idea what the problem is after talk with Chris Wright
about it, but am at a loss for how to make it better. I hope to address this
in the coming days since adding more load to auditd will make it worse.
> Now the question is what happens if the network hiccups and I cannot
> send the events from a client?
There will be a couple admin defined actions just like when disk logging has
problems. Anyone that wants to enhance what is in this first cut, please send
patches.
> I could still write the events to the local disk, but them getting them onto
> the intended aggregator is now tricky right? Will the sender keep track of
> the last event sent and recover once the connection is restored?
At first, I think a best effort solution is what we'll have. IPA's delivery
service will be a more robust solution with failover capabilities. I do not
envision going to that length with auditd.
-Steve
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Add auditd listener and remote audit protocol
2008-08-14 23:50 ` LC Bruzenak
@ 2008-08-15 0:07 ` Steve Grubb
2008-08-15 0:22 ` LC Bruzenak
2008-08-15 0:23 ` DJ Delorie
1 sibling, 1 reply; 25+ messages in thread
From: Steve Grubb @ 2008-08-15 0:07 UTC (permalink / raw)
To: linux-audit
On Thursday 14 August 2008 19:50:23 LC Bruzenak wrote:
> I cannot speak for other end-users...but my guess is that if they are
> using audit and aggregating they probably care about not dropping it,
> whereas others can just syslog the events if the auditd isn't enabled
> and then use centralized syslog, right?
Does syslog queue unsent messages and recover them?
-Steve
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Add auditd listener and remote audit protocol
2008-08-14 23:26 ` LC Bruzenak
2008-08-14 23:37 ` John Dennis
2008-08-15 0:04 ` Steve Grubb
@ 2008-08-15 0:19 ` DJ Delorie
2 siblings, 0 replies; 25+ messages in thread
From: DJ Delorie @ 2008-08-15 0:19 UTC (permalink / raw)
To: LC Bruzenak; +Cc: linux-audit
> > This is similar to centralized syslog logging.
>
> Maybe in theory...but a couple of differences matter a bit:
Right, I was just trying to get the basic idea across ;-)
> 1: Yesterday I saved 95MB of audit data. The past 3 days' syslog is so
> far under 3.5MB. I believe my audit data will grow more as my system
> matures and gets tested. I don't know if those numbers are anywhere
> close to representative or not though.
My machine is doing about 5M/day. Most of it is cron.
> 2: If I lose a portion of syslog data it doesn't hurt me too much
> usually; not the case if I rely on my audit data to be complete and
> accurate.
Understood.
> This is about to get interesting! :)
Let's hope so :-)
> Not certain why I didn't get it the first time, but for some reason I
> had not considered sending the events into the auditd loop.
> I was thinking of just aggregating the logfiles. Now it makes sense.
Note that it injects it *after* the plugins are called; the aggregator
will not pass along remote messages to its own plugins.
> Now the question is what happens if the network hiccups and I cannot
> send the events from a client?
The basis for passing failure modes from the plugins back up to auditd
is still up for discussion; in the patch those functions are empty.
In general, though, if the network hangs, eventually the queues fill
up and the usual queue-filled rules apply.
There are three likely failure modes:
* network timeout. Eventually, the queues (and pipes) fill up and
local panic sets in.
* network failure (aggregator reboots or restarts, usually) -
connection is closed or sync is lost, we know about it immediately.
Currently audispd-remote just exits when that happens.
* remote error - the aggregator has an error (disk full, etc) and
passes it back to the clients. The clients act on it, but currently
those functions are empty.
Of course, a full review of the failure modes and actions will be
needed at some point. Plus we have to decide if we want to feed the
status back to auditd and use its configuration, or have a separate
configuration in audisp-remote, for what to do about each error case.
> Will the sender keep track of the last event sent and recover once
> the connection is restored?
The event that gets the network error gets lost at the moment (and
every event after it), and the code currently doesn't have a "try
again" mechanism if it loses connectivity. Again, the whole "what do
we do when a problem happens" is still somewhat TBD.
Note that you can still log to the local disk *as well as* to the
remote aggregator.
> I'm not disputing the approach, just trying to look down the road
> knowing problems I've experienced myself.
:-)
> There are some definite benefits to this approach I see also - the
> log files now are "blended" and you don't have to do any special
> directory hierarchy to accommodate the other events, for one.
Well, you *could* based on the node= field, if you wanted to code it
that way. At least they're no longer on the machine being
attacked/saturated/whatever, if/when that happens.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Add auditd listener and remote audit protocol
2008-08-15 0:07 ` Steve Grubb
@ 2008-08-15 0:22 ` LC Bruzenak
2008-08-15 0:27 ` Steve Grubb
0 siblings, 1 reply; 25+ messages in thread
From: LC Bruzenak @ 2008-08-15 0:22 UTC (permalink / raw)
To: Steve Grubb; +Cc: linux-audit
On Thu, 2008-08-14 at 20:07 -0400, Steve Grubb wrote:
> On Thursday 14 August 2008 19:50:23 LC Bruzenak wrote:
> > I cannot speak for other end-users...but my guess is that if they are
> > using audit and aggregating they probably care about not dropping it,
> > whereas others can just syslog the events if the auditd isn't enabled
> > and then use centralized syslog, right?
>
> Does syslog queue unsent messages and recover them?
>
> -Steve
Not AFAIK...but then again it isn't configurable to panic the machine on
failure.
I think you have a good point - this is the first cut and maybe later on
institute a "replay daemon" or something which can send events on
reconnect.
We will not lose them locally so that's covered. After that it is a
different problem.
Thx,
LCB.
--
LC (Lenny) Bruzenak
lenny@magitekltd.com
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Add auditd listener and remote audit protocol
2008-08-14 21:43 [PATCH] Add auditd listener and remote audit protocol DJ Delorie
2008-08-14 21:58 ` LC Bruzenak
@ 2008-08-15 0:23 ` Steve Grubb
1 sibling, 0 replies; 25+ messages in thread
From: Steve Grubb @ 2008-08-15 0:23 UTC (permalink / raw)
To: linux-audit
On Thursday 14 August 2008 17:43:00 DJ Delorie wrote:
> Second in a series, a bit bigger than the first one.
> (http://www.redhat.com/archives/linux-audit/2008-August/msg00070.html)
>
> The goal of this patch is to add the server side of the remote logging
> feature.
Applied. Thanks for the patch !
For anyone following along...I will probably ready a release of the audit
daemon in the next couple days. There is at least one more patch coming for
remote logging and that is to add flow control. DJ says that remote logging
is usable now, so be aware that its still being worked on an at least this
one is a known issue. I think its important to go ahead with a release
because there are a lot of bugs fixed recently and we should start getting
some runtime on this new audit code to make sure its stable.
Thanks,
-Steve
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Add auditd listener and remote audit protocol
2008-08-14 23:50 ` LC Bruzenak
2008-08-15 0:07 ` Steve Grubb
@ 2008-08-15 0:23 ` DJ Delorie
1 sibling, 0 replies; 25+ messages in thread
From: DJ Delorie @ 2008-08-15 0:23 UTC (permalink / raw)
To: LC Bruzenak; +Cc: linux-audit
> I do require centralized auditing and I also require (more importantly)
> not losing any.
The key code is in audisp/plugins/remote/audisp-remote.c
I think I put a couple of FIXMEs in there where the various errors are
noted. If you want to put in a queue and retry mechanism, go ahead :-)
> AMQP may be heavyweight, however if you start down the road of trying to
> not lose networked audit data you probably end up somewhere near there
> anyway...
You can always buy more paranoia.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Add auditd listener and remote audit protocol
2008-08-15 0:22 ` LC Bruzenak
@ 2008-08-15 0:27 ` Steve Grubb
2008-08-15 0:31 ` LC Bruzenak
0 siblings, 1 reply; 25+ messages in thread
From: Steve Grubb @ 2008-08-15 0:27 UTC (permalink / raw)
To: LC Bruzenak; +Cc: linux-audit
On Thursday 14 August 2008 20:22:24 LC Bruzenak wrote:
> I think you have a good point - this is the first cut and maybe later on
> institute a "replay daemon" or something which can send events on
> reconnect.
Note that all audispd plugins take their input from stdin. At the worst, if
you had the time hacks, you could
ausearch --start <time> --end <time> --raw | /sbin.audisp-remote
-Steve
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Add auditd listener and remote audit protocol
2008-08-15 0:27 ` Steve Grubb
@ 2008-08-15 0:31 ` LC Bruzenak
2008-08-15 0:36 ` DJ Delorie
2009-09-29 17:52 ` LC Bruzenak
0 siblings, 2 replies; 25+ messages in thread
From: LC Bruzenak @ 2008-08-15 0:31 UTC (permalink / raw)
To: Steve Grubb; +Cc: linux-audit
On Thu, 2008-08-14 at 20:27 -0400, Steve Grubb wrote:
> On Thursday 14 August 2008 20:22:24 LC Bruzenak wrote:
> > I think you have a good point - this is the first cut and maybe later on
> > institute a "replay daemon" or something which can send events on
> > reconnect.
>
> Note that all audispd plugins take their input from stdin. At the worst, if
> you had the time hacks, you could
>
> ausearch --start <time> --end <time> --raw | /sbin.audisp-remote
>
> -Steve
I like that idea too.
Since we get an ACK on delivery it can probably be automated at some
point I'd guess.
Thx,
LCB.
--
LC (Lenny) Bruzenak
lenny@magitekltd.com
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Add auditd listener and remote audit protocol
2008-08-15 0:31 ` LC Bruzenak
@ 2008-08-15 0:36 ` DJ Delorie
2008-08-15 0:41 ` LC Bruzenak
2009-09-29 17:52 ` LC Bruzenak
1 sibling, 1 reply; 25+ messages in thread
From: DJ Delorie @ 2008-08-15 0:36 UTC (permalink / raw)
To: LC Bruzenak; +Cc: linux-audit
> Since we get an ACK on delivery
Right, and the ACK comes from the event logger thread *after* it
pushes it out to disk.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Add auditd listener and remote audit protocol
2008-08-15 0:36 ` DJ Delorie
@ 2008-08-15 0:41 ` LC Bruzenak
0 siblings, 0 replies; 25+ messages in thread
From: LC Bruzenak @ 2008-08-15 0:41 UTC (permalink / raw)
To: DJ Delorie; +Cc: linux-audit
On Thu, 2008-08-14 at 20:36 -0400, DJ Delorie wrote:
> > Since we get an ACK on delivery
>
> Right, and the ACK comes from the event logger thread *after* it
> pushes it out to disk.
Seems like a workable plan to me.
Thanks again,
LCB.
--
LC (Lenny) Bruzenak
lenny@magitekltd.com
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Add auditd listener and remote audit protocol
2008-08-15 0:31 ` LC Bruzenak
2008-08-15 0:36 ` DJ Delorie
@ 2009-09-29 17:52 ` LC Bruzenak
2009-09-29 18:51 ` Norman Mark St. Laurent
2009-09-29 19:27 ` Steve Grubb
1 sibling, 2 replies; 25+ messages in thread
From: LC Bruzenak @ 2009-09-29 17:52 UTC (permalink / raw)
To: Steve Grubb; +Cc: linux-audit
On Thu, 2008-08-14 at 19:31 -0500, LC Bruzenak wrote:
>
> On Thu, 2008-08-14 at 20:27 -0400, Steve Grubb wrote:
> > On Thursday 14 August 2008 20:22:24 LC Bruzenak wrote:
> > > I think you have a good point - this is the first cut and maybe
> later on
> > > institute a "replay daemon" or something which can send events on
> > > reconnect.
> >
> > Note that all audispd plugins take their input from stdin. At the
> worst, if
> > you had the time hacks, you could
> >
> > ausearch --start <time> --end <time> --raw | /sbin.audisp-remote
> >
> > -Steve
Steve,
I have been doing this but I really cannot tell if the audisp-remote
connection succeeds; it returns "0" either way.
Would there be an easy way to return a non-zero failure indicator?
Thx,
LCB.
--
LC (Lenny) Bruzenak
lenny@magitekltd.com
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Add auditd listener and remote audit protocol
2009-09-29 17:52 ` LC Bruzenak
@ 2009-09-29 18:51 ` Norman Mark St. Laurent
2009-09-29 19:14 ` LC Bruzenak
2009-09-29 19:27 ` Steve Grubb
1 sibling, 1 reply; 25+ messages in thread
From: Norman Mark St. Laurent @ 2009-09-29 18:51 UTC (permalink / raw)
To: LC Bruzenak; +Cc: linux-audit
Hi LCB,
I hope I answer u correctly...
I would look in your /etc/audisp/audisp-remote.conf file and note the
port you communicate on, as an alternate you can grab the port with
"lsof -i -nP" or "netstat -taupe". Then you can use tcpdump to watch
the connections.
#tcpdump -i eth0 port 1001 --> or what ever port you have setup to
the remote data on and the correct nic.
Sounds like this could help u out.
Norman Mark St. Laurent
Conceras | Chief Technology Officer and ISSE
Phone: 703-965-4892
Email: mstlaurent@conceras.com
Web: http://www.conceras.com
Connect. Collaborate. Conceras.
LC Bruzenak wrote:
> On Thu, 2008-08-14 at 19:31 -0500, LC Bruzenak wrote:
>
>> On Thu, 2008-08-14 at 20:27 -0400, Steve Grubb wrote:
>>
>>> On Thursday 14 August 2008 20:22:24 LC Bruzenak wrote:
>>>
>>>> I think you have a good point - this is the first cut and maybe
>>>>
>> later on
>>
>>>> institute a "replay daemon" or something which can send events on
>>>> reconnect.
>>>>
>>> Note that all audispd plugins take their input from stdin. At the
>>>
>> worst, if
>>
>>> you had the time hacks, you could
>>>
>>> ausearch --start <time> --end <time> --raw | /sbin.audisp-remote
>>>
>>> -Steve
>>>
>
> Steve,
>
> I have been doing this but I really cannot tell if the audisp-remote
> connection succeeds; it returns "0" either way.
> Would there be an easy way to return a non-zero failure indicator?
>
> Thx,
> LCB.
>
>
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Add auditd listener and remote audit protocol
2009-09-29 18:51 ` Norman Mark St. Laurent
@ 2009-09-29 19:14 ` LC Bruzenak
0 siblings, 0 replies; 25+ messages in thread
From: LC Bruzenak @ 2009-09-29 19:14 UTC (permalink / raw)
To: Norman Mark St. Laurent; +Cc: linux-audit
On Tue, 2009-09-29 at 14:51 -0400, Norman Mark St. Laurent wrote:
> Hi LCB,
>
> I hope I answer u correctly...
>
> I would look in your /etc/audisp/audisp-remote.conf file and note the
> port you communicate on, as an alternate you can grab the port with
> "lsof -i -nP" or "netstat -taupe". Then you can use tcpdump to watch
> the connections.
>
> #tcpdump -i eth0 port 1001 --> or what ever port you have setup to
> the remote data on and the correct nic.
>
> Sounds like this could help u out.
>
> Norman Mark St. Laurent
> Conceras | Chief Technology Officer and ISSE
> Phone: 703-965-4892
> Email: mstlaurent@conceras.com
> Web: http://www.conceras.com
>
> Connect. Collaborate. Conceras.
>
>
>
> LC Bruzenak wrote:
> > On Thu, 2008-08-14 at 19:31 -0500, LC Bruzenak wrote:
> >
> >> On Thu, 2008-08-14 at 20:27 -0400, Steve Grubb wrote:
> >>
> >>> On Thursday 14 August 2008 20:22:24 LC Bruzenak wrote:
> >>>
> >>>> I think you have a good point - this is the first cut and maybe
> >>>>
> >> later on
> >>
> >>>> institute a "replay daemon" or something which can send events on
> >>>> reconnect.
> >>>>
> >>> Note that all audispd plugins take their input from stdin. At the
> >>>
> >> worst, if
> >>
> >>> you had the time hacks, you could
> >>>
> >>> ausearch --start <time> --end <time> --raw | /sbin.audisp-remote
> >>>
> >>> -Steve
> >>>
> >
> > Steve,
> >
> > I have been doing this but I really cannot tell if the audisp-remote
> > connection succeeds; it returns "0" either way.
> > Would there be an easy way to return a non-zero failure indicator?
> >
> > Thx,
> > LCB.
> >
Norman,
Thank for the reply but I wasn't quite clear enough.
The context of this is within a recovery script, so I'm concerned that I
can get the return value of the audisp-remote within the script to
decide if the recovery was successful or if it failed.
I don't think that was clear above; my apologies since the conversation
I referenced was > 1 year old.
LCB.
--
LC (Lenny) Bruzenak
lenny@magitekltd.com
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Add auditd listener and remote audit protocol
2009-09-29 17:52 ` LC Bruzenak
2009-09-29 18:51 ` Norman Mark St. Laurent
@ 2009-09-29 19:27 ` Steve Grubb
1 sibling, 0 replies; 25+ messages in thread
From: Steve Grubb @ 2009-09-29 19:27 UTC (permalink / raw)
To: LC Bruzenak; +Cc: linux-audit
On Tuesday 29 September 2009 01:52:48 pm LC Bruzenak wrote:
> I have been doing this but I really cannot tell if the audisp-remote
> connection succeeds; it returns "0" either way.
> Would there be an easy way to return a non-zero failure indicator?
It sounds like a reasonable request. Looking at the source, it does return
non-zero on certain things. I think its just a matter of checking the queue
size on exit and using that to decide the return value.
-Steve
^ permalink raw reply [flat|nested] 25+ messages in thread
end of thread, other threads:[~2009-09-29 19:27 UTC | newest]
Thread overview: 25+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-08-14 21:43 [PATCH] Add auditd listener and remote audit protocol DJ Delorie
2008-08-14 21:58 ` LC Bruzenak
2008-08-14 22:16 ` DJ Delorie
2008-08-14 23:00 ` John Dennis
2008-08-14 23:02 ` LC Bruzenak
2008-08-14 23:16 ` John Dennis
2008-08-14 23:55 ` Steve Grubb
2008-08-14 23:16 ` DJ Delorie
2008-08-14 23:26 ` LC Bruzenak
2008-08-14 23:37 ` John Dennis
2008-08-14 23:50 ` LC Bruzenak
2008-08-15 0:07 ` Steve Grubb
2008-08-15 0:22 ` LC Bruzenak
2008-08-15 0:27 ` Steve Grubb
2008-08-15 0:31 ` LC Bruzenak
2008-08-15 0:36 ` DJ Delorie
2008-08-15 0:41 ` LC Bruzenak
2009-09-29 17:52 ` LC Bruzenak
2009-09-29 18:51 ` Norman Mark St. Laurent
2009-09-29 19:14 ` LC Bruzenak
2009-09-29 19:27 ` Steve Grubb
2008-08-15 0:23 ` DJ Delorie
2008-08-15 0:04 ` Steve Grubb
2008-08-15 0:19 ` DJ Delorie
2008-08-15 0:23 ` Steve Grubb
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox