17a0a89d2SRobert Watson /*- 2c0020399SRobert Watson * Copyright (c) 2004-2009 Apple Inc. 37a0a89d2SRobert Watson * All rights reserved. 47a0a89d2SRobert Watson * 57a0a89d2SRobert Watson * Redistribution and use in source and binary forms, with or without 67a0a89d2SRobert Watson * modification, are permitted provided that the following conditions 77a0a89d2SRobert Watson * are met: 87a0a89d2SRobert Watson * 97a0a89d2SRobert Watson * 1. Redistributions of source code must retain the above copyright 107a0a89d2SRobert Watson * notice, this list of conditions and the following disclaimer. 117a0a89d2SRobert Watson * 2. Redistributions in binary form must reproduce the above copyright 127a0a89d2SRobert Watson * notice, this list of conditions and the following disclaimer in the 137a0a89d2SRobert Watson * documentation and/or other materials provided with the distribution. 147a0a89d2SRobert Watson * 3. Neither the name of Apple Inc. ("Apple") nor the names of 157a0a89d2SRobert Watson * its contributors may be used to endorse or promote products derived 167a0a89d2SRobert Watson * from this software without specific prior written permission. 177a0a89d2SRobert Watson * 187a0a89d2SRobert Watson * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 197a0a89d2SRobert Watson * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 207a0a89d2SRobert Watson * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 217a0a89d2SRobert Watson * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 227a0a89d2SRobert Watson * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 237a0a89d2SRobert Watson * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 247a0a89d2SRobert Watson * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 257a0a89d2SRobert Watson * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 267a0a89d2SRobert Watson * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 277a0a89d2SRobert Watson * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 287a0a89d2SRobert Watson * 29c0020399SRobert Watson * $P4: //depot/projects/trustedbsd/openbsm/bin/auditd/auditd_fbsd.c#4 $ 307a0a89d2SRobert Watson */ 317a0a89d2SRobert Watson 327a0a89d2SRobert Watson #include <sys/types.h> 337a0a89d2SRobert Watson 347a0a89d2SRobert Watson #include <config/config.h> 357a0a89d2SRobert Watson 367a0a89d2SRobert Watson #include <errno.h> 377a0a89d2SRobert Watson #include <fcntl.h> 387a0a89d2SRobert Watson #include <stdarg.h> 39c74c7b73SRobert Watson #include <signal.h> 40c74c7b73SRobert Watson #include <string.h> 41c74c7b73SRobert Watson #include <syslog.h> 42c74c7b73SRobert Watson #include <unistd.h> 437a0a89d2SRobert Watson 447a0a89d2SRobert Watson #include <bsm/audit.h> 457a0a89d2SRobert Watson #include <bsm/audit_uevents.h> 467a0a89d2SRobert Watson #include <bsm/auditd_lib.h> 477a0a89d2SRobert Watson #include <bsm/libbsm.h> 487a0a89d2SRobert Watson 497a0a89d2SRobert Watson #include "auditd.h" 507a0a89d2SRobert Watson 517a0a89d2SRobert Watson /* 527a0a89d2SRobert Watson * Current auditing state (cache). 537a0a89d2SRobert Watson */ 547a0a89d2SRobert Watson static int auditing_state = AUD_STATE_INIT; 557a0a89d2SRobert Watson 567a0a89d2SRobert Watson /* 577a0a89d2SRobert Watson * Maximum idle time before auditd terminates under launchd. 587a0a89d2SRobert Watson * If it is zero then auditd does not timeout while idle. 597a0a89d2SRobert Watson */ 607a0a89d2SRobert Watson static int max_idletime = 0; 617a0a89d2SRobert Watson 627a0a89d2SRobert Watson static int sigchlds, sigchlds_handled; 637a0a89d2SRobert Watson static int sighups, sighups_handled; 647a0a89d2SRobert Watson static int sigterms, sigterms_handled; 657a0a89d2SRobert Watson static int sigalrms, sigalrms_handled; 667a0a89d2SRobert Watson 677a0a89d2SRobert Watson static int triggerfd = 0; 687a0a89d2SRobert Watson 697a0a89d2SRobert Watson /* 707a0a89d2SRobert Watson * Open and set up system logging. 717a0a89d2SRobert Watson */ 727a0a89d2SRobert Watson void 737a0a89d2SRobert Watson auditd_openlog(int debug, gid_t __unused gid) 747a0a89d2SRobert Watson { 757a0a89d2SRobert Watson int logopts = LOG_CONS | LOG_PID; 767a0a89d2SRobert Watson 777a0a89d2SRobert Watson if (debug) 787a0a89d2SRobert Watson logopts |= LOG_PERROR; 797a0a89d2SRobert Watson 807a0a89d2SRobert Watson #ifdef LOG_SECURITY 817a0a89d2SRobert Watson openlog("auditd", logopts, LOG_SECURITY); 827a0a89d2SRobert Watson #else 837a0a89d2SRobert Watson openlog("auditd", logopts, LOG_AUTH); 847a0a89d2SRobert Watson #endif 857a0a89d2SRobert Watson } 867a0a89d2SRobert Watson 877a0a89d2SRobert Watson /* 887a0a89d2SRobert Watson * Log messages at different priority levels. 897a0a89d2SRobert Watson */ 907a0a89d2SRobert Watson void 917a0a89d2SRobert Watson auditd_log_err(const char *fmt, ...) 927a0a89d2SRobert Watson { 937a0a89d2SRobert Watson va_list ap; 947a0a89d2SRobert Watson 957a0a89d2SRobert Watson va_start(ap, fmt); 967a0a89d2SRobert Watson vsyslog(LOG_ERR, fmt, ap); 977a0a89d2SRobert Watson va_end(ap); 987a0a89d2SRobert Watson } 997a0a89d2SRobert Watson 1007a0a89d2SRobert Watson void 1017a0a89d2SRobert Watson auditd_log_notice(const char *fmt, ...) 1027a0a89d2SRobert Watson { 1037a0a89d2SRobert Watson va_list ap; 1047a0a89d2SRobert Watson 1057a0a89d2SRobert Watson va_start(ap, fmt); 1067a0a89d2SRobert Watson vsyslog(LOG_NOTICE, fmt, ap); 1077a0a89d2SRobert Watson va_end(ap); 1087a0a89d2SRobert Watson } 1097a0a89d2SRobert Watson 1107a0a89d2SRobert Watson void 1117a0a89d2SRobert Watson auditd_log_info(const char *fmt, ...) 1127a0a89d2SRobert Watson { 1137a0a89d2SRobert Watson va_list ap; 1147a0a89d2SRobert Watson 1157a0a89d2SRobert Watson va_start(ap, fmt); 1167a0a89d2SRobert Watson vsyslog(LOG_INFO, fmt, ap); 1177a0a89d2SRobert Watson va_end(ap); 1187a0a89d2SRobert Watson } 1197a0a89d2SRobert Watson 1207a0a89d2SRobert Watson void 1217a0a89d2SRobert Watson auditd_log_debug(const char *fmt, ...) 1227a0a89d2SRobert Watson { 1237a0a89d2SRobert Watson va_list ap; 1247a0a89d2SRobert Watson 1257a0a89d2SRobert Watson va_start(ap, fmt); 1267a0a89d2SRobert Watson vsyslog(LOG_DEBUG, fmt, ap); 1277a0a89d2SRobert Watson va_end(ap); 1287a0a89d2SRobert Watson } 1297a0a89d2SRobert Watson 1307a0a89d2SRobert Watson /* 1317a0a89d2SRobert Watson * Get the auditing state from the kernel and cache it. 1327a0a89d2SRobert Watson */ 1337a0a89d2SRobert Watson static void 1347a0a89d2SRobert Watson init_audit_state(void) 1357a0a89d2SRobert Watson { 136c0020399SRobert Watson int au_cond; 1377a0a89d2SRobert Watson 138c0020399SRobert Watson if (audit_get_cond(&au_cond) < 0) { 1397a0a89d2SRobert Watson if (errno != ENOSYS) { 1407a0a89d2SRobert Watson auditd_log_err("Audit status check failed (%s)", 1417a0a89d2SRobert Watson strerror(errno)); 1427a0a89d2SRobert Watson } 1437a0a89d2SRobert Watson auditing_state = AUD_STATE_DISABLED; 1447a0a89d2SRobert Watson } else 1457a0a89d2SRobert Watson if (au_cond == AUC_NOAUDIT || au_cond == AUC_DISABLED) 1467a0a89d2SRobert Watson auditing_state = AUD_STATE_DISABLED; 1477a0a89d2SRobert Watson else 1487a0a89d2SRobert Watson auditing_state = AUD_STATE_ENABLED; 1497a0a89d2SRobert Watson } 1507a0a89d2SRobert Watson 1517a0a89d2SRobert Watson /* 1527a0a89d2SRobert Watson * Update the cached auditing state. 1537a0a89d2SRobert Watson */ 1547a0a89d2SRobert Watson void 1557a0a89d2SRobert Watson auditd_set_state(int state) 1567a0a89d2SRobert Watson { 1577a0a89d2SRobert Watson int old_auditing_state = auditing_state; 1587a0a89d2SRobert Watson 1597a0a89d2SRobert Watson if (state == AUD_STATE_INIT) 1607a0a89d2SRobert Watson init_audit_state(); 1617a0a89d2SRobert Watson else 1627a0a89d2SRobert Watson auditing_state = state; 1637a0a89d2SRobert Watson 1647a0a89d2SRobert Watson if (auditing_state != old_auditing_state) { 1657a0a89d2SRobert Watson if (auditing_state == AUD_STATE_ENABLED) 1667a0a89d2SRobert Watson auditd_log_notice("Auditing enabled"); 1677a0a89d2SRobert Watson if (auditing_state == AUD_STATE_DISABLED) 1687a0a89d2SRobert Watson auditd_log_notice("Auditing disabled"); 1697a0a89d2SRobert Watson } 1707a0a89d2SRobert Watson } 1717a0a89d2SRobert Watson 1727a0a89d2SRobert Watson /* 1737a0a89d2SRobert Watson * Get the cached auditing state. 1747a0a89d2SRobert Watson */ 1757a0a89d2SRobert Watson int 1767a0a89d2SRobert Watson auditd_get_state(void) 1777a0a89d2SRobert Watson { 1787a0a89d2SRobert Watson 1797a0a89d2SRobert Watson if (auditing_state == AUD_STATE_INIT) 1807a0a89d2SRobert Watson init_audit_state(); 1817a0a89d2SRobert Watson 1827a0a89d2SRobert Watson return (auditing_state); 1837a0a89d2SRobert Watson } 1847a0a89d2SRobert Watson 1857a0a89d2SRobert Watson /* 1867a0a89d2SRobert Watson * Open the trigger messaging mechanism. 1877a0a89d2SRobert Watson */ 1887a0a89d2SRobert Watson int 1897a0a89d2SRobert Watson auditd_open_trigger(int __unused launchd_flag) 1907a0a89d2SRobert Watson { 1917a0a89d2SRobert Watson 1927a0a89d2SRobert Watson return ((triggerfd = open(AUDIT_TRIGGER_FILE, O_RDONLY, 0))); 1937a0a89d2SRobert Watson } 1947a0a89d2SRobert Watson 1957a0a89d2SRobert Watson /* 1967a0a89d2SRobert Watson * Close the trigger messaging mechanism. 1977a0a89d2SRobert Watson */ 1987a0a89d2SRobert Watson int 1997a0a89d2SRobert Watson auditd_close_trigger(void) 2007a0a89d2SRobert Watson { 2017a0a89d2SRobert Watson 2027a0a89d2SRobert Watson return (close(triggerfd)); 2037a0a89d2SRobert Watson } 2047a0a89d2SRobert Watson 2057a0a89d2SRobert Watson /* 2067a0a89d2SRobert Watson * The main event loop. Wait for trigger messages or signals and handle them. 2077a0a89d2SRobert Watson * It should not return unless there is a problem. 2087a0a89d2SRobert Watson */ 2097a0a89d2SRobert Watson void 2107a0a89d2SRobert Watson auditd_wait_for_events(void) 2117a0a89d2SRobert Watson { 2127a0a89d2SRobert Watson int num; 2137a0a89d2SRobert Watson unsigned int trigger; 2147a0a89d2SRobert Watson 2157a0a89d2SRobert Watson for (;;) { 2167a0a89d2SRobert Watson num = read(triggerfd, &trigger, sizeof(trigger)); 2177a0a89d2SRobert Watson if ((num == -1) && (errno != EINTR)) { 2187a0a89d2SRobert Watson auditd_log_err("%s: error %d", __FUNCTION__, errno); 2197a0a89d2SRobert Watson return; 2207a0a89d2SRobert Watson } 2217a0a89d2SRobert Watson 2227a0a89d2SRobert Watson /* Reset the idle time alarm, if used. */ 2237a0a89d2SRobert Watson if (max_idletime) 2247a0a89d2SRobert Watson alarm(max_idletime); 2257a0a89d2SRobert Watson 2267a0a89d2SRobert Watson if (sigterms != sigterms_handled) { 2277a0a89d2SRobert Watson auditd_log_debug("%s: SIGTERM", __FUNCTION__); 2287a0a89d2SRobert Watson auditd_terminate(); 2297a0a89d2SRobert Watson /* not reached */ 2307a0a89d2SRobert Watson } 2317a0a89d2SRobert Watson if (sigalrms != sigalrms_handled) { 2327a0a89d2SRobert Watson auditd_log_debug("%s: SIGALRM", __FUNCTION__); 2337a0a89d2SRobert Watson auditd_terminate(); 2347a0a89d2SRobert Watson /* not reached */ 2357a0a89d2SRobert Watson } 2367a0a89d2SRobert Watson if (sigchlds != sigchlds_handled) { 2377a0a89d2SRobert Watson sigchlds_handled = sigchlds; 2387a0a89d2SRobert Watson auditd_reap_children(); 2397a0a89d2SRobert Watson } 2407a0a89d2SRobert Watson if (sighups != sighups_handled) { 2417a0a89d2SRobert Watson auditd_log_debug("%s: SIGHUP", __FUNCTION__); 2427a0a89d2SRobert Watson sighups_handled = sighups; 2437a0a89d2SRobert Watson auditd_config_controls(); 2447a0a89d2SRobert Watson } 2457a0a89d2SRobert Watson 2467a0a89d2SRobert Watson if ((num == -1) && (errno == EINTR)) 2477a0a89d2SRobert Watson continue; 2487a0a89d2SRobert Watson if (num == 0) { 2497a0a89d2SRobert Watson auditd_log_err("%s: read EOF", __FUNCTION__); 2507a0a89d2SRobert Watson return; 2517a0a89d2SRobert Watson } 2527a0a89d2SRobert Watson auditd_handle_trigger(trigger); 2537a0a89d2SRobert Watson } 2547a0a89d2SRobert Watson } 2557a0a89d2SRobert Watson 2567a0a89d2SRobert Watson /* 2577a0a89d2SRobert Watson * When we get a signal, we are often not at a clean point. So, little can 2587a0a89d2SRobert Watson * be done in the signal handler itself. Instead, we send a message to the 2597a0a89d2SRobert Watson * main servicing loop to do proper handling from a non-signal-handler 2607a0a89d2SRobert Watson * context. 2617a0a89d2SRobert Watson */ 2627a0a89d2SRobert Watson void 2637a0a89d2SRobert Watson auditd_relay_signal(int signal) 2647a0a89d2SRobert Watson { 2657a0a89d2SRobert Watson if (signal == SIGHUP) 2667a0a89d2SRobert Watson sighups++; 2677a0a89d2SRobert Watson if (signal == SIGTERM) 2687a0a89d2SRobert Watson sigterms++; 2697a0a89d2SRobert Watson if (signal == SIGCHLD) 2707a0a89d2SRobert Watson sigchlds++; 2717a0a89d2SRobert Watson if (signal == SIGALRM) 2727a0a89d2SRobert Watson sigalrms++; 2737a0a89d2SRobert Watson } 2747a0a89d2SRobert Watson 275