changeset 5007:51890a00057d

6411336 audit_binfile(5) creates an empty audit trail file on startup 6430878 audit_binfile(5) doesn't rotate the audit.log at all 6483684 auditd drops audit records when the allhard condition is reached and continue policy is not set 6492045 auditd does not honor its 20second interval if log file system is full 6555845 auditd creates audit files in / if no directory specified in audit_control
author paulson
date Fri, 07 Sep 2007 02:20:59 -0700
parents 304eb1332eef
children 4ceab57ff7f2
files usr/src/cmd/audit/audit.c usr/src/cmd/audit_warn/audit_warn.sh usr/src/cmd/auditd/doorway.c usr/src/lib/auditd_plugins/binfile/binfile.c usr/src/lib/libbsm/common/getacval.c
diffstat 5 files changed, 128 insertions(+), 78 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/audit/audit.c	Thu Sep 06 19:30:39 2007 -0700
+++ b/usr/src/cmd/audit/audit.c	Fri Sep 07 02:20:59 2007 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
@@ -217,7 +217,8 @@
 	int		rc;
 	int		min;
 	kva_t		*kvlist;
-	char		*value;
+	char		*plugin_name;
+	char		*plugin_dir;
 	au_acinfo_t	*ach;
 
 	ach = _openac(filename);	/* open audit_control */
@@ -242,18 +243,29 @@
 	 * _getacplug -- all that is of interest is the return code.
 	 */
 	_rewindac(ach);	/* rewind audit_control */
-	if ((rc = _getacplug(ach, &kvlist)) == 0) {
-		value = kva_match(kvlist, "name");
-		if (value == NULL) {
+	while ((rc = _getacplug(ach, &kvlist)) == 0) {
+		plugin_name = kva_match(kvlist, "name");
+		if (plugin_name == NULL) {
 			(void) fprintf(stderr, gettext("%s: audit_control "
 			    "\"plugin:\" missing name\n"), progname);
 			state = 0;	/* is_not_ok */
+		} else {
+			if (strcmp(plugin_name, "audit_binfile.so") == 0) {
+				plugin_dir = kva_match(kvlist, "p_dir");
+				if ((plugin_dir == NULL) && (outputs == 0)) {
+					(void) fprintf(stderr,
+					    gettext("%s: audit_control "
+					    "\"plugin:\" missing p_dir\n"),
+					    progname);
+					state = 0;	/* is_not_ok */
+				} else {
+					outputs++;
+				}
+			}
 		}
-		else
-			outputs++;
-
 		_kva_free(kvlist);
-	} else if (rc < -1) {
+	}
+	if (rc < -1) {
 		(void) fprintf(stderr,
 			gettext("%s: audit_control \"plugin:\" spec invalid\n"),
 				progname);
@@ -262,7 +274,8 @@
 	if (outputs == 0) {
 		(void) fprintf(stderr,
 			gettext("%s: audit_control must have either a "
-				"\"dir:\" or a \"plugin:\" specified.\n"),
+				"valid \"dir:\" entry or a valid \"plugin:\" "
+				"entry with \"p_dir:\" specified.\n"),
 				progname);
 		state = 0;	/* is_not_ok */
 	}
--- a/usr/src/cmd/audit_warn/audit_warn.sh	Thu Sep 06 19:30:39 2007 -0700
+++ b/usr/src/cmd/audit_warn/audit_warn.sh	Fri Sep 07 02:20:59 2007 -0700
@@ -3,9 +3,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -23,7 +22,7 @@
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
 #
-# Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -246,12 +245,17 @@
 				exit 1
 			else
 				COUNT=$2
+				if [ $COUNT -eq 1 ]; then
+					S=""
+				else
+					S="s"
+				fi
 			fi
 
 			# Set message
 			MESSAGE="There is a problem getting the directory\
- list from audit_control.  The audit daemon will hang until this file is\
- fixed.  This message has been displayed $COUNT times."
+ list or plugin list from audit_control(4).  The audit daemon will hang
+ until this file is fixed.  This message has been displayed $COUNT time$S."
 			send_msg
 			break
 			;;
@@ -292,6 +296,11 @@
 				exit 1
 			else
 				COUNT=$5
+				if [ $COUNT -eq 1 ]; then
+					S=""
+				else
+					S="s"
+				fi
 			fi
 
 			# Set message
@@ -299,7 +308,7 @@
  following problem with loading or executing plugins:\n\n\
 $PLUGNAME: $ERROR\n\
 $TEXT\n\
-This message has been displayed $COUNT times."
+This message has been displayed $COUNT time$S."
 			send_msg
 			break
 			;;
--- a/usr/src/cmd/auditd/doorway.c	Thu Sep 06 19:30:39 2007 -0700
+++ b/usr/src/cmd/auditd/doorway.c	Fri Sep 07 02:20:59 2007 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  *
  */
@@ -588,7 +587,7 @@
 	audit_queue_init(&(p->plg_pool));
 
 	DPRINT((dbfp, "qpool_init(%d) max, min, threshhold = %d, %d, %d\n",
-		p->plg_tid, p->plg_qmax, p->plg_qmin, threshold));
+	    p->plg_tid, p->plg_qmax, p->plg_qmin, threshold));
 
 	if (p->plg_qmax > largest_queue)
 		largest_queue = p->plg_qmax;
@@ -707,8 +706,8 @@
 	rc = audit_dequeue(&b_pool, (void *)&node);
 
 	DPRINT((dbfp, "bpool_withdraw buf length=%d,"
-		" requested size=%d, dequeue rc=%d\n",
-		new_length, request_size, rc));
+	    " requested size=%d, dequeue rc=%d\n",
+	    new_length, request_size, rc));
 
 	if (rc == 0) {
 		DPRINT((dbfp, "bpool_withdraw node=%X (pool=%d)\n", node,
@@ -911,8 +910,7 @@
 	audit_q_t	*q_copy;
 	boolean_t	referenced = 0;
 	static char	*invalid_msg = "invalid audit record discarded";
-	static char	*invalid_control =
-			    "invalid audit control discarded";
+	static char	*invalid_control = "invalid audit control discarded";
 
 	static audit_rec_t	*alt_b_copy = NULL;
 	static size_t		alt_length;
@@ -1196,6 +1194,7 @@
 	int			sendsignal;
 	int			queue_len;
 	struct sched_param	param;
+	static boolean_t	once = B_FALSE;
 
 	DPRINT((dbfp, "%s is thread %d\n", p->plg_path, p->plg_tid));
 	p->plg_priority = param.sched_priority = BASE_PRIORITY;
@@ -1204,8 +1203,6 @@
 	delay.tv_nsec = 0;
 
 	for (;;) {
-		retry_mode:
-
 		while (audit_dequeue(&(p->plg_queue), (void *)&q_node) != 0) {
 			DUMP("process", p, p->plg_last_seq_out, "blocked");
 			(void) pthread_cond_signal(&(in_thr.thd_cv));
@@ -1218,12 +1215,10 @@
 			(void) pthread_mutex_unlock(&(p->plg_mutex));
 
 			if (p->plg_removed)
-				break;
+				goto plugin_removed;
 
 			DUMP("process", p, p->plg_last_seq_out, "unblocked");
 		}
-		if (p->plg_removed)
-			break;
 #if DEBUG
 		if (q_node->aqq_sequence != p->plg_last_seq_out + 1)
 			(void) fprintf(dbfp,
@@ -1234,15 +1229,21 @@
 		error_string = NULL;
 
 		b_node = q_node->aqq_data;
+retry_mode:
 		plugrc = p->plg_fplugin(b_node->abq_buffer,
-			b_node->abq_data_len,
-			q_node->aqq_sequence, &error_string);
+		    b_node->abq_data_len, q_node->aqq_sequence, &error_string);
+
+		if (p->plg_removed)
+			goto plugin_removed;
 #if DEBUG
 		p->plg_last_seq_out = q_node->aqq_sequence;
 #endif
 		switch (plugrc) {
 		case AUDITD_RETRY:
-			report_error(plugrc, error_string, p->plg_path);
+			if (!once) {
+				report_error(plugrc, error_string, p->plg_path);
+				once = B_TRUE;
+			}
 			free(error_string);
 			error_string = NULL;
 
@@ -1257,7 +1258,7 @@
 			(void) pthread_mutex_lock(&(p->plg_mutex));
 			p->plg_waiting++;
 			(void) pthread_cond_reltimedwait_np(&(p->plg_cv),
-				&(p->plg_mutex), &delay);
+			    &(p->plg_mutex), &delay);
 			p->plg_waiting--;
 			(void) pthread_mutex_unlock(&(p->plg_mutex));
 
@@ -1266,6 +1267,7 @@
 
 		case AUDITD_SUCCESS:
 			p->plg_output++;
+			once = B_FALSE;
 			break;
 		default:
 			report_error(plugrc, error_string, p->plg_path);
@@ -1303,6 +1305,7 @@
 			    &param);
 		}
 	}	/* end for (;;) */
+plugin_removed:
 	DUMP("process", p, p->plg_last_seq_out, "exit");
 	error_string = NULL;
 	if ((rc = p->plg_fplugin_close(&error_string)) !=
--- a/usr/src/lib/auditd_plugins/binfile/binfile.c	Thu Sep 06 19:30:39 2007 -0700
+++ b/usr/src/lib/auditd_plugins/binfile/binfile.c	Fri Sep 07 02:20:59 2007 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  *
  * write binary audit records directly to a file.
@@ -73,12 +72,13 @@
 #define	SOFT_SPACE	0	/* minfree or less space available	*/
 #define	PLENTY_SPACE	1	/* more than minfree available		*/
 #define	SPACE_FULL	2	/* out of space				*/
-#define	STAY_FULL	3	/* unusable file system			*/
 
 #define	AVAIL_MIN	50	/* If there are less that this number	*/
 				/* of blocks avail, the filesystem is	*/
 				/* presumed full.			*/
 
+#define	ALLHARD_DELAY	20	/* Call audit_warn(allhard) every 20 seconds */
+
 
 /*
  * The directory list is a circular linked list.  It is pointed into by
@@ -114,9 +114,10 @@
 static int		minfreeblocks;		/* minfree in blocks */
 
 static dirlist_t	*activeDir = NULL;	/* current directory */
+static dirlist_t	*startdir;		/* first dir in the ring */
 static int		activeCount = 0;	/* number of dirs in the ring */
 
-static int		openNewFile = 1;	/* need to open a new file */
+static int		openNewFile = 0;	/* need to open a new file */
 static int		hung_count = 0;		/* count of audit_warn hard */
 
 /* flag from audit_plugin_open to audit_plugin_close */
@@ -253,7 +254,7 @@
 
 	/* at least one directory is needed */
 	while ((acresult = _getacdir(ach, buf, sizeof (buf))) == 0 ||
-		acresult == 2 || acresult == -3) {
+	    acresult == 2 || acresult == -3) {
 		/*
 		 * loop if the result is 0 (success), 2 (a warning
 		 * that the audit_data file has been rewound),
@@ -370,11 +371,14 @@
 	if (rc == -2) {
 		(void) pthread_mutex_lock(&log_mutex);
 		DPRINT((dbfp, "loadauditlist:  close / open log\n"));
-		if (open_log(listhead) == 0)
+		if (open_log(listhead) == 0) {
 			openNewFile = 1;	/* try again later */
+		} else {
+			openNewFile = 0;
+		}
 		freedirlist(activeList);	/* old list */
 		activeList = listhead;		/* new list */
-		activeDir = thisdir;
+		activeDir = startdir = thisdir;
 		activeCount = node_count;
 		(void) pthread_mutex_unlock(&log_mutex);
 	} else
@@ -426,8 +430,8 @@
 	 *	tzfile.h .
 	 */
 	(void) sprintf(date, "%.4d%.2d%.2d%.2d%.2d%.2d",
-		tm.tm_year + TM_YEAR_BASE, tm.tm_mon + 1, tm.tm_mday,
-		tm.tm_hour, tm.tm_min, tm.tm_sec);
+	    tm.tm_year + TM_YEAR_BASE, tm.tm_mon + 1, tm.tm_mday,
+	    tm.tm_hour, tm.tm_min, tm.tm_sec);
 }
 
 
@@ -598,7 +602,7 @@
 		name = (char *)strrchr(oldname, '/') + 1;
 
 		(void) memcpy(name + AUDIT_DATE_SZ + 1, auditdate,
-			AUDIT_DATE_SZ);
+		    AUDIT_DATE_SZ);
 
 		close_log(lastOpenDir, oldname, newname);
 	}
@@ -661,10 +665,7 @@
 
 	assert(thisdir != NULL);
 
-	if (thisdir->dl_space == STAY_FULL) {
-		thisdir->dl_space = SPACE_FULL;
-		minfreeblocks = AVAIL_MIN;
-	} else if (statvfs(thisdir->dl_dirname, &sb) < 0) {
+	if (statvfs(thisdir->dl_dirname, &sb) < 0) {
 		thisdir->dl_space = SPACE_FULL;
 		minfreeblocks = AVAIL_MIN;
 		return (-1);
@@ -673,9 +674,10 @@
 
 		if (sb.f_bavail < AVAIL_MIN)
 			thisdir->dl_space = SPACE_FULL;
-		else if (sb.f_bavail > minfreeblocks)
-			thisdir->dl_space = PLENTY_SPACE;
-		else
+		else if (sb.f_bavail > minfreeblocks) {
+			thisdir->dl_space = fullness_state = PLENTY_SPACE;
+			ignore_size = 0;
+		} else
 			thisdir->dl_space = SOFT_SPACE;
 	}
 	if (thisdir->dl_space == PLENTY_SPACE)
@@ -685,10 +687,12 @@
 }
 
 /*
- * auditd_plugin() writes a buffer to the currently open file The
- * global "openNewFile" is used to force a new log file for the
- * initial open; for "audit -s" with changed audit_control data or
- * "audit -n" the new log file is opened immediately.
+ * auditd_plugin() writes a buffer to the currently open file. The
+ * global "openNewFile" is used to force a new log file for cases
+ * such as the initial open, when minfree is reached or the current
+ * file system fills up, and "audit -s" with changed audit_control
+ * data.  For "audit -n" a new log file is opened immediately in
+ * auditd_plugin_open().
  *
  * This function manages one or more audit directories as follows:
  *
@@ -713,14 +717,15 @@
 auditd_plugin(const char *input, size_t in_len, uint32_t sequence, char **error)
 {
 	auditd_rc_t	rc = AUDITD_FAIL;
-	dirlist_t	*startdir;
 	int		open_status;
 	size_t		out_len;
 	/* LINTED */
 	int		statrc;
 	/* avoid excess audit_warnage */
-	static int	somesoftfull_warning = 0;
 	static int	allsoftfull_warning = 0;
+	static int	allhard_pause = 0;
+	static struct timeval	next_allhard;
+	struct timeval	now;
 #if DEBUG
 	static char	*last_file_written_to = NULL;
 	static uint32_t	last_sequence = 0;
@@ -728,18 +733,17 @@
 
 	if ((last_sequence > 0) && (sequence != last_sequence + 1))
 		fprintf(dbfp, "binfile: buffer sequence=%d but prev=%d=n",
-				sequence, last_sequence);
+		    sequence, last_sequence);
 	last_sequence = sequence;
 
 	fprintf(dbfp, "binfile: input seq=%d, len=%d\n",
-		sequence, in_len);
+	    sequence, in_len);
 #endif
 	*error = NULL;
 	/*
 	 * lock is for activeDir, referenced by open_log() and close_log()
 	 */
 	(void) pthread_mutex_lock(&log_mutex);
-	startdir = activeDir;
 	while (rc == AUDITD_FAIL) {
 		open_status = 1;
 		if (openNewFile) {
@@ -781,12 +785,11 @@
 				    " l=%u\n",
 				    ++write_count, sequence, out_len));
 				allsoftfull_warning = 0;
-				if (fullness_state == PLENTY_SPACE)
-					somesoftfull_warning = 0;
+				activeDir->dl_flags = 0;
 
 				rc = AUDITD_SUCCESS;
 				break;
-			} else if (!activeDir->dl_flags & HARD_WARNED) {
+			} else if (!(activeDir->dl_flags & HARD_WARNED)) {
 				DPRINT((dbfp,
 				    "binfile: write failed, sequence=%u, "
 				    "l=%u\n", sequence, out_len));
@@ -799,18 +802,18 @@
 		} else {
 			DPRINT((dbfp, "binfile: statrc=%d, fullness_state=%d\n",
 			    statrc, fullness_state));
-			somesoftfull_warning++;
-			if ((somesoftfull_warning <= activeCount) &&
-			    !(activeDir->dl_flags & SOFT_WARNED)) {
+			if (!(activeDir->dl_flags & SOFT_WARNED) &&
+			    (activeDir->dl_space == SOFT_SPACE)) {
 				DPRINT((dbfp, "soft warning sent\n"));
 				__audit_dowarn("soft",
 				    activeDir->dl_dirname, 0);
 				activeDir->dl_flags |= SOFT_WARNED;
 			}
-			if (!activeDir->dl_flags & HARD_WARNED) {
+			if (!(activeDir->dl_flags & HARD_WARNED) &&
+			    (activeDir->dl_space == SPACE_FULL)) {
 				DPRINT((dbfp, "hard warning sent.\n"));
 				__audit_dowarn("hard",
-				activeDir->dl_dirname, 0);
+				    activeDir->dl_dirname, 0);
 				activeDir->dl_flags |= HARD_WARNED;
 			}
 		}
@@ -818,6 +821,7 @@
 		    activeDir->dl_dirname, activeDir->dl_next->dl_dirname));
 
 		activeDir = activeDir->dl_next;
+		openNewFile = 1;
 
 		if (activeDir == startdir) {		/* full circle */
 			if (fullness_state == PLENTY_SPACE) {	/* once */
@@ -827,7 +831,24 @@
 					__audit_dowarn("allsoft", "", 0);
 				}
 			} else {			/* full circle twice */
-				__audit_dowarn("allhard", "", ++hung_count);
+				if ((hung_count > 0) && !allhard_pause) {
+					allhard_pause = 1;
+					(void) gettimeofday(&next_allhard,
+					    NULL);
+					next_allhard.tv_sec += ALLHARD_DELAY;
+				}
+
+				if (allhard_pause) {
+					(void) gettimeofday(&now, NULL);
+					if (now.tv_sec >= next_allhard.tv_sec) {
+						allhard_pause = 0;
+						__audit_dowarn("allhard", "",
+						    ++hung_count);
+					}
+				} else {
+					__audit_dowarn("allhard", "",
+					    ++hung_count);
+				}
 				minfreeblocks = AVAIL_MIN;
 				rc = AUDITD_RETRY;
 				*error = strdup(gettext(
@@ -913,7 +934,7 @@
 		} else {	/* status is 0 or -2 (no change or changed) */
 			hung_count = 0;
 			DPRINT((dbfp, "binfile: loadauditlist returned %d\n",
-				status));
+			    status));
 		}
 		break;
 	case 1:			/* audit -n */
--- a/usr/src/lib/libbsm/common/getacval.c	Thu Sep 06 19:30:39 2007 -0700
+++ b/usr/src/lib/libbsm/common/getacval.c	Fri Sep 07 02:20:59 2007 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
@@ -217,10 +217,14 @@
 	if (retstat >= SUCCESS) do {
 		if (getlongline(entry, REALLY_LONG_LINE, context->fp) != NULL) {
 			if (*entry == 'd') {
-				retstat = getvalue(dir, entry, DIRLABEL,
-				    len);
-				if (retstat == SUCCESS)
-					gotone = 1;
+				retstat = getvalue(dir, entry, DIRLABEL, len);
+				if (retstat == SUCCESS) {
+					if (strlen(dir) == 0) {
+						retstat = FORMAT_ERR;
+					} else {
+						gotone = 1;
+					}
+				}
 			}
 		} else if ((feof(context->fp)) == 0) {
 			retstat = ERROR;