1185573Srwatson/*-
2189279Srwatson * Copyright (c) 2004-2009 Apple Inc.
3155131Srwatson * All rights reserved.
4155131Srwatson *
5155131Srwatson * Redistribution and use in source and binary forms, with or without
6155131Srwatson * modification, are permitted provided that the following conditions
7155131Srwatson * are met:
8155131Srwatson *
9155131Srwatson * 1.  Redistributions of source code must retain the above copyright
10155131Srwatson *     notice, this list of conditions and the following disclaimer.
11155131Srwatson * 2.  Redistributions in binary form must reproduce the above copyright
12155131Srwatson *     notice, this list of conditions and the following disclaimer in the
13155131Srwatson *     documentation and/or other materials provided with the distribution.
14185573Srwatson * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
15155131Srwatson *     its contributors may be used to endorse or promote products derived
16155131Srwatson *     from this software without specific prior written permission.
17155131Srwatson *
18155131Srwatson * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19155131Srwatson * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20155131Srwatson * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21155131Srwatson * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22155131Srwatson * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23155131Srwatson * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24155131Srwatson * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25155131Srwatson * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26155131Srwatson * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27155131Srwatson * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28155131Srwatson */
29155131Srwatson
30186647Srwatson#include <sys/types.h>
31185573Srwatson
32185573Srwatson#include <config/config.h>
33185573Srwatson
34155131Srwatson#include <sys/dirent.h>
35185573Srwatson#ifdef HAVE_FULL_QUEUE_H
36155131Srwatson#include <sys/queue.h>
37243750Srwatson#else	/* !HAVE_FULL_QUEUE_H */
38185573Srwatson#include <compat/queue.h>
39243750Srwatson#endif	/* !HAVE_FULL_QUEUE_H */
40186647Srwatson#include <sys/mman.h>
41186647Srwatson#include <sys/param.h>
42155131Srwatson#include <sys/stat.h>
43155131Srwatson#include <sys/wait.h>
44155131Srwatson
45155131Srwatson#include <bsm/audit.h>
46155131Srwatson#include <bsm/audit_uevents.h>
47186647Srwatson#include <bsm/auditd_lib.h>
48155131Srwatson#include <bsm/libbsm.h>
49155131Srwatson
50159248Srwatson#include <err.h>
51155131Srwatson#include <errno.h>
52155131Srwatson#include <fcntl.h>
53155364Srwatson#include <grp.h>
54155131Srwatson#include <stdio.h>
55155131Srwatson#include <stdlib.h>
56155131Srwatson#include <time.h>
57155131Srwatson#include <unistd.h>
58155131Srwatson#include <signal.h>
59155131Srwatson#include <string.h>
60155131Srwatson
61155131Srwatson#include "auditd.h"
62155131Srwatson
63185573Srwatson#ifndef HAVE_STRLCPY
64185573Srwatson#include <compat/strlcpy.h>
65185573Srwatson#endif
66185573Srwatson
67186647Srwatson/*
68189279Srwatson * XXX The following are temporary until these can be added to the kernel
69186647Srwatson * audit.h header.
70186647Srwatson */
71186647Srwatson#ifndef	AUDIT_TRIGGER_INITIALIZE
72186647Srwatson#define	AUDIT_TRIGGER_INITIALIZE	7
73186647Srwatson#endif
74189279Srwatson#ifndef	AUDIT_TRIGGER_EXPIRE_TRAILS
75189279Srwatson#define	AUDIT_TRIGGER_EXPIRE_TRAILS	8
76189279Srwatson#endif
77155131Srwatson
78189279Srwatson
79186647Srwatson/*
80243750Srwatson * LaunchD flag (Mac OS X and, maybe, FreeBSD only.)  See launchd(8) and
81186647Srwatson * http://wiki.freebsd.org/launchd for more information.
82186647Srwatson *
83243750Srwatson *	In order for auditd to work "on demand" with launchd(8) it can't:
84243750Srwatson *		call daemon(3)
85243750Srwatson *		call fork and having the parent process exit
86243750Srwatson *		change uids or gids.
87243750Srwatson *		set up the current working directory or chroot.
88243750Srwatson *		set the session id
89243750Srwatson *		change stdio to /dev/null.
90243750Srwatson *		call setrusage(2)
91243750Srwatson *		call setpriority(2)
92243750Srwatson *		Ignore SIGTERM.
93243750Srwatson *	auditd (in 'launchd mode') is launched on demand so it must catch
94243750Srwatson *	SIGTERM to exit cleanly.
95186647Srwatson */
96186647Srwatsonstatic int	launchd_flag = 0;
97185573Srwatson
98186647Srwatson/*
99186647Srwatson * The GID of the audit review group (if used).  The audit trail files and
100186647Srwatson * system logs (Mac OS X only) can only be reviewed by members of this group
101186647Srwatson * or the audit administrator (aka. "root").
102186647Srwatson */
103186647Srwatsonstatic gid_t	audit_review_gid = -1;
104185573Srwatson
105186647Srwatson/*
106186647Srwatson * The path and file name of the last audit trail file.
107186647Srwatson */
108186647Srwatsonstatic char	*lastfile = NULL;
109185573Srwatson
110155131Srwatson/*
111186647Srwatson * Error starting auditd. Run warn script and exit.
112155131Srwatson */
113155131Srwatsonstatic void
114155131Srwatsonfail_exit(void)
115155131Srwatson{
116155131Srwatson
117155131Srwatson	audit_warn_nostart();
118155131Srwatson	exit(1);
119155131Srwatson}
120155131Srwatson
121155131Srwatson/*
122186647Srwatson * Follow the 'current' symlink to get the active trail file name.
123155131Srwatson */
124186647Srwatsonstatic char *
125186647Srwatsonget_curfile(void)
126155131Srwatson{
127186647Srwatson	char *cf;
128186647Srwatson	int len;
129155131Srwatson
130186647Srwatson	cf = malloc(MAXPATHLEN);
131186647Srwatson	if (cf == NULL) {
132186647Srwatson		auditd_log_err("malloc failed: %m");
133186647Srwatson		return (NULL);
134243750Srwatson	}
135186647Srwatson
136186647Srwatson	len = readlink(AUDIT_CURRENT_LINK, cf, MAXPATHLEN - 1);
137186647Srwatson	if (len < 0) {
138186647Srwatson		free(cf);
139186647Srwatson		return (NULL);
140155131Srwatson	}
141155131Srwatson
142186647Srwatson	/* readlink() doesn't terminate string. */
143243750Srwatson	cf[len] = '\0';
144155131Srwatson
145186647Srwatson	return (cf);
146155131Srwatson}
147155131Srwatson
148155131Srwatson/*
149155131Srwatson * Close the previous audit trail file.
150155131Srwatson */
151155131Srwatsonstatic int
152155131Srwatsonclose_lastfile(char *TS)
153155131Srwatson{
154155131Srwatson	char *ptr;
155155131Srwatson	char *oldname;
156155131Srwatson
157186647Srwatson	/* If lastfile is NULL try to get it from the 'current' link.  */
158186647Srwatson	if (lastfile == NULL)
159186647Srwatson		lastfile = get_curfile();
160243750Srwatson
161155131Srwatson	if (lastfile != NULL) {
162243750Srwatson		oldname = strdup(lastfile);
163155131Srwatson		if (oldname == NULL)
164155131Srwatson			return (-1);
165155131Srwatson
166155131Srwatson		/* Rename the last file -- append timestamp. */
167155131Srwatson		if ((ptr = strstr(lastfile, NOT_TERMINATED)) != NULL) {
168189279Srwatson			memcpy(ptr, TS, POSTFIX_LEN);
169243750Srwatson			if (auditd_rename(oldname, lastfile) != 0)
170186647Srwatson				auditd_log_err(
171162503Srwatson				    "Could not rename %s to %s: %m", oldname,
172162503Srwatson				    lastfile);
173162621Srwatson			else {
174243750Srwatson				/*
175186647Srwatson				 * Remove the 'current' symlink since the link
176243750Srwatson				 * is now invalid.
177186647Srwatson				 */
178186647Srwatson				(void) unlink(AUDIT_CURRENT_LINK);
179243750Srwatson				auditd_log_notice("renamed %s to %s",
180155131Srwatson				    oldname, lastfile);
181162621Srwatson				audit_warn_closefile(lastfile);
182162621Srwatson			}
183243750Srwatson		} else
184243750Srwatson			auditd_log_err("Could not rename %s to %s", oldname,
185185573Srwatson			    lastfile);
186155131Srwatson		free(lastfile);
187155131Srwatson		free(oldname);
188155131Srwatson		lastfile = NULL;
189155131Srwatson	}
190155131Srwatson	return (0);
191155131Srwatson}
192155131Srwatson
193155131Srwatson/*
194155131Srwatson * Create the new file name, swap with existing audit file.
195155131Srwatson */
196155131Srwatsonstatic int
197155131Srwatsonswap_audit_file(void)
198155131Srwatson{
199186647Srwatson	int err;
200243750Srwatson	char *newfile, *name;
201243750Srwatson	char TS[TIMESTAMP_LEN + 1];
202186647Srwatson	time_t tt;
203155131Srwatson
204243750Srwatson	if (getTSstr(tt, TS, sizeof(TS)) != 0)
205155131Srwatson		return (-1);
206243750Srwatson	/*
207243750Srwatson	 * If prefix and suffix are the same, it means that records are
208243750Srwatson	 * being produced too fast. We don't want to rename now, because
209243750Srwatson	 * next trail file can get the same name and once that one is
210243750Srwatson	 * terminated also within one second it will overwrite the current
211243750Srwatson	 * one. Just keep writing to the same trail and wait for the next
212243750Srwatson	 * trigger from the kernel.
213243750Srwatson	 * FREEBSD KERNEL WAS UPDATED TO KEEP SENDING TRIGGERS, WHICH MIGHT
214243750Srwatson	 * NOT BE THE CASE FOR OTHER OSES.
215243750Srwatson	 * If the kernel will not keep sending triggers, trail file will not
216243750Srwatson	 * be terminated.
217243750Srwatson	 */
218243750Srwatson	if (lastfile == NULL) {
219243750Srwatson		name = NULL;
220243750Srwatson	} else {
221243750Srwatson		name = strrchr(lastfile, '/');
222243750Srwatson		if (name != NULL)
223243750Srwatson			name++;
224243750Srwatson	}
225243750Srwatson	if (name != NULL && strncmp(name, TS, TIMESTAMP_LEN) == 0) {
226243750Srwatson		auditd_log_debug("Not ready to terminate trail file yet.");
227243750Srwatson		return (0);
228243750Srwatson	}
229186647Srwatson	err = auditd_swap_trail(TS, &newfile, audit_review_gid,
230186647Srwatson	    audit_warn_getacdir);
231186647Srwatson	if (err != ADE_NOERR) {
232243750Srwatson		auditd_log_err("%s: %m", auditd_strerror(err));
233186647Srwatson		if (err != ADE_ACTL)
234186647Srwatson			return (-1);
235186647Srwatson	}
236155131Srwatson
237155364Srwatson	/*
238186647Srwatson	 * Only close the last file if were in an auditing state before
239186647Srwatson	 * calling swap_audit_file().  We may need to recover from a crash.
240155364Srwatson	 */
241186647Srwatson	if (auditd_get_state() == AUD_STATE_ENABLED)
242186647Srwatson		close_lastfile(TS);
243155364Srwatson
244155131Srwatson
245186647Srwatson	/*
246186647Srwatson	 * auditd_swap_trail() potentially enables auditing (if not already
247186647Srwatson	 * enabled) so updated the cached state as well.
248186647Srwatson	 */
249186647Srwatson	auditd_set_state(AUD_STATE_ENABLED);
250243750Srwatson
251186647Srwatson	/*
252186647Srwatson	 *  Create 'current' symlink.  Recover from crash, if needed.
253186647Srwatson	 */
254186647Srwatson	if (auditd_new_curlink(newfile) != 0)
255243750Srwatson		auditd_log_err("auditd_new_curlink(\"%s\") failed: %s: %m",
256243750Srwatson		    newfile, auditd_strerror(err));
257155131Srwatson
258186647Srwatson	lastfile = newfile;
259186647Srwatson	auditd_log_notice("New audit file is %s", newfile);
260155131Srwatson
261186647Srwatson	return (0);
262155131Srwatson}
263155131Srwatson
264155131Srwatson/*
265186647Srwatson * Create a new audit log trail file and swap with the current one, if any.
266155131Srwatson */
267155131Srwatsonstatic int
268186647Srwatsondo_trail_file(void)
269155131Srwatson{
270186647Srwatson	int err;
271155131Srwatson
272155131Srwatson	/*
273186647Srwatson	 * First, refresh the list of audit log directories.
274155131Srwatson	 */
275186647Srwatson	err = auditd_read_dirs(audit_warn_soft, audit_warn_hard);
276186647Srwatson	if (err) {
277187214Srwatson		auditd_log_err("auditd_read_dirs(): %s",
278186647Srwatson		    auditd_strerror(err));
279186647Srwatson		if (err == ADE_HARDLIM)
280186647Srwatson			audit_warn_allhard();
281186647Srwatson		if (err != ADE_SOFTLIM)
282186647Srwatson			return (-1);
283186647Srwatson		else
284186647Srwatson			audit_warn_allsoft();
285186647Srwatson			/* continue on with soft limit error */
286186647Srwatson	}
287155131Srwatson
288155131Srwatson	/*
289186647Srwatson	 * Create a new file and swap with the one being used in kernel.
290155131Srwatson	 */
291155131Srwatson	if (swap_audit_file() == -1) {
292155131Srwatson		/*
293155131Srwatson		 * XXX Faulty directory listing? - user should be given
294155131Srwatson		 * XXX an opportunity to change the audit_control file
295155131Srwatson		 * XXX switch to a reduced mode of auditing?
296155131Srwatson		 */
297155131Srwatson		return (-1);
298155131Srwatson	}
299155131Srwatson
300189279Srwatson	/*
301189279Srwatson	 * Finally, see if there are any trail files to expire.
302189279Srwatson	 */
303189279Srwatson	err = auditd_expire_trails(audit_warn_expired);
304189279Srwatson	if (err)
305189279Srwatson		auditd_log_err("auditd_expire_trails(): %s",
306189279Srwatson		    auditd_strerror(err));
307189279Srwatson
308186647Srwatson	return (0);
309186647Srwatson}
310186647Srwatson
311186647Srwatson/*
312186647Srwatson * Start up auditing.
313186647Srwatson */
314186647Srwatsonstatic void
315186647Srwatsonaudit_setup(void)
316186647Srwatson{
317186647Srwatson	int err;
318186647Srwatson
319243750Srwatson	/* Configure trail files distribution. */
320243750Srwatson	err = auditd_set_dist();
321243750Srwatson	if (err) {
322243750Srwatson		auditd_log_err("auditd_set_dist() %s: %m",
323243750Srwatson		    auditd_strerror(err));
324243750Srwatson	} else
325243750Srwatson		auditd_log_debug("Configured trail files distribution.");
326243750Srwatson
327186647Srwatson	if (do_trail_file() == -1) {
328186647Srwatson		auditd_log_err("Error creating audit trail file");
329186647Srwatson		fail_exit();
330155131Srwatson	}
331155131Srwatson
332186647Srwatson	/* Generate an audit record. */
333186647Srwatson	err = auditd_gen_record(AUE_audit_startup, NULL);
334186647Srwatson	if (err)
335243750Srwatson		auditd_log_err("auditd_gen_record(AUE_audit_startup) %s: %m",
336186647Srwatson		    auditd_strerror(err));
337243750Srwatson
338186647Srwatson	if (auditd_config_controls() == 0)
339186647Srwatson		auditd_log_info("Audit controls init successful");
340186647Srwatson	else
341186647Srwatson		auditd_log_err("Audit controls init failed");
342186647Srwatson}
343186647Srwatson
344186647Srwatson
345186647Srwatson/*
346243750Srwatson * Close auditd pid file and trigger mechanism.
347186647Srwatson */
348186647Srwatsonstatic int
349186647Srwatsonclose_misc(void)
350186647Srwatson{
351186647Srwatson
352186647Srwatson	auditd_close_dirs();
353186647Srwatson	if (unlink(AUDITD_PIDFILE) == -1 && errno != ENOENT) {
354186647Srwatson		auditd_log_err("Couldn't remove %s: %m", AUDITD_PIDFILE);
355186647Srwatson		return (1);
356186647Srwatson	}
357186647Srwatson	endac();
358186647Srwatson
359186647Srwatson	if (auditd_close_trigger() != 0) {
360186647Srwatson		auditd_log_err("Error closing trigger messaging mechanism");
361186647Srwatson		return (1);
362186647Srwatson	}
363155131Srwatson	return (0);
364155131Srwatson}
365155131Srwatson
366155131Srwatson/*
367155131Srwatson * Close all log files, control files, and tell the audit system.
368155131Srwatson */
369155131Srwatsonstatic int
370155131Srwatsonclose_all(void)
371155131Srwatson{
372155131Srwatson	int err_ret = 0;
373243750Srwatson	char TS[TIMESTAMP_LEN + 1];
374186647Srwatson	int err;
375191273Srwatson	int cond;
376186647Srwatson	time_t tt;
377155131Srwatson
378186647Srwatson	err = auditd_gen_record(AUE_audit_shutdown, NULL);
379186647Srwatson	if (err)
380243750Srwatson		auditd_log_err("auditd_gen_record(AUE_audit_shutdown) %s: %m",
381186647Srwatson		    auditd_strerror(err));
382155131Srwatson
383155131Srwatson	/* Flush contents. */
384155131Srwatson	cond = AUC_DISABLED;
385191273Srwatson	err_ret = audit_set_cond(&cond);
386155131Srwatson	if (err_ret != 0) {
387186647Srwatson		auditd_log_err("Disabling audit failed! : %s", strerror(errno));
388155131Srwatson		err_ret = 1;
389155131Srwatson	}
390186647Srwatson
391186647Srwatson	/*
392186647Srwatson	 * Updated the cached state that auditing has been disabled.
393185573Srwatson	 */
394186647Srwatson	auditd_set_state(AUD_STATE_DISABLED);
395186647Srwatson
396243750Srwatson	if (getTSstr(tt, TS, sizeof(TS)) == 0)
397155131Srwatson		close_lastfile(TS);
398155131Srwatson	if (lastfile != NULL)
399155131Srwatson		free(lastfile);
400155131Srwatson
401186647Srwatson	err_ret += close_misc();
402186647Srwatson
403186647Srwatson	if (err_ret) {
404186647Srwatson		auditd_log_err("Could not unregister");
405155131Srwatson		audit_warn_postsigterm();
406155131Srwatson	}
407155131Srwatson
408186647Srwatson	auditd_log_info("Finished");
409186647Srwatson	return (err_ret);
410155131Srwatson}
411155131Srwatson
412155131Srwatson/*
413186647Srwatson * Register the daemon with the signal handler and the auditd pid file.
414155131Srwatson */
415155131Srwatsonstatic int
416155131Srwatsonregister_daemon(void)
417155131Srwatson{
418155131Srwatson	FILE * pidfile;
419155131Srwatson	int fd;
420155131Srwatson	pid_t pid;
421155131Srwatson
422155131Srwatson	/* Set up the signal hander. */
423186647Srwatson	if (signal(SIGTERM, auditd_relay_signal) == SIG_ERR) {
424186647Srwatson		auditd_log_err(
425159248Srwatson		    "Could not set signal handler for SIGTERM");
426155131Srwatson		fail_exit();
427155131Srwatson	}
428186647Srwatson	if (signal(SIGCHLD, auditd_relay_signal) == SIG_ERR) {
429186647Srwatson		auditd_log_err(
430159248Srwatson		    "Could not set signal handler for SIGCHLD");
431155131Srwatson		fail_exit();
432155131Srwatson	}
433186647Srwatson	if (signal(SIGHUP, auditd_relay_signal) == SIG_ERR) {
434186647Srwatson		auditd_log_err(
435159248Srwatson		    "Could not set signal handler for SIGHUP");
436155131Srwatson		fail_exit();
437155131Srwatson	}
438186647Srwatson	if (signal(SIGALRM, auditd_relay_signal) == SIG_ERR) {
439186647Srwatson		auditd_log_err(
440186647Srwatson		    "Could not set signal handler for SIGALRM");
441186647Srwatson		fail_exit();
442186647Srwatson	}
443155131Srwatson
444155131Srwatson	if ((pidfile = fopen(AUDITD_PIDFILE, "a")) == NULL) {
445186647Srwatson		auditd_log_err("Could not open PID file");
446155131Srwatson		audit_warn_tmpfile();
447155131Srwatson		return (-1);
448155131Srwatson	}
449155131Srwatson
450155131Srwatson	/* Attempt to lock the pid file; if a lock is present, exit. */
451155131Srwatson	fd = fileno(pidfile);
452155131Srwatson	if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
453186647Srwatson		auditd_log_err(
454159248Srwatson		    "PID file is locked (is another auditd running?).");
455155131Srwatson		audit_warn_ebusy();
456155131Srwatson		return (-1);
457155131Srwatson	}
458155131Srwatson
459155131Srwatson	pid = getpid();
460155131Srwatson	ftruncate(fd, 0);
461155131Srwatson	if (fprintf(pidfile, "%u\n", pid) < 0) {
462155131Srwatson		/* Should not start the daemon. */
463155131Srwatson		fail_exit();
464155131Srwatson	}
465155131Srwatson
466155131Srwatson	fflush(pidfile);
467155131Srwatson	return (0);
468155131Srwatson}
469155131Srwatson
470155131Srwatson/*
471162503Srwatson * Handle the audit trigger event.
472162503Srwatson *
473162503Srwatson * We suppress (ignore) duplicated triggers in close succession in order to
474162503Srwatson * try to avoid thrashing-like behavior.  However, not all triggers can be
475162503Srwatson * ignored, as triggers generally represent edge triggers, not level
476162503Srwatson * triggers, and won't be retransmitted if the condition persists.  Of
477162503Srwatson * specific concern is the rotate trigger -- if one is dropped, then it will
478162503Srwatson * not be retransmitted, and the log file will grow in an unbounded fashion.
479155131Srwatson */
480155131Srwatson#define	DUPLICATE_INTERVAL	30
481186647Srwatsonvoid
482186647Srwatsonauditd_handle_trigger(int trigger)
483155131Srwatson{
484162503Srwatson	static int last_trigger, last_warning;
485155131Srwatson	static time_t last_time;
486162503Srwatson	struct timeval ts;
487162503Srwatson	struct timezone tzp;
488162503Srwatson	time_t tt;
489186647Srwatson	int au_state;
490186647Srwatson	int err = 0;
491155131Srwatson
492155131Srwatson	/*
493162503Srwatson	 * Suppress duplicate messages from the kernel within the specified
494155131Srwatson	 * interval.
495155131Srwatson	 */
496155131Srwatson	if (gettimeofday(&ts, &tzp) == 0) {
497155131Srwatson		tt = (time_t)ts.tv_sec;
498162503Srwatson		switch (trigger) {
499162503Srwatson		case AUDIT_TRIGGER_LOW_SPACE:
500162503Srwatson		case AUDIT_TRIGGER_NO_SPACE:
501162503Srwatson			/*
502162503Srwatson			 * Triggers we can suppress.  Of course, we also need
503162503Srwatson			 * to rate limit the warnings, so apply the same
504162503Srwatson			 * interval limit on syslog messages.
505162503Srwatson			 */
506162503Srwatson			if ((trigger == last_trigger) &&
507162503Srwatson			    (tt < (last_time + DUPLICATE_INTERVAL))) {
508162503Srwatson				if (tt >= (last_warning + DUPLICATE_INTERVAL))
509186647Srwatson					auditd_log_info(
510162503Srwatson					    "Suppressing duplicate trigger %d",
511162503Srwatson					    trigger);
512186647Srwatson				return;
513162503Srwatson			}
514162503Srwatson			last_warning = tt;
515162503Srwatson			break;
516162503Srwatson
517162503Srwatson		case AUDIT_TRIGGER_ROTATE_KERNEL:
518162503Srwatson		case AUDIT_TRIGGER_ROTATE_USER:
519162503Srwatson		case AUDIT_TRIGGER_READ_FILE:
520186647Srwatson		case AUDIT_TRIGGER_CLOSE_AND_DIE:
521186647Srwatson		case AUDIT_TRIGGER_INITIALIZE:
522162503Srwatson			/*
523162503Srwatson			 * Triggers that we cannot suppress.
524162503Srwatson			 */
525162503Srwatson			break;
526162503Srwatson		}
527162503Srwatson
528162503Srwatson		/*
529162503Srwatson		 * Only update last_trigger after aborting due to a duplicate
530162503Srwatson		 * trigger, not before, or we will never allow that trigger
531162503Srwatson		 * again.
532162503Srwatson		 */
533155131Srwatson		last_trigger = trigger;
534155131Srwatson		last_time = tt;
535155131Srwatson	}
536155131Srwatson
537186647Srwatson	au_state = auditd_get_state();
538186647Srwatson
539155131Srwatson	/*
540155131Srwatson	 * Message processing is done here.
541243750Srwatson	 */
542155131Srwatson	switch(trigger) {
543155131Srwatson	case AUDIT_TRIGGER_LOW_SPACE:
544186647Srwatson		auditd_log_notice("Got low space trigger");
545186647Srwatson		if (do_trail_file() == -1)
546186647Srwatson			auditd_log_err("Error swapping audit file");
547155131Srwatson		break;
548155131Srwatson
549155131Srwatson	case AUDIT_TRIGGER_NO_SPACE:
550186647Srwatson		auditd_log_notice("Got no space trigger");
551186647Srwatson		if (do_trail_file() == -1)
552186647Srwatson			auditd_log_err("Error swapping audit file");
553155131Srwatson		break;
554155131Srwatson
555162503Srwatson	case AUDIT_TRIGGER_ROTATE_KERNEL:
556162503Srwatson	case AUDIT_TRIGGER_ROTATE_USER:
557186647Srwatson		auditd_log_info("Got open new trigger from %s", trigger ==
558162503Srwatson		    AUDIT_TRIGGER_ROTATE_KERNEL ? "kernel" : "user");
559186647Srwatson		if (au_state == AUD_STATE_ENABLED && do_trail_file() == -1)
560186647Srwatson			auditd_log_err("Error swapping audit file");
561155131Srwatson		break;
562155131Srwatson
563155131Srwatson	case AUDIT_TRIGGER_READ_FILE:
564186647Srwatson		auditd_log_info("Got read file trigger");
565191273Srwatson		if (au_state == AUD_STATE_ENABLED) {
566191273Srwatson			if (auditd_config_controls() == -1)
567191273Srwatson				auditd_log_err("Error setting audit controls");
568191273Srwatson			else if (do_trail_file() == -1)
569191273Srwatson				auditd_log_err("Error swapping audit file");
570191273Srwatson		}
571155131Srwatson		break;
572155131Srwatson
573186647Srwatson	case AUDIT_TRIGGER_CLOSE_AND_DIE:
574186647Srwatson		auditd_log_info("Got close and die trigger");
575186647Srwatson		if (au_state == AUD_STATE_ENABLED)
576186647Srwatson			err = close_all();
577185573Srwatson		/*
578186647Srwatson		 * Running under launchd don't exit.  Wait for launchd to
579186647Srwatson		 * send SIGTERM.
580185573Srwatson		 */
581186647Srwatson		if (!launchd_flag) {
582243750Srwatson			auditd_log_info("auditd exiting.");
583186647Srwatson			exit (err);
584185573Srwatson		}
585185573Srwatson		break;
586186647Srwatson
587186647Srwatson	case AUDIT_TRIGGER_INITIALIZE:
588186647Srwatson		auditd_log_info("Got audit initialize trigger");
589186647Srwatson		if (au_state == AUD_STATE_DISABLED)
590186647Srwatson			audit_setup();
591185573Srwatson		break;
592186647Srwatson
593189279Srwatson	case AUDIT_TRIGGER_EXPIRE_TRAILS:
594189279Srwatson		auditd_log_info("Got audit expire trails trigger");
595189279Srwatson		err = auditd_expire_trails(audit_warn_expired);
596189279Srwatson		if (err)
597189279Srwatson			auditd_log_err("auditd_expire_trails(): %s",
598243750Srwatson			    auditd_strerror(err));
599189279Srwatson		break;
600189279Srwatson
601185573Srwatson	default:
602186647Srwatson		auditd_log_err("Got unknown trigger %d", trigger);
603186647Srwatson		break;
604185573Srwatson	}
605185573Srwatson}
606185573Srwatson
607155131Srwatson/*
608159248Srwatson * Reap our children.
609155131Srwatson */
610186647Srwatsonvoid
611186647Srwatsonauditd_reap_children(void)
612159248Srwatson{
613159248Srwatson	pid_t child;
614159248Srwatson	int wstatus;
615159248Srwatson
616159248Srwatson	while ((child = waitpid(-1, &wstatus, WNOHANG)) > 0) {
617159248Srwatson		if (!wstatus)
618159248Srwatson			continue;
619186647Srwatson		auditd_log_info("warn process [pid=%d] %s %d.", child,
620159248Srwatson		    ((WIFEXITED(wstatus)) ? "exited with non-zero status" :
621159248Srwatson		    "exited as a result of signal"),
622159248Srwatson		    ((WIFEXITED(wstatus)) ? WEXITSTATUS(wstatus) :
623159248Srwatson		    WTERMSIG(wstatus)));
624159248Srwatson	}
625159248Srwatson}
626159248Srwatson
627159248Srwatson/*
628186647Srwatson * Reap any children and terminate.  If under launchd don't shutdown auditing
629186647Srwatson * but just the other stuff.
630159248Srwatson */
631186647Srwatsonvoid
632186647Srwatsonauditd_terminate(void)
633185573Srwatson{
634186647Srwatson	int ret;
635185573Srwatson
636186647Srwatson	auditd_reap_children();
637243750Srwatson
638186647Srwatson	if (launchd_flag)
639186647Srwatson		ret = close_misc();
640186647Srwatson	else
641186647Srwatson		ret = close_all();
642185573Srwatson
643186647Srwatson	exit(ret);
644185573Srwatson}
645185573Srwatson
646155131Srwatson/*
647155131Srwatson * Configure the audit controls in the kernel: the event to class mapping,
648155131Srwatson * kernel preselection mask, etc.
649155131Srwatson */
650186647Srwatsonint
651186647Srwatsonauditd_config_controls(void)
652155131Srwatson{
653186647Srwatson	int cnt, err;
654186647Srwatson	int ret = 0;
655155131Srwatson
656155131Srwatson	/*
657186647Srwatson	 * Configure event to class mappings in kernel.
658243750Srwatson	 */
659186647Srwatson	cnt = auditd_set_evcmap();
660186647Srwatson	if (cnt < 0) {
661186647Srwatson		auditd_log_err("auditd_set_evcmap() failed: %m");
662186647Srwatson		ret = -1;
663186647Srwatson	} else if (cnt == 0) {
664186647Srwatson		auditd_log_err("No events to class mappings registered.");
665186647Srwatson		ret = -1;
666186647Srwatson	} else
667186647Srwatson		auditd_log_debug("Registered %d event to class mappings.", cnt);
668162503Srwatson
669162503Srwatson	/*
670186647Srwatson	 * Configure non-attributable event mask in kernel.
671162503Srwatson	 */
672186647Srwatson	err = auditd_set_namask();
673186647Srwatson	if (err) {
674243750Srwatson		auditd_log_err("auditd_set_namask() %s: %m",
675186647Srwatson		    auditd_strerror(err));
676186647Srwatson		ret = -1;
677186647Srwatson	} else
678186647Srwatson		auditd_log_debug("Registered non-attributable event mask.");
679155131Srwatson
680155131Srwatson	/*
681186647Srwatson	 * Configure audit policy in kernel.
682155131Srwatson	 */
683186647Srwatson	err = auditd_set_policy();
684186647Srwatson	if (err) {
685243750Srwatson		auditd_log_err("auditd_set_policy() %s: %m",
686186647Srwatson		    auditd_strerror(err));
687186647Srwatson		ret = -1;
688155131Srwatson	} else
689186647Srwatson		auditd_log_debug("Set audit policy in kernel.");
690243750Srwatson
691155131Srwatson	/*
692186647Srwatson	 * Configure audit trail log size in kernel.
693155131Srwatson	 */
694186647Srwatson	err = auditd_set_fsize();
695186647Srwatson	if (err) {
696186647Srwatson		auditd_log_err("audit_set_fsize() %s: %m",
697186647Srwatson		    auditd_strerror(err));
698186647Srwatson		ret = -1;
699186647Srwatson	} else
700186647Srwatson		auditd_log_debug("Set audit trail size in kernel.");
701243750Srwatson
702162621Srwatson	/*
703243750Srwatson	 * Configure audit trail volume minimum free percentage of blocks in
704186647Srwatson	 * kernel.
705162621Srwatson	 */
706186647Srwatson	err = auditd_set_minfree();
707186647Srwatson	if (err) {
708186647Srwatson		auditd_log_err("auditd_set_minfree() %s: %m",
709186647Srwatson		    auditd_strerror(err));
710186647Srwatson		ret = -1;
711162621Srwatson	} else
712243750Srwatson		auditd_log_debug(
713186647Srwatson		    "Set audit trail min free percent in kernel.");
714162621Srwatson
715185573Srwatson	/*
716243750Srwatson	 * Configure host address in the audit kernel information.
717185573Srwatson	 */
718186647Srwatson	err = auditd_set_host();
719186647Srwatson	if (err) {
720189279Srwatson		if (err == ADE_PARSE) {
721189279Srwatson			auditd_log_notice(
722189279Srwatson			    "audit_control(5) may be missing 'host:' field");
723189279Srwatson		} else {
724189279Srwatson			auditd_log_err("auditd_set_host() %s: %m",
725189279Srwatson			    auditd_strerror(err));
726189279Srwatson			ret = -1;
727189279Srwatson		}
728185573Srwatson	} else
729186647Srwatson		auditd_log_debug(
730186647Srwatson		    "Set audit host address information in kernel.");
731189279Srwatson
732186647Srwatson	return (ret);
733185573Srwatson}
734185573Srwatson
735186647Srwatson/*
736186647Srwatson * Setup and initialize auditd.
737186647Srwatson */
738185573Srwatsonstatic void
739155131Srwatsonsetup(void)
740155131Srwatson{
741186647Srwatson	int err;
742155131Srwatson
743186647Srwatson	if (auditd_open_trigger(launchd_flag) < 0) {
744186647Srwatson		auditd_log_err("Error opening trigger messaging mechanism");
745155131Srwatson		fail_exit();
746155131Srwatson	}
747155131Srwatson
748159248Srwatson	/*
749185573Srwatson	 * To prevent event feedback cycles and avoid auditd becoming
750159248Srwatson	 * stalled if auditing is suspended, auditd and its children run
751159248Srwatson	 * without their events being audited.  We allow the uid, tid, and
752159248Srwatson	 * mask fields to be implicitly set to zero, but do set the pid.  We
753159248Srwatson	 * run this after opening the trigger device to avoid configuring
754159248Srwatson	 * audit state without audit present in the system.
755159248Srwatson	 */
756186647Srwatson	err = auditd_prevent_audit();
757186647Srwatson	if (err) {
758243750Srwatson		auditd_log_err("auditd_prevent_audit() %s: %m",
759186647Srwatson		    auditd_strerror(err));
760159248Srwatson		fail_exit();
761159248Srwatson	}
762159248Srwatson
763186647Srwatson	/*
764186647Srwatson	 * Make sure auditd auditing state is correct.
765186647Srwatson	 */
766186647Srwatson	auditd_set_state(AUD_STATE_INIT);
767155131Srwatson
768186647Srwatson	/*
769186647Srwatson	 * If under launchd, don't start auditing.  Wait for a trigger to
770186647Srwatson	 * do so.
771186647Srwatson	 */
772186647Srwatson	if (!launchd_flag)
773186647Srwatson		audit_setup();
774155131Srwatson}
775155131Srwatson
776155131Srwatsonint
777155131Srwatsonmain(int argc, char **argv)
778155131Srwatson{
779155364Srwatson	int ch;
780155131Srwatson	int debug = 0;
781186647Srwatson#ifdef AUDIT_REVIEW_GROUP
782186647Srwatson	struct group *grp;
783186647Srwatson#endif
784155131Srwatson
785186647Srwatson	while ((ch = getopt(argc, argv, "dl")) != -1) {
786155131Srwatson		switch(ch) {
787155131Srwatson		case 'd':
788155131Srwatson			/* Debug option. */
789155131Srwatson			debug = 1;
790155131Srwatson			break;
791155131Srwatson
792186647Srwatson		case 'l':
793186647Srwatson			/* Be launchd friendly. */
794186647Srwatson			launchd_flag = 1;
795186647Srwatson			break;
796186647Srwatson
797155131Srwatson		case '?':
798155131Srwatson		default:
799155131Srwatson			(void)fprintf(stderr,
800186647Srwatson			    "usage: auditd [-d] [-l]\n");
801155131Srwatson			exit(1);
802155131Srwatson		}
803155131Srwatson	}
804155131Srwatson
805186647Srwatson	audit_review_gid = getgid();
806185573Srwatson
807186647Srwatson#ifdef AUDIT_REVIEW_GROUP
808186647Srwatson	/*
809186647Srwatson	 * XXXRW: Currently, this code falls back to the daemon gid, which is
810186647Srwatson	 * likely the wheel group.  Is there a better way to deal with this?
811186647Srwatson	 */
812186647Srwatson	grp = getgrnam(AUDIT_REVIEW_GROUP);
813243750Srwatson	if (grp != NULL)
814186647Srwatson		audit_review_gid = grp->gr_gid;
815156283Srwatson#endif
816155131Srwatson
817186647Srwatson	auditd_openlog(debug, audit_review_gid);
818186647Srwatson
819186647Srwatson	if (launchd_flag)
820186647Srwatson		auditd_log_info("started by launchd...");
821186647Srwatson	else
822186647Srwatson		auditd_log_info("starting...");
823186647Srwatson
824186647Srwatson#ifdef AUDIT_REVIEW_GROUP
825186647Srwatson	if (grp == NULL)
826186647Srwatson		auditd_log_info(
827186647Srwatson		    "Audit review group '%s' not available, using daemon gid (%d)",
828186647Srwatson		    AUDIT_REVIEW_GROUP, audit_review_gid);
829186647Srwatson#endif
830186647Srwatson	if (debug == 0 && launchd_flag == 0 && daemon(0, 0) == -1) {
831186647Srwatson		auditd_log_err("Failed to daemonize");
832155131Srwatson		exit(1);
833155131Srwatson	}
834155131Srwatson
835155131Srwatson	if (register_daemon() == -1) {
836186647Srwatson		auditd_log_err("Could not register as daemon");
837155131Srwatson		exit(1);
838155131Srwatson	}
839155131Srwatson
840155131Srwatson	setup();
841155131Srwatson
842186647Srwatson	/*
843243750Srwatson	 * auditd_wait_for_events() shouldn't return unless something is wrong.
844186647Srwatson	 */
845186647Srwatson	auditd_wait_for_events();
846155131Srwatson
847186647Srwatson	auditd_log_err("abnormal exit.");
848186647Srwatson	close_all();
849186647Srwatson	exit(-1);
850155131Srwatson}
851