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