a4bd134433
changes since the last imported OpenBSM release: OpenBSM 1.1 alpha 5 - Stub libauditd(3) man page added. - All BSM error number constants with BSM_ERRNO_. - Interfaces to convert between local and BSM socket types and protocol families have been added: au_bsm_to_domain(3), au_bsm_to_socket_type(3), au_domain_to_bsm(3), and au_socket_type_to_bsm(3), along with definitions of constants in audit_domain.h and audit_socket_type.h. This improves interoperability by converting local constant spaces, which vary by OS, to and from Solaris constants (where available) or OpenBSM constants for protocol domains not present in Solaris (a fair number). These routines should be used when generating and interpreting extended socket tokens. - Fix build warnings with full gcc warnings enabled on most supported platforms. - Don't compile error strings into bsm_errno.c when building it in the kernel environment. - When started by launchd, use the label com.apple.auditd rather than org.trustedbsd.auditd. Obtained from: TrustedBSD Project Sponsored by: Apple Inc.
798 lines
18 KiB
C
798 lines
18 KiB
C
/*-
|
|
* Copyright (c) 2004-2008 Apple Inc.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. Neither the name of Apple Inc. ("Apple") nor the names of
|
|
* its contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* $P4: //depot/projects/trustedbsd/openbsm/bin/auditd/auditd.c#41 $
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <config/config.h>
|
|
|
|
#include <sys/dirent.h>
|
|
#ifdef HAVE_FULL_QUEUE_H
|
|
#include <sys/queue.h>
|
|
#else /* !HAVE_FULL_QUEUE_H */
|
|
#include <compat/queue.h>
|
|
#endif /* !HAVE_FULL_QUEUE_H */
|
|
#include <sys/mman.h>
|
|
#include <sys/param.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/wait.h>
|
|
|
|
#include <bsm/audit.h>
|
|
#include <bsm/audit_uevents.h>
|
|
#include <bsm/auditd_lib.h>
|
|
#include <bsm/libbsm.h>
|
|
|
|
#include <err.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <grp.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
#include <signal.h>
|
|
#include <string.h>
|
|
|
|
#include "auditd.h"
|
|
|
|
#ifndef HAVE_STRLCPY
|
|
#include <compat/strlcpy.h>
|
|
#endif
|
|
|
|
/*
|
|
* XXX the following is temporary until this can be added to the kernel
|
|
* audit.h header.
|
|
*/
|
|
#ifndef AUDIT_TRIGGER_INITIALIZE
|
|
#define AUDIT_TRIGGER_INITIALIZE 7
|
|
#endif
|
|
|
|
/*
|
|
* LaunchD flag (Mac OS X and, maybe, FreeBSD only.) See launchd(8) and
|
|
* http://wiki.freebsd.org/launchd for more information.
|
|
*
|
|
* In order for auditd to work "on demand" with launchd(8) it can't:
|
|
* call daemon(3)
|
|
* call fork and having the parent process exit
|
|
* change uids or gids.
|
|
* set up the current working directory or chroot.
|
|
* set the session id
|
|
* change stdio to /dev/null.
|
|
* call setrusage(2)
|
|
* call setpriority(2)
|
|
* Ignore SIGTERM.
|
|
* auditd (in 'launchd mode') is launched on demand so it must catch
|
|
* SIGTERM to exit cleanly.
|
|
*/
|
|
static int launchd_flag = 0;
|
|
|
|
/*
|
|
* The GID of the audit review group (if used). The audit trail files and
|
|
* system logs (Mac OS X only) can only be reviewed by members of this group
|
|
* or the audit administrator (aka. "root").
|
|
*/
|
|
static gid_t audit_review_gid = -1;
|
|
|
|
/*
|
|
* The path and file name of the last audit trail file.
|
|
*/
|
|
static char *lastfile = NULL;
|
|
|
|
/*
|
|
* Error starting auditd. Run warn script and exit.
|
|
*/
|
|
static void
|
|
fail_exit(void)
|
|
{
|
|
|
|
audit_warn_nostart();
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
* Follow the 'current' symlink to get the active trail file name.
|
|
*/
|
|
static char *
|
|
get_curfile(void)
|
|
{
|
|
char *cf;
|
|
int len;
|
|
|
|
cf = malloc(MAXPATHLEN);
|
|
if (cf == NULL) {
|
|
auditd_log_err("malloc failed: %m");
|
|
return (NULL);
|
|
}
|
|
|
|
len = readlink(AUDIT_CURRENT_LINK, cf, MAXPATHLEN - 1);
|
|
if (len < 0) {
|
|
free(cf);
|
|
return (NULL);
|
|
}
|
|
|
|
/* readlink() doesn't terminate string. */
|
|
cf[len] = '\0';
|
|
|
|
return (cf);
|
|
}
|
|
|
|
/*
|
|
* Close the previous audit trail file.
|
|
*/
|
|
static int
|
|
close_lastfile(char *TS)
|
|
{
|
|
char *ptr;
|
|
char *oldname;
|
|
size_t len;
|
|
|
|
/* If lastfile is NULL try to get it from the 'current' link. */
|
|
if (lastfile == NULL)
|
|
lastfile = get_curfile();
|
|
|
|
if (lastfile != NULL) {
|
|
len = strlen(lastfile) + 1;
|
|
oldname = (char *)malloc(len);
|
|
if (oldname == NULL)
|
|
return (-1);
|
|
strlcpy(oldname, lastfile, len);
|
|
|
|
/* Rename the last file -- append timestamp. */
|
|
if ((ptr = strstr(lastfile, NOT_TERMINATED)) != NULL) {
|
|
strlcpy(ptr, TS, TIMESTAMP_LEN);
|
|
if (rename(oldname, lastfile) != 0)
|
|
auditd_log_err(
|
|
"Could not rename %s to %s: %m", oldname,
|
|
lastfile);
|
|
else {
|
|
/*
|
|
* Remove the 'current' symlink since the link
|
|
* is now invalid.
|
|
*/
|
|
(void) unlink(AUDIT_CURRENT_LINK);
|
|
auditd_log_notice( "renamed %s to %s",
|
|
oldname, lastfile);
|
|
audit_warn_closefile(lastfile);
|
|
}
|
|
} else
|
|
auditd_log_err( "Could not rename %s to %s", oldname,
|
|
lastfile);
|
|
free(lastfile);
|
|
free(oldname);
|
|
lastfile = NULL;
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Create the new file name, swap with existing audit file.
|
|
*/
|
|
static int
|
|
swap_audit_file(void)
|
|
{
|
|
int err;
|
|
char *newfile;
|
|
char TS[TIMESTAMP_LEN];
|
|
time_t tt;
|
|
|
|
if (getTSstr(tt, TS, TIMESTAMP_LEN) != 0)
|
|
return (-1);
|
|
err = auditd_swap_trail(TS, &newfile, audit_review_gid,
|
|
audit_warn_getacdir);
|
|
if (err != ADE_NOERR) {
|
|
auditd_log_err( "%s: %m", auditd_strerror(err));
|
|
if (err != ADE_ACTL)
|
|
return (-1);
|
|
}
|
|
|
|
/*
|
|
* Only close the last file if were in an auditing state before
|
|
* calling swap_audit_file(). We may need to recover from a crash.
|
|
*/
|
|
if (auditd_get_state() == AUD_STATE_ENABLED)
|
|
close_lastfile(TS);
|
|
|
|
|
|
/*
|
|
* auditd_swap_trail() potentially enables auditing (if not already
|
|
* enabled) so updated the cached state as well.
|
|
*/
|
|
auditd_set_state(AUD_STATE_ENABLED);
|
|
|
|
/*
|
|
* Create 'current' symlink. Recover from crash, if needed.
|
|
*/
|
|
if (auditd_new_curlink(newfile) != 0)
|
|
auditd_log_err("auditd_new_curlink(\"%s\") failed: %s: %m",
|
|
newfile, auditd_strerror(err));
|
|
|
|
lastfile = newfile;
|
|
auditd_log_notice("New audit file is %s", newfile);
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Create a new audit log trail file and swap with the current one, if any.
|
|
*/
|
|
static int
|
|
do_trail_file(void)
|
|
{
|
|
int err;
|
|
|
|
/*
|
|
* First, refresh the list of audit log directories.
|
|
*/
|
|
err = auditd_read_dirs(audit_warn_soft, audit_warn_hard);
|
|
if (err) {
|
|
auditd_log_err("auditd_read_dirs(): %s",
|
|
auditd_strerror(err));
|
|
if (err == ADE_HARDLIM)
|
|
audit_warn_allhard();
|
|
if (err != ADE_SOFTLIM)
|
|
return (-1);
|
|
else
|
|
audit_warn_allsoft();
|
|
/* continue on with soft limit error */
|
|
}
|
|
|
|
/*
|
|
* Create a new file and swap with the one being used in kernel.
|
|
*/
|
|
if (swap_audit_file() == -1) {
|
|
/*
|
|
* XXX Faulty directory listing? - user should be given
|
|
* XXX an opportunity to change the audit_control file
|
|
* XXX switch to a reduced mode of auditing?
|
|
*/
|
|
return (-1);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Start up auditing.
|
|
*/
|
|
static void
|
|
audit_setup(void)
|
|
{
|
|
int err;
|
|
|
|
if (do_trail_file() == -1) {
|
|
auditd_log_err("Error creating audit trail file");
|
|
fail_exit();
|
|
}
|
|
|
|
/* Generate an audit record. */
|
|
err = auditd_gen_record(AUE_audit_startup, NULL);
|
|
if (err)
|
|
auditd_log_err("auditd_gen_record(AUE_audit_startup) %s: %m",
|
|
auditd_strerror(err));
|
|
|
|
if (auditd_config_controls() == 0)
|
|
auditd_log_info("Audit controls init successful");
|
|
else
|
|
auditd_log_err("Audit controls init failed");
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* Close auditd pid file and trigger mechanism.
|
|
*/
|
|
static int
|
|
close_misc(void)
|
|
{
|
|
|
|
auditd_close_dirs();
|
|
if (unlink(AUDITD_PIDFILE) == -1 && errno != ENOENT) {
|
|
auditd_log_err("Couldn't remove %s: %m", AUDITD_PIDFILE);
|
|
return (1);
|
|
}
|
|
endac();
|
|
|
|
if (auditd_close_trigger() != 0) {
|
|
auditd_log_err("Error closing trigger messaging mechanism");
|
|
return (1);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Close all log files, control files, and tell the audit system.
|
|
*/
|
|
static int
|
|
close_all(void)
|
|
{
|
|
int err_ret = 0;
|
|
char TS[TIMESTAMP_LEN];
|
|
int err;
|
|
long cond;
|
|
time_t tt;
|
|
|
|
err = auditd_gen_record(AUE_audit_shutdown, NULL);
|
|
if (err)
|
|
auditd_log_err("auditd_gen_record(AUE_audit_shutdown) %s: %m",
|
|
auditd_strerror(err));
|
|
|
|
/* Flush contents. */
|
|
cond = AUC_DISABLED;
|
|
err_ret = auditon(A_SETCOND, &cond, sizeof(cond));
|
|
if (err_ret != 0) {
|
|
auditd_log_err("Disabling audit failed! : %s", strerror(errno));
|
|
err_ret = 1;
|
|
}
|
|
|
|
/*
|
|
* Updated the cached state that auditing has been disabled.
|
|
*/
|
|
auditd_set_state(AUD_STATE_DISABLED);
|
|
|
|
if (getTSstr(tt, TS, TIMESTAMP_LEN) == 0)
|
|
close_lastfile(TS);
|
|
if (lastfile != NULL)
|
|
free(lastfile);
|
|
|
|
err_ret += close_misc();
|
|
|
|
if (err_ret) {
|
|
auditd_log_err("Could not unregister");
|
|
audit_warn_postsigterm();
|
|
}
|
|
|
|
auditd_log_info("Finished");
|
|
return (err_ret);
|
|
}
|
|
|
|
/*
|
|
* Register the daemon with the signal handler and the auditd pid file.
|
|
*/
|
|
static int
|
|
register_daemon(void)
|
|
{
|
|
FILE * pidfile;
|
|
int fd;
|
|
pid_t pid;
|
|
|
|
/* Set up the signal hander. */
|
|
if (signal(SIGTERM, auditd_relay_signal) == SIG_ERR) {
|
|
auditd_log_err(
|
|
"Could not set signal handler for SIGTERM");
|
|
fail_exit();
|
|
}
|
|
if (signal(SIGCHLD, auditd_relay_signal) == SIG_ERR) {
|
|
auditd_log_err(
|
|
"Could not set signal handler for SIGCHLD");
|
|
fail_exit();
|
|
}
|
|
if (signal(SIGHUP, auditd_relay_signal) == SIG_ERR) {
|
|
auditd_log_err(
|
|
"Could not set signal handler for SIGHUP");
|
|
fail_exit();
|
|
}
|
|
if (signal(SIGALRM, auditd_relay_signal) == SIG_ERR) {
|
|
auditd_log_err(
|
|
"Could not set signal handler for SIGALRM");
|
|
fail_exit();
|
|
}
|
|
|
|
if ((pidfile = fopen(AUDITD_PIDFILE, "a")) == NULL) {
|
|
auditd_log_err("Could not open PID file");
|
|
audit_warn_tmpfile();
|
|
return (-1);
|
|
}
|
|
|
|
/* Attempt to lock the pid file; if a lock is present, exit. */
|
|
fd = fileno(pidfile);
|
|
if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
|
|
auditd_log_err(
|
|
"PID file is locked (is another auditd running?).");
|
|
audit_warn_ebusy();
|
|
return (-1);
|
|
}
|
|
|
|
pid = getpid();
|
|
ftruncate(fd, 0);
|
|
if (fprintf(pidfile, "%u\n", pid) < 0) {
|
|
/* Should not start the daemon. */
|
|
fail_exit();
|
|
}
|
|
|
|
fflush(pidfile);
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Handle the audit trigger event.
|
|
*
|
|
* We suppress (ignore) duplicated triggers in close succession in order to
|
|
* try to avoid thrashing-like behavior. However, not all triggers can be
|
|
* ignored, as triggers generally represent edge triggers, not level
|
|
* triggers, and won't be retransmitted if the condition persists. Of
|
|
* specific concern is the rotate trigger -- if one is dropped, then it will
|
|
* not be retransmitted, and the log file will grow in an unbounded fashion.
|
|
*/
|
|
#define DUPLICATE_INTERVAL 30
|
|
void
|
|
auditd_handle_trigger(int trigger)
|
|
{
|
|
static int last_trigger, last_warning;
|
|
static time_t last_time;
|
|
struct timeval ts;
|
|
struct timezone tzp;
|
|
time_t tt;
|
|
int au_state;
|
|
int err = 0;
|
|
|
|
/*
|
|
* Suppress duplicate messages from the kernel within the specified
|
|
* interval.
|
|
*/
|
|
if (gettimeofday(&ts, &tzp) == 0) {
|
|
tt = (time_t)ts.tv_sec;
|
|
switch (trigger) {
|
|
case AUDIT_TRIGGER_LOW_SPACE:
|
|
case AUDIT_TRIGGER_NO_SPACE:
|
|
/*
|
|
* Triggers we can suppress. Of course, we also need
|
|
* to rate limit the warnings, so apply the same
|
|
* interval limit on syslog messages.
|
|
*/
|
|
if ((trigger == last_trigger) &&
|
|
(tt < (last_time + DUPLICATE_INTERVAL))) {
|
|
if (tt >= (last_warning + DUPLICATE_INTERVAL))
|
|
auditd_log_info(
|
|
"Suppressing duplicate trigger %d",
|
|
trigger);
|
|
return;
|
|
}
|
|
last_warning = tt;
|
|
break;
|
|
|
|
case AUDIT_TRIGGER_ROTATE_KERNEL:
|
|
case AUDIT_TRIGGER_ROTATE_USER:
|
|
case AUDIT_TRIGGER_READ_FILE:
|
|
case AUDIT_TRIGGER_CLOSE_AND_DIE:
|
|
case AUDIT_TRIGGER_INITIALIZE:
|
|
/*
|
|
* Triggers that we cannot suppress.
|
|
*/
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Only update last_trigger after aborting due to a duplicate
|
|
* trigger, not before, or we will never allow that trigger
|
|
* again.
|
|
*/
|
|
last_trigger = trigger;
|
|
last_time = tt;
|
|
}
|
|
|
|
au_state = auditd_get_state();
|
|
|
|
/*
|
|
* Message processing is done here.
|
|
*/
|
|
switch(trigger) {
|
|
case AUDIT_TRIGGER_LOW_SPACE:
|
|
auditd_log_notice("Got low space trigger");
|
|
if (do_trail_file() == -1)
|
|
auditd_log_err("Error swapping audit file");
|
|
break;
|
|
|
|
case AUDIT_TRIGGER_NO_SPACE:
|
|
auditd_log_notice("Got no space trigger");
|
|
if (do_trail_file() == -1)
|
|
auditd_log_err("Error swapping audit file");
|
|
break;
|
|
|
|
case AUDIT_TRIGGER_ROTATE_KERNEL:
|
|
case AUDIT_TRIGGER_ROTATE_USER:
|
|
auditd_log_info("Got open new trigger from %s", trigger ==
|
|
AUDIT_TRIGGER_ROTATE_KERNEL ? "kernel" : "user");
|
|
if (au_state == AUD_STATE_ENABLED && do_trail_file() == -1)
|
|
auditd_log_err("Error swapping audit file");
|
|
break;
|
|
|
|
case AUDIT_TRIGGER_READ_FILE:
|
|
auditd_log_info("Got read file trigger");
|
|
if (au_state == AUD_STATE_ENABLED &&
|
|
auditd_config_controls() == -1)
|
|
auditd_log_err("Error setting audit controls");
|
|
break;
|
|
|
|
case AUDIT_TRIGGER_CLOSE_AND_DIE:
|
|
auditd_log_info("Got close and die trigger");
|
|
if (au_state == AUD_STATE_ENABLED)
|
|
err = close_all();
|
|
/*
|
|
* Running under launchd don't exit. Wait for launchd to
|
|
* send SIGTERM.
|
|
*/
|
|
if (!launchd_flag) {
|
|
auditd_log_info("auditd exiting.");
|
|
exit (err);
|
|
}
|
|
break;
|
|
|
|
case AUDIT_TRIGGER_INITIALIZE:
|
|
auditd_log_info("Got audit initialize trigger");
|
|
if (au_state == AUD_STATE_DISABLED)
|
|
audit_setup();
|
|
break;
|
|
|
|
default:
|
|
auditd_log_err("Got unknown trigger %d", trigger);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Reap our children.
|
|
*/
|
|
void
|
|
auditd_reap_children(void)
|
|
{
|
|
pid_t child;
|
|
int wstatus;
|
|
|
|
while ((child = waitpid(-1, &wstatus, WNOHANG)) > 0) {
|
|
if (!wstatus)
|
|
continue;
|
|
auditd_log_info("warn process [pid=%d] %s %d.", child,
|
|
((WIFEXITED(wstatus)) ? "exited with non-zero status" :
|
|
"exited as a result of signal"),
|
|
((WIFEXITED(wstatus)) ? WEXITSTATUS(wstatus) :
|
|
WTERMSIG(wstatus)));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Reap any children and terminate. If under launchd don't shutdown auditing
|
|
* but just the other stuff.
|
|
*/
|
|
void
|
|
auditd_terminate(void)
|
|
{
|
|
int ret;
|
|
|
|
auditd_reap_children();
|
|
|
|
if (launchd_flag)
|
|
ret = close_misc();
|
|
else
|
|
ret = close_all();
|
|
|
|
exit(ret);
|
|
}
|
|
|
|
/*
|
|
* Configure the audit controls in the kernel: the event to class mapping,
|
|
* kernel preselection mask, etc.
|
|
*/
|
|
int
|
|
auditd_config_controls(void)
|
|
{
|
|
int cnt, err;
|
|
int ret = 0;
|
|
|
|
/*
|
|
* Configure event to class mappings in kernel.
|
|
*/
|
|
cnt = auditd_set_evcmap();
|
|
if (cnt < 0) {
|
|
auditd_log_err("auditd_set_evcmap() failed: %m");
|
|
ret = -1;
|
|
} else if (cnt == 0) {
|
|
auditd_log_err("No events to class mappings registered.");
|
|
ret = -1;
|
|
} else
|
|
auditd_log_debug("Registered %d event to class mappings.", cnt);
|
|
|
|
/*
|
|
* Configure non-attributable event mask in kernel.
|
|
*/
|
|
err = auditd_set_namask();
|
|
if (err) {
|
|
auditd_log_err("auditd_set_namask() %s: %m",
|
|
auditd_strerror(err));
|
|
ret = -1;
|
|
} else
|
|
auditd_log_debug("Registered non-attributable event mask.");
|
|
|
|
/*
|
|
* Configure audit policy in kernel.
|
|
*/
|
|
err = auditd_set_policy();
|
|
if (err) {
|
|
auditd_log_err("auditd_set_policy() %s: %m",
|
|
auditd_strerror(err));
|
|
ret = -1;
|
|
} else
|
|
auditd_log_debug("Set audit policy in kernel.");
|
|
|
|
/*
|
|
* Configure audit trail log size in kernel.
|
|
*/
|
|
err = auditd_set_fsize();
|
|
if (err) {
|
|
auditd_log_err("audit_set_fsize() %s: %m",
|
|
auditd_strerror(err));
|
|
ret = -1;
|
|
} else
|
|
auditd_log_debug("Set audit trail size in kernel.");
|
|
|
|
/*
|
|
* Configure audit trail volume minimum free percentage of blocks in
|
|
* kernel.
|
|
*/
|
|
err = auditd_set_minfree();
|
|
if (err) {
|
|
auditd_log_err("auditd_set_minfree() %s: %m",
|
|
auditd_strerror(err));
|
|
ret = -1;
|
|
} else
|
|
auditd_log_debug(
|
|
"Set audit trail min free percent in kernel.");
|
|
|
|
/*
|
|
* Configure host address in the audit kernel information.
|
|
*/
|
|
err = auditd_set_host();
|
|
if (err) {
|
|
auditd_log_err("auditd_set_host() %s: %m",
|
|
auditd_strerror(err));
|
|
ret = -1;
|
|
} else
|
|
auditd_log_debug(
|
|
"Set audit host address information in kernel.");
|
|
|
|
return (ret);
|
|
}
|
|
|
|
/*
|
|
* Setup and initialize auditd.
|
|
*/
|
|
static void
|
|
setup(void)
|
|
{
|
|
int err;
|
|
|
|
if (auditd_open_trigger(launchd_flag) < 0) {
|
|
auditd_log_err("Error opening trigger messaging mechanism");
|
|
fail_exit();
|
|
}
|
|
|
|
/*
|
|
* To prevent event feedback cycles and avoid auditd becoming
|
|
* stalled if auditing is suspended, auditd and its children run
|
|
* without their events being audited. We allow the uid, tid, and
|
|
* mask fields to be implicitly set to zero, but do set the pid. We
|
|
* run this after opening the trigger device to avoid configuring
|
|
* audit state without audit present in the system.
|
|
*/
|
|
err = auditd_prevent_audit();
|
|
if (err) {
|
|
auditd_log_err("auditd_prevent_audit() %s: %m",
|
|
auditd_strerror(err));
|
|
fail_exit();
|
|
}
|
|
|
|
/*
|
|
* Make sure auditd auditing state is correct.
|
|
*/
|
|
auditd_set_state(AUD_STATE_INIT);
|
|
|
|
/*
|
|
* If under launchd, don't start auditing. Wait for a trigger to
|
|
* do so.
|
|
*/
|
|
if (!launchd_flag)
|
|
audit_setup();
|
|
}
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
int ch;
|
|
int debug = 0;
|
|
#ifdef AUDIT_REVIEW_GROUP
|
|
struct group *grp;
|
|
#endif
|
|
|
|
while ((ch = getopt(argc, argv, "dl")) != -1) {
|
|
switch(ch) {
|
|
case 'd':
|
|
/* Debug option. */
|
|
debug = 1;
|
|
break;
|
|
|
|
case 'l':
|
|
/* Be launchd friendly. */
|
|
launchd_flag = 1;
|
|
break;
|
|
|
|
case '?':
|
|
default:
|
|
(void)fprintf(stderr,
|
|
"usage: auditd [-d] [-l]\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
audit_review_gid = getgid();
|
|
|
|
#ifdef AUDIT_REVIEW_GROUP
|
|
/*
|
|
* XXXRW: Currently, this code falls back to the daemon gid, which is
|
|
* likely the wheel group. Is there a better way to deal with this?
|
|
*/
|
|
grp = getgrnam(AUDIT_REVIEW_GROUP);
|
|
if (grp != NULL)
|
|
audit_review_gid = grp->gr_gid;
|
|
#endif
|
|
|
|
auditd_openlog(debug, audit_review_gid);
|
|
|
|
if (launchd_flag)
|
|
auditd_log_info("started by launchd...");
|
|
else
|
|
auditd_log_info("starting...");
|
|
|
|
#ifdef AUDIT_REVIEW_GROUP
|
|
if (grp == NULL)
|
|
auditd_log_info(
|
|
"Audit review group '%s' not available, using daemon gid (%d)",
|
|
AUDIT_REVIEW_GROUP, audit_review_gid);
|
|
#endif
|
|
if (debug == 0 && launchd_flag == 0 && daemon(0, 0) == -1) {
|
|
auditd_log_err("Failed to daemonize");
|
|
exit(1);
|
|
}
|
|
|
|
if (register_daemon() == -1) {
|
|
auditd_log_err("Could not register as daemon");
|
|
exit(1);
|
|
}
|
|
|
|
setup();
|
|
|
|
/*
|
|
* auditd_wait_for_events() shouldn't return unless something is wrong.
|
|
*/
|
|
auditd_wait_for_events();
|
|
|
|
auditd_log_err("abnormal exit.");
|
|
close_all();
|
|
exit(-1);
|
|
}
|