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