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 *
29243750Srwatson * $P4: //depot/projects/trustedbsd/openbsm/bin/auditd/auditd.c#50 $
30155131Srwatson */
31155131Srwatson
32186647Srwatson#include <sys/types.h>
33185573Srwatson
34185573Srwatson#include <config/config.h>
35185573Srwatson
36155131Srwatson#include <sys/dirent.h>
37185573Srwatson#ifdef HAVE_FULL_QUEUE_H
38155131Srwatson#include <sys/queue.h>
39243750Srwatson#else	/* !HAVE_FULL_QUEUE_H */
40185573Srwatson#include <compat/queue.h>
41243750Srwatson#endif	/* !HAVE_FULL_QUEUE_H */
42186647Srwatson#include <sys/mman.h>
43186647Srwatson#include <sys/param.h>
44155131Srwatson#include <sys/stat.h>
45155131Srwatson#include <sys/wait.h>
46155131Srwatson
47155131Srwatson#include <bsm/audit.h>
48155131Srwatson#include <bsm/audit_uevents.h>
49186647Srwatson#include <bsm/auditd_lib.h>
50155131Srwatson#include <bsm/libbsm.h>
51155131Srwatson
52159248Srwatson#include <err.h>
53155131Srwatson#include <errno.h>
54155131Srwatson#include <fcntl.h>
55155364Srwatson#include <grp.h>
56155131Srwatson#include <stdio.h>
57155131Srwatson#include <stdlib.h>
58155131Srwatson#include <time.h>
59155131Srwatson#include <unistd.h>
60155131Srwatson#include <signal.h>
61155131Srwatson#include <string.h>
62155131Srwatson
63155131Srwatson#include "auditd.h"
64155131Srwatson
65185573Srwatson#ifndef HAVE_STRLCPY
66185573Srwatson#include <compat/strlcpy.h>
67185573Srwatson#endif
68185573Srwatson
69186647Srwatson/*
70189279Srwatson * XXX The following are temporary until these can be added to the kernel
71186647Srwatson * audit.h header.
72186647Srwatson */
73186647Srwatson#ifndef	AUDIT_TRIGGER_INITIALIZE
74186647Srwatson#define	AUDIT_TRIGGER_INITIALIZE	7
75186647Srwatson#endif
76189279Srwatson#ifndef	AUDIT_TRIGGER_EXPIRE_TRAILS
77189279Srwatson#define	AUDIT_TRIGGER_EXPIRE_TRAILS	8
78189279Srwatson#endif
79155131Srwatson
80189279Srwatson
81186647Srwatson/*
82243750Srwatson * LaunchD flag (Mac OS X and, maybe, FreeBSD only.)  See launchd(8) and
83186647Srwatson * http://wiki.freebsd.org/launchd for more information.
84186647Srwatson *
85243750Srwatson *	In order for auditd to work "on demand" with launchd(8) it can't:
86243750Srwatson *		call daemon(3)
87243750Srwatson *		call fork and having the parent process exit
88243750Srwatson *		change uids or gids.
89243750Srwatson *		set up the current working directory or chroot.
90243750Srwatson *		set the session id
91243750Srwatson *		change stdio to /dev/null.
92243750Srwatson *		call setrusage(2)
93243750Srwatson *		call setpriority(2)
94243750Srwatson *		Ignore SIGTERM.
95243750Srwatson *	auditd (in 'launchd mode') is launched on demand so it must catch
96243750Srwatson *	SIGTERM to exit cleanly.
97186647Srwatson */
98186647Srwatsonstatic int	launchd_flag = 0;
99185573Srwatson
100186647Srwatson/*
101186647Srwatson * The GID of the audit review group (if used).  The audit trail files and
102186647Srwatson * system logs (Mac OS X only) can only be reviewed by members of this group
103186647Srwatson * or the audit administrator (aka. "root").
104186647Srwatson */
105186647Srwatsonstatic gid_t	audit_review_gid = -1;
106185573Srwatson
107186647Srwatson/*
108186647Srwatson * The path and file name of the last audit trail file.
109186647Srwatson */
110186647Srwatsonstatic char	*lastfile = NULL;
111185573Srwatson
112155131Srwatson/*
113186647Srwatson * Error starting auditd. Run warn script and exit.
114155131Srwatson */
115155131Srwatsonstatic void
116155131Srwatsonfail_exit(void)
117155131Srwatson{
118155131Srwatson
119155131Srwatson	audit_warn_nostart();
120155131Srwatson	exit(1);
121155131Srwatson}
122155131Srwatson
123155131Srwatson/*
124186647Srwatson * Follow the 'current' symlink to get the active trail file name.
125155131Srwatson */
126186647Srwatsonstatic char *
127186647Srwatsonget_curfile(void)
128155131Srwatson{
129186647Srwatson	char *cf;
130186647Srwatson	int len;
131155131Srwatson
132186647Srwatson	cf = malloc(MAXPATHLEN);
133186647Srwatson	if (cf == NULL) {
134186647Srwatson		auditd_log_err("malloc failed: %m");
135186647Srwatson		return (NULL);
136243750Srwatson	}
137186647Srwatson
138186647Srwatson	len = readlink(AUDIT_CURRENT_LINK, cf, MAXPATHLEN - 1);
139186647Srwatson	if (len < 0) {
140186647Srwatson		free(cf);
141186647Srwatson		return (NULL);
142155131Srwatson	}
143155131Srwatson
144186647Srwatson	/* readlink() doesn't terminate string. */
145243750Srwatson	cf[len] = '\0';
146155131Srwatson
147186647Srwatson	return (cf);
148155131Srwatson}
149155131Srwatson
150155131Srwatson/*
151155131Srwatson * Close the previous audit trail file.
152155131Srwatson */
153155131Srwatsonstatic int
154155131Srwatsonclose_lastfile(char *TS)
155155131Srwatson{
156155131Srwatson	char *ptr;
157155131Srwatson	char *oldname;
158155131Srwatson
159186647Srwatson	/* If lastfile is NULL try to get it from the 'current' link.  */
160186647Srwatson	if (lastfile == NULL)
161186647Srwatson		lastfile = get_curfile();
162243750Srwatson
163155131Srwatson	if (lastfile != NULL) {
164243750Srwatson		oldname = strdup(lastfile);
165155131Srwatson		if (oldname == NULL)
166155131Srwatson			return (-1);
167155131Srwatson
168155131Srwatson		/* Rename the last file -- append timestamp. */
169155131Srwatson		if ((ptr = strstr(lastfile, NOT_TERMINATED)) != NULL) {
170189279Srwatson			memcpy(ptr, TS, POSTFIX_LEN);
171243750Srwatson			if (auditd_rename(oldname, lastfile) != 0)
172186647Srwatson				auditd_log_err(
173162503Srwatson				    "Could not rename %s to %s: %m", oldname,
174162503Srwatson				    lastfile);
175162621Srwatson			else {
176243750Srwatson				/*
177186647Srwatson				 * Remove the 'current' symlink since the link
178243750Srwatson				 * is now invalid.
179186647Srwatson				 */
180186647Srwatson				(void) unlink(AUDIT_CURRENT_LINK);
181243750Srwatson				auditd_log_notice("renamed %s to %s",
182155131Srwatson				    oldname, lastfile);
183162621Srwatson				audit_warn_closefile(lastfile);
184162621Srwatson			}
185243750Srwatson		} else
186243750Srwatson			auditd_log_err("Could not rename %s to %s", oldname,
187185573Srwatson			    lastfile);
188155131Srwatson		free(lastfile);
189155131Srwatson		free(oldname);
190155131Srwatson		lastfile = NULL;
191155131Srwatson	}
192155131Srwatson	return (0);
193155131Srwatson}
194155131Srwatson
195155131Srwatson/*
196155131Srwatson * Create the new file name, swap with existing audit file.
197155131Srwatson */
198155131Srwatsonstatic int
199155131Srwatsonswap_audit_file(void)
200155131Srwatson{
201186647Srwatson	int err;
202243750Srwatson	char *newfile, *name;
203243750Srwatson	char TS[TIMESTAMP_LEN + 1];
204186647Srwatson	time_t tt;
205155131Srwatson
206243750Srwatson	if (getTSstr(tt, TS, sizeof(TS)) != 0)
207155131Srwatson		return (-1);
208243750Srwatson	/*
209243750Srwatson	 * If prefix and suffix are the same, it means that records are
210243750Srwatson	 * being produced too fast. We don't want to rename now, because
211243750Srwatson	 * next trail file can get the same name and once that one is
212243750Srwatson	 * terminated also within one second it will overwrite the current
213243750Srwatson	 * one. Just keep writing to the same trail and wait for the next
214243750Srwatson	 * trigger from the kernel.
215243750Srwatson	 * FREEBSD KERNEL WAS UPDATED TO KEEP SENDING TRIGGERS, WHICH MIGHT
216243750Srwatson	 * NOT BE THE CASE FOR OTHER OSES.
217243750Srwatson	 * If the kernel will not keep sending triggers, trail file will not
218243750Srwatson	 * be terminated.
219243750Srwatson	 */
220243750Srwatson	if (lastfile == NULL) {
221243750Srwatson		name = NULL;
222243750Srwatson	} else {
223243750Srwatson		name = strrchr(lastfile, '/');
224243750Srwatson		if (name != NULL)
225243750Srwatson			name++;
226243750Srwatson	}
227243750Srwatson	if (name != NULL && strncmp(name, TS, TIMESTAMP_LEN) == 0) {
228243750Srwatson		auditd_log_debug("Not ready to terminate trail file yet.");
229243750Srwatson		return (0);
230243750Srwatson	}
231186647Srwatson	err = auditd_swap_trail(TS, &newfile, audit_review_gid,
232186647Srwatson	    audit_warn_getacdir);
233186647Srwatson	if (err != ADE_NOERR) {
234243750Srwatson		auditd_log_err("%s: %m", auditd_strerror(err));
235186647Srwatson		if (err != ADE_ACTL)
236186647Srwatson			return (-1);
237186647Srwatson	}
238155131Srwatson
239155364Srwatson	/*
240186647Srwatson	 * Only close the last file if were in an auditing state before
241186647Srwatson	 * calling swap_audit_file().  We may need to recover from a crash.
242155364Srwatson	 */
243186647Srwatson	if (auditd_get_state() == AUD_STATE_ENABLED)
244186647Srwatson		close_lastfile(TS);
245155364Srwatson
246155131Srwatson
247186647Srwatson	/*
248186647Srwatson	 * auditd_swap_trail() potentially enables auditing (if not already
249186647Srwatson	 * enabled) so updated the cached state as well.
250186647Srwatson	 */
251186647Srwatson	auditd_set_state(AUD_STATE_ENABLED);
252243750Srwatson
253186647Srwatson	/*
254186647Srwatson	 *  Create 'current' symlink.  Recover from crash, if needed.
255186647Srwatson	 */
256186647Srwatson	if (auditd_new_curlink(newfile) != 0)
257243750Srwatson		auditd_log_err("auditd_new_curlink(\"%s\") failed: %s: %m",
258243750Srwatson		    newfile, auditd_strerror(err));
259155131Srwatson
260186647Srwatson	lastfile = newfile;
261186647Srwatson	auditd_log_notice("New audit file is %s", newfile);
262155131Srwatson
263186647Srwatson	return (0);
264155131Srwatson}
265155131Srwatson
266155131Srwatson/*
267186647Srwatson * Create a new audit log trail file and swap with the current one, if any.
268155131Srwatson */
269155131Srwatsonstatic int
270186647Srwatsondo_trail_file(void)
271155131Srwatson{
272186647Srwatson	int err;
273155131Srwatson
274155131Srwatson	/*
275186647Srwatson	 * First, refresh the list of audit log directories.
276155131Srwatson	 */
277186647Srwatson	err = auditd_read_dirs(audit_warn_soft, audit_warn_hard);
278186647Srwatson	if (err) {
279187214Srwatson		auditd_log_err("auditd_read_dirs(): %s",
280186647Srwatson		    auditd_strerror(err));
281186647Srwatson		if (err == ADE_HARDLIM)
282186647Srwatson			audit_warn_allhard();
283186647Srwatson		if (err != ADE_SOFTLIM)
284186647Srwatson			return (-1);
285186647Srwatson		else
286186647Srwatson			audit_warn_allsoft();
287186647Srwatson			/* continue on with soft limit error */
288186647Srwatson	}
289155131Srwatson
290155131Srwatson	/*
291186647Srwatson	 * Create a new file and swap with the one being used in kernel.
292155131Srwatson	 */
293155131Srwatson	if (swap_audit_file() == -1) {
294155131Srwatson		/*
295155131Srwatson		 * XXX Faulty directory listing? - user should be given
296155131Srwatson		 * XXX an opportunity to change the audit_control file
297155131Srwatson		 * XXX switch to a reduced mode of auditing?
298155131Srwatson		 */
299155131Srwatson		return (-1);
300155131Srwatson	}
301155131Srwatson
302189279Srwatson	/*
303189279Srwatson	 * Finally, see if there are any trail files to expire.
304189279Srwatson	 */
305189279Srwatson	err = auditd_expire_trails(audit_warn_expired);
306189279Srwatson	if (err)
307189279Srwatson		auditd_log_err("auditd_expire_trails(): %s",
308189279Srwatson		    auditd_strerror(err));
309189279Srwatson
310186647Srwatson	return (0);
311186647Srwatson}
312186647Srwatson
313186647Srwatson/*
314186647Srwatson * Start up auditing.
315186647Srwatson */
316186647Srwatsonstatic void
317186647Srwatsonaudit_setup(void)
318186647Srwatson{
319186647Srwatson	int err;
320186647Srwatson
321243750Srwatson	/* Configure trail files distribution. */
322243750Srwatson	err = auditd_set_dist();
323243750Srwatson	if (err) {
324243750Srwatson		auditd_log_err("auditd_set_dist() %s: %m",
325243750Srwatson		    auditd_strerror(err));
326243750Srwatson	} else
327243750Srwatson		auditd_log_debug("Configured trail files distribution.");
328243750Srwatson
329186647Srwatson	if (do_trail_file() == -1) {
330186647Srwatson		auditd_log_err("Error creating audit trail file");
331186647Srwatson		fail_exit();
332155131Srwatson	}
333155131Srwatson
334186647Srwatson	/* Generate an audit record. */
335186647Srwatson	err = auditd_gen_record(AUE_audit_startup, NULL);
336186647Srwatson	if (err)
337243750Srwatson		auditd_log_err("auditd_gen_record(AUE_audit_startup) %s: %m",
338186647Srwatson		    auditd_strerror(err));
339243750Srwatson
340186647Srwatson	if (auditd_config_controls() == 0)
341186647Srwatson		auditd_log_info("Audit controls init successful");
342186647Srwatson	else
343186647Srwatson		auditd_log_err("Audit controls init failed");
344186647Srwatson}
345186647Srwatson
346186647Srwatson
347186647Srwatson/*
348243750Srwatson * Close auditd pid file and trigger mechanism.
349186647Srwatson */
350186647Srwatsonstatic int
351186647Srwatsonclose_misc(void)
352186647Srwatson{
353186647Srwatson
354186647Srwatson	auditd_close_dirs();
355186647Srwatson	if (unlink(AUDITD_PIDFILE) == -1 && errno != ENOENT) {
356186647Srwatson		auditd_log_err("Couldn't remove %s: %m", AUDITD_PIDFILE);
357186647Srwatson		return (1);
358186647Srwatson	}
359186647Srwatson	endac();
360186647Srwatson
361186647Srwatson	if (auditd_close_trigger() != 0) {
362186647Srwatson		auditd_log_err("Error closing trigger messaging mechanism");
363186647Srwatson		return (1);
364186647Srwatson	}
365155131Srwatson	return (0);
366155131Srwatson}
367155131Srwatson
368155131Srwatson/*
369155131Srwatson * Close all log files, control files, and tell the audit system.
370155131Srwatson */
371155131Srwatsonstatic int
372155131Srwatsonclose_all(void)
373155131Srwatson{
374155131Srwatson	int err_ret = 0;
375243750Srwatson	char TS[TIMESTAMP_LEN + 1];
376186647Srwatson	int err;
377191273Srwatson	int cond;
378186647Srwatson	time_t tt;
379155131Srwatson
380186647Srwatson	err = auditd_gen_record(AUE_audit_shutdown, NULL);
381186647Srwatson	if (err)
382243750Srwatson		auditd_log_err("auditd_gen_record(AUE_audit_shutdown) %s: %m",
383186647Srwatson		    auditd_strerror(err));
384155131Srwatson
385155131Srwatson	/* Flush contents. */
386155131Srwatson	cond = AUC_DISABLED;
387191273Srwatson	err_ret = audit_set_cond(&cond);
388155131Srwatson	if (err_ret != 0) {
389186647Srwatson		auditd_log_err("Disabling audit failed! : %s", strerror(errno));
390155131Srwatson		err_ret = 1;
391155131Srwatson	}
392186647Srwatson
393186647Srwatson	/*
394186647Srwatson	 * Updated the cached state that auditing has been disabled.
395185573Srwatson	 */
396186647Srwatson	auditd_set_state(AUD_STATE_DISABLED);
397186647Srwatson
398243750Srwatson	if (getTSstr(tt, TS, sizeof(TS)) == 0)
399155131Srwatson		close_lastfile(TS);
400155131Srwatson	if (lastfile != NULL)
401155131Srwatson		free(lastfile);
402155131Srwatson
403186647Srwatson	err_ret += close_misc();
404186647Srwatson
405186647Srwatson	if (err_ret) {
406186647Srwatson		auditd_log_err("Could not unregister");
407155131Srwatson		audit_warn_postsigterm();
408155131Srwatson	}
409155131Srwatson
410186647Srwatson	auditd_log_info("Finished");
411186647Srwatson	return (err_ret);
412155131Srwatson}
413155131Srwatson
414155131Srwatson/*
415186647Srwatson * Register the daemon with the signal handler and the auditd pid file.
416155131Srwatson */
417155131Srwatsonstatic int
418155131Srwatsonregister_daemon(void)
419155131Srwatson{
420155131Srwatson	FILE * pidfile;
421155131Srwatson	int fd;
422155131Srwatson	pid_t pid;
423155131Srwatson
424155131Srwatson	/* Set up the signal hander. */
425186647Srwatson	if (signal(SIGTERM, auditd_relay_signal) == SIG_ERR) {
426186647Srwatson		auditd_log_err(
427159248Srwatson		    "Could not set signal handler for SIGTERM");
428155131Srwatson		fail_exit();
429155131Srwatson	}
430186647Srwatson	if (signal(SIGCHLD, auditd_relay_signal) == SIG_ERR) {
431186647Srwatson		auditd_log_err(
432159248Srwatson		    "Could not set signal handler for SIGCHLD");
433155131Srwatson		fail_exit();
434155131Srwatson	}
435186647Srwatson	if (signal(SIGHUP, auditd_relay_signal) == SIG_ERR) {
436186647Srwatson		auditd_log_err(
437159248Srwatson		    "Could not set signal handler for SIGHUP");
438155131Srwatson		fail_exit();
439155131Srwatson	}
440186647Srwatson	if (signal(SIGALRM, auditd_relay_signal) == SIG_ERR) {
441186647Srwatson		auditd_log_err(
442186647Srwatson		    "Could not set signal handler for SIGALRM");
443186647Srwatson		fail_exit();
444186647Srwatson	}
445155131Srwatson
446155131Srwatson	if ((pidfile = fopen(AUDITD_PIDFILE, "a")) == NULL) {
447186647Srwatson		auditd_log_err("Could not open PID file");
448155131Srwatson		audit_warn_tmpfile();
449155131Srwatson		return (-1);
450155131Srwatson	}
451155131Srwatson
452155131Srwatson	/* Attempt to lock the pid file; if a lock is present, exit. */
453155131Srwatson	fd = fileno(pidfile);
454155131Srwatson	if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
455186647Srwatson		auditd_log_err(
456159248Srwatson		    "PID file is locked (is another auditd running?).");
457155131Srwatson		audit_warn_ebusy();
458155131Srwatson		return (-1);
459155131Srwatson	}
460155131Srwatson
461155131Srwatson	pid = getpid();
462155131Srwatson	ftruncate(fd, 0);
463155131Srwatson	if (fprintf(pidfile, "%u\n", pid) < 0) {
464155131Srwatson		/* Should not start the daemon. */
465155131Srwatson		fail_exit();
466155131Srwatson	}
467155131Srwatson
468155131Srwatson	fflush(pidfile);
469155131Srwatson	return (0);
470155131Srwatson}
471155131Srwatson
472155131Srwatson/*
473162503Srwatson * Handle the audit trigger event.
474162503Srwatson *
475162503Srwatson * We suppress (ignore) duplicated triggers in close succession in order to
476162503Srwatson * try to avoid thrashing-like behavior.  However, not all triggers can be
477162503Srwatson * ignored, as triggers generally represent edge triggers, not level
478162503Srwatson * triggers, and won't be retransmitted if the condition persists.  Of
479162503Srwatson * specific concern is the rotate trigger -- if one is dropped, then it will
480162503Srwatson * not be retransmitted, and the log file will grow in an unbounded fashion.
481155131Srwatson */
482155131Srwatson#define	DUPLICATE_INTERVAL	30
483186647Srwatsonvoid
484186647Srwatsonauditd_handle_trigger(int trigger)
485155131Srwatson{
486162503Srwatson	static int last_trigger, last_warning;
487155131Srwatson	static time_t last_time;
488162503Srwatson	struct timeval ts;
489162503Srwatson	struct timezone tzp;
490162503Srwatson	time_t tt;
491186647Srwatson	int au_state;
492186647Srwatson	int err = 0;
493155131Srwatson
494155131Srwatson	/*
495162503Srwatson	 * Suppress duplicate messages from the kernel within the specified
496155131Srwatson	 * interval.
497155131Srwatson	 */
498155131Srwatson	if (gettimeofday(&ts, &tzp) == 0) {
499155131Srwatson		tt = (time_t)ts.tv_sec;
500162503Srwatson		switch (trigger) {
501162503Srwatson		case AUDIT_TRIGGER_LOW_SPACE:
502162503Srwatson		case AUDIT_TRIGGER_NO_SPACE:
503162503Srwatson			/*
504162503Srwatson			 * Triggers we can suppress.  Of course, we also need
505162503Srwatson			 * to rate limit the warnings, so apply the same
506162503Srwatson			 * interval limit on syslog messages.
507162503Srwatson			 */
508162503Srwatson			if ((trigger == last_trigger) &&
509162503Srwatson			    (tt < (last_time + DUPLICATE_INTERVAL))) {
510162503Srwatson				if (tt >= (last_warning + DUPLICATE_INTERVAL))
511186647Srwatson					auditd_log_info(
512162503Srwatson					    "Suppressing duplicate trigger %d",
513162503Srwatson					    trigger);
514186647Srwatson				return;
515162503Srwatson			}
516162503Srwatson			last_warning = tt;
517162503Srwatson			break;
518162503Srwatson
519162503Srwatson		case AUDIT_TRIGGER_ROTATE_KERNEL:
520162503Srwatson		case AUDIT_TRIGGER_ROTATE_USER:
521162503Srwatson		case AUDIT_TRIGGER_READ_FILE:
522186647Srwatson		case AUDIT_TRIGGER_CLOSE_AND_DIE:
523186647Srwatson		case AUDIT_TRIGGER_INITIALIZE:
524162503Srwatson			/*
525162503Srwatson			 * Triggers that we cannot suppress.
526162503Srwatson			 */
527162503Srwatson			break;
528162503Srwatson		}
529162503Srwatson
530162503Srwatson		/*
531162503Srwatson		 * Only update last_trigger after aborting due to a duplicate
532162503Srwatson		 * trigger, not before, or we will never allow that trigger
533162503Srwatson		 * again.
534162503Srwatson		 */
535155131Srwatson		last_trigger = trigger;
536155131Srwatson		last_time = tt;
537155131Srwatson	}
538155131Srwatson
539186647Srwatson	au_state = auditd_get_state();
540186647Srwatson
541155131Srwatson	/*
542155131Srwatson	 * Message processing is done here.
543243750Srwatson	 */
544155131Srwatson	switch(trigger) {
545155131Srwatson	case AUDIT_TRIGGER_LOW_SPACE:
546186647Srwatson		auditd_log_notice("Got low space trigger");
547186647Srwatson		if (do_trail_file() == -1)
548186647Srwatson			auditd_log_err("Error swapping audit file");
549155131Srwatson		break;
550155131Srwatson
551155131Srwatson	case AUDIT_TRIGGER_NO_SPACE:
552186647Srwatson		auditd_log_notice("Got no space trigger");
553186647Srwatson		if (do_trail_file() == -1)
554186647Srwatson			auditd_log_err("Error swapping audit file");
555155131Srwatson		break;
556155131Srwatson
557162503Srwatson	case AUDIT_TRIGGER_ROTATE_KERNEL:
558162503Srwatson	case AUDIT_TRIGGER_ROTATE_USER:
559186647Srwatson		auditd_log_info("Got open new trigger from %s", trigger ==
560162503Srwatson		    AUDIT_TRIGGER_ROTATE_KERNEL ? "kernel" : "user");
561186647Srwatson		if (au_state == AUD_STATE_ENABLED && do_trail_file() == -1)
562186647Srwatson			auditd_log_err("Error swapping audit file");
563155131Srwatson		break;
564155131Srwatson
565155131Srwatson	case AUDIT_TRIGGER_READ_FILE:
566186647Srwatson		auditd_log_info("Got read file trigger");
567191273Srwatson		if (au_state == AUD_STATE_ENABLED) {
568191273Srwatson			if (auditd_config_controls() == -1)
569191273Srwatson				auditd_log_err("Error setting audit controls");
570191273Srwatson			else if (do_trail_file() == -1)
571191273Srwatson				auditd_log_err("Error swapping audit file");
572191273Srwatson		}
573155131Srwatson		break;
574155131Srwatson
575186647Srwatson	case AUDIT_TRIGGER_CLOSE_AND_DIE:
576186647Srwatson		auditd_log_info("Got close and die trigger");
577186647Srwatson		if (au_state == AUD_STATE_ENABLED)
578186647Srwatson			err = close_all();
579185573Srwatson		/*
580186647Srwatson		 * Running under launchd don't exit.  Wait for launchd to
581186647Srwatson		 * send SIGTERM.
582185573Srwatson		 */
583186647Srwatson		if (!launchd_flag) {
584243750Srwatson			auditd_log_info("auditd exiting.");
585186647Srwatson			exit (err);
586185573Srwatson		}
587185573Srwatson		break;
588186647Srwatson
589186647Srwatson	case AUDIT_TRIGGER_INITIALIZE:
590186647Srwatson		auditd_log_info("Got audit initialize trigger");
591186647Srwatson		if (au_state == AUD_STATE_DISABLED)
592186647Srwatson			audit_setup();
593185573Srwatson		break;
594186647Srwatson
595189279Srwatson	case AUDIT_TRIGGER_EXPIRE_TRAILS:
596189279Srwatson		auditd_log_info("Got audit expire trails trigger");
597189279Srwatson		err = auditd_expire_trails(audit_warn_expired);
598189279Srwatson		if (err)
599189279Srwatson			auditd_log_err("auditd_expire_trails(): %s",
600243750Srwatson			    auditd_strerror(err));
601189279Srwatson		break;
602189279Srwatson
603185573Srwatson	default:
604186647Srwatson		auditd_log_err("Got unknown trigger %d", trigger);
605186647Srwatson		break;
606185573Srwatson	}
607185573Srwatson}
608185573Srwatson
609155131Srwatson/*
610159248Srwatson * Reap our children.
611155131Srwatson */
612186647Srwatsonvoid
613186647Srwatsonauditd_reap_children(void)
614159248Srwatson{
615159248Srwatson	pid_t child;
616159248Srwatson	int wstatus;
617159248Srwatson
618159248Srwatson	while ((child = waitpid(-1, &wstatus, WNOHANG)) > 0) {
619159248Srwatson		if (!wstatus)
620159248Srwatson			continue;
621186647Srwatson		auditd_log_info("warn process [pid=%d] %s %d.", child,
622159248Srwatson		    ((WIFEXITED(wstatus)) ? "exited with non-zero status" :
623159248Srwatson		    "exited as a result of signal"),
624159248Srwatson		    ((WIFEXITED(wstatus)) ? WEXITSTATUS(wstatus) :
625159248Srwatson		    WTERMSIG(wstatus)));
626159248Srwatson	}
627159248Srwatson}
628159248Srwatson
629159248Srwatson/*
630186647Srwatson * Reap any children and terminate.  If under launchd don't shutdown auditing
631186647Srwatson * but just the other stuff.
632159248Srwatson */
633186647Srwatsonvoid
634186647Srwatsonauditd_terminate(void)
635185573Srwatson{
636186647Srwatson	int ret;
637185573Srwatson
638186647Srwatson	auditd_reap_children();
639243750Srwatson
640186647Srwatson	if (launchd_flag)
641186647Srwatson		ret = close_misc();
642186647Srwatson	else
643186647Srwatson		ret = close_all();
644185573Srwatson
645186647Srwatson	exit(ret);
646185573Srwatson}
647185573Srwatson
648155131Srwatson/*
649155131Srwatson * Configure the audit controls in the kernel: the event to class mapping,
650155131Srwatson * kernel preselection mask, etc.
651155131Srwatson */
652186647Srwatsonint
653186647Srwatsonauditd_config_controls(void)
654155131Srwatson{
655186647Srwatson	int cnt, err;
656186647Srwatson	int ret = 0;
657155131Srwatson
658155131Srwatson	/*
659186647Srwatson	 * Configure event to class mappings in kernel.
660243750Srwatson	 */
661186647Srwatson	cnt = auditd_set_evcmap();
662186647Srwatson	if (cnt < 0) {
663186647Srwatson		auditd_log_err("auditd_set_evcmap() failed: %m");
664186647Srwatson		ret = -1;
665186647Srwatson	} else if (cnt == 0) {
666186647Srwatson		auditd_log_err("No events to class mappings registered.");
667186647Srwatson		ret = -1;
668186647Srwatson	} else
669186647Srwatson		auditd_log_debug("Registered %d event to class mappings.", cnt);
670162503Srwatson
671162503Srwatson	/*
672186647Srwatson	 * Configure non-attributable event mask in kernel.
673162503Srwatson	 */
674186647Srwatson	err = auditd_set_namask();
675186647Srwatson	if (err) {
676243750Srwatson		auditd_log_err("auditd_set_namask() %s: %m",
677186647Srwatson		    auditd_strerror(err));
678186647Srwatson		ret = -1;
679186647Srwatson	} else
680186647Srwatson		auditd_log_debug("Registered non-attributable event mask.");
681155131Srwatson
682155131Srwatson	/*
683186647Srwatson	 * Configure audit policy in kernel.
684155131Srwatson	 */
685186647Srwatson	err = auditd_set_policy();
686186647Srwatson	if (err) {
687243750Srwatson		auditd_log_err("auditd_set_policy() %s: %m",
688186647Srwatson		    auditd_strerror(err));
689186647Srwatson		ret = -1;
690155131Srwatson	} else
691186647Srwatson		auditd_log_debug("Set audit policy in kernel.");
692243750Srwatson
693155131Srwatson	/*
694186647Srwatson	 * Configure audit trail log size in kernel.
695155131Srwatson	 */
696186647Srwatson	err = auditd_set_fsize();
697186647Srwatson	if (err) {
698186647Srwatson		auditd_log_err("audit_set_fsize() %s: %m",
699186647Srwatson		    auditd_strerror(err));
700186647Srwatson		ret = -1;
701186647Srwatson	} else
702186647Srwatson		auditd_log_debug("Set audit trail size in kernel.");
703243750Srwatson
704162621Srwatson	/*
705243750Srwatson	 * Configure audit trail volume minimum free percentage of blocks in
706186647Srwatson	 * kernel.
707162621Srwatson	 */
708186647Srwatson	err = auditd_set_minfree();
709186647Srwatson	if (err) {
710186647Srwatson		auditd_log_err("auditd_set_minfree() %s: %m",
711186647Srwatson		    auditd_strerror(err));
712186647Srwatson		ret = -1;
713162621Srwatson	} else
714243750Srwatson		auditd_log_debug(
715186647Srwatson		    "Set audit trail min free percent in kernel.");
716162621Srwatson
717185573Srwatson	/*
718243750Srwatson	 * Configure host address in the audit kernel information.
719185573Srwatson	 */
720186647Srwatson	err = auditd_set_host();
721186647Srwatson	if (err) {
722189279Srwatson		if (err == ADE_PARSE) {
723189279Srwatson			auditd_log_notice(
724189279Srwatson			    "audit_control(5) may be missing 'host:' field");
725189279Srwatson		} else {
726189279Srwatson			auditd_log_err("auditd_set_host() %s: %m",
727189279Srwatson			    auditd_strerror(err));
728189279Srwatson			ret = -1;
729189279Srwatson		}
730185573Srwatson	} else
731186647Srwatson		auditd_log_debug(
732186647Srwatson		    "Set audit host address information in kernel.");
733189279Srwatson
734186647Srwatson	return (ret);
735185573Srwatson}
736185573Srwatson
737186647Srwatson/*
738186647Srwatson * Setup and initialize auditd.
739186647Srwatson */
740185573Srwatsonstatic void
741155131Srwatsonsetup(void)
742155131Srwatson{
743186647Srwatson	int err;
744155131Srwatson
745186647Srwatson	if (auditd_open_trigger(launchd_flag) < 0) {
746186647Srwatson		auditd_log_err("Error opening trigger messaging mechanism");
747155131Srwatson		fail_exit();
748155131Srwatson	}
749155131Srwatson
750159248Srwatson	/*
751185573Srwatson	 * To prevent event feedback cycles and avoid auditd becoming
752159248Srwatson	 * stalled if auditing is suspended, auditd and its children run
753159248Srwatson	 * without their events being audited.  We allow the uid, tid, and
754159248Srwatson	 * mask fields to be implicitly set to zero, but do set the pid.  We
755159248Srwatson	 * run this after opening the trigger device to avoid configuring
756159248Srwatson	 * audit state without audit present in the system.
757159248Srwatson	 */
758186647Srwatson	err = auditd_prevent_audit();
759186647Srwatson	if (err) {
760243750Srwatson		auditd_log_err("auditd_prevent_audit() %s: %m",
761186647Srwatson		    auditd_strerror(err));
762159248Srwatson		fail_exit();
763159248Srwatson	}
764159248Srwatson
765186647Srwatson	/*
766186647Srwatson	 * Make sure auditd auditing state is correct.
767186647Srwatson	 */
768186647Srwatson	auditd_set_state(AUD_STATE_INIT);
769155131Srwatson
770186647Srwatson	/*
771186647Srwatson	 * If under launchd, don't start auditing.  Wait for a trigger to
772186647Srwatson	 * do so.
773186647Srwatson	 */
774186647Srwatson	if (!launchd_flag)
775186647Srwatson		audit_setup();
776155131Srwatson}
777155131Srwatson
778155131Srwatsonint
779155131Srwatsonmain(int argc, char **argv)
780155131Srwatson{
781155364Srwatson	int ch;
782155131Srwatson	int debug = 0;
783186647Srwatson#ifdef AUDIT_REVIEW_GROUP
784186647Srwatson	struct group *grp;
785186647Srwatson#endif
786155131Srwatson
787186647Srwatson	while ((ch = getopt(argc, argv, "dl")) != -1) {
788155131Srwatson		switch(ch) {
789155131Srwatson		case 'd':
790155131Srwatson			/* Debug option. */
791155131Srwatson			debug = 1;
792155131Srwatson			break;
793155131Srwatson
794186647Srwatson		case 'l':
795186647Srwatson			/* Be launchd friendly. */
796186647Srwatson			launchd_flag = 1;
797186647Srwatson			break;
798186647Srwatson
799155131Srwatson		case '?':
800155131Srwatson		default:
801155131Srwatson			(void)fprintf(stderr,
802186647Srwatson			    "usage: auditd [-d] [-l]\n");
803155131Srwatson			exit(1);
804155131Srwatson		}
805155131Srwatson	}
806155131Srwatson
807186647Srwatson	audit_review_gid = getgid();
808185573Srwatson
809186647Srwatson#ifdef AUDIT_REVIEW_GROUP
810186647Srwatson	/*
811186647Srwatson	 * XXXRW: Currently, this code falls back to the daemon gid, which is
812186647Srwatson	 * likely the wheel group.  Is there a better way to deal with this?
813186647Srwatson	 */
814186647Srwatson	grp = getgrnam(AUDIT_REVIEW_GROUP);
815243750Srwatson	if (grp != NULL)
816186647Srwatson		audit_review_gid = grp->gr_gid;
817156283Srwatson#endif
818155131Srwatson
819186647Srwatson	auditd_openlog(debug, audit_review_gid);
820186647Srwatson
821186647Srwatson	if (launchd_flag)
822186647Srwatson		auditd_log_info("started by launchd...");
823186647Srwatson	else
824186647Srwatson		auditd_log_info("starting...");
825186647Srwatson
826186647Srwatson#ifdef AUDIT_REVIEW_GROUP
827186647Srwatson	if (grp == NULL)
828186647Srwatson		auditd_log_info(
829186647Srwatson		    "Audit review group '%s' not available, using daemon gid (%d)",
830186647Srwatson		    AUDIT_REVIEW_GROUP, audit_review_gid);
831186647Srwatson#endif
832186647Srwatson	if (debug == 0 && launchd_flag == 0 && daemon(0, 0) == -1) {
833186647Srwatson		auditd_log_err("Failed to daemonize");
834155131Srwatson		exit(1);
835155131Srwatson	}
836155131Srwatson
837155131Srwatson	if (register_daemon() == -1) {
838186647Srwatson		auditd_log_err("Could not register as daemon");
839155131Srwatson		exit(1);
840155131Srwatson	}
841155131Srwatson
842155131Srwatson	setup();
843155131Srwatson
844186647Srwatson	/*
845243750Srwatson	 * auditd_wait_for_events() shouldn't return unless something is wrong.
846186647Srwatson	 */
847186647Srwatson	auditd_wait_for_events();
848155131Srwatson
849186647Srwatson	auditd_log_err("abnormal exit.");
850186647Srwatson	close_all();
851186647Srwatson	exit(-1);
852155131Srwatson}
853