xref: /freebsd/contrib/openbsm/bin/auditd/auditd.c (revision 5e386598a6d77973b93c073080f0cc574edda9e2)
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
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 *
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
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
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
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
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
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
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
416ca0716f5SRobert Watson register_daemon(void)
417ca0716f5SRobert Watson {
418ca0716f5SRobert Watson 	FILE * pidfile;
419ca0716f5SRobert Watson 	int fd;
420ca0716f5SRobert Watson 	pid_t pid;
421ca0716f5SRobert Watson 
422ca0716f5SRobert Watson 	/* Set up the signal hander. */
4237a0a89d2SRobert Watson 	if (signal(SIGTERM, auditd_relay_signal) == SIG_ERR) {
4247a0a89d2SRobert Watson 		auditd_log_err(
425506764c6SRobert Watson 		    "Could not set signal handler for SIGTERM");
426ca0716f5SRobert Watson 		fail_exit();
427ca0716f5SRobert Watson 	}
4287a0a89d2SRobert Watson 	if (signal(SIGCHLD, auditd_relay_signal) == SIG_ERR) {
4297a0a89d2SRobert Watson 		auditd_log_err(
430506764c6SRobert Watson 		    "Could not set signal handler for SIGCHLD");
431ca0716f5SRobert Watson 		fail_exit();
432ca0716f5SRobert Watson 	}
4337a0a89d2SRobert Watson 	if (signal(SIGHUP, auditd_relay_signal) == SIG_ERR) {
4347a0a89d2SRobert Watson 		auditd_log_err(
435506764c6SRobert Watson 		    "Could not set signal handler for SIGHUP");
436ca0716f5SRobert Watson 		fail_exit();
437ca0716f5SRobert Watson 	}
4387a0a89d2SRobert Watson 	if (signal(SIGALRM, auditd_relay_signal) == SIG_ERR) {
4397a0a89d2SRobert Watson 		auditd_log_err(
4407a0a89d2SRobert Watson 		    "Could not set signal handler for SIGALRM");
4417a0a89d2SRobert Watson 		fail_exit();
4427a0a89d2SRobert Watson 	}
443ca0716f5SRobert Watson 
444ca0716f5SRobert Watson 	if ((pidfile = fopen(AUDITD_PIDFILE, "a")) == NULL) {
4457a0a89d2SRobert Watson 		auditd_log_err("Could not open PID file");
446ca0716f5SRobert Watson 		audit_warn_tmpfile();
447ca0716f5SRobert Watson 		return (-1);
448ca0716f5SRobert Watson 	}
449ca0716f5SRobert Watson 
450ca0716f5SRobert Watson 	/* Attempt to lock the pid file; if a lock is present, exit. */
451ca0716f5SRobert Watson 	fd = fileno(pidfile);
452ca0716f5SRobert Watson 	if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
4537a0a89d2SRobert Watson 		auditd_log_err(
454506764c6SRobert Watson 		    "PID file is locked (is another auditd running?).");
455ca0716f5SRobert Watson 		audit_warn_ebusy();
456ca0716f5SRobert Watson 		return (-1);
457ca0716f5SRobert Watson 	}
458ca0716f5SRobert Watson 
459ca0716f5SRobert Watson 	pid = getpid();
460ca0716f5SRobert Watson 	ftruncate(fd, 0);
461ca0716f5SRobert Watson 	if (fprintf(pidfile, "%u\n", pid) < 0) {
462ca0716f5SRobert Watson 		/* Should not start the daemon. */
463ca0716f5SRobert Watson 		fail_exit();
464ca0716f5SRobert Watson 	}
465ca0716f5SRobert Watson 
466ca0716f5SRobert Watson 	fflush(pidfile);
467ca0716f5SRobert Watson 	return (0);
468ca0716f5SRobert Watson }
469ca0716f5SRobert Watson 
470ca0716f5SRobert Watson /*
471bb97b418SRobert Watson  * Handle the audit trigger event.
472bb97b418SRobert Watson  *
473bb97b418SRobert Watson  * We suppress (ignore) duplicated triggers in close succession in order to
474bb97b418SRobert Watson  * try to avoid thrashing-like behavior.  However, not all triggers can be
475bb97b418SRobert Watson  * ignored, as triggers generally represent edge triggers, not level
476bb97b418SRobert Watson  * triggers, and won't be retransmitted if the condition persists.  Of
477bb97b418SRobert Watson  * specific concern is the rotate trigger -- if one is dropped, then it will
478bb97b418SRobert Watson  * not be retransmitted, and the log file will grow in an unbounded fashion.
479ca0716f5SRobert Watson  */
480ca0716f5SRobert Watson #define	DUPLICATE_INTERVAL	30
4817a0a89d2SRobert Watson void
4827a0a89d2SRobert Watson auditd_handle_trigger(int trigger)
483ca0716f5SRobert Watson {
484bb97b418SRobert Watson 	static int last_trigger, last_warning;
485ca0716f5SRobert Watson 	static time_t last_time;
486ca0716f5SRobert Watson 	struct timeval ts;
487ca0716f5SRobert Watson 	struct timezone tzp;
488ca0716f5SRobert Watson 	time_t tt;
4897a0a89d2SRobert Watson 	int au_state;
4907a0a89d2SRobert Watson 	int err = 0;
491ca0716f5SRobert Watson 
492bb97b418SRobert Watson 	/*
493bb97b418SRobert Watson 	 * Suppress duplicate messages from the kernel within the specified
494bb97b418SRobert Watson 	 * interval.
495bb97b418SRobert Watson 	 */
496ca0716f5SRobert Watson 	if (gettimeofday(&ts, &tzp) == 0) {
497ca0716f5SRobert Watson 		tt = (time_t)ts.tv_sec;
498bb97b418SRobert Watson 		switch (trigger) {
499bb97b418SRobert Watson 		case AUDIT_TRIGGER_LOW_SPACE:
500bb97b418SRobert Watson 		case AUDIT_TRIGGER_NO_SPACE:
501bb97b418SRobert Watson 			/*
502bb97b418SRobert Watson 			 * Triggers we can suppress.  Of course, we also need
503bb97b418SRobert Watson 			 * to rate limit the warnings, so apply the same
504bb97b418SRobert Watson 			 * interval limit on syslog messages.
505bb97b418SRobert Watson 			 */
506ca0716f5SRobert Watson 			if ((trigger == last_trigger) &&
507bb97b418SRobert Watson 			    (tt < (last_time + DUPLICATE_INTERVAL))) {
508bb97b418SRobert Watson 				if (tt >= (last_warning + DUPLICATE_INTERVAL))
5097a0a89d2SRobert Watson 					auditd_log_info(
510bb97b418SRobert Watson 					    "Suppressing duplicate trigger %d",
511bb97b418SRobert Watson 					    trigger);
5127a0a89d2SRobert Watson 				return;
513bb97b418SRobert Watson 			}
514bb97b418SRobert Watson 			last_warning = tt;
515bb97b418SRobert Watson 			break;
516bb97b418SRobert Watson 
517bb97b418SRobert Watson 		case AUDIT_TRIGGER_ROTATE_KERNEL:
518bb97b418SRobert Watson 		case AUDIT_TRIGGER_ROTATE_USER:
519bb97b418SRobert Watson 		case AUDIT_TRIGGER_READ_FILE:
5207a0a89d2SRobert Watson 		case AUDIT_TRIGGER_CLOSE_AND_DIE:
5217a0a89d2SRobert Watson 		case AUDIT_TRIGGER_INITIALIZE:
522bb97b418SRobert Watson 			/*
523bb97b418SRobert Watson 			 * Triggers that we cannot suppress.
524bb97b418SRobert Watson 			 */
525bb97b418SRobert Watson 			break;
526bb97b418SRobert Watson 		}
527bb97b418SRobert Watson 
528bb97b418SRobert Watson 		/*
529bb97b418SRobert Watson 		 * Only update last_trigger after aborting due to a duplicate
530bb97b418SRobert Watson 		 * trigger, not before, or we will never allow that trigger
531bb97b418SRobert Watson 		 * again.
532bb97b418SRobert Watson 		 */
533ca0716f5SRobert Watson 		last_trigger = trigger;
534ca0716f5SRobert Watson 		last_time = tt;
535ca0716f5SRobert Watson 	}
536ca0716f5SRobert Watson 
5377a0a89d2SRobert Watson 	au_state = auditd_get_state();
5387a0a89d2SRobert Watson 
539ca0716f5SRobert Watson 	/*
540ca0716f5SRobert Watson 	 * Message processing is done here.
541ca0716f5SRobert Watson 	 */
542ca0716f5SRobert Watson 	switch(trigger) {
543ca0716f5SRobert Watson 	case AUDIT_TRIGGER_LOW_SPACE:
5447a0a89d2SRobert Watson 		auditd_log_notice("Got low space trigger");
5457a0a89d2SRobert Watson 		if (do_trail_file() == -1)
5467a0a89d2SRobert Watson 			auditd_log_err("Error swapping audit file");
547ca0716f5SRobert Watson 		break;
548ca0716f5SRobert Watson 
549ca0716f5SRobert Watson 	case AUDIT_TRIGGER_NO_SPACE:
5507a0a89d2SRobert Watson 		auditd_log_notice("Got no space trigger");
5517a0a89d2SRobert Watson 		if (do_trail_file() == -1)
5527a0a89d2SRobert Watson 			auditd_log_err("Error swapping audit file");
553ca0716f5SRobert Watson 		break;
554ca0716f5SRobert Watson 
555bb97b418SRobert Watson 	case AUDIT_TRIGGER_ROTATE_KERNEL:
556bb97b418SRobert Watson 	case AUDIT_TRIGGER_ROTATE_USER:
5577a0a89d2SRobert Watson 		auditd_log_info("Got open new trigger from %s", trigger ==
558bb97b418SRobert Watson 		    AUDIT_TRIGGER_ROTATE_KERNEL ? "kernel" : "user");
5597a0a89d2SRobert Watson 		if (au_state == AUD_STATE_ENABLED && do_trail_file() == -1)
5607a0a89d2SRobert Watson 			auditd_log_err("Error swapping audit file");
561ca0716f5SRobert Watson 		break;
562ca0716f5SRobert Watson 
563ca0716f5SRobert Watson 	case AUDIT_TRIGGER_READ_FILE:
5647a0a89d2SRobert Watson 		auditd_log_info("Got read file trigger");
565c0020399SRobert Watson 		if (au_state == AUD_STATE_ENABLED) {
566c0020399SRobert Watson 			if (auditd_config_controls() == -1)
5677a0a89d2SRobert Watson 				auditd_log_err("Error setting audit controls");
568c0020399SRobert Watson 			else if (do_trail_file() == -1)
569c0020399SRobert Watson 				auditd_log_err("Error swapping audit file");
570c0020399SRobert Watson 		}
571ca0716f5SRobert Watson 		break;
572ca0716f5SRobert Watson 
5737a0a89d2SRobert Watson 	case AUDIT_TRIGGER_CLOSE_AND_DIE:
5747a0a89d2SRobert Watson 		auditd_log_info("Got close and die trigger");
5757a0a89d2SRobert Watson 		if (au_state == AUD_STATE_ENABLED)
5767a0a89d2SRobert Watson 			err = close_all();
57752267f74SRobert Watson 		/*
5787a0a89d2SRobert Watson 		 * Running under launchd don't exit.  Wait for launchd to
5797a0a89d2SRobert Watson 		 * send SIGTERM.
58052267f74SRobert Watson 		 */
5817a0a89d2SRobert Watson 		if (!launchd_flag) {
5827a0a89d2SRobert Watson 			auditd_log_info("auditd exiting.");
5837a0a89d2SRobert Watson 			exit (err);
58452267f74SRobert Watson 		}
58552267f74SRobert Watson 		break;
5867a0a89d2SRobert Watson 
5877a0a89d2SRobert Watson 	case AUDIT_TRIGGER_INITIALIZE:
5887a0a89d2SRobert Watson 		auditd_log_info("Got audit initialize trigger");
5897a0a89d2SRobert Watson 		if (au_state == AUD_STATE_DISABLED)
5907a0a89d2SRobert Watson 			audit_setup();
59152267f74SRobert Watson 		break;
5927a0a89d2SRobert Watson 
59306edd2f1SRobert Watson 	case AUDIT_TRIGGER_EXPIRE_TRAILS:
59406edd2f1SRobert Watson 		auditd_log_info("Got audit expire trails trigger");
59506edd2f1SRobert Watson 		err = auditd_expire_trails(audit_warn_expired);
59606edd2f1SRobert Watson 		if (err)
59706edd2f1SRobert Watson 			auditd_log_err("auditd_expire_trails(): %s",
59806edd2f1SRobert Watson 			    auditd_strerror(err));
59906edd2f1SRobert Watson 		break;
60006edd2f1SRobert Watson 
60152267f74SRobert Watson 	default:
6027a0a89d2SRobert Watson 		auditd_log_err("Got unknown trigger %d", trigger);
6037a0a89d2SRobert Watson 		break;
60452267f74SRobert Watson 	}
60552267f74SRobert Watson }
60652267f74SRobert Watson 
607ca0716f5SRobert Watson /*
608ca0716f5SRobert Watson  * Reap our children.
609ca0716f5SRobert Watson  */
6107a0a89d2SRobert Watson void
6117a0a89d2SRobert Watson auditd_reap_children(void)
612ca0716f5SRobert Watson {
613ca0716f5SRobert Watson 	pid_t child;
614ca0716f5SRobert Watson 	int wstatus;
615ca0716f5SRobert Watson 
616ca0716f5SRobert Watson 	while ((child = waitpid(-1, &wstatus, WNOHANG)) > 0) {
617ca0716f5SRobert Watson 		if (!wstatus)
618ca0716f5SRobert Watson 			continue;
6197a0a89d2SRobert Watson 		auditd_log_info("warn process [pid=%d] %s %d.", child,
620ca0716f5SRobert Watson 		    ((WIFEXITED(wstatus)) ? "exited with non-zero status" :
621ca0716f5SRobert Watson 		    "exited as a result of signal"),
622ca0716f5SRobert Watson 		    ((WIFEXITED(wstatus)) ? WEXITSTATUS(wstatus) :
623ca0716f5SRobert Watson 		    WTERMSIG(wstatus)));
624ca0716f5SRobert Watson 	}
625ca0716f5SRobert Watson }
626ca0716f5SRobert Watson 
627506764c6SRobert Watson /*
6287a0a89d2SRobert Watson  * Reap any children and terminate.  If under launchd don't shutdown auditing
6297a0a89d2SRobert Watson  * but just the other stuff.
630506764c6SRobert Watson  */
6317a0a89d2SRobert Watson void
6327a0a89d2SRobert Watson auditd_terminate(void)
63352267f74SRobert Watson {
63452267f74SRobert Watson 	int ret;
63552267f74SRobert Watson 
6367a0a89d2SRobert Watson 	auditd_reap_children();
63752267f74SRobert Watson 
6387a0a89d2SRobert Watson 	if (launchd_flag)
6397a0a89d2SRobert Watson 		ret = close_misc();
640506764c6SRobert Watson 	else
6417a0a89d2SRobert Watson 		ret = close_all();
6427a0a89d2SRobert Watson 
6437a0a89d2SRobert Watson 	exit(ret);
644506764c6SRobert Watson }
645506764c6SRobert Watson 
646ca0716f5SRobert Watson /*
647ca0716f5SRobert Watson  * Configure the audit controls in the kernel: the event to class mapping,
648ca0716f5SRobert Watson  * kernel preselection mask, etc.
649ca0716f5SRobert Watson  */
6507a0a89d2SRobert Watson int
6517a0a89d2SRobert Watson auditd_config_controls(void)
652ca0716f5SRobert Watson {
6537a0a89d2SRobert Watson 	int cnt, err;
6547a0a89d2SRobert Watson 	int ret = 0;
655ca0716f5SRobert Watson 
656ca0716f5SRobert Watson 	/*
6577a0a89d2SRobert Watson 	 * Configure event to class mappings in kernel.
658ca0716f5SRobert Watson 	 */
6597a0a89d2SRobert Watson 	cnt = auditd_set_evcmap();
6607a0a89d2SRobert Watson 	if (cnt < 0) {
6617a0a89d2SRobert Watson 		auditd_log_err("auditd_set_evcmap() failed: %m");
6627a0a89d2SRobert Watson 		ret = -1;
6637a0a89d2SRobert Watson 	} else if (cnt == 0) {
6647a0a89d2SRobert Watson 		auditd_log_err("No events to class mappings registered.");
6657a0a89d2SRobert Watson 		ret = -1;
666ca0716f5SRobert Watson 	} else
6677a0a89d2SRobert Watson 		auditd_log_debug("Registered %d event to class mappings.", cnt);
668ca0716f5SRobert Watson 
669ca0716f5SRobert Watson 	/*
6707a0a89d2SRobert Watson 	 * Configure non-attributable event mask in kernel.
671ca0716f5SRobert Watson 	 */
6727a0a89d2SRobert Watson 	err = auditd_set_namask();
6737a0a89d2SRobert Watson 	if (err) {
6747a0a89d2SRobert Watson 		auditd_log_err("auditd_set_namask() %s: %m",
6757a0a89d2SRobert Watson 		    auditd_strerror(err));
6767a0a89d2SRobert Watson 		ret = -1;
6774bd0c025SRobert Watson 	} else
6787a0a89d2SRobert Watson 		auditd_log_debug("Registered non-attributable event mask.");
67952267f74SRobert Watson 
68052267f74SRobert Watson 	/*
6817a0a89d2SRobert Watson 	 * Configure audit policy in kernel.
68252267f74SRobert Watson 	 */
6837a0a89d2SRobert Watson 	err = auditd_set_policy();
6847a0a89d2SRobert Watson 	if (err) {
6857a0a89d2SRobert Watson 		auditd_log_err("auditd_set_policy() %s: %m",
6867a0a89d2SRobert Watson 		    auditd_strerror(err));
6877a0a89d2SRobert Watson 		ret = -1;
68852267f74SRobert Watson 	} else
6897a0a89d2SRobert Watson 		auditd_log_debug("Set audit policy in kernel.");
69052267f74SRobert Watson 
6917a0a89d2SRobert Watson 	/*
6927a0a89d2SRobert Watson 	 * Configure audit trail log size in kernel.
6937a0a89d2SRobert Watson 	 */
6947a0a89d2SRobert Watson 	err = auditd_set_fsize();
6957a0a89d2SRobert Watson 	if (err) {
6967a0a89d2SRobert Watson 		auditd_log_err("audit_set_fsize() %s: %m",
6977a0a89d2SRobert Watson 		    auditd_strerror(err));
6987a0a89d2SRobert Watson 		ret = -1;
6997a0a89d2SRobert Watson 	} else
7007a0a89d2SRobert Watson 		auditd_log_debug("Set audit trail size in kernel.");
7017a0a89d2SRobert Watson 
7027a0a89d2SRobert Watson 	/*
703*5e386598SRobert Watson 	 * Configure audit trail queue size in kernel.
704*5e386598SRobert Watson 	 */
705*5e386598SRobert Watson 	err = auditd_set_qsize();
706*5e386598SRobert Watson 	if (err) {
707*5e386598SRobert Watson 		auditd_log_err("audit_set_qsize() %s: %m",
708*5e386598SRobert Watson 		    auditd_strerror(err));
709*5e386598SRobert Watson 		ret = -1;
710*5e386598SRobert Watson 	} else
711*5e386598SRobert Watson 		auditd_log_debug("Set audit trail queue in kernel.");
712*5e386598SRobert Watson 
713*5e386598SRobert Watson 	/*
7147a0a89d2SRobert Watson 	 * Configure audit trail volume minimum free percentage of blocks in
7157a0a89d2SRobert Watson 	 * kernel.
7167a0a89d2SRobert Watson 	 */
7177a0a89d2SRobert Watson 	err = auditd_set_minfree();
7187a0a89d2SRobert Watson 	if (err) {
7197a0a89d2SRobert Watson 		auditd_log_err("auditd_set_minfree() %s: %m",
7207a0a89d2SRobert Watson 		    auditd_strerror(err));
7217a0a89d2SRobert Watson 		ret = -1;
7227a0a89d2SRobert Watson 	} else
7237a0a89d2SRobert Watson 		auditd_log_debug(
7247a0a89d2SRobert Watson 		    "Set audit trail min free percent in kernel.");
7257a0a89d2SRobert Watson 
7267a0a89d2SRobert Watson 	/*
7277a0a89d2SRobert Watson 	 * Configure host address in the audit kernel information.
7287a0a89d2SRobert Watson 	 */
7297a0a89d2SRobert Watson 	err = auditd_set_host();
7307a0a89d2SRobert Watson 	if (err) {
73106edd2f1SRobert Watson 		if (err == ADE_PARSE) {
73206edd2f1SRobert Watson 			auditd_log_notice(
73306edd2f1SRobert Watson 			    "audit_control(5) may be missing 'host:' field");
73406edd2f1SRobert Watson 		} else {
7357a0a89d2SRobert Watson 			auditd_log_err("auditd_set_host() %s: %m",
7367a0a89d2SRobert Watson 			    auditd_strerror(err));
7377a0a89d2SRobert Watson 			ret = -1;
73806edd2f1SRobert Watson 		}
7397a0a89d2SRobert Watson 	} else
7407a0a89d2SRobert Watson 		auditd_log_debug(
7417a0a89d2SRobert Watson 		    "Set audit host address information in kernel.");
7427a0a89d2SRobert Watson 
7437a0a89d2SRobert Watson 	return (ret);
7447a0a89d2SRobert Watson }
7457a0a89d2SRobert Watson 
7467a0a89d2SRobert Watson /*
7477a0a89d2SRobert Watson  * Setup and initialize auditd.
7487a0a89d2SRobert Watson  */
749ca0716f5SRobert Watson static void
750ca0716f5SRobert Watson setup(void)
751ca0716f5SRobert Watson {
7527a0a89d2SRobert Watson 	int err;
753ca0716f5SRobert Watson 
7547a0a89d2SRobert Watson 	if (auditd_open_trigger(launchd_flag) < 0) {
7557a0a89d2SRobert Watson 		auditd_log_err("Error opening trigger messaging mechanism");
756506764c6SRobert Watson 		fail_exit();
757506764c6SRobert Watson 	}
758506764c6SRobert Watson 
759506764c6SRobert Watson 	/*
76052267f74SRobert Watson 	 * To prevent event feedback cycles and avoid auditd becoming
761506764c6SRobert Watson 	 * stalled if auditing is suspended, auditd and its children run
762506764c6SRobert Watson 	 * without their events being audited.  We allow the uid, tid, and
763506764c6SRobert Watson 	 * mask fields to be implicitly set to zero, but do set the pid.  We
764506764c6SRobert Watson 	 * run this after opening the trigger device to avoid configuring
765506764c6SRobert Watson 	 * audit state without audit present in the system.
766506764c6SRobert Watson 	 */
7677a0a89d2SRobert Watson 	err = auditd_prevent_audit();
7687a0a89d2SRobert Watson 	if (err) {
7697a0a89d2SRobert Watson 		auditd_log_err("auditd_prevent_audit() %s: %m",
7707a0a89d2SRobert Watson 		    auditd_strerror(err));
771ca0716f5SRobert Watson 		fail_exit();
772ca0716f5SRobert Watson 	}
773ca0716f5SRobert Watson 
774fdb4472cSRobert Watson 	/*
7757a0a89d2SRobert Watson 	 * Make sure auditd auditing state is correct.
776fdb4472cSRobert Watson 	 */
7777a0a89d2SRobert Watson 	auditd_set_state(AUD_STATE_INIT);
778ca0716f5SRobert Watson 
7797a0a89d2SRobert Watson 	/*
7807a0a89d2SRobert Watson 	 * If under launchd, don't start auditing.  Wait for a trigger to
7817a0a89d2SRobert Watson 	 * do so.
7827a0a89d2SRobert Watson 	 */
7837a0a89d2SRobert Watson 	if (!launchd_flag)
7847a0a89d2SRobert Watson 		audit_setup();
785ca0716f5SRobert Watson }
786ca0716f5SRobert Watson 
787ca0716f5SRobert Watson int
788ca0716f5SRobert Watson main(int argc, char **argv)
789ca0716f5SRobert Watson {
79023bf6e20SRobert Watson 	int ch;
791ca0716f5SRobert Watson 	int debug = 0;
7927a0a89d2SRobert Watson #ifdef AUDIT_REVIEW_GROUP
7937a0a89d2SRobert Watson 	struct group *grp;
7947a0a89d2SRobert Watson #endif
795ca0716f5SRobert Watson 
7967a0a89d2SRobert Watson 	while ((ch = getopt(argc, argv, "dl")) != -1) {
797ca0716f5SRobert Watson 		switch(ch) {
798ca0716f5SRobert Watson 		case 'd':
799ca0716f5SRobert Watson 			/* Debug option. */
800ca0716f5SRobert Watson 			debug = 1;
801ca0716f5SRobert Watson 			break;
802ca0716f5SRobert Watson 
8037a0a89d2SRobert Watson 		case 'l':
8047a0a89d2SRobert Watson 			/* Be launchd friendly. */
8057a0a89d2SRobert Watson 			launchd_flag = 1;
8067a0a89d2SRobert Watson 			break;
8077a0a89d2SRobert Watson 
808ca0716f5SRobert Watson 		case '?':
809ca0716f5SRobert Watson 		default:
810ca0716f5SRobert Watson 			(void)fprintf(stderr,
8117a0a89d2SRobert Watson 			    "usage: auditd [-d] [-l]\n");
812ca0716f5SRobert Watson 			exit(1);
813ca0716f5SRobert Watson 		}
814ca0716f5SRobert Watson 	}
815ca0716f5SRobert Watson 
8167a0a89d2SRobert Watson 	audit_review_gid = getgid();
81752267f74SRobert Watson 
8187a0a89d2SRobert Watson #ifdef AUDIT_REVIEW_GROUP
8197a0a89d2SRobert Watson 	/*
8207a0a89d2SRobert Watson 	 * XXXRW: Currently, this code falls back to the daemon gid, which is
8217a0a89d2SRobert Watson 	 * likely the wheel group.  Is there a better way to deal with this?
8227a0a89d2SRobert Watson 	 */
8237a0a89d2SRobert Watson 	grp = getgrnam(AUDIT_REVIEW_GROUP);
8247a0a89d2SRobert Watson 	if (grp != NULL)
8257a0a89d2SRobert Watson 		audit_review_gid = grp->gr_gid;
8263b97a967SRobert Watson #endif
827ca0716f5SRobert Watson 
8287a0a89d2SRobert Watson 	auditd_openlog(debug, audit_review_gid);
8297a0a89d2SRobert Watson 
8307a0a89d2SRobert Watson 	if (launchd_flag)
8317a0a89d2SRobert Watson 		auditd_log_info("started by launchd...");
8327a0a89d2SRobert Watson 	else
8337a0a89d2SRobert Watson 		auditd_log_info("starting...");
8347a0a89d2SRobert Watson 
8357a0a89d2SRobert Watson #ifdef AUDIT_REVIEW_GROUP
8367a0a89d2SRobert Watson 	if (grp == NULL)
8377a0a89d2SRobert Watson 		auditd_log_info(
8387a0a89d2SRobert Watson 		    "Audit review group '%s' not available, using daemon gid (%d)",
8397a0a89d2SRobert Watson 		    AUDIT_REVIEW_GROUP, audit_review_gid);
8407a0a89d2SRobert Watson #endif
8417a0a89d2SRobert Watson 	if (debug == 0 && launchd_flag == 0 && daemon(0, 0) == -1) {
8427a0a89d2SRobert Watson 		auditd_log_err("Failed to daemonize");
843ca0716f5SRobert Watson 		exit(1);
844ca0716f5SRobert Watson 	}
845ca0716f5SRobert Watson 
846ca0716f5SRobert Watson 	if (register_daemon() == -1) {
8477a0a89d2SRobert Watson 		auditd_log_err("Could not register as daemon");
848ca0716f5SRobert Watson 		exit(1);
849ca0716f5SRobert Watson 	}
850ca0716f5SRobert Watson 
851ca0716f5SRobert Watson 	setup();
852ca0716f5SRobert Watson 
8537a0a89d2SRobert Watson 	/*
8547a0a89d2SRobert Watson 	 * auditd_wait_for_events() shouldn't return unless something is wrong.
8557a0a89d2SRobert Watson 	 */
8567a0a89d2SRobert Watson 	auditd_wait_for_events();
857ca0716f5SRobert Watson 
8587a0a89d2SRobert Watson 	auditd_log_err("abnormal exit.");
8597a0a89d2SRobert Watson 	close_all();
8607a0a89d2SRobert Watson 	exit(-1);
861ca0716f5SRobert Watson }
862