xref: /onnv-gate/usr/src/lib/libbsm/common/audit_plugin.c (revision 12918:32a41a5f8110)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51914Scasper  * Common Development and Distribution License (the "License").
61914Scasper  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*12918SJan.Friedel@Sun.COM  * Copyright (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  *
240Sstevel@tonic-gate  * private interfaces for auditd plugins and auditd.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #include <bsm/audit.h>
280Sstevel@tonic-gate #include <bsm/audit_record.h>
290Sstevel@tonic-gate #include <bsm/audit_uevents.h>
300Sstevel@tonic-gate #include <bsm/libbsm.h>
310Sstevel@tonic-gate #include <errno.h>
320Sstevel@tonic-gate #include <fcntl.h>
330Sstevel@tonic-gate #include <libintl.h>
340Sstevel@tonic-gate #include <pthread.h>
350Sstevel@tonic-gate #include <stdio.h>
360Sstevel@tonic-gate #include <stdlib.h>
370Sstevel@tonic-gate #include <string.h>
380Sstevel@tonic-gate #include <sys/file.h>
390Sstevel@tonic-gate #include <sys/stat.h>
400Sstevel@tonic-gate #include <sys/types.h>
410Sstevel@tonic-gate #include <syslog.h>
420Sstevel@tonic-gate #include <unistd.h>
430Sstevel@tonic-gate #include <wait.h>
440Sstevel@tonic-gate #include "audit_plugin.h"
450Sstevel@tonic-gate 
460Sstevel@tonic-gate static char	auditwarn[] = "/etc/security/audit_warn";
470Sstevel@tonic-gate static pthread_mutex_t	syslog_lock;
480Sstevel@tonic-gate 
490Sstevel@tonic-gate static void
init_syslog_mutex()500Sstevel@tonic-gate init_syslog_mutex()
510Sstevel@tonic-gate {
520Sstevel@tonic-gate 	(void) pthread_mutex_init(&syslog_lock, NULL);
530Sstevel@tonic-gate }
540Sstevel@tonic-gate 
550Sstevel@tonic-gate /*
560Sstevel@tonic-gate  * audit_syslog() -- generate syslog messages from threads that use
570Sstevel@tonic-gate  * different severity, facility code, and application names.
580Sstevel@tonic-gate  *
590Sstevel@tonic-gate  * syslog(3C) is thread safe, but the set openlog() / syslog() /
600Sstevel@tonic-gate  * closelog() is not.
610Sstevel@tonic-gate  *
620Sstevel@tonic-gate  * Assumption:  the app_name and facility code are paired, i.e.,
630Sstevel@tonic-gate  * if the facility code for this call is the same as for the
640Sstevel@tonic-gate  * the previous, the app_name hasn't changed.
650Sstevel@tonic-gate  */
660Sstevel@tonic-gate void
__audit_syslog(const char * app_name,int flags,int facility,int severity,const char * message)6711700Sgww@eng.sun.com __audit_syslog(const char *app_name, int flags, int facility, int severity,
6811700Sgww@eng.sun.com     const char *message)
690Sstevel@tonic-gate {
707427SJan.Friedel@Sun.COM 	static pthread_once_t	once_control = PTHREAD_ONCE_INIT;
710Sstevel@tonic-gate 	static int		logopen = 0;
720Sstevel@tonic-gate 	static int		prev_facility = -1;
730Sstevel@tonic-gate 
740Sstevel@tonic-gate 	(void) pthread_once(&once_control, init_syslog_mutex);
750Sstevel@tonic-gate 
760Sstevel@tonic-gate 	(void) pthread_mutex_lock(&syslog_lock);
770Sstevel@tonic-gate 	if (prev_facility != facility) {
780Sstevel@tonic-gate 		if (logopen)
790Sstevel@tonic-gate 			closelog();
800Sstevel@tonic-gate 		openlog(app_name, flags, facility);
812540Spaulson 		syslog(severity, "%s", message);
820Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&syslog_lock);
830Sstevel@tonic-gate 	} else {
842540Spaulson 		syslog(severity, "%s", message);
850Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&syslog_lock);
860Sstevel@tonic-gate 	}
870Sstevel@tonic-gate }
880Sstevel@tonic-gate 
890Sstevel@tonic-gate /*
900Sstevel@tonic-gate  * __audit_dowarn - invoke the shell script auditwarn to notify the
910Sstevel@tonic-gate  *	adminstrator about a given problem.
920Sstevel@tonic-gate  * parameters -
930Sstevel@tonic-gate  *	option - what the problem is
940Sstevel@tonic-gate  *	text - when used with options soft and hard: which file was being
950Sstevel@tonic-gate  *		   used when the filesystem filled up
960Sstevel@tonic-gate  *	       when used with the plugin option:  error detail
970Sstevel@tonic-gate  *	count - used with various options: how many times auditwarn has
980Sstevel@tonic-gate  *		been called for this problem since it was last cleared.
990Sstevel@tonic-gate  */
1000Sstevel@tonic-gate void
__audit_dowarn(char * option,char * text,int count)1010Sstevel@tonic-gate __audit_dowarn(char *option, char *text, int count)
1020Sstevel@tonic-gate {
1030Sstevel@tonic-gate 	pid_t		pid;
1040Sstevel@tonic-gate 	int		st;
1050Sstevel@tonic-gate 	char		countstr[5];
1060Sstevel@tonic-gate 	char		warnstring[80];
1070Sstevel@tonic-gate 	char		empty[1] = "";
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate 	if ((pid = fork1()) == -1) {
1100Sstevel@tonic-gate 		__audit_syslog("auditd", LOG_PID | LOG_ODELAY | LOG_CONS,
1110Sstevel@tonic-gate 		    LOG_DAEMON, LOG_ALERT, gettext("audit_warn fork failed\n"));
1120Sstevel@tonic-gate 		return;
1130Sstevel@tonic-gate 	}
1140Sstevel@tonic-gate 	if (pid != 0) {
1150Sstevel@tonic-gate 		(void) waitpid(pid, &st, 0);
1160Sstevel@tonic-gate 		return;
1170Sstevel@tonic-gate 	}
118*12918SJan.Friedel@Sun.COM 	(void) snprintf(countstr, 5, "%d", count);
1190Sstevel@tonic-gate 	if (text == NULL)
1200Sstevel@tonic-gate 		text = empty;
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate 	if (strcmp(option, "soft") == 0 || strcmp(option, "hard") == 0)
1230Sstevel@tonic-gate 		(void) execl(auditwarn, auditwarn, option, text, 0);
1240Sstevel@tonic-gate 
125*12918SJan.Friedel@Sun.COM 	else if (strcmp(option, "allhard") == 0)
1260Sstevel@tonic-gate 		(void) execl(auditwarn, auditwarn, option, countstr, 0);
1270Sstevel@tonic-gate 	else if (strcmp(option, "plugin") == 0)
1280Sstevel@tonic-gate 		(void) execl(auditwarn, auditwarn, option, text, countstr, 0);
1290Sstevel@tonic-gate 	else
1300Sstevel@tonic-gate 		(void) execl(auditwarn, auditwarn, option, 0);
1310Sstevel@tonic-gate 	/*
1320Sstevel@tonic-gate 	 * (execl failed)
1330Sstevel@tonic-gate 	 */
1340Sstevel@tonic-gate 	if (strcmp(option, "soft") == 0)
135*12918SJan.Friedel@Sun.COM 		(void) snprintf(warnstring, 80,
1360Sstevel@tonic-gate 		    gettext("soft limit in %s.\n"), text);
1370Sstevel@tonic-gate 	else if (strcmp(option, "hard") == 0)
138*12918SJan.Friedel@Sun.COM 		(void) snprintf(warnstring, 80,
1390Sstevel@tonic-gate 		    gettext("hard limit in %s.\n"), text);
1400Sstevel@tonic-gate 	else if (strcmp(option, "allhard") == 0)
1410Sstevel@tonic-gate 		(void) sprintf(warnstring,
1420Sstevel@tonic-gate 		    gettext("All audit filesystems are full.\n"));
1430Sstevel@tonic-gate 	else
144*12918SJan.Friedel@Sun.COM 		(void) snprintf(warnstring, 80,
1450Sstevel@tonic-gate 		    gettext("error %s.\n"), option);
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 	__audit_syslog("auditd", LOG_PID | LOG_ODELAY | LOG_CONS, LOG_AUTH,
1480Sstevel@tonic-gate 	    LOG_ALERT, (const char *)warnstring);
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate 	exit(1);
1510Sstevel@tonic-gate }
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate /*
1540Sstevel@tonic-gate  * __audit_dowarn2 - invoke the shell script auditwarn to notify the
1550Sstevel@tonic-gate  *	adminstrator about a given problem.
1560Sstevel@tonic-gate  * parameters -
1570Sstevel@tonic-gate  *	option - what the problem is
1580Sstevel@tonic-gate  *	name - entity reporting the problem (ie, plugin name)
1590Sstevel@tonic-gate  *	error - error string
1600Sstevel@tonic-gate  *	text - when used with options soft and hard: which file was being
1610Sstevel@tonic-gate  *		   used when the filesystem filled up
1620Sstevel@tonic-gate  *	       when used with the plugin option:  error detail
1630Sstevel@tonic-gate  *	count - used with various options: how many times auditwarn has
1640Sstevel@tonic-gate  *		been called for this problem since it was last cleared.
1650Sstevel@tonic-gate  */
1660Sstevel@tonic-gate void
__audit_dowarn2(char * option,char * name,char * error,char * text,int count)1670Sstevel@tonic-gate __audit_dowarn2(char *option, char *name, char *error, char *text, int count)
1680Sstevel@tonic-gate {
1690Sstevel@tonic-gate 	pid_t		pid;
1700Sstevel@tonic-gate 	int		st;
1710Sstevel@tonic-gate 	char		countstr[5];
1720Sstevel@tonic-gate 	char		warnstring[80];
1730Sstevel@tonic-gate 	char		empty[4] = "...";
1740Sstevel@tonic-gate 	char		none[3] = "--";
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	if ((pid = fork()) == -1) {
1770Sstevel@tonic-gate 		__audit_syslog("auditd", LOG_PID | LOG_ODELAY | LOG_CONS,
1780Sstevel@tonic-gate 		    LOG_DAEMON, LOG_ALERT, gettext("audit_warn fork failed\n"));
1790Sstevel@tonic-gate 		return;
1800Sstevel@tonic-gate 	}
1810Sstevel@tonic-gate 	if (pid != 0) {
1820Sstevel@tonic-gate 		(void) waitpid(pid, &st, 0);
1830Sstevel@tonic-gate 		return;
1840Sstevel@tonic-gate 	}
185*12918SJan.Friedel@Sun.COM 	(void) snprintf(countstr, 5, "%d", count);
1860Sstevel@tonic-gate 	if ((text == NULL) || (*text == '\0'))
1870Sstevel@tonic-gate 		text = empty;
1880Sstevel@tonic-gate 	if ((name == NULL) || (*name == '\0'))
1890Sstevel@tonic-gate 		name = none;
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 	(void) execl(auditwarn, auditwarn, option, name, error, text,
1920Sstevel@tonic-gate 	    countstr, 0);
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate 	/*
1950Sstevel@tonic-gate 	 * (execl failed)
1960Sstevel@tonic-gate 	 */
197*12918SJan.Friedel@Sun.COM 	(void) snprintf(warnstring, 80,
198*12918SJan.Friedel@Sun.COM 	    gettext("%s plugin error: %s\n"), name, text);
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 	__audit_syslog("auditd", LOG_PID | LOG_ODELAY | LOG_CONS, LOG_AUTH,
2010Sstevel@tonic-gate 	    LOG_ALERT, (const char *)warnstring);
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	exit(1);
2040Sstevel@tonic-gate }
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate /*
20711700Sgww@eng.sun.com  * logpost - post the new audit log file name.
2080Sstevel@tonic-gate  *
20911700Sgww@eng.sun.com  *	Entry	name = active audit.log file name
21011700Sgww@eng.sun.com  *			NULL, if checking writability (auditd),
21111700Sgww@eng.sun.com  *			changing audit log files, error, or exiting (binfile).
21211700Sgww@eng.sun.com  *
21311700Sgww@eng.sun.com  *	Exit	0 = success
21411700Sgww@eng.sun.com  *		1 = system error -- errno
21511700Sgww@eng.sun.com  *		    audit_warn called with the specific error
21611700Sgww@eng.sun.com  *
2170Sstevel@tonic-gate  */
2180Sstevel@tonic-gate int
__logpost(char * name)2190Sstevel@tonic-gate __logpost(char *name)
2200Sstevel@tonic-gate {
22111700Sgww@eng.sun.com 	int lerrno;
2220Sstevel@tonic-gate 
22311700Sgww@eng.sun.com 	if (unlink(BINFILE_FILE) != 0 &&
22411700Sgww@eng.sun.com 	    errno != ENOENT) {
2250Sstevel@tonic-gate 
22611700Sgww@eng.sun.com 		lerrno = errno;
22711700Sgww@eng.sun.com 		__audit_dowarn("tmpfile", strerror(errno), 0);
22811700Sgww@eng.sun.com 		errno = lerrno;
22911700Sgww@eng.sun.com 		return (1);
2300Sstevel@tonic-gate 	}
23111700Sgww@eng.sun.com 	if (name == NULL || *name == '\0') {
23211700Sgww@eng.sun.com 		/* audit_binfile not active, no file pointer */
23311700Sgww@eng.sun.com 		return (0);
23411700Sgww@eng.sun.com 	}
23511700Sgww@eng.sun.com 	if (symlink(name, BINFILE_FILE) != 0) {
2360Sstevel@tonic-gate 
23711700Sgww@eng.sun.com 		lerrno = errno;
23811700Sgww@eng.sun.com 		__audit_dowarn("tmpfile", strerror(errno), 0);
23911700Sgww@eng.sun.com 		errno = lerrno;
24011700Sgww@eng.sun.com 		return (1);
24111700Sgww@eng.sun.com 	}
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	return (0);
2440Sstevel@tonic-gate }
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate /*
2470Sstevel@tonic-gate  * debug use - open a file for auditd and its plugins for debug
2480Sstevel@tonic-gate  */
2490Sstevel@tonic-gate FILE *
__auditd_debug_file_open()2500Sstevel@tonic-gate __auditd_debug_file_open() {
2510Sstevel@tonic-gate 	static FILE	*fp = NULL;
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate 	if (fp != NULL)
2540Sstevel@tonic-gate 		return (fp);
2551914Scasper 	if ((fp = fopen("/var/audit/dump", "aF")) == NULL)
2560Sstevel@tonic-gate 		(void) fprintf(stderr, "failed to open debug file:  %s\n",
2570Sstevel@tonic-gate 		    strerror(errno));
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate 	return (fp);
2600Sstevel@tonic-gate }
261