RE: [PATCH] Add error-handling actions to audisp-remote

Chu Li
2008-12-15T07:45:02Z

Hi DJ,
Recently I used audisp-remote function and I found in audisp-remote.conf
there is "remote_ending_action" parameter. From the manpage, it's the same with
"disk_error_action". But from the codes, its meaning seems to be "the action
taken
when the remote audit ends". So I set it as "syslog" and then stopped the remote
audit, then the local audisp-remote stopped but no message about "remote ending".
I think if "network_retry_time" is reached, whatever the "fail-safe"(e.g.
remote_ending_action) action is set in audisp-remote.conf. The audisp-remote will
exit. Is that true?

Regards
Chu Li
> -----Original Message-----
> From: linux-audit-bounces@redhat.com [mailto:linux-audit-bounces@redhat.com] On
> Behalf Of DJ Delorie
> Sent: Friday, August 29, 2008 2:48 AM
> To: linux-audit@redhat.com
> Subject: [PATCH] Add error-handling actions to audisp-remote
>
>
> Third in a series.
> (http://www.redhat.com/archives/linux-audit/2008-August/msg00118.html)
>
> The goal of this patch is to robustify the error handling in the
> client end of the remote protocol. The following changes are made
> by this patch:
>
> * Failure to send a record to the aggregator results in a series of
> retry attempts, tunable by the administrator.
>
> * Overall network failure (after retries) and server-indicated error
> conditions now have admin-specified actions associated with them.
>
> * Miscellaneous additional error handling for reads and writes.
>
> Comments?
>
> DJ
>
>
> diff -x .svn -U 3 -r pristine/audisp/plugins/remote/audisp-remote.c
> trunk/audisp/plugins/remote/audisp-remote.c
> --- pristine/audisp/plugins/remote/audisp-remote.c 2008-08-27
> 18:55:41.000000000 -0400
> +++ trunk/audisp/plugins/remote/audisp-remote.c 2008-08-28
> 14:15:42.000000000 -0400
> @@ -40,15 +40,27 @@
> #define CONFIG_FILE "/etc/audisp/audisp-remote.conf"
> #define BUF_SIZE 32
>
> +/* Error types */
> +#define ET_SUCCESS 0
> +#define ET_PERMANENT -1
> +#define ET_TEMPORARY -2
> +
> /* Global Data */
> static volatile int stop = 0;
> static volatile int hup = 0;
> +static volatile int suspend = 0;
> static remote_conf_t config;
> static int sock=-1;
>
> +static const char *SINGLE = "1";
> +static const char *HALT = "0";
> +
> +static int transport_ok = 0;
> +
> /* Local function declarations */
> static int relay_event(const char *s, size_t len);
> static int init_transport(void);
> +static int stop_transport(void);
>
>
> /*
> @@ -69,10 +81,19 @@
>
> static void reload_config(void)
> {
> + stop_transport ();
> hup = 0;
> }
>
> /*
> + * SIGSUR2 handler: resume logging
> + */
> +static void user2_handler( int sig )
> +{
> + suspend = 0;
> +}
> +
> +/*
> * Handlers for various events coming back from the remote server.
> * Return -1 if the remote dispatcher should exit.
> */
> @@ -81,45 +102,135 @@
> 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;
> + be losing) sync. Sync errors are transient - if a retry
> + doesn't fix it, we eventually call network_failure_handler
> + which has all the user-tweakable actions. */
> + if (config.network_failure_action == FA_SYSLOG)
> + syslog (LOG_ERR, "lost/losing sync, %s", why);
> + return 0;
> +}
> +
> +static void change_runlevel(const char *level)
> +{
> + char *argv[3];
> + int pid;
> + static const char *init_pgm = "/sbin/init";
> +
> + pid = fork();
> + if (pid < 0) {
> + syslog(LOG_ALERT,
> + "Audit daemon failed to fork switching runlevels");
> + return;
> + }
> + if (pid) /* Parent */
> + return;
> + /* Child */
> + argv[0] = (char *)init_pgm;
> + argv[1] = (char *)level;
> + argv[2] = NULL;
> + execve(init_pgm, argv, NULL);
> + syslog(LOG_ALERT, "Audit daemon failed to exec %s", init_pgm);
> + exit(1);
> +}
> +
> +static void safe_exec(const char *exe, const char *message)
> +{
> + char *argv[3];
> + int pid;
> +
> + pid = fork();
> + if (pid < 0) {
> + syslog(LOG_ALERT,
> + "Audit daemon failed to fork doing safe_exec");
> + return;
> + }
> + if (pid) /* Parent */
> + return;
> + /* Child */
> + argv[0] = (char *)exe;
> + argv[1] = (char *)message;
> + argv[2] = NULL;
> + execve(exe, argv, NULL);
> + syslog(LOG_ALERT, "Audit daemon failed to exec %s", exe);
> + exit(1);
> +}
> +
> +static int do_action (const char *desc, const char *message,
> + int log_level,
> + failure_action_t action, const char *exe)
> +{
> + switch (action)
> + {
> + case FA_IGNORE:
> + return 0;
> + case FA_SYSLOG:
> + syslog (log_level, "%s, %s", desc, message);
> + return 0;
> + case FA_EXEC:
> + safe_exec (exe, message);
> + return 0;
> + case FA_SUSPEND:
> + suspend = 1;
> + return 0;
> + case FA_SINGLE:
> + change_runlevel(SINGLE);
> + return 1;
> + case FA_HALT:
> + change_runlevel(HALT);
> + return 1;
> + case FA_STOP:
> + syslog (log_level, "stopping due to %s, %s", desc, message);
> + stop = 1;
> + return 1;
> + }
> +}
> +
> +static int network_failure_handler (const char *message)
> +{
> + return do_action ("network failure", message,
> + LOG_WARNING,
> + config.network_failure_action, config.network_failure_exe);
> }
>
> static int remote_disk_low_handler (const char *message)
> {
> - syslog (LOG_WARNING, "remote disk low, %s", message);
> - return 0;
> + return do_action ("remote disk low", message,
> + LOG_WARNING,
> + config.disk_low_action, config.disk_low_exe);
> }
>
> static int remote_disk_full_handler (const char *message)
> {
> - syslog (LOG_ERR, "remote disk full, %s", message);
> - return -1;
> + return do_action ("remote disk full", message,
> + LOG_ERR,
> + config.disk_full_action, config.disk_full_exe);
> }
>
> static int remote_disk_error_handler (const char *message)
> {
> - syslog (LOG_ERR, "remote disk error, %s", message);
> - return -1;
> + return do_action ("remote disk error", message,
> + LOG_ERR,
> + config.disk_error_action, config.disk_error_exe);
> }
>
> static int remote_server_ending_handler (const char *message)
> {
> - syslog (LOG_INFO, "remote server ending, %s", message);
> - return -1;
> + return do_action ("remote server ending", message,
> + LOG_INFO,
> + config.remote_ending_action, config.remote_ending_exe);
> }
>
> static int generic_remote_error_handler (const char *message)
> {
> - stop = 1;
> - syslog(LOG_INFO, "audisp-remote: remote error: %s", message);
> - return -1;
> + return do_action ("unrecognized remote error", message,
> + LOG_ERR,
> + config.generic_error_action, config.generic_error_exe);
> }
> static int generic_remote_warning_handler (const char *message)
> {
> - syslog(LOG_INFO, "audisp-remote: remote warning: %s", message);
> - return 0;
> + return do_action ("unrecognized remote warning", message,
> + LOG_WARNING,
> + config.generic_warning_action, config.generic_warning_exe);
> }
>
>
> @@ -137,11 +248,16 @@
> sigaction(SIGTERM, &sa, NULL);
> sa.sa_handler = hup_handler;
> sigaction(SIGHUP, &sa, NULL);
> + sa.sa_handler = user2_handler;
> + sigaction(SIGUSR2, &sa, NULL);
> if (load_config(&config, CONFIG_FILE))
> return 6;
>
> + /* We fail here if the transport can't be initialized because
> + * of some permenent (i.e. operator) problem, such as
> + * misspelled host name. */
> rc = init_transport();
> - if (rc < 0)
> + if (rc == ET_PERMANENT)
> return 1;
>
> syslog(LOG_INFO, "audisp-remote is ready for events");
> @@ -155,10 +271,12 @@
> /* Now the event loop */
> while (fgets_unlocked(tmp, MAX_AUDIT_MESSAGE_LENGTH, stdin) &&
> hup==0 && stop==0) {
> - rc = relay_event(tmp, strnlen(tmp,
> - MAX_AUDIT_MESSAGE_LENGTH));
> - if (rc < 0) {
> - break;
> + if (!suspend) {
> + rc = relay_event(tmp, strnlen(tmp,
> + MAX_AUDIT_MESSAGE_LENGTH));
> + if (rc < 0) {
> + break;
> + }
> }
> }
> if (feof(stdin))
> @@ -186,14 +304,14 @@
> if (rc) {
> syslog(LOG_ERR, "Error looking up remote host: %s - exiting",
> gai_strerror(rc));
> - return -1;
> + return ET_PERMANENT;
> }
> sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
> if (sock < 0) {
> syslog(LOG_ERR, "Error creating socket: %s - exiting",
> strerror(errno));
> freeaddrinfo(ai);
> - return -1;
> + return ET_TEMPORARY;
> }
>
> setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof (int));
> @@ -210,7 +328,7 @@
> syslog(LOG_ERR, "Cannot bind local socket to port %d - exiting",
> config.local_port);
> close(sock);
> - return -1;
> + return ET_TEMPORARY;
> }
>
> }
> @@ -218,14 +336,22 @@
> syslog(LOG_ERR, "Error connecting to %s: %s - exiting",
> config.remote_server, strerror(errno));
> freeaddrinfo(ai);
> - return -1;
> + return ET_TEMPORARY;
> }
>
> setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&one, sizeof (int));
> - setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof (int));
> +
> + /* The idea here is to minimize the time between the message
> + and the ACK, assuming that individual messages are
> + infrequent enough that we can ignore the inefficiency of
> + sending the header and message in separate packets. */
> + if (config.format == F_MANAGED)
> + setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof (int));
> +
> + transport_ok = 1;
>
> freeaddrinfo(ai);
> - return 0;
> + return ET_SUCCESS;
> }
>
> static int init_transport(void)
> @@ -238,6 +364,28 @@
> rc = init_sock();
> break;
> default:
> + rc = ET_PERMANENT;
> + break;
> + }
> + return rc;
> +}
> +
> +static int stop_sock(void)
> +{
> + close (sock);
> + transport_ok = 0;
> +}
> +
> +static int stop_transport(void)
> +{
> + int rc;
> +
> + switch (config.transport)
> + {
> + case T_TCP:
> + rc = stop_sock();
> + break;
> + default:
> rc = -1;
> break;
> }
> @@ -246,10 +394,19 @@
>
> static int ar_write (int sock, const void *buf, int len)
> {
> - int rc;
> - do {
> - rc = write(sock, buf, len);
> - } while (rc < 0 && errno == EINTR);
> + int rc = 0, r;
> + while (len > 0) {
> + do {
> + r = write(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;
> }
>
> @@ -275,6 +432,10 @@
> {
> int rc;
>
> + if (!transport_ok)
> + if (init_transport ())
> + return -1;
> +
> rc = ar_write(sock, s, len);
> if (rc <= 0) {
> stop = 1;
> @@ -294,53 +455,103 @@
> int hver, mver;
> uint32_t type, rlen, seq;
> char msg[MAX_AUDIT_MESSAGE_LENGTH+1];
> + int n_tries_this_message = 0;
> + time_t now, then;
>
> sequence_id ++;
> +
> + time (&then);
> +try_again:
> + time (&now);
> +
> + /* We want the first retry to be quick, in case the network
> + failed for some fail-once reason. In this case, it goes
> + "failure - reconnect - send". Only if this quick retry
> + fails do we start pausing between retries to prevent
> + swamping the local computer and the network. */
> + if (n_tries_this_message > 1)
> + sleep (config.network_retry_time);
> +
> + if (n_tries_this_message > config.max_tries_per_record) {
> + network_failure_handler ("max retries exhausted");
> + return -1;
> + }
> + if ((now - then) > config.max_time_per_record) {
> + network_failure_handler ("max retry time exhausted");
> + return -1;
> + }
> +
> + n_tries_this_message ++;
> +
> + if (!transport_ok) {
> + if (init_transport ())
> + goto try_again;
> + }
> +
> 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;
> + if (config.network_failure_action == FA_SYSLOG)
> + syslog(LOG_ERR, "connection to %s closed unexpectedly",
> + config.remote_server);
> + stop_transport();
> + goto try_again;
> }
>
> 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;
> + if (config.network_failure_action == FA_SYSLOG)
> + syslog(LOG_ERR, "connection to %s closed unexpectedly",
> + config.remote_server);
> + stop_transport();
> + goto try_again;
> }
>
> 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 (config.network_failure_action == FA_SYSLOG)
> + syslog(LOG_ERR, "connection to %s closed unexpectedly",
> + config.remote_server);
> + stop_transport();
> + goto try_again;
> }
>
>
> - if (! AUDIT_RMW_IS_MAGIC (header, AUDIT_RMW_HEADER_SIZE))
> + 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");
> + if (sync_error_handler ("bad magic number"))
> + return -1;
> + stop_transport();
> + goto try_again;
> + }
>
> 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 > MAX_AUDIT_MESSAGE_LENGTH) {
> + if (sync_error_handler ("message too long"))
> + return -1;
> + stop_transport();
> + goto try_again;
> + }
>
> if (rlen > 0
> - && ar_read (sock, msg, rlen) < rlen)
> - return sync_error_handler ("ran out of data reading reply");
> + && ar_read (sock, msg, rlen) < rlen) {
> + if (sync_error_handler ("ran out of data reading reply"))
> + return -1;
> + stop_transport();
> + goto try_again;
> + }
> msg[rlen] = 0;
>
> - if (seq != sequence_id)
> + 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");
> + if (sync_error_handler ("mismatched response"))
> + return -1;
> + stop_transport();
> + goto try_again;
> + }
>
> /* Specific errors we know how to deal with. */
>
> diff -x .svn -U 3 -r pristine/audisp/plugins/remote/audisp-remote.conf
> trunk/audisp/plugins/remote/audisp-remote.conf
> --- pristine/audisp/plugins/remote/audisp-remote.conf 2008-08-15
> 15:52:05.000000000 -0400
> +++ trunk/audisp/plugins/remote/audisp-remote.conf 2008-08-28
> 14:34:48.000000000 -0400
> @@ -9,5 +9,15 @@
> transport = tcp
> mode = immediate
> queue_depth = 20
> -fail_action = SYSLOG
> format = managed
> +network_retry_time = 1
> +max_tries_per_record = 3
> +max_time_per_record = 5
> +
> +network_failure_action = stop
> +disk_low_action = ignore
> +disk_full_action = ignore
> +disk_error_action = syslog
> +remote_ending_action = suspend
> +generic_error_action = syslog
> +generic_warning_action = syslog
> diff -x .svn -U 3 -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-15
> 15:52:05.000000000 -0400
> +++ trunk/audisp/plugins/remote/audisp-remote.conf.5 2008-08-28
> 11:45:55.000000000 -0400
> @@ -45,24 +45,52 @@
> .I mode
> option. The default depth is 20.
> .TP
> -.I fail_action
> +.I network_failure_action
> This parameter tells the system what action to take whenever there is an error
> -detected when sending audit events to the remote system, or if the remote
> system
> reports an error. Valid values are
> -.IR ignore ", " syslog ", " exec ", " suspend ", " single ", and " halt .
> +detected when sending audit events to the remote system. Valid values are
> +.IR ignore ", " syslog ", " exec ", " suspend ", " single ", " halt ", and "
> stop .
> If set to
> .IR ignore ,
> the audit daemon does nothing.
> .I Syslog
> -means that it will issue a warning to syslog.
> +means that it will issue a warning to syslog. This is the default.
> .I exec
> /path-to-script will execute the script. You cannot pass parameters to the
> script.
> .I Suspend
> will cause the remote logging app to stop sending records to the remote system.
> The logging app will still be alive. The
> .I single
> -option will cause the remote logging app to put the computer system in single
> user
> mode.
> +option will cause the remote logging app to put the computer system in single
> user
> mode. The
> +.I stop
> +option will cause the remote logging app to exit, but leave other plugins
> running.
> The
> .I halt
> option will cause the remote logging app to shutdown the computer system.
> .TP
> +.I disk_low_action
> +Likewise, this parameter tells the system what action to take if the
> +remote end signals a disk low error. The default is to ignore it.
> +.TP
> +.I disk_full_action
> +Likewise, this parameter tells the system what action to take if the
> +remote end signals a disk full error. The default is to ignore it.
> +.TP
> +.I disk_error_action
> +Likewise, this parameter tells the system what action to take if the
> +remote end signals a disk error. The default is to log it to syslog.
> +.TP
> +.I remote_ending_action
> +Likewise, this parameter tells the system what action to take if the
> +remote end signals a disk error. The default is to suspend logging.
> +.TP
> +.I generic_error_action
> +Likewise, this parameter tells the system what action to take if the
> +remote end signals an error we don't recognize. The default is to log
> +it to syslog.
> +.TP
> +.I generic_warning_action
> +Likewise, this parameter tells the system what action to take if the
> +remote end signals a warning we don't recognize. The default is to
> +log it to syslog.
> +.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
> @@ -73,11 +101,43 @@
> .I ascii
> is given instead, each message is a simple ASCII text line with no
> overhead at all.
> +.TP
> +.I network_retry_time
> +The time, in seconds, between retries when a network error is
> +detected. Note that this pause applies starting after the second
> +attempt, so as to avoid unneeded delays if a reconnect is sufficient
> +to fix the problem. The default is 1 second.
> +.TP
> +.I max_tries_per_record
> +The maximum number of times an attempt is made to deliver each
> +message. The minimum value is one, as even a completely successful
> +delivery requires at least one try. If too many attempts are made,
> +the network_failure_action action is performed. The default is 3.
> +.TP
> +.I max_time_per_record
> +The maximum amount of time, in seconds, spent attempting to deliver
> +each message. Note that both this and
> +.I max_tries_per_record
> +should be set, as each try may take a long time to time out. The
> +default value is 5 seconds. If too much time is used on a message,
> +the network_failure_action action is performed.
>
> .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.
> +
> +The network failure logic works as follows: The first attempt to
> +deliver normally "just works". If it doesn't, a second attempt is
> +immediately made, perhaps after reconnecting to the server. If
> +the second attempt also fails,
> +.I audispd-remote
> +pauses for the configured time and tries again. It continues to pause
> +and retry until either too many attempts have been made or the allowed
> +time expires. Note that these times govern the maximum amount of time
> +the remote server is allowed in order to reboot, if you want to
> +maintain logging across a reboot.
> +
> .SH "SEE ALSO"
> .BR audispd (8),
> .BR audisp-remote(8).
> diff -x .svn -U 3 -r pristine/audisp/plugins/remote/remote-config.c
> trunk/audisp/plugins/remote/remote-config.c
> --- pristine/audisp/plugins/remote/remote-config.c 2008-08-15
> 15:52:05.000000000 -0400
> +++ trunk/audisp/plugins/remote/remote-config.c 2008-08-28
> 11:45:38.000000000 -0400
> @@ -74,6 +74,22 @@
> remote_conf_t *config);
> static int format_parser(struct nv_pair *nv, int line,
> remote_conf_t *config);
> +static int network_retry_time_parser(struct nv_pair *nv, int line,
> + remote_conf_t *config);
> +static int max_tries_per_record_parser(struct nv_pair *nv, int line,
> + remote_conf_t *config);
> +static int max_time_per_record_parser(struct nv_pair *nv, int line,
> + remote_conf_t *config);
> +#define AP(x) static int x##_action_parser(struct nv_pair *nv, int line, \
> + remote_conf_t *config);
> +AP(network_failure)
> +AP(disk_low)
> +AP(disk_full)
> +AP(disk_error)
> +AP(remote_ending)
> +AP(generic_error)
> +AP(generic_warning)
> +#undef AP
> static int sanity_check(remote_conf_t *config, const char *file);
>
> static const struct kw_pair keywords[] =
> @@ -84,8 +100,17 @@
> {"transport", transport_parser, 0 },
> {"mode", mode_parser, 0 },
> {"queue_depth", depth_parser, 0 },
> - {"fail_action", fail_action_parser, 0 },
> {"format", format_parser, 0 },
> + {"network_retry_time", network_retry_time_parser, 0 },
> + {"max_tries_per_record", max_tries_per_record_parser, 0 },
> + {"max_time_per_record", max_time_per_record_parser, 0 },
> + {"network_failure_action", network_failure_action_parser, 0 },
> + {"disk_low_action", disk_low_action_parser, 0 },
> + {"disk_full_action", disk_full_action_parser, 0 },
> + {"disk_error_action", disk_error_action_parser, 0 },
> + {"remote_ending_action", remote_ending_action_parser, 0 },
> + {"generic_error_action", generic_error_action_parser, 0 },
> + {"generic_warning_action", generic_warning_action_parser, 0 },
> { NULL, NULL }
> };
>
> @@ -104,12 +129,13 @@
>
> static const struct nv_list fail_action_words[] =
> {
> - {"ignore", F_IGNORE },
> - {"syslog", F_SYSLOG },
> - {"exec", F_EXEC },
> - {"suspend", F_SUSPEND },
> - {"single", F_SINGLE },
> - {"halt", F_HALT },
> + {"ignore", FA_IGNORE },
> + {"syslog", FA_SYSLOG },
> + {"exec", FA_EXEC },
> + {"suspend", FA_SUSPEND },
> + {"single", FA_SINGLE },
> + {"halt", FA_HALT },
> + {"stop", FA_STOP },
> { NULL, 0 }
> };
>
> @@ -131,9 +157,21 @@
> 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;
> +
> + config->network_retry_time = 1;
> + config->max_tries_per_record = 3;
> + config->max_time_per_record = 5;
> +
> +#define IA(x,f) config->x##_action = f; config->x##_exe = NULL
> + IA(network_failure, FA_STOP);
> + IA(disk_low, FA_IGNORE);
> + IA(disk_full, FA_IGNORE);
> + IA(disk_error, FA_SYSLOG);
> + IA(remote_ending, FA_SUSPEND);
> + IA(generic_error, FA_SYSLOG);
> + IA(generic_warning, FA_SYSLOG);
> +#undef IA
> }
>
> int load_config(remote_conf_t *config, const char *file)
> @@ -372,10 +410,10 @@
> return 0;
> }
>
> -static int port_parser(struct nv_pair *nv, int line, remote_conf_t *config)
> +static int parse_uint (struct nv_pair *nv, int line, unsigned int *valp,
> unsigned
> int min, unsigned int max)
> {
> const char *ptr = nv->value;
> - int i;
> + unsigned int i;
>
> /* check that all chars are numbers */
> for (i=0; ptr[i]; i++) {
> @@ -397,56 +435,32 @@
> return 1;
> }
> /* Check its range */
> - if (i > INT_MAX) {
> + if (min != 0 && i < (int)min) {
> syslog(LOG_ERR,
> - "Error - converted number (%s) is too large - line %d",
> + "Error - converted number (%s) is too small - line %d",
> nv->value, line);
> return 1;
> }
> - config->port = (unsigned int)i;
> - 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) {
> + if (max != 0 && i > max) {
> syslog(LOG_ERR,
> "Error - converted number (%s) is too large - line %d",
> nv->value, line);
> return 1;
> }
> - config->local_port = (unsigned int)i;
> + *valp = (unsigned int)i;
> return 0;
> }
>
> +static int port_parser(struct nv_pair *nv, int line, remote_conf_t *config)
> +{
> + return parse_uint (nv, line, &(config->port), 0, INT_MAX);
> +}
> +
> +static int local_port_parser(struct nv_pair *nv, int line, remote_conf_t
> *config)
> +{
> + return parse_uint (nv, line, &(config->local_port), 0, INT_MAX);
> +}
> +
> static int transport_parser(struct nv_pair *nv, int line, remote_conf_t
> *config)
> {
> int i;
> @@ -476,54 +490,24 @@
> static int depth_parser(struct nv_pair *nv, int line,
> remote_conf_t *config)
> {
> - const char *ptr = nv->value;
> - int i;
> -
> - /* 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->queue_depth = (unsigned int)i;
> - return 0;
> + return parse_uint (nv, line, &(config->queue_depth), 1, INT_MAX);
> }
>
> -static int fail_action_parser(struct nv_pair *nv, int line,
> - remote_conf_t *config)
> +static int action_parser(struct nv_pair *nv, int line,
> + failure_action_t *actp, const char **exep)
> {
> int i;
> for (i=0; fail_action_words[i].name != NULL; i++) {
> if (strcasecmp(nv->value, fail_action_words[i].name) == 0) {
> - config->fail_action = fail_action_words[i].option;
> + *actp = fail_action_words[i].option;
> return 0;
> - } else if (i == F_EXEC) {
> + } else if (i == FA_EXEC) {
> if (strncasecmp(fail_action_words[i].name,
> nv->value, 4) == 0){
> if (check_exe_name(nv->option))
> return 1;
> - config->fail_exe = strdup(nv->option);
> - config->fail_action = F_EXEC;
> + *exep = strdup(nv->option);
> + *actp = FA_EXEC;
> return 0;
> }
> }
> @@ -532,6 +516,22 @@
> return 1;
> }
>
> +#define AP(x) \
> +static int x##_action_parser(struct nv_pair *nv, int line, \
> + remote_conf_t *config) \
> +{ \
> + return action_parser (nv, line, &(config->x##_action), &(config->x##_exe));
> \
> +} \
> +
> +AP(network_failure)
> +AP(disk_low)
> +AP(disk_full)
> +AP(disk_error)
> +AP(remote_ending)
> +AP(generic_error)
> +AP(generic_warning)
> +#undef AP
> +
> static int format_parser(struct nv_pair *nv, int line,
> remote_conf_t *config)
> {
> @@ -546,6 +546,24 @@
> return 1;
> }
>
> +static int network_retry_time_parser(struct nv_pair *nv, int line,
> + remote_conf_t *config)
> +{
> + return parse_uint (nv, line, &(config->network_retry_time), 1, INT_MAX);
> +}
> +
> +static int max_tries_per_record_parser(struct nv_pair *nv, int line,
> + remote_conf_t *config)
> +{
> + return parse_uint (nv, line, &(config->max_tries_per_record), 1, INT_MAX);
> +}
> +
> +static int max_time_per_record_parser(struct nv_pair *nv, int line,
> + remote_conf_t *config)
> +{
> + return parse_uint (nv, line, &(config->max_time_per_record), 1, INT_MAX);
> +}
> +
> /*
> * 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 -x .svn -U 3 -r pristine/audisp/plugins/remote/remote-config.h
> trunk/audisp/plugins/remote/remote-config.h
> --- pristine/audisp/plugins/remote/remote-config.h 2008-08-15
> 15:52:05.000000000 -0400
> +++ trunk/audisp/plugins/remote/remote-config.h 2008-08-28
> 14:18:18.000000000 -0400
> @@ -26,8 +26,9 @@
>
> 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 enum { FA_IGNORE, FA_SYSLOG, FA_EXEC, FA_SUSPEND,
> + FA_SINGLE, FA_HALT, FA_STOP } failure_action_t;
>
> typedef struct remote_conf
> {
> @@ -37,9 +38,25 @@
> transport_t transport;
> mode_t mode;
> unsigned int queue_depth;
> - fail_t fail_action;
> - const char *fail_exe;
> format_t format;
> + unsigned int network_retry_time;
> + unsigned int max_tries_per_record;
> + unsigned int max_time_per_record;
> +
> + failure_action_t network_failure_action;
> + const char *network_failure_exe;
> + failure_action_t disk_low_action;
> + const char *disk_low_exe;
> + failure_action_t disk_full_action;
> + const char *disk_full_exe;
> + failure_action_t disk_error_action;
> + const char *disk_error_exe;
> + failure_action_t remote_ending_action;
> + const char *remote_ending_exe;
> + failure_action_t generic_error_action;
> + const char *generic_error_exe;
> + failure_action_t generic_warning_action;
> + const char *generic_warning_exe;
> } remote_conf_t;
>
> void clear_config(remote_conf_t *config);
> diff -x .svn -U 3 -r pristine/src/auditd-event.c trunk/src/auditd-event.c
> --- pristine/src/auditd-event.c 2008-08-15 15:52:05.000000000 -0400
> +++ trunk/src/auditd-event.c 2008-08-16 01:04:33.000000000 -0400
> @@ -398,6 +398,9 @@
> if (data->head->ack_socket) {
> unsigned char header[AUDIT_RMW_HEADER_SIZE];
>
> + if (fs_space_warning)
> + ack_type = AUDIT_RMW_TYPE_DISKLOW;
> +
> 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);
>
> --
> Linux-audit mailing list
> Linux-audit@redhat.com
> https://www.redhat.com/mailman/listinfo/linux-audit