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