xref: /freebsd/contrib/openbsm/bin/auditd/auditd.c (revision c7aa572cacdeca83c35c12a378909d0b659300a9)
152267f74SRobert Watson /*-
206edd2f1SRobert Watson  * Copyright (c) 2004-2009 Apple Inc.
3ca0716f5SRobert Watson  * All rights reserved.
4ca0716f5SRobert Watson  *
5ca0716f5SRobert Watson  * Redistribution and use in source and binary forms, with or without
6ca0716f5SRobert Watson  * modification, are permitted provided that the following conditions
7ca0716f5SRobert Watson  * are met:
8ca0716f5SRobert Watson  *
9ca0716f5SRobert Watson  * 1.  Redistributions of source code must retain the above copyright
10ca0716f5SRobert Watson  *     notice, this list of conditions and the following disclaimer.
11ca0716f5SRobert Watson  * 2.  Redistributions in binary form must reproduce the above copyright
12ca0716f5SRobert Watson  *     notice, this list of conditions and the following disclaimer in the
13ca0716f5SRobert Watson  *     documentation and/or other materials provided with the distribution.
1452267f74SRobert Watson  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
15ca0716f5SRobert Watson  *     its contributors may be used to endorse or promote products derived
16ca0716f5SRobert Watson  *     from this software without specific prior written permission.
17ca0716f5SRobert Watson  *
18ca0716f5SRobert Watson  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19ca0716f5SRobert Watson  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20ca0716f5SRobert Watson  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21ca0716f5SRobert Watson  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22ca0716f5SRobert Watson  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23ca0716f5SRobert Watson  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24ca0716f5SRobert Watson  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25ca0716f5SRobert Watson  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26ca0716f5SRobert Watson  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27ca0716f5SRobert Watson  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28ca0716f5SRobert Watson  */
29ca0716f5SRobert Watson 
307a0a89d2SRobert Watson #include <sys/types.h>
3152267f74SRobert Watson 
3252267f74SRobert Watson #include <config/config.h>
3352267f74SRobert Watson 
34ca0716f5SRobert Watson #include <sys/dirent.h>
3552267f74SRobert Watson #ifdef HAVE_FULL_QUEUE_H
36ca0716f5SRobert Watson #include <sys/queue.h>
3752267f74SRobert Watson #else	/* !HAVE_FULL_QUEUE_H */
3852267f74SRobert Watson #include <compat/queue.h>
3952267f74SRobert Watson #endif	/* !HAVE_FULL_QUEUE_H */
407a0a89d2SRobert Watson #include <sys/mman.h>
417a0a89d2SRobert Watson #include <sys/param.h>
42ca0716f5SRobert Watson #include <sys/stat.h>
43ca0716f5SRobert Watson #include <sys/wait.h>
44ca0716f5SRobert Watson 
45ca0716f5SRobert Watson #include <bsm/audit.h>
46ca0716f5SRobert Watson #include <bsm/audit_uevents.h>
477a0a89d2SRobert Watson #include <bsm/auditd_lib.h>
48ca0716f5SRobert Watson #include <bsm/libbsm.h>
49ca0716f5SRobert Watson 
50506764c6SRobert Watson #include <err.h>
51ca0716f5SRobert Watson #include <errno.h>
52ca0716f5SRobert Watson #include <fcntl.h>
5323bf6e20SRobert Watson #include <grp.h>
54ca0716f5SRobert Watson #include <stdio.h>
55ca0716f5SRobert Watson #include <stdlib.h>
56ca0716f5SRobert Watson #include <time.h>
57ca0716f5SRobert Watson #include <unistd.h>
58ca0716f5SRobert Watson #include <signal.h>
59ca0716f5SRobert Watson #include <string.h>
60ca0716f5SRobert Watson 
61ca0716f5SRobert Watson #include "auditd.h"
6252267f74SRobert Watson 
6352267f74SRobert Watson #ifndef HAVE_STRLCPY
6452267f74SRobert Watson #include <compat/strlcpy.h>
6552267f74SRobert Watson #endif
66ca0716f5SRobert Watson 
677a0a89d2SRobert Watson /*
6806edd2f1SRobert Watson  * XXX The following are temporary until these can be added to the kernel
697a0a89d2SRobert Watson  * audit.h header.
707a0a89d2SRobert Watson  */
717a0a89d2SRobert Watson #ifndef	AUDIT_TRIGGER_INITIALIZE
727a0a89d2SRobert Watson #define	AUDIT_TRIGGER_INITIALIZE	7
737a0a89d2SRobert Watson #endif
7406edd2f1SRobert Watson #ifndef	AUDIT_TRIGGER_EXPIRE_TRAILS
7506edd2f1SRobert Watson #define	AUDIT_TRIGGER_EXPIRE_TRAILS	8
7606edd2f1SRobert Watson #endif
7706edd2f1SRobert Watson 
78ca0716f5SRobert Watson 
79ca0716f5SRobert Watson /*
807a0a89d2SRobert Watson  * LaunchD flag (Mac OS X and, maybe, FreeBSD only.)  See launchd(8) and
817a0a89d2SRobert Watson  * http://wiki.freebsd.org/launchd for more information.
827a0a89d2SRobert Watson  *
837a0a89d2SRobert Watson  *	In order for auditd to work "on demand" with launchd(8) it can't:
847a0a89d2SRobert Watson  *		call daemon(3)
857a0a89d2SRobert Watson  *		call fork and having the parent process exit
867a0a89d2SRobert Watson  *		change uids or gids.
877a0a89d2SRobert Watson  *		set up the current working directory or chroot.
887a0a89d2SRobert Watson  *		set the session id
897a0a89d2SRobert Watson  *		change stdio to /dev/null.
907a0a89d2SRobert Watson  *		call setrusage(2)
917a0a89d2SRobert Watson  *		call setpriority(2)
927a0a89d2SRobert Watson  *		Ignore SIGTERM.
937a0a89d2SRobert Watson  *	auditd (in 'launchd mode') is launched on demand so it must catch
947a0a89d2SRobert Watson  *	SIGTERM to exit cleanly.
957a0a89d2SRobert Watson  */
967a0a89d2SRobert Watson static int	launchd_flag = 0;
977a0a89d2SRobert Watson 
987a0a89d2SRobert Watson /*
997a0a89d2SRobert Watson  * The GID of the audit review group (if used).  The audit trail files and
1007a0a89d2SRobert Watson  * system logs (Mac OS X only) can only be reviewed by members of this group
1017a0a89d2SRobert Watson  * or the audit administrator (aka. "root").
1027a0a89d2SRobert Watson  */
1037a0a89d2SRobert Watson static gid_t	audit_review_gid = -1;
1047a0a89d2SRobert Watson 
1057a0a89d2SRobert Watson /*
1067a0a89d2SRobert Watson  * The path and file name of the last audit trail file.
1077a0a89d2SRobert Watson  */
1087a0a89d2SRobert Watson static char	*lastfile = NULL;
1097a0a89d2SRobert Watson 
1107a0a89d2SRobert Watson /*
1117a0a89d2SRobert Watson  * Error starting auditd. Run warn script and exit.
112ca0716f5SRobert Watson  */
113ca0716f5SRobert Watson static void
fail_exit(void)114ca0716f5SRobert Watson fail_exit(void)
115ca0716f5SRobert Watson {
116ca0716f5SRobert Watson 
117ca0716f5SRobert Watson 	audit_warn_nostart();
118ca0716f5SRobert Watson 	exit(1);
119ca0716f5SRobert Watson }
120ca0716f5SRobert Watson 
121ca0716f5SRobert Watson /*
1227a0a89d2SRobert Watson  * Follow the 'current' symlink to get the active trail file name.
123ca0716f5SRobert Watson  */
124ca0716f5SRobert Watson static char *
get_curfile(void)1257a0a89d2SRobert Watson get_curfile(void)
126ca0716f5SRobert Watson {
1277a0a89d2SRobert Watson 	char *cf;
1287a0a89d2SRobert Watson 	int len;
129ca0716f5SRobert Watson 
1307a0a89d2SRobert Watson 	cf = malloc(MAXPATHLEN);
1317a0a89d2SRobert Watson 	if (cf == NULL) {
1327a0a89d2SRobert Watson 		auditd_log_err("malloc failed: %m");
133ca0716f5SRobert Watson 		return (NULL);
13452267f74SRobert Watson 	}
1357a0a89d2SRobert Watson 
1367a0a89d2SRobert Watson 	len = readlink(AUDIT_CURRENT_LINK, cf, MAXPATHLEN - 1);
1377a0a89d2SRobert Watson 	if (len < 0) {
1387a0a89d2SRobert Watson 		free(cf);
1397a0a89d2SRobert Watson 		return (NULL);
1407a0a89d2SRobert Watson 	}
1417a0a89d2SRobert Watson 
1427a0a89d2SRobert Watson 	/* readlink() doesn't terminate string. */
1437a0a89d2SRobert Watson 	cf[len] = '\0';
1447a0a89d2SRobert Watson 
1457a0a89d2SRobert Watson 	return (cf);
146ca0716f5SRobert Watson }
147ca0716f5SRobert Watson 
148ca0716f5SRobert Watson /*
149ca0716f5SRobert Watson  * Close the previous audit trail file.
150ca0716f5SRobert Watson  */
151ca0716f5SRobert Watson static int
close_lastfile(char * TS)152ca0716f5SRobert Watson close_lastfile(char *TS)
153ca0716f5SRobert Watson {
154ca0716f5SRobert Watson 	char *ptr;
155ca0716f5SRobert Watson 	char *oldname;
156ca0716f5SRobert Watson 
1577a0a89d2SRobert Watson 	/* If lastfile is NULL try to get it from the 'current' link.  */
1587a0a89d2SRobert Watson 	if (lastfile == NULL)
1597a0a89d2SRobert Watson 		lastfile = get_curfile();
1607a0a89d2SRobert Watson 
161ca0716f5SRobert Watson 	if (lastfile != NULL) {
162aa772005SRobert Watson 		oldname = strdup(lastfile);
163ca0716f5SRobert Watson 		if (oldname == NULL)
164ca0716f5SRobert Watson 			return (-1);
165ca0716f5SRobert Watson 
166ca0716f5SRobert Watson 		/* Rename the last file -- append timestamp. */
167ca0716f5SRobert Watson 		if ((ptr = strstr(lastfile, NOT_TERMINATED)) != NULL) {
16806edd2f1SRobert Watson 			memcpy(ptr, TS, POSTFIX_LEN);
169aa772005SRobert Watson 			if (auditd_rename(oldname, lastfile) != 0)
1707a0a89d2SRobert Watson 				auditd_log_err(
171bb97b418SRobert Watson 				    "Could not rename %s to %s: %m", oldname,
172bb97b418SRobert Watson 				    lastfile);
1734bd0c025SRobert Watson 			else {
1747a0a89d2SRobert Watson 				/*
1757a0a89d2SRobert Watson 				 * Remove the 'current' symlink since the link
1767a0a89d2SRobert Watson 				 * is now invalid.
1777a0a89d2SRobert Watson 				 */
1787a0a89d2SRobert Watson 				(void) unlink(AUDIT_CURRENT_LINK);
1797a0a89d2SRobert Watson 				auditd_log_notice("renamed %s to %s",
180ca0716f5SRobert Watson 				    oldname, lastfile);
1814bd0c025SRobert Watson 				audit_warn_closefile(lastfile);
1824bd0c025SRobert Watson 			}
18352267f74SRobert Watson 		} else
1847a0a89d2SRobert Watson 			auditd_log_err("Could not rename %s to %s", oldname,
18552267f74SRobert Watson 			    lastfile);
186ca0716f5SRobert Watson 		free(lastfile);
187ca0716f5SRobert Watson 		free(oldname);
188ca0716f5SRobert Watson 		lastfile = NULL;
189ca0716f5SRobert Watson 	}
190ca0716f5SRobert Watson 	return (0);
191ca0716f5SRobert Watson }
192ca0716f5SRobert Watson 
193ca0716f5SRobert Watson /*
194ca0716f5SRobert Watson  * Create the new file name, swap with existing audit file.
195ca0716f5SRobert Watson  */
196ca0716f5SRobert Watson static int
swap_audit_file(void)197ca0716f5SRobert Watson swap_audit_file(void)
198ca0716f5SRobert Watson {
1997a0a89d2SRobert Watson 	int err;
200aa772005SRobert Watson 	char *newfile, *name;
201aa772005SRobert Watson 	char TS[TIMESTAMP_LEN + 1];
2027a0a89d2SRobert Watson 	time_t tt;
203ca0716f5SRobert Watson 
204aa772005SRobert Watson 	if (getTSstr(tt, TS, sizeof(TS)) != 0)
205ca0716f5SRobert Watson 		return (-1);
206aa772005SRobert Watson 	/*
207aa772005SRobert Watson 	 * If prefix and suffix are the same, it means that records are
208aa772005SRobert Watson 	 * being produced too fast. We don't want to rename now, because
209aa772005SRobert Watson 	 * next trail file can get the same name and once that one is
210aa772005SRobert Watson 	 * terminated also within one second it will overwrite the current
211aa772005SRobert Watson 	 * one. Just keep writing to the same trail and wait for the next
212aa772005SRobert Watson 	 * trigger from the kernel.
213aa772005SRobert Watson 	 * FREEBSD KERNEL WAS UPDATED TO KEEP SENDING TRIGGERS, WHICH MIGHT
214aa772005SRobert Watson 	 * NOT BE THE CASE FOR OTHER OSES.
215aa772005SRobert Watson 	 * If the kernel will not keep sending triggers, trail file will not
216aa772005SRobert Watson 	 * be terminated.
217aa772005SRobert Watson 	 */
218aa772005SRobert Watson 	if (lastfile == NULL) {
219aa772005SRobert Watson 		name = NULL;
220aa772005SRobert Watson 	} else {
221aa772005SRobert Watson 		name = strrchr(lastfile, '/');
222aa772005SRobert Watson 		if (name != NULL)
223aa772005SRobert Watson 			name++;
224aa772005SRobert Watson 	}
225aa772005SRobert Watson 	if (name != NULL && strncmp(name, TS, TIMESTAMP_LEN) == 0) {
226aa772005SRobert Watson 		auditd_log_debug("Not ready to terminate trail file yet.");
227aa772005SRobert Watson 		return (0);
228aa772005SRobert Watson 	}
2297a0a89d2SRobert Watson 	err = auditd_swap_trail(TS, &newfile, audit_review_gid,
2307a0a89d2SRobert Watson 	    audit_warn_getacdir);
2317a0a89d2SRobert Watson 	if (err != ADE_NOERR) {
2327a0a89d2SRobert Watson 		auditd_log_err("%s: %m", auditd_strerror(err));
2337a0a89d2SRobert Watson 		if (err != ADE_ACTL)
234ca0716f5SRobert Watson 			return (-1);
235ca0716f5SRobert Watson 	}
236ca0716f5SRobert Watson 
237ca0716f5SRobert Watson 	/*
2387a0a89d2SRobert Watson 	 * Only close the last file if were in an auditing state before
2397a0a89d2SRobert Watson 	 * calling swap_audit_file().  We may need to recover from a crash.
240ca0716f5SRobert Watson 	 */
2417a0a89d2SRobert Watson 	if (auditd_get_state() == AUD_STATE_ENABLED)
242ca0716f5SRobert Watson 		close_lastfile(TS);
2437a0a89d2SRobert Watson 
2447a0a89d2SRobert Watson 
2457a0a89d2SRobert Watson 	/*
2467a0a89d2SRobert Watson 	 * auditd_swap_trail() potentially enables auditing (if not already
2477a0a89d2SRobert Watson 	 * enabled) so updated the cached state as well.
2487a0a89d2SRobert Watson 	 */
2497a0a89d2SRobert Watson 	auditd_set_state(AUD_STATE_ENABLED);
2507a0a89d2SRobert Watson 
2517a0a89d2SRobert Watson 	/*
2527a0a89d2SRobert Watson 	 *  Create 'current' symlink.  Recover from crash, if needed.
2537a0a89d2SRobert Watson 	 */
2547a0a89d2SRobert Watson 	if (auditd_new_curlink(newfile) != 0)
2557a0a89d2SRobert Watson 		auditd_log_err("auditd_new_curlink(\"%s\") failed: %s: %m",
2567a0a89d2SRobert Watson 		    newfile, auditd_strerror(err));
2577a0a89d2SRobert Watson 
2587a0a89d2SRobert Watson 	lastfile = newfile;
2597a0a89d2SRobert Watson 	auditd_log_notice("New audit file is %s", newfile);
2607a0a89d2SRobert Watson 
261ca0716f5SRobert Watson 	return (0);
262ca0716f5SRobert Watson }
263ca0716f5SRobert Watson 
264ca0716f5SRobert Watson /*
2657a0a89d2SRobert Watson  * Create a new audit log trail file and swap with the current one, if any.
266ca0716f5SRobert Watson  */
267ca0716f5SRobert Watson static int
do_trail_file(void)2687a0a89d2SRobert Watson do_trail_file(void)
269ca0716f5SRobert Watson {
2707a0a89d2SRobert Watson 	int err;
271ca0716f5SRobert Watson 
272ca0716f5SRobert Watson 	/*
2737a0a89d2SRobert Watson 	 * First, refresh the list of audit log directories.
274ca0716f5SRobert Watson 	 */
2757a0a89d2SRobert Watson 	err = auditd_read_dirs(audit_warn_soft, audit_warn_hard);
2767a0a89d2SRobert Watson 	if (err) {
277c74c7b73SRobert Watson 		auditd_log_err("auditd_read_dirs(): %s",
2787a0a89d2SRobert Watson 		    auditd_strerror(err));
2797a0a89d2SRobert Watson 		if (err == ADE_HARDLIM)
2807a0a89d2SRobert Watson 			audit_warn_allhard();
2817a0a89d2SRobert Watson 		if (err != ADE_SOFTLIM)
2827a0a89d2SRobert Watson 			return (-1);
2837a0a89d2SRobert Watson 		else
2847a0a89d2SRobert Watson 			audit_warn_allsoft();
2857a0a89d2SRobert Watson 			/* continue on with soft limit error */
2867a0a89d2SRobert Watson 	}
287ca0716f5SRobert Watson 
288ca0716f5SRobert Watson 	/*
2897a0a89d2SRobert Watson 	 * Create a new file and swap with the one being used in kernel.
290ca0716f5SRobert Watson 	 */
291ca0716f5SRobert Watson 	if (swap_audit_file() == -1) {
292ca0716f5SRobert Watson 		/*
293ca0716f5SRobert Watson 		 * XXX Faulty directory listing? - user should be given
294ca0716f5SRobert Watson 		 * XXX an opportunity to change the audit_control file
295ca0716f5SRobert Watson 		 * XXX switch to a reduced mode of auditing?
296ca0716f5SRobert Watson 		 */
297ca0716f5SRobert Watson 		return (-1);
298ca0716f5SRobert Watson 	}
299ca0716f5SRobert Watson 
30006edd2f1SRobert Watson 	/*
30106edd2f1SRobert Watson 	 * Finally, see if there are any trail files to expire.
30206edd2f1SRobert Watson 	 */
30306edd2f1SRobert Watson 	err = auditd_expire_trails(audit_warn_expired);
30406edd2f1SRobert Watson 	if (err)
30506edd2f1SRobert Watson 		auditd_log_err("auditd_expire_trails(): %s",
30606edd2f1SRobert Watson 		    auditd_strerror(err));
30706edd2f1SRobert Watson 
3087a0a89d2SRobert Watson 	return (0);
309ca0716f5SRobert Watson }
310ca0716f5SRobert Watson 
3117a0a89d2SRobert Watson /*
3127a0a89d2SRobert Watson  * Start up auditing.
3137a0a89d2SRobert Watson  */
3147a0a89d2SRobert Watson static void
audit_setup(void)3157a0a89d2SRobert Watson audit_setup(void)
3167a0a89d2SRobert Watson {
3177a0a89d2SRobert Watson 	int err;
3187a0a89d2SRobert Watson 
319aa772005SRobert Watson 	/* Configure trail files distribution. */
320aa772005SRobert Watson 	err = auditd_set_dist();
321aa772005SRobert Watson 	if (err) {
322aa772005SRobert Watson 		auditd_log_err("auditd_set_dist() %s: %m",
323aa772005SRobert Watson 		    auditd_strerror(err));
324aa772005SRobert Watson 	} else
325aa772005SRobert Watson 		auditd_log_debug("Configured trail files distribution.");
326aa772005SRobert Watson 
3277a0a89d2SRobert Watson 	if (do_trail_file() == -1) {
3287a0a89d2SRobert Watson 		auditd_log_err("Error creating audit trail file");
3297a0a89d2SRobert Watson 		fail_exit();
3307a0a89d2SRobert Watson 	}
3317a0a89d2SRobert Watson 
3327a0a89d2SRobert Watson 	/* Generate an audit record. */
3337a0a89d2SRobert Watson 	err = auditd_gen_record(AUE_audit_startup, NULL);
3347a0a89d2SRobert Watson 	if (err)
3357a0a89d2SRobert Watson 		auditd_log_err("auditd_gen_record(AUE_audit_startup) %s: %m",
3367a0a89d2SRobert Watson 		    auditd_strerror(err));
3377a0a89d2SRobert Watson 
3387a0a89d2SRobert Watson 	if (auditd_config_controls() == 0)
3397a0a89d2SRobert Watson 		auditd_log_info("Audit controls init successful");
3407a0a89d2SRobert Watson 	else
3417a0a89d2SRobert Watson 		auditd_log_err("Audit controls init failed");
3427a0a89d2SRobert Watson }
3437a0a89d2SRobert Watson 
3447a0a89d2SRobert Watson 
3457a0a89d2SRobert Watson /*
3467a0a89d2SRobert Watson  * Close auditd pid file and trigger mechanism.
3477a0a89d2SRobert Watson  */
3487a0a89d2SRobert Watson static int
close_misc(void)3497a0a89d2SRobert Watson close_misc(void)
3507a0a89d2SRobert Watson {
3517a0a89d2SRobert Watson 
3527a0a89d2SRobert Watson 	auditd_close_dirs();
3537a0a89d2SRobert Watson 	if (unlink(AUDITD_PIDFILE) == -1 && errno != ENOENT) {
3547a0a89d2SRobert Watson 		auditd_log_err("Couldn't remove %s: %m", AUDITD_PIDFILE);
3557a0a89d2SRobert Watson 		return (1);
3567a0a89d2SRobert Watson 	}
3577a0a89d2SRobert Watson 	endac();
3587a0a89d2SRobert Watson 
3597a0a89d2SRobert Watson 	if (auditd_close_trigger() != 0) {
3607a0a89d2SRobert Watson 		auditd_log_err("Error closing trigger messaging mechanism");
3617a0a89d2SRobert Watson 		return (1);
3627a0a89d2SRobert Watson 	}
363ca0716f5SRobert Watson 	return (0);
364ca0716f5SRobert Watson }
365ca0716f5SRobert Watson 
366ca0716f5SRobert Watson /*
367ca0716f5SRobert Watson  * Close all log files, control files, and tell the audit system.
368ca0716f5SRobert Watson  */
369ca0716f5SRobert Watson static int
close_all(void)370ca0716f5SRobert Watson close_all(void)
371ca0716f5SRobert Watson {
372ca0716f5SRobert Watson 	int err_ret = 0;
373aa772005SRobert Watson 	char TS[TIMESTAMP_LEN + 1];
3747a0a89d2SRobert Watson 	int err;
375c0020399SRobert Watson 	int cond;
3767a0a89d2SRobert Watson 	time_t tt;
377ca0716f5SRobert Watson 
3787a0a89d2SRobert Watson 	err = auditd_gen_record(AUE_audit_shutdown, NULL);
3797a0a89d2SRobert Watson 	if (err)
3807a0a89d2SRobert Watson 		auditd_log_err("auditd_gen_record(AUE_audit_shutdown) %s: %m",
3817a0a89d2SRobert Watson 		    auditd_strerror(err));
382ca0716f5SRobert Watson 
383ca0716f5SRobert Watson 	/* Flush contents. */
384ca0716f5SRobert Watson 	cond = AUC_DISABLED;
385c0020399SRobert Watson 	err_ret = audit_set_cond(&cond);
386ca0716f5SRobert Watson 	if (err_ret != 0) {
3877a0a89d2SRobert Watson 		auditd_log_err("Disabling audit failed! : %s", strerror(errno));
388ca0716f5SRobert Watson 		err_ret = 1;
389ca0716f5SRobert Watson 	}
3907a0a89d2SRobert Watson 
39152267f74SRobert Watson 	/*
3927a0a89d2SRobert Watson 	 * Updated the cached state that auditing has been disabled.
39352267f74SRobert Watson 	 */
3947a0a89d2SRobert Watson 	auditd_set_state(AUD_STATE_DISABLED);
3957a0a89d2SRobert Watson 
396aa772005SRobert Watson 	if (getTSstr(tt, TS, sizeof(TS)) == 0)
397ca0716f5SRobert Watson 		close_lastfile(TS);
398ca0716f5SRobert Watson 	if (lastfile != NULL)
399ca0716f5SRobert Watson 		free(lastfile);
400ca0716f5SRobert Watson 
4017a0a89d2SRobert Watson 	err_ret += close_misc();
4027a0a89d2SRobert Watson 
4037a0a89d2SRobert Watson 	if (err_ret) {
4047a0a89d2SRobert Watson 		auditd_log_err("Could not unregister");
405ca0716f5SRobert Watson 		audit_warn_postsigterm();
406ca0716f5SRobert Watson 	}
407ca0716f5SRobert Watson 
4087a0a89d2SRobert Watson 	auditd_log_info("Finished");
4097a0a89d2SRobert Watson 	return (err_ret);
410ca0716f5SRobert Watson }
411ca0716f5SRobert Watson 
412ca0716f5SRobert Watson /*
4137a0a89d2SRobert Watson  * Register the daemon with the signal handler and the auditd pid file.
414ca0716f5SRobert Watson  */
415ca0716f5SRobert Watson static int
register_daemon(void)416ca0716f5SRobert Watson register_daemon(void)
417ca0716f5SRobert Watson {
418fb2cd86aSAlan Somers 	struct sigaction action;
419ca0716f5SRobert Watson 	FILE * pidfile;
420ca0716f5SRobert Watson 	int fd;
421ca0716f5SRobert Watson 	pid_t pid;
422ca0716f5SRobert Watson 
423ca0716f5SRobert Watson 	/* Set up the signal hander. */
424fb2cd86aSAlan Somers 	action.sa_handler = auditd_relay_signal;
425fb2cd86aSAlan Somers 	/*
426fb2cd86aSAlan Somers 	 * sa_flags must not include SA_RESTART, so that read(2) will be
427fb2cd86aSAlan Somers 	 * interruptible in auditd_wait_for_events
428fb2cd86aSAlan Somers 	 */
429fb2cd86aSAlan Somers 	action.sa_flags = 0;
430fb2cd86aSAlan Somers 	sigemptyset(&action.sa_mask);
431fb2cd86aSAlan Somers 	if (sigaction(SIGTERM, &action, NULL) != 0) {
4327a0a89d2SRobert Watson 		auditd_log_err(
433506764c6SRobert Watson 		    "Could not set signal handler for SIGTERM");
434ca0716f5SRobert Watson 		fail_exit();
435ca0716f5SRobert Watson 	}
436fb2cd86aSAlan Somers 	if (sigaction(SIGCHLD, &action, NULL) != 0) {
4377a0a89d2SRobert Watson 		auditd_log_err(
438506764c6SRobert Watson 		    "Could not set signal handler for SIGCHLD");
439ca0716f5SRobert Watson 		fail_exit();
440ca0716f5SRobert Watson 	}
441fb2cd86aSAlan Somers 	if (sigaction(SIGHUP, &action, NULL) != 0) {
4427a0a89d2SRobert Watson 		auditd_log_err(
443506764c6SRobert Watson 		    "Could not set signal handler for SIGHUP");
444ca0716f5SRobert Watson 		fail_exit();
445ca0716f5SRobert Watson 	}
446fb2cd86aSAlan Somers 	if (sigaction(SIGALRM, &action, NULL) != 0) {
4477a0a89d2SRobert Watson 		auditd_log_err(
4487a0a89d2SRobert Watson 		    "Could not set signal handler for SIGALRM");
4497a0a89d2SRobert Watson 		fail_exit();
4507a0a89d2SRobert Watson 	}
451ca0716f5SRobert Watson 
452ca0716f5SRobert Watson 	if ((pidfile = fopen(AUDITD_PIDFILE, "a")) == NULL) {
4537a0a89d2SRobert Watson 		auditd_log_err("Could not open PID file");
454ca0716f5SRobert Watson 		audit_warn_tmpfile();
455ca0716f5SRobert Watson 		return (-1);
456ca0716f5SRobert Watson 	}
457ca0716f5SRobert Watson 
458ca0716f5SRobert Watson 	/* Attempt to lock the pid file; if a lock is present, exit. */
459ca0716f5SRobert Watson 	fd = fileno(pidfile);
460ca0716f5SRobert Watson 	if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
4617a0a89d2SRobert Watson 		auditd_log_err(
462506764c6SRobert Watson 		    "PID file is locked (is another auditd running?).");
463ca0716f5SRobert Watson 		audit_warn_ebusy();
464ca0716f5SRobert Watson 		return (-1);
465ca0716f5SRobert Watson 	}
466ca0716f5SRobert Watson 
467ca0716f5SRobert Watson 	pid = getpid();
468ca0716f5SRobert Watson 	ftruncate(fd, 0);
469ca0716f5SRobert Watson 	if (fprintf(pidfile, "%u\n", pid) < 0) {
470ca0716f5SRobert Watson 		/* Should not start the daemon. */
471ca0716f5SRobert Watson 		fail_exit();
472ca0716f5SRobert Watson 	}
473ca0716f5SRobert Watson 
474ca0716f5SRobert Watson 	fflush(pidfile);
475ca0716f5SRobert Watson 	return (0);
476ca0716f5SRobert Watson }
477ca0716f5SRobert Watson 
478ca0716f5SRobert Watson /*
479bb97b418SRobert Watson  * Handle the audit trigger event.
480bb97b418SRobert Watson  *
481bb97b418SRobert Watson  * We suppress (ignore) duplicated triggers in close succession in order to
482bb97b418SRobert Watson  * try to avoid thrashing-like behavior.  However, not all triggers can be
483bb97b418SRobert Watson  * ignored, as triggers generally represent edge triggers, not level
484bb97b418SRobert Watson  * triggers, and won't be retransmitted if the condition persists.  Of
485bb97b418SRobert Watson  * specific concern is the rotate trigger -- if one is dropped, then it will
486bb97b418SRobert Watson  * not be retransmitted, and the log file will grow in an unbounded fashion.
487ca0716f5SRobert Watson  */
488ca0716f5SRobert Watson #define	DUPLICATE_INTERVAL	30
4897a0a89d2SRobert Watson void
auditd_handle_trigger(int trigger)4907a0a89d2SRobert Watson auditd_handle_trigger(int trigger)
491ca0716f5SRobert Watson {
492bb97b418SRobert Watson 	static int last_trigger, last_warning;
493ca0716f5SRobert Watson 	static time_t last_time;
494ca0716f5SRobert Watson 	struct timeval ts;
495ca0716f5SRobert Watson 	struct timezone tzp;
496ca0716f5SRobert Watson 	time_t tt;
4977a0a89d2SRobert Watson 	int au_state;
4987a0a89d2SRobert Watson 	int err = 0;
499ca0716f5SRobert Watson 
500bb97b418SRobert Watson 	/*
501bb97b418SRobert Watson 	 * Suppress duplicate messages from the kernel within the specified
502bb97b418SRobert Watson 	 * interval.
503bb97b418SRobert Watson 	 */
504ca0716f5SRobert Watson 	if (gettimeofday(&ts, &tzp) == 0) {
505ca0716f5SRobert Watson 		tt = (time_t)ts.tv_sec;
506bb97b418SRobert Watson 		switch (trigger) {
507bb97b418SRobert Watson 		case AUDIT_TRIGGER_LOW_SPACE:
508bb97b418SRobert Watson 		case AUDIT_TRIGGER_NO_SPACE:
509bb97b418SRobert Watson 			/*
510bb97b418SRobert Watson 			 * Triggers we can suppress.  Of course, we also need
511bb97b418SRobert Watson 			 * to rate limit the warnings, so apply the same
512bb97b418SRobert Watson 			 * interval limit on syslog messages.
513bb97b418SRobert Watson 			 */
514ca0716f5SRobert Watson 			if ((trigger == last_trigger) &&
515bb97b418SRobert Watson 			    (tt < (last_time + DUPLICATE_INTERVAL))) {
516bb97b418SRobert Watson 				if (tt >= (last_warning + DUPLICATE_INTERVAL))
5177a0a89d2SRobert Watson 					auditd_log_info(
518bb97b418SRobert Watson 					    "Suppressing duplicate trigger %d",
519bb97b418SRobert Watson 					    trigger);
5207a0a89d2SRobert Watson 				return;
521bb97b418SRobert Watson 			}
522bb97b418SRobert Watson 			last_warning = tt;
523bb97b418SRobert Watson 			break;
524bb97b418SRobert Watson 
525bb97b418SRobert Watson 		case AUDIT_TRIGGER_ROTATE_KERNEL:
526bb97b418SRobert Watson 		case AUDIT_TRIGGER_ROTATE_USER:
527bb97b418SRobert Watson 		case AUDIT_TRIGGER_READ_FILE:
5287a0a89d2SRobert Watson 		case AUDIT_TRIGGER_CLOSE_AND_DIE:
5297a0a89d2SRobert Watson 		case AUDIT_TRIGGER_INITIALIZE:
530bb97b418SRobert Watson 			/*
531bb97b418SRobert Watson 			 * Triggers that we cannot suppress.
532bb97b418SRobert Watson 			 */
533bb97b418SRobert Watson 			break;
534bb97b418SRobert Watson 		}
535bb97b418SRobert Watson 
536bb97b418SRobert Watson 		/*
537bb97b418SRobert Watson 		 * Only update last_trigger after aborting due to a duplicate
538bb97b418SRobert Watson 		 * trigger, not before, or we will never allow that trigger
539bb97b418SRobert Watson 		 * again.
540bb97b418SRobert Watson 		 */
541ca0716f5SRobert Watson 		last_trigger = trigger;
542ca0716f5SRobert Watson 		last_time = tt;
543ca0716f5SRobert Watson 	}
544ca0716f5SRobert Watson 
5457a0a89d2SRobert Watson 	au_state = auditd_get_state();
5467a0a89d2SRobert Watson 
547ca0716f5SRobert Watson 	/*
548ca0716f5SRobert Watson 	 * Message processing is done here.
549ca0716f5SRobert Watson 	 */
550ca0716f5SRobert Watson 	switch(trigger) {
551ca0716f5SRobert Watson 	case AUDIT_TRIGGER_LOW_SPACE:
5527a0a89d2SRobert Watson 		auditd_log_notice("Got low space trigger");
5537a0a89d2SRobert Watson 		if (do_trail_file() == -1)
5547a0a89d2SRobert Watson 			auditd_log_err("Error swapping audit file");
555ca0716f5SRobert Watson 		break;
556ca0716f5SRobert Watson 
557ca0716f5SRobert Watson 	case AUDIT_TRIGGER_NO_SPACE:
5587a0a89d2SRobert Watson 		auditd_log_notice("Got no space trigger");
5597a0a89d2SRobert Watson 		if (do_trail_file() == -1)
5607a0a89d2SRobert Watson 			auditd_log_err("Error swapping audit file");
561ca0716f5SRobert Watson 		break;
562ca0716f5SRobert Watson 
563bb97b418SRobert Watson 	case AUDIT_TRIGGER_ROTATE_KERNEL:
564bb97b418SRobert Watson 	case AUDIT_TRIGGER_ROTATE_USER:
5657a0a89d2SRobert Watson 		auditd_log_info("Got open new trigger from %s", trigger ==
566bb97b418SRobert Watson 		    AUDIT_TRIGGER_ROTATE_KERNEL ? "kernel" : "user");
5677a0a89d2SRobert Watson 		if (au_state == AUD_STATE_ENABLED && do_trail_file() == -1)
5687a0a89d2SRobert Watson 			auditd_log_err("Error swapping audit file");
569ca0716f5SRobert Watson 		break;
570ca0716f5SRobert Watson 
571ca0716f5SRobert Watson 	case AUDIT_TRIGGER_READ_FILE:
5727a0a89d2SRobert Watson 		auditd_log_info("Got read file trigger");
573c0020399SRobert Watson 		if (au_state == AUD_STATE_ENABLED) {
574c0020399SRobert Watson 			if (auditd_config_controls() == -1)
5757a0a89d2SRobert Watson 				auditd_log_err("Error setting audit controls");
576c0020399SRobert Watson 			else if (do_trail_file() == -1)
577c0020399SRobert Watson 				auditd_log_err("Error swapping audit file");
578c0020399SRobert Watson 		}
579ca0716f5SRobert Watson 		break;
580ca0716f5SRobert Watson 
5817a0a89d2SRobert Watson 	case AUDIT_TRIGGER_CLOSE_AND_DIE:
5827a0a89d2SRobert Watson 		auditd_log_info("Got close and die trigger");
5837a0a89d2SRobert Watson 		if (au_state == AUD_STATE_ENABLED)
5847a0a89d2SRobert Watson 			err = close_all();
58552267f74SRobert Watson 		/*
5867a0a89d2SRobert Watson 		 * Running under launchd don't exit.  Wait for launchd to
5877a0a89d2SRobert Watson 		 * send SIGTERM.
58852267f74SRobert Watson 		 */
5897a0a89d2SRobert Watson 		if (!launchd_flag) {
5907a0a89d2SRobert Watson 			auditd_log_info("auditd exiting.");
5917a0a89d2SRobert Watson 			exit (err);
59252267f74SRobert Watson 		}
59352267f74SRobert Watson 		break;
5947a0a89d2SRobert Watson 
5957a0a89d2SRobert Watson 	case AUDIT_TRIGGER_INITIALIZE:
5967a0a89d2SRobert Watson 		auditd_log_info("Got audit initialize trigger");
5977a0a89d2SRobert Watson 		if (au_state == AUD_STATE_DISABLED)
5987a0a89d2SRobert Watson 			audit_setup();
59952267f74SRobert Watson 		break;
6007a0a89d2SRobert Watson 
60106edd2f1SRobert Watson 	case AUDIT_TRIGGER_EXPIRE_TRAILS:
60206edd2f1SRobert Watson 		auditd_log_info("Got audit expire trails trigger");
60306edd2f1SRobert Watson 		err = auditd_expire_trails(audit_warn_expired);
60406edd2f1SRobert Watson 		if (err)
60506edd2f1SRobert Watson 			auditd_log_err("auditd_expire_trails(): %s",
60606edd2f1SRobert Watson 			    auditd_strerror(err));
60706edd2f1SRobert Watson 		break;
60806edd2f1SRobert Watson 
60952267f74SRobert Watson 	default:
6107a0a89d2SRobert Watson 		auditd_log_err("Got unknown trigger %d", trigger);
6117a0a89d2SRobert Watson 		break;
61252267f74SRobert Watson 	}
61352267f74SRobert Watson }
61452267f74SRobert Watson 
615ca0716f5SRobert Watson /*
616ca0716f5SRobert Watson  * Reap our children.
617ca0716f5SRobert Watson  */
6187a0a89d2SRobert Watson void
auditd_reap_children(void)6197a0a89d2SRobert Watson auditd_reap_children(void)
620ca0716f5SRobert Watson {
621ca0716f5SRobert Watson 	pid_t child;
622ca0716f5SRobert Watson 	int wstatus;
623ca0716f5SRobert Watson 
624ca0716f5SRobert Watson 	while ((child = waitpid(-1, &wstatus, WNOHANG)) > 0) {
625ca0716f5SRobert Watson 		if (!wstatus)
626ca0716f5SRobert Watson 			continue;
6277a0a89d2SRobert Watson 		auditd_log_info("warn process [pid=%d] %s %d.", child,
628ca0716f5SRobert Watson 		    ((WIFEXITED(wstatus)) ? "exited with non-zero status" :
629ca0716f5SRobert Watson 		    "exited as a result of signal"),
630ca0716f5SRobert Watson 		    ((WIFEXITED(wstatus)) ? WEXITSTATUS(wstatus) :
631ca0716f5SRobert Watson 		    WTERMSIG(wstatus)));
632ca0716f5SRobert Watson 	}
633ca0716f5SRobert Watson }
634ca0716f5SRobert Watson 
635506764c6SRobert Watson /*
6367a0a89d2SRobert Watson  * Reap any children and terminate.  If under launchd don't shutdown auditing
6377a0a89d2SRobert Watson  * but just the other stuff.
638506764c6SRobert Watson  */
6397a0a89d2SRobert Watson void
auditd_terminate(void)6407a0a89d2SRobert Watson auditd_terminate(void)
64152267f74SRobert Watson {
64252267f74SRobert Watson 	int ret;
64352267f74SRobert Watson 
6447a0a89d2SRobert Watson 	auditd_reap_children();
64552267f74SRobert Watson 
6467a0a89d2SRobert Watson 	if (launchd_flag)
6477a0a89d2SRobert Watson 		ret = close_misc();
648506764c6SRobert Watson 	else
6497a0a89d2SRobert Watson 		ret = close_all();
6507a0a89d2SRobert Watson 
6517a0a89d2SRobert Watson 	exit(ret);
652506764c6SRobert Watson }
653506764c6SRobert Watson 
654ca0716f5SRobert Watson /*
655ca0716f5SRobert Watson  * Configure the audit controls in the kernel: the event to class mapping,
656ca0716f5SRobert Watson  * kernel preselection mask, etc.
657ca0716f5SRobert Watson  */
6587a0a89d2SRobert Watson int
auditd_config_controls(void)6597a0a89d2SRobert Watson auditd_config_controls(void)
660ca0716f5SRobert Watson {
6617a0a89d2SRobert Watson 	int cnt, err;
6627a0a89d2SRobert Watson 	int ret = 0;
663ca0716f5SRobert Watson 
664ca0716f5SRobert Watson 	/*
6657a0a89d2SRobert Watson 	 * Configure event to class mappings in kernel.
666ca0716f5SRobert Watson 	 */
6677a0a89d2SRobert Watson 	cnt = auditd_set_evcmap();
6687a0a89d2SRobert Watson 	if (cnt < 0) {
6697a0a89d2SRobert Watson 		auditd_log_err("auditd_set_evcmap() failed: %m");
6707a0a89d2SRobert Watson 		ret = -1;
6717a0a89d2SRobert Watson 	} else if (cnt == 0) {
6727a0a89d2SRobert Watson 		auditd_log_err("No events to class mappings registered.");
6737a0a89d2SRobert Watson 		ret = -1;
674ca0716f5SRobert Watson 	} else
6757a0a89d2SRobert Watson 		auditd_log_debug("Registered %d event to class mappings.", cnt);
676ca0716f5SRobert Watson 
677ca0716f5SRobert Watson 	/*
6787a0a89d2SRobert Watson 	 * Configure non-attributable event mask in kernel.
679ca0716f5SRobert Watson 	 */
6807a0a89d2SRobert Watson 	err = auditd_set_namask();
6817a0a89d2SRobert Watson 	if (err) {
6827a0a89d2SRobert Watson 		auditd_log_err("auditd_set_namask() %s: %m",
6837a0a89d2SRobert Watson 		    auditd_strerror(err));
6847a0a89d2SRobert Watson 		ret = -1;
6854bd0c025SRobert Watson 	} else
6867a0a89d2SRobert Watson 		auditd_log_debug("Registered non-attributable event mask.");
68752267f74SRobert Watson 
68852267f74SRobert Watson 	/*
6897a0a89d2SRobert Watson 	 * Configure audit policy in kernel.
69052267f74SRobert Watson 	 */
6917a0a89d2SRobert Watson 	err = auditd_set_policy();
6927a0a89d2SRobert Watson 	if (err) {
6937a0a89d2SRobert Watson 		auditd_log_err("auditd_set_policy() %s: %m",
6947a0a89d2SRobert Watson 		    auditd_strerror(err));
6957a0a89d2SRobert Watson 		ret = -1;
69652267f74SRobert Watson 	} else
6977a0a89d2SRobert Watson 		auditd_log_debug("Set audit policy in kernel.");
69852267f74SRobert Watson 
6997a0a89d2SRobert Watson 	/*
7007a0a89d2SRobert Watson 	 * Configure audit trail log size in kernel.
7017a0a89d2SRobert Watson 	 */
7027a0a89d2SRobert Watson 	err = auditd_set_fsize();
7037a0a89d2SRobert Watson 	if (err) {
7047a0a89d2SRobert Watson 		auditd_log_err("audit_set_fsize() %s: %m",
7057a0a89d2SRobert Watson 		    auditd_strerror(err));
7067a0a89d2SRobert Watson 		ret = -1;
7077a0a89d2SRobert Watson 	} else
7087a0a89d2SRobert Watson 		auditd_log_debug("Set audit trail size in kernel.");
7097a0a89d2SRobert Watson 
7107a0a89d2SRobert Watson 	/*
7115e386598SRobert Watson 	 * Configure audit trail queue size in kernel.
7125e386598SRobert Watson 	 */
7135e386598SRobert Watson 	err = auditd_set_qsize();
7145e386598SRobert Watson 	if (err) {
715*3008333dSChristian S.J. Peron 		auditd_log_err("auditd_set_qsize() %s: %m",
7165e386598SRobert Watson 		    auditd_strerror(err));
7175e386598SRobert Watson 		ret = -1;
7185e386598SRobert Watson 	} else
7195e386598SRobert Watson 		auditd_log_debug("Set audit trail queue in kernel.");
7205e386598SRobert Watson 
7215e386598SRobert Watson 	/*
7227a0a89d2SRobert Watson 	 * Configure audit trail volume minimum free percentage of blocks in
7237a0a89d2SRobert Watson 	 * kernel.
7247a0a89d2SRobert Watson 	 */
7257a0a89d2SRobert Watson 	err = auditd_set_minfree();
7267a0a89d2SRobert Watson 	if (err) {
7277a0a89d2SRobert Watson 		auditd_log_err("auditd_set_minfree() %s: %m",
7287a0a89d2SRobert Watson 		    auditd_strerror(err));
7297a0a89d2SRobert Watson 		ret = -1;
7307a0a89d2SRobert Watson 	} else
7317a0a89d2SRobert Watson 		auditd_log_debug(
7327a0a89d2SRobert Watson 		    "Set audit trail min free percent in kernel.");
7337a0a89d2SRobert Watson 
7347a0a89d2SRobert Watson 	/*
7357a0a89d2SRobert Watson 	 * Configure host address in the audit kernel information.
7367a0a89d2SRobert Watson 	 */
7377a0a89d2SRobert Watson 	err = auditd_set_host();
7387a0a89d2SRobert Watson 	if (err) {
73906edd2f1SRobert Watson 		if (err == ADE_PARSE) {
74006edd2f1SRobert Watson 			auditd_log_notice(
74106edd2f1SRobert Watson 			    "audit_control(5) may be missing 'host:' field");
74206edd2f1SRobert Watson 		} else {
7437a0a89d2SRobert Watson 			auditd_log_err("auditd_set_host() %s: %m",
7447a0a89d2SRobert Watson 			    auditd_strerror(err));
7457a0a89d2SRobert Watson 			ret = -1;
74606edd2f1SRobert Watson 		}
7477a0a89d2SRobert Watson 	} else
7487a0a89d2SRobert Watson 		auditd_log_debug(
7497a0a89d2SRobert Watson 		    "Set audit host address information in kernel.");
7507a0a89d2SRobert Watson 
7517a0a89d2SRobert Watson 	return (ret);
7527a0a89d2SRobert Watson }
7537a0a89d2SRobert Watson 
7547a0a89d2SRobert Watson /*
7557a0a89d2SRobert Watson  * Setup and initialize auditd.
7567a0a89d2SRobert Watson  */
757ca0716f5SRobert Watson static void
setup(void)758ca0716f5SRobert Watson setup(void)
759ca0716f5SRobert Watson {
7607a0a89d2SRobert Watson 	int err;
761ca0716f5SRobert Watson 
7627a0a89d2SRobert Watson 	if (auditd_open_trigger(launchd_flag) < 0) {
7637a0a89d2SRobert Watson 		auditd_log_err("Error opening trigger messaging mechanism");
764506764c6SRobert Watson 		fail_exit();
765506764c6SRobert Watson 	}
766506764c6SRobert Watson 
767506764c6SRobert Watson 	/*
76852267f74SRobert Watson 	 * To prevent event feedback cycles and avoid auditd becoming
769506764c6SRobert Watson 	 * stalled if auditing is suspended, auditd and its children run
770506764c6SRobert Watson 	 * without their events being audited.  We allow the uid, tid, and
771506764c6SRobert Watson 	 * mask fields to be implicitly set to zero, but do set the pid.  We
772506764c6SRobert Watson 	 * run this after opening the trigger device to avoid configuring
773506764c6SRobert Watson 	 * audit state without audit present in the system.
774506764c6SRobert Watson 	 */
7757a0a89d2SRobert Watson 	err = auditd_prevent_audit();
7767a0a89d2SRobert Watson 	if (err) {
7777a0a89d2SRobert Watson 		auditd_log_err("auditd_prevent_audit() %s: %m",
7787a0a89d2SRobert Watson 		    auditd_strerror(err));
779ca0716f5SRobert Watson 		fail_exit();
780ca0716f5SRobert Watson 	}
781ca0716f5SRobert Watson 
782fdb4472cSRobert Watson 	/*
7837a0a89d2SRobert Watson 	 * Make sure auditd auditing state is correct.
784fdb4472cSRobert Watson 	 */
7857a0a89d2SRobert Watson 	auditd_set_state(AUD_STATE_INIT);
786ca0716f5SRobert Watson 
7877a0a89d2SRobert Watson 	/*
7887a0a89d2SRobert Watson 	 * If under launchd, don't start auditing.  Wait for a trigger to
7897a0a89d2SRobert Watson 	 * do so.
7907a0a89d2SRobert Watson 	 */
7917a0a89d2SRobert Watson 	if (!launchd_flag)
7927a0a89d2SRobert Watson 		audit_setup();
793ca0716f5SRobert Watson }
794ca0716f5SRobert Watson 
795ca0716f5SRobert Watson int
main(int argc,char ** argv)796ca0716f5SRobert Watson main(int argc, char **argv)
797ca0716f5SRobert Watson {
79823bf6e20SRobert Watson 	int ch;
799ca0716f5SRobert Watson 	int debug = 0;
8007a0a89d2SRobert Watson #ifdef AUDIT_REVIEW_GROUP
8017a0a89d2SRobert Watson 	struct group *grp;
8027a0a89d2SRobert Watson #endif
803ca0716f5SRobert Watson 
8047a0a89d2SRobert Watson 	while ((ch = getopt(argc, argv, "dl")) != -1) {
805ca0716f5SRobert Watson 		switch(ch) {
806ca0716f5SRobert Watson 		case 'd':
807ca0716f5SRobert Watson 			/* Debug option. */
808ca0716f5SRobert Watson 			debug = 1;
809ca0716f5SRobert Watson 			break;
810ca0716f5SRobert Watson 
8117a0a89d2SRobert Watson 		case 'l':
8127a0a89d2SRobert Watson 			/* Be launchd friendly. */
8137a0a89d2SRobert Watson 			launchd_flag = 1;
8147a0a89d2SRobert Watson 			break;
8157a0a89d2SRobert Watson 
816ca0716f5SRobert Watson 		case '?':
817ca0716f5SRobert Watson 		default:
818ca0716f5SRobert Watson 			(void)fprintf(stderr,
8197a0a89d2SRobert Watson 			    "usage: auditd [-d] [-l]\n");
820ca0716f5SRobert Watson 			exit(1);
821ca0716f5SRobert Watson 		}
822ca0716f5SRobert Watson 	}
823ca0716f5SRobert Watson 
8247a0a89d2SRobert Watson 	audit_review_gid = getgid();
82552267f74SRobert Watson 
8267a0a89d2SRobert Watson #ifdef AUDIT_REVIEW_GROUP
8277a0a89d2SRobert Watson 	/*
8287a0a89d2SRobert Watson 	 * XXXRW: Currently, this code falls back to the daemon gid, which is
8297a0a89d2SRobert Watson 	 * likely the wheel group.  Is there a better way to deal with this?
8307a0a89d2SRobert Watson 	 */
8317a0a89d2SRobert Watson 	grp = getgrnam(AUDIT_REVIEW_GROUP);
8327a0a89d2SRobert Watson 	if (grp != NULL)
8337a0a89d2SRobert Watson 		audit_review_gid = grp->gr_gid;
8343b97a967SRobert Watson #endif
835ca0716f5SRobert Watson 
8367a0a89d2SRobert Watson 	auditd_openlog(debug, audit_review_gid);
8377a0a89d2SRobert Watson 
8387a0a89d2SRobert Watson 	if (launchd_flag)
8397a0a89d2SRobert Watson 		auditd_log_info("started by launchd...");
8407a0a89d2SRobert Watson 	else
8417a0a89d2SRobert Watson 		auditd_log_info("starting...");
8427a0a89d2SRobert Watson 
8437a0a89d2SRobert Watson #ifdef AUDIT_REVIEW_GROUP
8447a0a89d2SRobert Watson 	if (grp == NULL)
8457a0a89d2SRobert Watson 		auditd_log_info(
8467a0a89d2SRobert Watson 		    "Audit review group '%s' not available, using daemon gid (%d)",
8477a0a89d2SRobert Watson 		    AUDIT_REVIEW_GROUP, audit_review_gid);
8487a0a89d2SRobert Watson #endif
8497a0a89d2SRobert Watson 	if (debug == 0 && launchd_flag == 0 && daemon(0, 0) == -1) {
8507a0a89d2SRobert Watson 		auditd_log_err("Failed to daemonize");
851ca0716f5SRobert Watson 		exit(1);
852ca0716f5SRobert Watson 	}
853ca0716f5SRobert Watson 
854ca0716f5SRobert Watson 	if (register_daemon() == -1) {
8557a0a89d2SRobert Watson 		auditd_log_err("Could not register as daemon");
856ca0716f5SRobert Watson 		exit(1);
857ca0716f5SRobert Watson 	}
858ca0716f5SRobert Watson 
859ca0716f5SRobert Watson 	setup();
860ca0716f5SRobert Watson 
8617a0a89d2SRobert Watson 	/*
8627a0a89d2SRobert Watson 	 * auditd_wait_for_events() shouldn't return unless something is wrong.
8637a0a89d2SRobert Watson 	 */
8647a0a89d2SRobert Watson 	auditd_wait_for_events();
865ca0716f5SRobert Watson 
8667a0a89d2SRobert Watson 	auditd_log_err("abnormal exit.");
8677a0a89d2SRobert Watson 	close_all();
8687a0a89d2SRobert Watson 	exit(-1);
869ca0716f5SRobert Watson }
870