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

Chu Li chul at cn.fujitsu.com
Mon Dec 15 07:45:02 UTC 2008


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 at redhat.com [mailto:linux-audit-bounces at redhat.com] On
> Behalf Of DJ Delorie
> Sent: Friday, August 29, 2008 2:48 AM
> To: linux-audit at 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 at redhat.com
> https://www.redhat.com/mailman/listinfo/linux-audit







More information about the Linux-audit mailing list