xref: /onnv-gate/usr/src/cmd/auditd/auditd.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
57091Sgww  * Common Development and Distribution License (the "License").
67091Sgww  * 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) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate /* Audit daemon server */
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * These routines make up the audit daemon server.  This daemon, called
280Sstevel@tonic-gate  * auditd, handles the user level parts of auditing.  It receives buffered
290Sstevel@tonic-gate  * audit records (usually one or more per buffer, potentially less than
300Sstevel@tonic-gate  * one) and passes them to one or more plugins for processing.
310Sstevel@tonic-gate  *
32*12918SJan.Friedel@Sun.COM  * The major interrupts are SIGHUP (start over), SIGTERM (start shutting down),
33*12918SJan.Friedel@Sun.COM  * SIGALRM (quit), and SIGUSR1 (start a new audit log file). SIGTERM is also
34*12918SJan.Friedel@Sun.COM  * used for the child to tell the parent that audit is ready.
350Sstevel@tonic-gate  *
36*12918SJan.Friedel@Sun.COM  * Configuration data comes from audit service configuration
37*12918SJan.Friedel@Sun.COM  * (AUDITD_FMRI/smf(5)) and the auditon system call.
380Sstevel@tonic-gate  *
390Sstevel@tonic-gate  * The major errors are EBUSY (auditing is already in use) and EINTR
400Sstevel@tonic-gate  * (one of the above signals was received).  File space errors are
410Sstevel@tonic-gate  * handled by the audit_binfile plugin
420Sstevel@tonic-gate  */
430Sstevel@tonic-gate 
4411129SJan.Friedel@Sun.COM /* #define	DEBUG    - define for debug messages to be generated */
4511129SJan.Friedel@Sun.COM /* #define	MEM_TEST - define to generate core dump on exit */
4611129SJan.Friedel@Sun.COM #define	DEBUG		0
4711129SJan.Friedel@Sun.COM #define	MEM_TEST	0
480Sstevel@tonic-gate 
490Sstevel@tonic-gate #include <assert.h>
507091Sgww #include <bsm/adt.h>
510Sstevel@tonic-gate #include <bsm/audit.h>
520Sstevel@tonic-gate #include <bsm/audit_record.h>
530Sstevel@tonic-gate #include <bsm/libbsm.h>
540Sstevel@tonic-gate #include <fcntl.h>
550Sstevel@tonic-gate #include <libintl.h>
560Sstevel@tonic-gate #include <locale.h>
570Sstevel@tonic-gate #include <netdb.h>
580Sstevel@tonic-gate #include <pwd.h>
590Sstevel@tonic-gate #include <secdb.h>
600Sstevel@tonic-gate #include <signal.h>
610Sstevel@tonic-gate #include <stdio.h>
620Sstevel@tonic-gate #include <stdlib.h>
630Sstevel@tonic-gate #include <string.h>
647091Sgww #include <syslog.h>
650Sstevel@tonic-gate #include <errno.h>
660Sstevel@tonic-gate #include <sys/file.h>
670Sstevel@tonic-gate #include <sys/param.h>
680Sstevel@tonic-gate #include <sys/stat.h>
690Sstevel@tonic-gate #include <sys/statvfs.h>
700Sstevel@tonic-gate #include <sys/time.h>
710Sstevel@tonic-gate #include <sys/types.h>
720Sstevel@tonic-gate #include <sys/wait.h>
730Sstevel@tonic-gate #include <termios.h>
740Sstevel@tonic-gate #include <unistd.h>
750Sstevel@tonic-gate #include "plugin.h"
760Sstevel@tonic-gate #include <audit_plugin.h>
7711129SJan.Friedel@Sun.COM #include <audit_scf.h>
780Sstevel@tonic-gate 
790Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
800Sstevel@tonic-gate #define	TEXT_DOMAIN	"SUNW_OST_OSCMD"
810Sstevel@tonic-gate #endif
820Sstevel@tonic-gate /*
83*12918SJan.Friedel@Sun.COM  * After we get a SIGTERM, we want to set a timer for 2 seconds
840Sstevel@tonic-gate  * and let c2audit write as many records as it can until the timer
85*12918SJan.Friedel@Sun.COM  * goes off (at which point it returns to auditd with SIGALRM).
86*12918SJan.Friedel@Sun.COM  * If any other signals are received during that time, we call
870Sstevel@tonic-gate  * __audit_dowarn() to indicate that the queue may not have been fully
880Sstevel@tonic-gate  * flushed.
890Sstevel@tonic-gate  */
900Sstevel@tonic-gate #define	ALRM_TIME	2
910Sstevel@tonic-gate #define	SLEEP_TIME	20	/* # of seconds to sleep in all hard loop */
920Sstevel@tonic-gate 
930Sstevel@tonic-gate static plugin_t	*binfile = NULL;
940Sstevel@tonic-gate 
950Sstevel@tonic-gate static int	turn_audit_on  = AUC_AUDITING;
960Sstevel@tonic-gate static int	turn_audit_off = AUC_NOAUDIT;
970Sstevel@tonic-gate 
980Sstevel@tonic-gate static int	running = 1;
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate /*
1010Sstevel@tonic-gate  * GLOBALS:
1020Sstevel@tonic-gate  */
1030Sstevel@tonic-gate plugin_t		*plugin_head = NULL;
1040Sstevel@tonic-gate static thr_data_t	main_thr;	/* auditd thread (0) */
1050Sstevel@tonic-gate pthread_mutex_t		plugin_mutex;	/* for plugin_t list */
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate static int	caught_alrm = 0;	/* number of SIGALRMs pending */
108*12918SJan.Friedel@Sun.COM static int	caught_readc = 0;	/* number of SIGHUPs pending */
109*12918SJan.Friedel@Sun.COM static int	caught_term = 0;	/* number of SIGTERMs pending */
110*12918SJan.Friedel@Sun.COM static int	caught_nextd = 0;	/* number of SIGUSR1s pending */
1110Sstevel@tonic-gate 
112*12918SJan.Friedel@Sun.COM static int	reset_list = 1;	/* 1 to re-read audit configuration */
1130Sstevel@tonic-gate static int	reset_file = 1; /* 1 to close/open binary log */
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate static int	auditing_set = 0;	/* 1 if auditon(A_SETCOND, on... */
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate static void	my_sleep();
1180Sstevel@tonic-gate static void	signal_thread();
1190Sstevel@tonic-gate static void	loadauditlist();
1200Sstevel@tonic-gate static void	block_signals();
1210Sstevel@tonic-gate static int	do_sethost();
1220Sstevel@tonic-gate 
12311129SJan.Friedel@Sun.COM static void	conf_to_kernel();
12411129SJan.Friedel@Sun.COM static void	scf_to_kernel_qctrl();
12511129SJan.Friedel@Sun.COM static void	scf_to_kernel_policy();
12611129SJan.Friedel@Sun.COM 
12711129SJan.Friedel@Sun.COM /*
12811129SJan.Friedel@Sun.COM  * err_exit() - exit function after the unsuccessful call to auditon();
12911129SJan.Friedel@Sun.COM  * prints_out / saves_via_syslog the necessary error messages.
13011129SJan.Friedel@Sun.COM  */
13111129SJan.Friedel@Sun.COM static void
err_exit(char * msg)13211703SJan.Friedel@Sun.COM err_exit(char *msg)
13311129SJan.Friedel@Sun.COM {
13411129SJan.Friedel@Sun.COM 	if (msg != NULL) {
13511129SJan.Friedel@Sun.COM 		DPRINT((dbfp, "%s\n", msg));
13611129SJan.Friedel@Sun.COM 		__audit_syslog("auditd", LOG_PID | LOG_CONS | LOG_NOWAIT,
13711129SJan.Friedel@Sun.COM 		    LOG_DAEMON, LOG_ALERT, msg);
13811129SJan.Friedel@Sun.COM 		free(msg);
13911129SJan.Friedel@Sun.COM 	} else {
14011129SJan.Friedel@Sun.COM 		DPRINT((dbfp, "the memory allocation failed\n"));
14111129SJan.Friedel@Sun.COM 		__audit_syslog("auditd", LOG_PID | LOG_CONS | LOG_NOWAIT,
14211129SJan.Friedel@Sun.COM 		    LOG_DAEMON, LOG_ALERT, gettext("no memory"));
14311129SJan.Friedel@Sun.COM 	}
14411129SJan.Friedel@Sun.COM 	auditd_thread_close();
14511703SJan.Friedel@Sun.COM 	auditd_exit(1);
14611129SJan.Friedel@Sun.COM }
14711129SJan.Friedel@Sun.COM 
1480Sstevel@tonic-gate /* common exit function */
1490Sstevel@tonic-gate void
auditd_exit(int status)1500Sstevel@tonic-gate auditd_exit(int status)
1510Sstevel@tonic-gate {
1520Sstevel@tonic-gate #if MEM_TEST
1530Sstevel@tonic-gate 	DPRINT((dbfp, "mem_test intentional abort (status=%d)\n",
1540Sstevel@tonic-gate 	    status));
1550Sstevel@tonic-gate 	abort();
1560Sstevel@tonic-gate #endif
1570Sstevel@tonic-gate 	DPRINT((dbfp, "%ld exit status = %d auditing_set = %d\n",
1580Sstevel@tonic-gate 	    getpid(), status, auditing_set));
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 	if (auditing_set)
1610Sstevel@tonic-gate 		(void) auditon(A_SETCOND, (caddr_t)&turn_audit_off,
162*12918SJan.Friedel@Sun.COM 		    sizeof (int));
1630Sstevel@tonic-gate 
16411129SJan.Friedel@Sun.COM #if DEBUG
16511129SJan.Friedel@Sun.COM 	(void) fclose(dbfp);
16611129SJan.Friedel@Sun.COM #endif
16711129SJan.Friedel@Sun.COM 
1680Sstevel@tonic-gate 	exit(status);
1690Sstevel@tonic-gate }
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate /* ARGSUSED */
172394Spaulson int
main(int argc,char * argv[])1730Sstevel@tonic-gate main(int argc, char *argv[])
1740Sstevel@tonic-gate {
1750Sstevel@tonic-gate 	auditinfo_addr_t	as_null;	/* audit state to set */
1760Sstevel@tonic-gate 	au_id_t			auid;
1770Sstevel@tonic-gate 	pthread_t		tid;
1780Sstevel@tonic-gate 	plugin_t		*p;
1790Sstevel@tonic-gate 	pid_t			pid;
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate #if DEBUG
18211706SJan.Friedel@Sun.COM #if MEM_TEST
18311706SJan.Friedel@Sun.COM 	char	*envp;
18411706SJan.Friedel@Sun.COM #endif
18511129SJan.Friedel@Sun.COM 	if (dbfp == NULL) {
18611129SJan.Friedel@Sun.COM 		dbfp = __auditd_debug_file_open();
18711129SJan.Friedel@Sun.COM 	}
1880Sstevel@tonic-gate #endif
1890Sstevel@tonic-gate 	(void) setsid();
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 	/* Internationalization */
1920Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
1930Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 	/*
1960Sstevel@tonic-gate 	 * Set the audit host-id.
1970Sstevel@tonic-gate 	 */
1980Sstevel@tonic-gate 	if (do_sethost() != 0) {
1990Sstevel@tonic-gate 		__audit_dowarn("nostart", "", 0);
2000Sstevel@tonic-gate 		auditd_exit(1);
2010Sstevel@tonic-gate 	}
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	/*
2040Sstevel@tonic-gate 	 * Turn off all auditing for this process.
2050Sstevel@tonic-gate 	 */
2060Sstevel@tonic-gate 	if (getaudit_addr(&as_null, sizeof (as_null)) == -1) {
2070Sstevel@tonic-gate 		__audit_dowarn("nostart", "", 0);
20811703SJan.Friedel@Sun.COM 		auditd_exit(1);
2090Sstevel@tonic-gate 	}
2100Sstevel@tonic-gate 	as_null.ai_mask.as_success = 0;
2110Sstevel@tonic-gate 	as_null.ai_mask.as_failure = 0;
2120Sstevel@tonic-gate 	(void) setaudit_addr(&as_null, sizeof (as_null));
2130Sstevel@tonic-gate 	auid = AU_NOAUDITID;
2140Sstevel@tonic-gate 	(void) setauid(&auid);
2150Sstevel@tonic-gate 	/*
2160Sstevel@tonic-gate 	 * Set the audit state flag to AUDITING.
2170Sstevel@tonic-gate 	 */
218*12918SJan.Friedel@Sun.COM 	if (auditon(A_SETCOND, (caddr_t)&turn_audit_on, sizeof (int)) !=
2190Sstevel@tonic-gate 	    0) {
2200Sstevel@tonic-gate 		DPRINT((dbfp, "auditon(A_SETCOND...) failed (exit)\n"));
2210Sstevel@tonic-gate 		__audit_dowarn("nostart", "", 0);
22211703SJan.Friedel@Sun.COM 		auditd_exit(1);
2230Sstevel@tonic-gate 	}
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 	block_signals();
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 	/*
2280Sstevel@tonic-gate 	 * wait for "ready" signal before exit -- for greenline
2290Sstevel@tonic-gate 	 */
2300Sstevel@tonic-gate 	if (fork()) {
2310Sstevel@tonic-gate 		sigset_t	set;
2320Sstevel@tonic-gate 		int		signal_caught = 0;
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate 		(void) sigemptyset(&set);
235*12918SJan.Friedel@Sun.COM 		(void) sigaddset(&set, SIGTERM);
2360Sstevel@tonic-gate 
237*12918SJan.Friedel@Sun.COM 		while (signal_caught != SIGTERM)
2380Sstevel@tonic-gate 			signal_caught = sigwait(&set);
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 		DPRINT((dbfp, "init complete:  parent can now exit\n"));
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 		auditd_exit(0);
2430Sstevel@tonic-gate 	}
2440Sstevel@tonic-gate 	pid = getppid();
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	auditing_set = 1;
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate #if DEBUG && MEM_TEST
2490Sstevel@tonic-gate 	envp = getenv("UMEM_DEBUG");
2500Sstevel@tonic-gate 	if (envp != NULL)
2510Sstevel@tonic-gate 		DPRINT((dbfp, "UMEM_DEBUG=%s\n", envp));
2520Sstevel@tonic-gate 	envp = getenv("UMEM_LOGGING");
2530Sstevel@tonic-gate 	if (envp != NULL)
2540Sstevel@tonic-gate 		DPRINT((dbfp, "UMEM_LOGGING=%s\n", envp));
2550Sstevel@tonic-gate #endif
2560Sstevel@tonic-gate 	DPRINT((dbfp, "auditd pid=%ld\n", getpid()));
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	/* thread 0 sync */
2590Sstevel@tonic-gate 	(void) pthread_mutex_init(&(main_thr.thd_mutex), NULL);
2600Sstevel@tonic-gate 	(void) pthread_cond_init(&(main_thr.thd_cv), NULL);
2610Sstevel@tonic-gate 	(void) pthread_mutex_init(&plugin_mutex, NULL);
2620Sstevel@tonic-gate 	/*
2630Sstevel@tonic-gate 	 * Set up a separate thread for signal handling.
2640Sstevel@tonic-gate 	 */
2650Sstevel@tonic-gate 	if (pthread_create(&tid, NULL, (void *(*)(void *))signal_thread,
2660Sstevel@tonic-gate 	    NULL)) {
2670Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
2680Sstevel@tonic-gate 		    "auditd can't create a thread\n"));
26911703SJan.Friedel@Sun.COM 		auditd_exit(1);
2700Sstevel@tonic-gate 	}
2710Sstevel@tonic-gate 	/*
2720Sstevel@tonic-gate 	 * Set the umask so that only audit or other users in the audit group
2730Sstevel@tonic-gate 	 * can get to the files created by auditd.
2740Sstevel@tonic-gate 	 */
2750Sstevel@tonic-gate 	(void) umask(007);
2760Sstevel@tonic-gate 
277*12918SJan.Friedel@Sun.COM 	if (__logpost("")) {	/* Cannot unlink pointer to audit.log(4) file */
2780Sstevel@tonic-gate 		DPRINT((dbfp, "logpost failed\n"));
27911703SJan.Friedel@Sun.COM 		auditd_exit(1);
2800Sstevel@tonic-gate 	}
2810Sstevel@tonic-gate 	/*
282*12918SJan.Friedel@Sun.COM 	 * Here is the main body of the audit daemon. running == 0 means that
283*12918SJan.Friedel@Sun.COM 	 * after flushing out the audit queue, it is time to exit in response
284*12918SJan.Friedel@Sun.COM 	 * to SIGTERM.
2850Sstevel@tonic-gate 	 */
2860Sstevel@tonic-gate 	while (running) {
2870Sstevel@tonic-gate 		/*
288*12918SJan.Friedel@Sun.COM 		 * Read auditd / auditd plugins related configuration from
289*12918SJan.Friedel@Sun.COM 		 * smf(5) repository and create plugin lists.
2900Sstevel@tonic-gate 		 *
2910Sstevel@tonic-gate 		 * loadauditlist() and auditd_thread_init() are called
2920Sstevel@tonic-gate 		 * while under the plugin_mutex lock to avoid a race
2930Sstevel@tonic-gate 		 * with unload_plugin().
2940Sstevel@tonic-gate 		 */
2950Sstevel@tonic-gate 		if (reset_list || reset_file) {
29611129SJan.Friedel@Sun.COM 			if (reset_list) {
29711129SJan.Friedel@Sun.COM 				conf_to_kernel();
29811129SJan.Friedel@Sun.COM 				scf_to_kernel_qctrl();
29911129SJan.Friedel@Sun.COM 				scf_to_kernel_policy();
30011129SJan.Friedel@Sun.COM 				(void) pthread_mutex_lock(&plugin_mutex);
3010Sstevel@tonic-gate 				loadauditlist();
30211129SJan.Friedel@Sun.COM 			} else {
30311129SJan.Friedel@Sun.COM 				(void) pthread_mutex_lock(&plugin_mutex);
30411129SJan.Friedel@Sun.COM 			}
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 			if (auditd_thread_init()) {
3070Sstevel@tonic-gate 				auditd_thread_close();
3080Sstevel@tonic-gate 				/* continue; wait for audit -s */
3090Sstevel@tonic-gate 			}
3100Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&plugin_mutex);
31111129SJan.Friedel@Sun.COM 
31211129SJan.Friedel@Sun.COM 			if (reset_list && reset_file) {
31311129SJan.Friedel@Sun.COM 				(void) printf(gettext("auditd started\n"));
31411129SJan.Friedel@Sun.COM 			} else {
31511129SJan.Friedel@Sun.COM 				(void) printf(gettext("auditd refreshed\n"));
31611129SJan.Friedel@Sun.COM 			}
317*12918SJan.Friedel@Sun.COM 
318*12918SJan.Friedel@Sun.COM 			reset_list = 0;
319*12918SJan.Friedel@Sun.COM 			reset_file = 0;
3200Sstevel@tonic-gate 		}
3210Sstevel@tonic-gate 		/*
3220Sstevel@tonic-gate 		 * tell parent I'm running whether or not the initialization
3230Sstevel@tonic-gate 		 * actually worked.  The failure case is to wait for an
3240Sstevel@tonic-gate 		 * audit -n or audit -s to fix the problem.
3250Sstevel@tonic-gate 		 */
3260Sstevel@tonic-gate 		if (pid != 0) {
327*12918SJan.Friedel@Sun.COM 			(void) kill(pid, SIGTERM);
3280Sstevel@tonic-gate 			pid = 0;
3290Sstevel@tonic-gate 		}
3300Sstevel@tonic-gate 		/*
3310Sstevel@tonic-gate 		 * thread_signal() signals main (this thread) when
3320Sstevel@tonic-gate 		 * it has received a signal.
3330Sstevel@tonic-gate 		 */
334*12918SJan.Friedel@Sun.COM 		DPRINT((dbfp, "main thread is waiting for signal\n"));
3350Sstevel@tonic-gate 		(void) pthread_mutex_lock(&(main_thr.thd_mutex));
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 		if (!(caught_readc || caught_term || caught_alrm ||
3380Sstevel@tonic-gate 		    caught_nextd))
3390Sstevel@tonic-gate 			(void) pthread_cond_wait(&(main_thr.thd_cv),
3400Sstevel@tonic-gate 			    &(main_thr.thd_mutex));
3410Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&(main_thr.thd_mutex));
3420Sstevel@tonic-gate 		/*
3430Sstevel@tonic-gate 		 * Got here because a signal came in.
3440Sstevel@tonic-gate 		 * Since we may have gotten more than one, we assume a
3450Sstevel@tonic-gate 		 * priority scheme with SIGALRM being the most
3460Sstevel@tonic-gate 		 * significant.
3470Sstevel@tonic-gate 		 */
3480Sstevel@tonic-gate 		if (caught_alrm) {
3490Sstevel@tonic-gate 			/*
3500Sstevel@tonic-gate 			 * We have returned from our timed wait for
3510Sstevel@tonic-gate 			 * c2audit to calm down.  We need to really shut
3520Sstevel@tonic-gate 			 * down here.
3530Sstevel@tonic-gate 			 */
3540Sstevel@tonic-gate 			caught_alrm = 0;
3550Sstevel@tonic-gate 			running = 0;	/* shut down now */
3560Sstevel@tonic-gate 		} else if (caught_term) {
3570Sstevel@tonic-gate 			/*
3580Sstevel@tonic-gate 			 * we are going to shut down, but need to
3590Sstevel@tonic-gate 			 * allow time for the audit queues in
3600Sstevel@tonic-gate 			 * c2audit and for the threads to empty.
3610Sstevel@tonic-gate 			 */
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate 			p = plugin_head;
3640Sstevel@tonic-gate 			while (p != NULL) {
3650Sstevel@tonic-gate 				DPRINT((dbfp, "signalling thread %d\n",
3660Sstevel@tonic-gate 				    p->plg_tid));
3670Sstevel@tonic-gate 				(void) pthread_mutex_lock(&(p->plg_mutex));
3680Sstevel@tonic-gate 				p->plg_removed = 1;
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 				if (p->plg_initialized)
3710Sstevel@tonic-gate 					(void) pthread_cond_signal(
3720Sstevel@tonic-gate 					    &(p->plg_cv));
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 				(void) pthread_mutex_unlock(&(p->plg_mutex));
3750Sstevel@tonic-gate 				p = p->plg_next;
3760Sstevel@tonic-gate 			}
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 			caught_alrm = 0;
3790Sstevel@tonic-gate 			caught_readc  = 0;
3800Sstevel@tonic-gate 			caught_term = 0;
3810Sstevel@tonic-gate 			caught_nextd = 0;
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate 			DPRINT((dbfp,
3840Sstevel@tonic-gate 			    "main thread is pausing before exit.\n"));
3850Sstevel@tonic-gate 			(void) pthread_mutex_lock(&(main_thr.thd_mutex));
3860Sstevel@tonic-gate 			caught_alrm = 0;
3870Sstevel@tonic-gate 			(void) alarm(ALRM_TIME);
3880Sstevel@tonic-gate 			while (!caught_alrm)
3890Sstevel@tonic-gate 				(void) pthread_cond_wait(&(main_thr.thd_cv),
3900Sstevel@tonic-gate 				    &(main_thr.thd_mutex));
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&(main_thr.thd_mutex));
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 			running = 0;	/* Close down auditing and exit */
3950Sstevel@tonic-gate 		} else if (caught_readc) {
3960Sstevel@tonic-gate 			/*
3970Sstevel@tonic-gate 			 * if both hup and usr1 are caught, the logic in
3980Sstevel@tonic-gate 			 * loadauditlist() results in hup winning.  The
3990Sstevel@tonic-gate 			 * result will be that the audit file is not rolled
400*12918SJan.Friedel@Sun.COM 			 * over unless audit configuration actually changed.
4010Sstevel@tonic-gate 			 *
402*12918SJan.Friedel@Sun.COM 			 * They want to reread the audit configuration from
403*12918SJan.Friedel@Sun.COM 			 * smf(5) repository (AUDITD_FMRI). Set reset_list
404*12918SJan.Friedel@Sun.COM 			 * which will return us to the main while loop in the
405*12918SJan.Friedel@Sun.COM 			 * main routine.
4060Sstevel@tonic-gate 			 */
4070Sstevel@tonic-gate 			caught_readc = 0;
4080Sstevel@tonic-gate 			reset_list = 1;
4090Sstevel@tonic-gate 		} else if (caught_nextd) {
4100Sstevel@tonic-gate 			/*
411*12918SJan.Friedel@Sun.COM 			 * This is a special case for the binfile plugin.
412*12918SJan.Friedel@Sun.COM 			 * (audit -n)  NULL out kvlist so binfile won't
413*12918SJan.Friedel@Sun.COM 			 * re-read audit configuration.
4140Sstevel@tonic-gate 			 */
4150Sstevel@tonic-gate 			caught_nextd = 0;
4160Sstevel@tonic-gate 			reset_file = 1;
4170Sstevel@tonic-gate 			if (binfile != NULL) {
4180Sstevel@tonic-gate 				_kva_free(binfile->plg_kvlist);
4190Sstevel@tonic-gate 				binfile->plg_kvlist = NULL;
4200Sstevel@tonic-gate 				binfile->plg_reopen = 1;
4210Sstevel@tonic-gate 			}
4220Sstevel@tonic-gate 		}
4230Sstevel@tonic-gate 	}	/* end while (running) */
4240Sstevel@tonic-gate 	auditd_thread_close();
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 	auditd_exit(0);
4270Sstevel@tonic-gate 	return (0);
4280Sstevel@tonic-gate }
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate /*
4310Sstevel@tonic-gate  * my_sleep - sleep for SLEEP_TIME seconds but only accept the signals
4320Sstevel@tonic-gate  *	that we want to accept.  (Premature termination just means the
4330Sstevel@tonic-gate  *	caller retries more often, not a big deal.)
4340Sstevel@tonic-gate  */
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate static void
my_sleep()4370Sstevel@tonic-gate my_sleep()
4380Sstevel@tonic-gate {
4390Sstevel@tonic-gate 	DPRINT((dbfp, "auditd: sleeping for 20 seconds\n"));
4400Sstevel@tonic-gate 	/*
4410Sstevel@tonic-gate 	 * Set timer to "sleep"
4420Sstevel@tonic-gate 	 */
4430Sstevel@tonic-gate 	(void) alarm(SLEEP_TIME);
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 	DPRINT((dbfp, "main thread is waiting for SIGALRM before exit.\n"));
4460Sstevel@tonic-gate 	(void) pthread_mutex_lock(&(main_thr.thd_mutex));
4470Sstevel@tonic-gate 	(void) pthread_cond_wait(&(main_thr.thd_cv), &(main_thr.thd_mutex));
4480Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&(main_thr.thd_mutex));
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 	if (caught_term) {
451*12918SJan.Friedel@Sun.COM 		DPRINT((dbfp, "normal SIGTERM exit\n"));
4520Sstevel@tonic-gate 		/*
4530Sstevel@tonic-gate 		 * Exit, as requested.
4540Sstevel@tonic-gate 		 */
4550Sstevel@tonic-gate 		auditd_thread_close();
4560Sstevel@tonic-gate 	}
4570Sstevel@tonic-gate 	if (caught_readc)
458*12918SJan.Friedel@Sun.COM 		reset_list = 1;		/* Reread the audit configuration */
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 	caught_readc = 0;
4610Sstevel@tonic-gate 	caught_nextd = 0;
4620Sstevel@tonic-gate }
4630Sstevel@tonic-gate 
4640Sstevel@tonic-gate /*
4650Sstevel@tonic-gate  * search for $ISA/ in path and replace it with "" if auditd
4660Sstevel@tonic-gate  * is 32 bit, else "sparcv9/"  The plugin $ISA must match however
4670Sstevel@tonic-gate  * auditd was compiled.
4680Sstevel@tonic-gate  */
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate static void
isa_ified(char * path,char ** newpath)4710Sstevel@tonic-gate isa_ified(char *path, char **newpath)
4720Sstevel@tonic-gate {
4730Sstevel@tonic-gate 	char	*p, *q;
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate 	if (((p = strchr(path, '$')) != NULL) &&
4760Sstevel@tonic-gate 	    (strncmp("$ISA/", p, 5) == 0)) {
4770Sstevel@tonic-gate 		(void) memcpy(*newpath, path, p - path);
4780Sstevel@tonic-gate 		q = *newpath + (p - path);
4790Sstevel@tonic-gate #ifdef __sparcv9
4800Sstevel@tonic-gate 		q += strlcpy(q, "sparcv9/", avail_length);
4810Sstevel@tonic-gate #endif
4820Sstevel@tonic-gate 		(void) strcpy(q, p + 5);
4830Sstevel@tonic-gate 	} else
4840Sstevel@tonic-gate 		*newpath = path;
4850Sstevel@tonic-gate }
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate /*
488*12918SJan.Friedel@Sun.COM  * init_plugin first searches the existing plugin list to see if the plugin
489*12918SJan.Friedel@Sun.COM  * already has been defined; if not, it creates it and links it into the list.
490*12918SJan.Friedel@Sun.COM  * It returns a pointer to the found or created struct. Note, that
491*12918SJan.Friedel@Sun.COM  * (manual/unsupported) change of path property in audit service configuration
492*12918SJan.Friedel@Sun.COM  * for given plugin will cause a miss.
4930Sstevel@tonic-gate  */
4940Sstevel@tonic-gate /*
4950Sstevel@tonic-gate  * for 64 bits, the path name can grow 3 bytes (minus 5 for the
4960Sstevel@tonic-gate  * removed "$ISA" and plus 8 for the added "sparcv9/"
4970Sstevel@tonic-gate  */
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate #define	ISA_GROW	8 - 5
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate static plugin_t *
init_plugin(char * name,kva_t * list,int cnt_flag)5020Sstevel@tonic-gate init_plugin(char *name, kva_t *list, int cnt_flag)
5030Sstevel@tonic-gate {
5040Sstevel@tonic-gate 	plugin_t	*p, *q;
5050Sstevel@tonic-gate 	char		filepath[MAXPATHLEN + 1 + ISA_GROW];
5060Sstevel@tonic-gate 	char		*path = filepath;
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 	if (*name != '/') {
5090Sstevel@tonic-gate #ifdef  __sparcv9
5100Sstevel@tonic-gate 		(void) strcpy(filepath, "/usr/lib/security/sparcv9/");
5110Sstevel@tonic-gate #else
5120Sstevel@tonic-gate 		(void) strcpy(filepath, "/usr/lib/security/");
5130Sstevel@tonic-gate #endif
5140Sstevel@tonic-gate 		if (strlcat(filepath, name, MAXPATHLEN) >= MAXPATHLEN)
5150Sstevel@tonic-gate 			return (NULL);
5160Sstevel@tonic-gate 	} else {
5170Sstevel@tonic-gate 		if (strlen(name) > MAXPATHLEN + ISA_GROW)
5180Sstevel@tonic-gate 			return (NULL);
5190Sstevel@tonic-gate 		isa_ified(name, &path);
5200Sstevel@tonic-gate 	}
5210Sstevel@tonic-gate 	p = plugin_head;
5220Sstevel@tonic-gate 	q = plugin_head;
5230Sstevel@tonic-gate 	while (p != NULL) {
5240Sstevel@tonic-gate 		if (p->plg_path != NULL) {
5250Sstevel@tonic-gate 			if (strcmp(p->plg_path, path) == 0) {
5260Sstevel@tonic-gate 				p->plg_removed = 0;
5270Sstevel@tonic-gate 				p->plg_to_be_removed = 0;
5280Sstevel@tonic-gate 				p->plg_cnt = cnt_flag;
5290Sstevel@tonic-gate 
5300Sstevel@tonic-gate 				_kva_free(p->plg_kvlist);
531*12918SJan.Friedel@Sun.COM 				p->plg_kvlist = _kva_dup(list);
532*12918SJan.Friedel@Sun.COM 				if (list != NULL && p->plg_kvlist == NULL) {
533*12918SJan.Friedel@Sun.COM 					err_exit(NULL);
534*12918SJan.Friedel@Sun.COM 				}
5350Sstevel@tonic-gate 				p->plg_reopen = 1;
5360Sstevel@tonic-gate 				DPRINT((dbfp, "reusing %s\n", p->plg_path));
5370Sstevel@tonic-gate 				return (p);
5380Sstevel@tonic-gate 			}
5390Sstevel@tonic-gate 		}
5400Sstevel@tonic-gate 		q = p;
5410Sstevel@tonic-gate 		p = p->plg_next;
5420Sstevel@tonic-gate 	}
5430Sstevel@tonic-gate 	DPRINT((dbfp, "creating new plugin structure for %s\n", path));
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 	p = malloc(sizeof (plugin_t));
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 	if (p == NULL) {
5480Sstevel@tonic-gate 		perror("auditd");
5490Sstevel@tonic-gate 		return (NULL);
5500Sstevel@tonic-gate 	}
5510Sstevel@tonic-gate 	if (q == NULL)
5520Sstevel@tonic-gate 		plugin_head = p;
5530Sstevel@tonic-gate 	else
5540Sstevel@tonic-gate 		q->plg_next = p;
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 	p->plg_next = NULL;
5570Sstevel@tonic-gate 	p->plg_initialized = 0;
5580Sstevel@tonic-gate 	p->plg_reopen = 1;
5590Sstevel@tonic-gate 	p->plg_tid = 0;
5600Sstevel@tonic-gate 	p->plg_removed = 0;
5610Sstevel@tonic-gate 	p->plg_to_be_removed = 0;
5620Sstevel@tonic-gate 	p->plg_tossed = 0;
5630Sstevel@tonic-gate 	p->plg_queued = 0;
5640Sstevel@tonic-gate 	p->plg_output = 0;
5650Sstevel@tonic-gate 	p->plg_sequence = 1;
5660Sstevel@tonic-gate 	p->plg_last_seq_out = 0;
5670Sstevel@tonic-gate 	p->plg_path = strdup(path);
568*12918SJan.Friedel@Sun.COM 	p->plg_kvlist = _kva_dup(list);
5690Sstevel@tonic-gate 	p->plg_cnt = cnt_flag;
5700Sstevel@tonic-gate 	p->plg_retry_time = SLEEP_TIME;
5710Sstevel@tonic-gate 	p->plg_qmax = 0;
5720Sstevel@tonic-gate 	p->plg_save_q_copy = NULL;
5730Sstevel@tonic-gate 
574*12918SJan.Friedel@Sun.COM 	if (list != NULL && p->plg_kvlist == NULL || p->plg_path == NULL) {
575*12918SJan.Friedel@Sun.COM 		err_exit(NULL);
576*12918SJan.Friedel@Sun.COM 	}
577*12918SJan.Friedel@Sun.COM 
5780Sstevel@tonic-gate 	DPRINT((dbfp, "created plugin:  %s\n", path));
5790Sstevel@tonic-gate 	return (p);
5800Sstevel@tonic-gate }
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate /*
583*12918SJan.Friedel@Sun.COM  * loadauditlist() - read the auditd plugin configuration from smf(5) and
584*12918SJan.Friedel@Sun.COM  * prepare appropriate plugin related structures (plugin_t). Set cnt policy here
585*12918SJan.Friedel@Sun.COM  * based on currently active policy settings. (future could have a policy =
586*12918SJan.Friedel@Sun.COM  * {+|-}cnt entry per plugin with auditconfig providing the default)
5870Sstevel@tonic-gate  */
5880Sstevel@tonic-gate static void
loadauditlist()5890Sstevel@tonic-gate loadauditlist()
5900Sstevel@tonic-gate {
591*12918SJan.Friedel@Sun.COM 	char			*value;
592*12918SJan.Friedel@Sun.COM 	char			*endptr;
593*12918SJan.Friedel@Sun.COM 	plugin_t		*p;
594*12918SJan.Friedel@Sun.COM 	uint32_t		policy;
595*12918SJan.Friedel@Sun.COM 	int			cnt_flag;
596*12918SJan.Friedel@Sun.COM 	struct au_qctrl		kqmax;
597*12918SJan.Friedel@Sun.COM 	scf_plugin_kva_node_t	*plugin_kva_ll;
598*12918SJan.Friedel@Sun.COM 	scf_plugin_kva_node_t	*plugin_kva_ll_head;
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	if (auditon(A_GETPOLICY, (char *)&policy, 0) == -1) {
6010Sstevel@tonic-gate 		DPRINT((dbfp, "auditon(A_GETPOLICY...) failed (exit)\n"));
6020Sstevel@tonic-gate 		__audit_dowarn("auditoff", "", 0);
6030Sstevel@tonic-gate 		auditd_thread_close();
60411703SJan.Friedel@Sun.COM 		auditd_exit(1);
6050Sstevel@tonic-gate 	}
6060Sstevel@tonic-gate 	cnt_flag = ((policy & AUDIT_CNT) != 0) ? 1 : 0;
607*12918SJan.Friedel@Sun.COM 	DPRINT((dbfp, "loadauditlist: policy is to %s\n", (cnt_flag == 1) ?
6080Sstevel@tonic-gate 	    "continue" : "block"));
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate #if DEBUG
611*12918SJan.Friedel@Sun.COM 	{
612*12918SJan.Friedel@Sun.COM 		int	acresult;
613*12918SJan.Friedel@Sun.COM 		if (auditon(A_GETCOND, (caddr_t)&acresult, sizeof (int)) != 0) {
614*12918SJan.Friedel@Sun.COM 			DPRINT((dbfp, "auditon(A_GETCOND...) failed (exit)\n"));
615*12918SJan.Friedel@Sun.COM 		}
616*12918SJan.Friedel@Sun.COM 		DPRINT((dbfp, "audit cond = %d (1 is on)\n", acresult));
617*12918SJan.Friedel@Sun.COM 	}
6180Sstevel@tonic-gate #endif
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 	if (auditon(A_GETQCTRL, (char *)&kqmax, sizeof (struct au_qctrl)) !=
6220Sstevel@tonic-gate 	    0) {
6230Sstevel@tonic-gate 		DPRINT((dbfp, "auditon(A_GETQCTRL...) failed (exit)\n"));
6240Sstevel@tonic-gate 		__audit_dowarn("auditoff", "", 0);
6250Sstevel@tonic-gate 		auditd_thread_close();
62611703SJan.Friedel@Sun.COM 		auditd_exit(1);
6270Sstevel@tonic-gate 	}
6280Sstevel@tonic-gate 	kqmax.aq_hiwater *= 5;		/* RAM is cheaper in userspace */
629*12918SJan.Friedel@Sun.COM 	DPRINT((dbfp, "auditd: reading audit configuration\n"));
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	p = plugin_head;
6320Sstevel@tonic-gate 	/*
6330Sstevel@tonic-gate 	 * two-step on setting p->plg_removed because the input thread
6340Sstevel@tonic-gate 	 * in doorway.c uses p->plg_removed to decide if the plugin is
6350Sstevel@tonic-gate 	 * active.
6360Sstevel@tonic-gate 	 */
6370Sstevel@tonic-gate 	while (p != NULL) {
638*12918SJan.Friedel@Sun.COM 		DPRINT((dbfp, "loadauditlist: %p, %s previously created\n",
63911129SJan.Friedel@Sun.COM 		    (void *)p, p->plg_path));
6400Sstevel@tonic-gate 		p->plg_to_be_removed = 1;	/* tentative removal */
6410Sstevel@tonic-gate 		p = p->plg_next;
6420Sstevel@tonic-gate 	}
643*12918SJan.Friedel@Sun.COM 
644*12918SJan.Friedel@Sun.COM 	if (!do_getpluginconfig_scf(NULL, &plugin_kva_ll)) {
645*12918SJan.Friedel@Sun.COM 		DPRINT((dbfp, "Could not get plugin configuration.\n"));
646*12918SJan.Friedel@Sun.COM 		auditd_thread_close();
647*12918SJan.Friedel@Sun.COM 		auditd_exit(1);
648*12918SJan.Friedel@Sun.COM 	}
649*12918SJan.Friedel@Sun.COM 	plugin_kva_ll_head = plugin_kva_ll;
650*12918SJan.Friedel@Sun.COM 
651*12918SJan.Friedel@Sun.COM 	while (plugin_kva_ll != NULL) {
652*12918SJan.Friedel@Sun.COM 		DPRINT((dbfp, "loadauditlist: starting with %s",
653*12918SJan.Friedel@Sun.COM 		    plugin_kva_ll->plugin_name));
654*12918SJan.Friedel@Sun.COM 
655*12918SJan.Friedel@Sun.COM 		/* skip inactive plugins */
656*12918SJan.Friedel@Sun.COM 		value = kva_match(plugin_kva_ll->plugin_kva, PLUGIN_ACTIVE);
657*12918SJan.Friedel@Sun.COM 		if (strcmp(value, "1") != 0) {
658*12918SJan.Friedel@Sun.COM 			DPRINT((dbfp, " (inactive:%s) skipping..\n", value));
659*12918SJan.Friedel@Sun.COM 			plugin_kva_ll = plugin_kva_ll->next;
660*12918SJan.Friedel@Sun.COM 			continue;
6610Sstevel@tonic-gate 		}
662*12918SJan.Friedel@Sun.COM 		DPRINT((dbfp, " (active)\n"));
663*12918SJan.Friedel@Sun.COM 
664*12918SJan.Friedel@Sun.COM 		value = kva_match(plugin_kva_ll->plugin_kva, PLUGIN_PATH);
665*12918SJan.Friedel@Sun.COM 		DPRINT((dbfp, "loadauditlist: have an entry for %s (%s)\n",
666*12918SJan.Friedel@Sun.COM 		    plugin_kva_ll->plugin_name, value));
6670Sstevel@tonic-gate 
668*12918SJan.Friedel@Sun.COM 		p = init_plugin(value, plugin_kva_ll->plugin_kva, cnt_flag);
669*12918SJan.Friedel@Sun.COM 		if (p == NULL) {
670*12918SJan.Friedel@Sun.COM 			DPRINT((dbfp, "Unsuccessful plugin_t "
671*12918SJan.Friedel@Sun.COM 			    "initialization.\n"));
672*12918SJan.Friedel@Sun.COM 			my_sleep();
673*12918SJan.Friedel@Sun.COM 			continue;
674*12918SJan.Friedel@Sun.COM 		}
6750Sstevel@tonic-gate 
676*12918SJan.Friedel@Sun.COM 		if (strcmp(plugin_kva_ll->plugin_name, "audit_binfile") == 0) {
677*12918SJan.Friedel@Sun.COM 			binfile = p;
678*12918SJan.Friedel@Sun.COM 		}
679*12918SJan.Friedel@Sun.COM 
680*12918SJan.Friedel@Sun.COM 		p->plg_qmax = kqmax.aq_hiwater; /* default */
681*12918SJan.Friedel@Sun.COM 		value = kva_match(plugin_kva_ll->plugin_kva, PLUGIN_QSIZE);
682*12918SJan.Friedel@Sun.COM 		if (value != NULL) {
683*12918SJan.Friedel@Sun.COM 			long	tmp;
684*12918SJan.Friedel@Sun.COM 			tmp = strtol(value, &endptr, 10);
685*12918SJan.Friedel@Sun.COM 			if (*endptr == '\0' && tmp != 0) {
686*12918SJan.Friedel@Sun.COM 				p->plg_qmax = tmp;
6870Sstevel@tonic-gate 			}
6880Sstevel@tonic-gate 		}
689*12918SJan.Friedel@Sun.COM 		DPRINT((dbfp, "%s queue max = %d\n", p->plg_path, p->plg_qmax));
6900Sstevel@tonic-gate 
691*12918SJan.Friedel@Sun.COM 		plugin_kva_ll = plugin_kva_ll->next;
692*12918SJan.Friedel@Sun.COM 	}
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate 	p = plugin_head;
6950Sstevel@tonic-gate 	while (p != NULL) {
6960Sstevel@tonic-gate 		DPRINT((dbfp, "loadauditlist: %s remove flag=%d; cnt=%d\n",
6970Sstevel@tonic-gate 		    p->plg_path, p->plg_to_be_removed, p->plg_cnt));
6980Sstevel@tonic-gate 		p->plg_removed = p->plg_to_be_removed;
6990Sstevel@tonic-gate 		p = p->plg_next;
7000Sstevel@tonic-gate 	}
701*12918SJan.Friedel@Sun.COM 
702*12918SJan.Friedel@Sun.COM 	plugin_kva_ll_free(plugin_kva_ll_head);
7030Sstevel@tonic-gate }
7040Sstevel@tonic-gate 
7050Sstevel@tonic-gate /*
7060Sstevel@tonic-gate  * block signals -- thread-specific blocking of the signals expected
7070Sstevel@tonic-gate  * by the main thread.
7080Sstevel@tonic-gate  */
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate static void
block_signals()7110Sstevel@tonic-gate block_signals()
7120Sstevel@tonic-gate {
7130Sstevel@tonic-gate 	sigset_t	set;
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 	(void) sigfillset(&set);
7160Sstevel@tonic-gate 	(void) pthread_sigmask(SIG_BLOCK, &set, NULL);
7170Sstevel@tonic-gate }
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate /*
7200Sstevel@tonic-gate  * signal_thread is the designated signal catcher.  It wakes up the
7210Sstevel@tonic-gate  * main thread whenever it receives a signal and then goes back to
7220Sstevel@tonic-gate  * sleep; it does not exit.  The global variables caught_* let
7230Sstevel@tonic-gate  * the main thread which signal was received.
7240Sstevel@tonic-gate  *
7250Sstevel@tonic-gate  * The thread is created with all signals blocked.
7260Sstevel@tonic-gate  */
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate static void
signal_thread()7290Sstevel@tonic-gate signal_thread()
7300Sstevel@tonic-gate {
7310Sstevel@tonic-gate 	sigset_t	set;
7320Sstevel@tonic-gate 	int		signal_caught;
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 	DPRINT((dbfp, "the signal thread is thread %d\n",
7350Sstevel@tonic-gate 	    pthread_self()));
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 	(void) sigemptyset(&set);
7380Sstevel@tonic-gate 	(void) sigaddset(&set, SIGALRM);
739*12918SJan.Friedel@Sun.COM 	(void) sigaddset(&set, SIGTERM);
740*12918SJan.Friedel@Sun.COM 	(void) sigaddset(&set, SIGHUP);
741*12918SJan.Friedel@Sun.COM 	(void) sigaddset(&set, SIGUSR1);
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate 	for (;;) {
7440Sstevel@tonic-gate 		signal_caught = sigwait(&set);
7450Sstevel@tonic-gate 		switch (signal_caught) {
7460Sstevel@tonic-gate 		case SIGALRM:
7470Sstevel@tonic-gate 			caught_alrm++;
7480Sstevel@tonic-gate 			DPRINT((dbfp, "caught SIGALRM\n"));
7490Sstevel@tonic-gate 			break;
750*12918SJan.Friedel@Sun.COM 		case SIGTERM:
7510Sstevel@tonic-gate 			caught_term++;
752*12918SJan.Friedel@Sun.COM 			DPRINT((dbfp, "caught SIGTERM\n"));
7530Sstevel@tonic-gate 			break;
754*12918SJan.Friedel@Sun.COM 		case SIGHUP:
7550Sstevel@tonic-gate 			caught_readc++;
756*12918SJan.Friedel@Sun.COM 			DPRINT((dbfp, "caught SIGHUP\n"));
7570Sstevel@tonic-gate 			break;
758*12918SJan.Friedel@Sun.COM 		case SIGUSR1:
7590Sstevel@tonic-gate 			caught_nextd++;
760*12918SJan.Friedel@Sun.COM 			DPRINT((dbfp, "caught SIGUSR1\n"));
7610Sstevel@tonic-gate 			break;
7620Sstevel@tonic-gate 		default:
7630Sstevel@tonic-gate 			DPRINT((dbfp, "caught unexpected signal:  %d\n",
7640Sstevel@tonic-gate 			    signal_caught));
7650Sstevel@tonic-gate 			break;
7660Sstevel@tonic-gate 		}
7670Sstevel@tonic-gate 		(void) pthread_cond_signal(&(main_thr.thd_cv));
7680Sstevel@tonic-gate 	}
7690Sstevel@tonic-gate }
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate /*
7720Sstevel@tonic-gate  * do_sethost - do auditon(2) to set the audit host-id.
7737091Sgww  *		Returns 0 if success or -1 otherwise.
7740Sstevel@tonic-gate  */
7750Sstevel@tonic-gate static int
do_sethost(void)7760Sstevel@tonic-gate do_sethost(void)
7770Sstevel@tonic-gate {
7787091Sgww 	au_tid_addr_t	*termid;
7790Sstevel@tonic-gate 	auditinfo_addr_t	audit_info;
7807091Sgww 	char	msg[512];
7810Sstevel@tonic-gate 
7827091Sgww 	if (adt_load_hostname(NULL, (adt_termid_t **)&termid) < 0) {
7837091Sgww 		(void) snprintf(msg, sizeof (msg), "unable to get local "
7847091Sgww 		    "IP address: %s", strerror(errno));
7857091Sgww 		goto fail;
7860Sstevel@tonic-gate 	}
7877091Sgww 	/* Get current kernel audit info, and fill in the IP address */
7887091Sgww 	if (auditon(A_GETKAUDIT, (caddr_t)&audit_info,
7897091Sgww 	    sizeof (audit_info)) < 0) {
7907091Sgww 		(void) snprintf(msg, sizeof (msg), "unable to get kernel "
7917091Sgww 		    "audit info: %s", strerror(errno));
7927091Sgww 		goto fail;
7930Sstevel@tonic-gate 	}
7940Sstevel@tonic-gate 
7957091Sgww 	audit_info.ai_termid = *termid;
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate 	/* Update the kernel audit info with new IP address */
7987091Sgww 	if (auditon(A_SETKAUDIT, (caddr_t)&audit_info,
7997091Sgww 	    sizeof (audit_info)) < 0) {
8007091Sgww 		(void) snprintf(msg, sizeof (msg), "unable to set kernel "
8017091Sgww 		    "audit info: %s", strerror(errno));
8027091Sgww 		goto fail;
8030Sstevel@tonic-gate 	}
8040Sstevel@tonic-gate 
8057091Sgww 	free(termid);
8060Sstevel@tonic-gate 	return (0);
8077091Sgww 
8087091Sgww fail:
8097091Sgww 	free(termid);
8107091Sgww 	__audit_syslog("auditd", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_DAEMON,
8117091Sgww 	    LOG_ALERT, msg);
8127091Sgww 	return (-1);
8130Sstevel@tonic-gate }
81411129SJan.Friedel@Sun.COM 
81511129SJan.Friedel@Sun.COM /*
81611129SJan.Friedel@Sun.COM  * conf_to_kernel() - configure the event to class mapping; see also
81711129SJan.Friedel@Sun.COM  * auditconfig(1M) -conf option.
81811129SJan.Friedel@Sun.COM  */
81911129SJan.Friedel@Sun.COM static void
conf_to_kernel(void)82011129SJan.Friedel@Sun.COM conf_to_kernel(void)
82111129SJan.Friedel@Sun.COM {
82211129SJan.Friedel@Sun.COM 	register au_event_ent_t *evp;
82311129SJan.Friedel@Sun.COM 	register int 		i;
82411129SJan.Friedel@Sun.COM 	char			*msg;
82511129SJan.Friedel@Sun.COM 	au_evclass_map_t 	ec;
82611129SJan.Friedel@Sun.COM 	au_stat_t 		as;
82711129SJan.Friedel@Sun.COM 
82811129SJan.Friedel@Sun.COM 	if (auditon(A_GETSTAT, (caddr_t)&as, 0) != 0) {
82911129SJan.Friedel@Sun.COM 		(void) asprintf(&msg, gettext("Audit module does not appear "
83011129SJan.Friedel@Sun.COM 		    "to be loaded."));
83111703SJan.Friedel@Sun.COM 		err_exit(msg);
83211129SJan.Friedel@Sun.COM 	}
83311129SJan.Friedel@Sun.COM 
83411129SJan.Friedel@Sun.COM 	i = 0;
83511129SJan.Friedel@Sun.COM 	setauevent();
83611129SJan.Friedel@Sun.COM 	while ((evp = getauevent()) != NULL) {
83711129SJan.Friedel@Sun.COM 		if (evp->ae_number <= as.as_numevent) {
83811129SJan.Friedel@Sun.COM 			++i;
83911129SJan.Friedel@Sun.COM 			ec.ec_number = evp->ae_number;
84011129SJan.Friedel@Sun.COM 			ec.ec_class = evp->ae_class;
84111129SJan.Friedel@Sun.COM 
84211129SJan.Friedel@Sun.COM 			if (auditon(A_SETCLASS, (caddr_t)&ec,
843*12918SJan.Friedel@Sun.COM 			    sizeof (ec)) != 0) {
84411129SJan.Friedel@Sun.COM 				(void) asprintf(&msg,
84511129SJan.Friedel@Sun.COM 				    gettext("Could not configure kernel audit "
84611129SJan.Friedel@Sun.COM 				    "event to class mappings."));
84711703SJan.Friedel@Sun.COM 				err_exit(msg);
84811129SJan.Friedel@Sun.COM 			}
84911129SJan.Friedel@Sun.COM 		}
85011129SJan.Friedel@Sun.COM 	}
85111129SJan.Friedel@Sun.COM 	endauevent();
85211129SJan.Friedel@Sun.COM 
85311129SJan.Friedel@Sun.COM 	DPRINT((dbfp, "configured %d kernel events.\n", i));
85411129SJan.Friedel@Sun.COM }
85511129SJan.Friedel@Sun.COM 
85611129SJan.Friedel@Sun.COM /*
85711129SJan.Friedel@Sun.COM  * scf_to_kernel_qctrl() - update the kernel queue control parameters
85811129SJan.Friedel@Sun.COM  */
85911129SJan.Friedel@Sun.COM static void
scf_to_kernel_qctrl(void)86011129SJan.Friedel@Sun.COM scf_to_kernel_qctrl(void)
86111129SJan.Friedel@Sun.COM {
86211129SJan.Friedel@Sun.COM 	struct au_qctrl	act_qctrl;
86311129SJan.Friedel@Sun.COM 	struct au_qctrl	cfg_qctrl;
86411129SJan.Friedel@Sun.COM 	char		*msg;
86511129SJan.Friedel@Sun.COM 
86611129SJan.Friedel@Sun.COM 	if (!do_getqctrl_scf(&cfg_qctrl)) {
86711129SJan.Friedel@Sun.COM 		(void) asprintf(&msg, gettext("Unable to gather audit queue "
86811129SJan.Friedel@Sun.COM 		    "control parameters from the SMF repository."));
86911703SJan.Friedel@Sun.COM 		err_exit(msg);
87011129SJan.Friedel@Sun.COM 	}
87111129SJan.Friedel@Sun.COM 
87211129SJan.Friedel@Sun.COM 	DPRINT((dbfp, "will check and set qctrl parameters:\n"));
87311129SJan.Friedel@Sun.COM 	DPRINT((dbfp, "\thiwater: %d\n", cfg_qctrl.aq_hiwater));
87411129SJan.Friedel@Sun.COM 	DPRINT((dbfp, "\tlowater: %d\n", cfg_qctrl.aq_lowater));
87511129SJan.Friedel@Sun.COM 	DPRINT((dbfp, "\tbufsz: %d\n", cfg_qctrl.aq_bufsz));
87611129SJan.Friedel@Sun.COM 	DPRINT((dbfp, "\tdelay: %ld\n", cfg_qctrl.aq_delay));
87711129SJan.Friedel@Sun.COM 
87811129SJan.Friedel@Sun.COM 	if (auditon(A_GETQCTRL, (caddr_t)&act_qctrl, 0) != 0) {
87911129SJan.Friedel@Sun.COM 		(void) asprintf(&msg, gettext("Could not retrieve "
88011129SJan.Friedel@Sun.COM 		    "audit queue controls from kernel."));
88111703SJan.Friedel@Sun.COM 		err_exit(msg);
88211129SJan.Friedel@Sun.COM 	}
88311129SJan.Friedel@Sun.COM 
88411129SJan.Friedel@Sun.COM 	/* overwrite the default (zeros) from the qctrl configuration */
88511129SJan.Friedel@Sun.COM 	if (cfg_qctrl.aq_hiwater == 0) {
88611129SJan.Friedel@Sun.COM 		cfg_qctrl.aq_hiwater = act_qctrl.aq_hiwater;
88711129SJan.Friedel@Sun.COM 		DPRINT((dbfp, "hiwater changed to active value: %u\n",
88811129SJan.Friedel@Sun.COM 		    cfg_qctrl.aq_hiwater));
88911129SJan.Friedel@Sun.COM 	}
89011129SJan.Friedel@Sun.COM 	if (cfg_qctrl.aq_lowater == 0) {
89111129SJan.Friedel@Sun.COM 		cfg_qctrl.aq_lowater = act_qctrl.aq_lowater;
89211129SJan.Friedel@Sun.COM 		DPRINT((dbfp, "lowater changed to active value: %u\n",
89311129SJan.Friedel@Sun.COM 		    cfg_qctrl.aq_lowater));
89411129SJan.Friedel@Sun.COM 	}
89511129SJan.Friedel@Sun.COM 	if (cfg_qctrl.aq_bufsz == 0) {
89611129SJan.Friedel@Sun.COM 		cfg_qctrl.aq_bufsz = act_qctrl.aq_bufsz;
89711129SJan.Friedel@Sun.COM 		DPRINT((dbfp, "bufsz changed to active value: %u\n",
89811129SJan.Friedel@Sun.COM 		    cfg_qctrl.aq_bufsz));
89911129SJan.Friedel@Sun.COM 	}
90011129SJan.Friedel@Sun.COM 	if (cfg_qctrl.aq_delay == 0) {
90111129SJan.Friedel@Sun.COM 		cfg_qctrl.aq_delay = act_qctrl.aq_delay;
90211129SJan.Friedel@Sun.COM 		DPRINT((dbfp, "delay changed to active value: %ld\n",
90311129SJan.Friedel@Sun.COM 		    cfg_qctrl.aq_delay));
90411129SJan.Friedel@Sun.COM 	}
90511129SJan.Friedel@Sun.COM 
90611129SJan.Friedel@Sun.COM 	if (auditon(A_SETQCTRL, (caddr_t)&cfg_qctrl, 0) != 0) {
90711129SJan.Friedel@Sun.COM 		(void) asprintf(&msg,
90811129SJan.Friedel@Sun.COM 		    gettext("Could not configure audit queue controls."));
90911703SJan.Friedel@Sun.COM 		err_exit(msg);
91011129SJan.Friedel@Sun.COM 	}
91111129SJan.Friedel@Sun.COM 
91211129SJan.Friedel@Sun.COM 	DPRINT((dbfp, "qctrl parameters set\n"));
91311129SJan.Friedel@Sun.COM }
91411129SJan.Friedel@Sun.COM 
91511129SJan.Friedel@Sun.COM /*
91611129SJan.Friedel@Sun.COM  * scf_to_kernel_policy() - update the audit service policies
91711129SJan.Friedel@Sun.COM  */
91811129SJan.Friedel@Sun.COM static void
scf_to_kernel_policy(void)91911129SJan.Friedel@Sun.COM scf_to_kernel_policy(void)
92011129SJan.Friedel@Sun.COM {
92111129SJan.Friedel@Sun.COM 	uint32_t	policy;
92211129SJan.Friedel@Sun.COM 	char		*msg;
92311129SJan.Friedel@Sun.COM 
92411129SJan.Friedel@Sun.COM 	if (!do_getpolicy_scf(&policy)) {
92511129SJan.Friedel@Sun.COM 		(void) asprintf(&msg, gettext("Unable to get audit policy "
92611129SJan.Friedel@Sun.COM 		    "configuration from the SMF repository."));
92711703SJan.Friedel@Sun.COM 		err_exit(msg);
92811129SJan.Friedel@Sun.COM 	}
92911129SJan.Friedel@Sun.COM 
93011129SJan.Friedel@Sun.COM 	if (auditon(A_SETPOLICY, (caddr_t)&policy, 0) != 0) {
93111129SJan.Friedel@Sun.COM 		(void) asprintf(&msg,
93211129SJan.Friedel@Sun.COM 		    gettext("Could not update active policy settings."));
93311703SJan.Friedel@Sun.COM 		err_exit(msg);
93411129SJan.Friedel@Sun.COM 	}
93511129SJan.Friedel@Sun.COM 
93611129SJan.Friedel@Sun.COM 	DPRINT((dbfp, "kernel policy settings updated\n"));
93711129SJan.Friedel@Sun.COM }
938