xref: /freebsd/contrib/openbsm/bin/auditd/auditd_fbsd.c (revision 8dd74db753c5c918971fbf5e515490c4c5245fb8)
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  */
297a0a89d2SRobert Watson 
307a0a89d2SRobert Watson #include <sys/types.h>
317a0a89d2SRobert Watson 
327a0a89d2SRobert Watson #include <config/config.h>
337a0a89d2SRobert Watson 
347a0a89d2SRobert Watson #include <errno.h>
357a0a89d2SRobert Watson #include <fcntl.h>
367a0a89d2SRobert Watson #include <stdarg.h>
37c74c7b73SRobert Watson #include <signal.h>
38c74c7b73SRobert Watson #include <string.h>
39c74c7b73SRobert Watson #include <syslog.h>
40c74c7b73SRobert Watson #include <unistd.h>
417a0a89d2SRobert Watson 
427a0a89d2SRobert Watson #include <bsm/audit.h>
437a0a89d2SRobert Watson #include <bsm/audit_uevents.h>
447a0a89d2SRobert Watson #include <bsm/auditd_lib.h>
457a0a89d2SRobert Watson #include <bsm/libbsm.h>
467a0a89d2SRobert Watson 
477a0a89d2SRobert Watson #include "auditd.h"
487a0a89d2SRobert Watson 
497a0a89d2SRobert Watson /*
507a0a89d2SRobert Watson  * Current auditing state (cache).
517a0a89d2SRobert Watson  */
527a0a89d2SRobert Watson static int	auditing_state = AUD_STATE_INIT;
537a0a89d2SRobert Watson 
547a0a89d2SRobert Watson /*
557a0a89d2SRobert Watson  * Maximum idle time before auditd terminates under launchd.
567a0a89d2SRobert Watson  * If it is zero then auditd does not timeout while idle.
577a0a89d2SRobert Watson  */
587a0a89d2SRobert Watson static int	max_idletime = 0;
597a0a89d2SRobert Watson 
607a0a89d2SRobert Watson static int	sigchlds, sigchlds_handled;
617a0a89d2SRobert Watson static int	sighups, sighups_handled;
627a0a89d2SRobert Watson static int	sigterms, sigterms_handled;
637a0a89d2SRobert Watson static int	sigalrms, sigalrms_handled;
647a0a89d2SRobert Watson 
657a0a89d2SRobert Watson static int	triggerfd = 0;
667a0a89d2SRobert Watson 
677a0a89d2SRobert Watson /*
687a0a89d2SRobert Watson  *  Open and set up system logging.
697a0a89d2SRobert Watson  */
707a0a89d2SRobert Watson void
auditd_openlog(int debug,gid_t __unused gid)717a0a89d2SRobert Watson auditd_openlog(int debug, gid_t __unused gid)
727a0a89d2SRobert Watson {
737a0a89d2SRobert Watson 	int logopts = LOG_CONS | LOG_PID;
747a0a89d2SRobert Watson 
757a0a89d2SRobert Watson 	if (debug)
767a0a89d2SRobert Watson 		logopts |= LOG_PERROR;
777a0a89d2SRobert Watson 
787a0a89d2SRobert Watson #ifdef LOG_SECURITY
797a0a89d2SRobert Watson 	openlog("auditd", logopts, LOG_SECURITY);
807a0a89d2SRobert Watson #else
817a0a89d2SRobert Watson 	openlog("auditd", logopts, LOG_AUTH);
827a0a89d2SRobert Watson #endif
837a0a89d2SRobert Watson }
847a0a89d2SRobert Watson 
857a0a89d2SRobert Watson /*
867a0a89d2SRobert Watson  * Log messages at different priority levels.
877a0a89d2SRobert Watson  */
887a0a89d2SRobert Watson void
auditd_log_err(const char * fmt,...)897a0a89d2SRobert Watson auditd_log_err(const char *fmt, ...)
907a0a89d2SRobert Watson {
917a0a89d2SRobert Watson 	va_list ap;
927a0a89d2SRobert Watson 
937a0a89d2SRobert Watson 	va_start(ap, fmt);
947a0a89d2SRobert Watson 	vsyslog(LOG_ERR, fmt, ap);
957a0a89d2SRobert Watson 	va_end(ap);
967a0a89d2SRobert Watson }
977a0a89d2SRobert Watson 
987a0a89d2SRobert Watson void
auditd_log_notice(const char * fmt,...)997a0a89d2SRobert Watson auditd_log_notice(const char *fmt, ...)
1007a0a89d2SRobert Watson {
1017a0a89d2SRobert Watson 	va_list ap;
1027a0a89d2SRobert Watson 
1037a0a89d2SRobert Watson 	va_start(ap, fmt);
1047a0a89d2SRobert Watson 	vsyslog(LOG_NOTICE, fmt, ap);
1057a0a89d2SRobert Watson 	va_end(ap);
1067a0a89d2SRobert Watson }
1077a0a89d2SRobert Watson 
1087a0a89d2SRobert Watson void
auditd_log_info(const char * fmt,...)1097a0a89d2SRobert Watson auditd_log_info(const char *fmt, ...)
1107a0a89d2SRobert Watson {
1117a0a89d2SRobert Watson 	va_list ap;
1127a0a89d2SRobert Watson 
1137a0a89d2SRobert Watson 	va_start(ap, fmt);
1147a0a89d2SRobert Watson 	vsyslog(LOG_INFO, fmt, ap);
1157a0a89d2SRobert Watson 	va_end(ap);
1167a0a89d2SRobert Watson }
1177a0a89d2SRobert Watson 
1187a0a89d2SRobert Watson void
auditd_log_debug(const char * fmt,...)1197a0a89d2SRobert Watson auditd_log_debug(const char *fmt, ...)
1207a0a89d2SRobert Watson {
1217a0a89d2SRobert Watson 	va_list ap;
1227a0a89d2SRobert Watson 
1237a0a89d2SRobert Watson 	va_start(ap, fmt);
1247a0a89d2SRobert Watson 	vsyslog(LOG_DEBUG, fmt, ap);
1257a0a89d2SRobert Watson 	va_end(ap);
1267a0a89d2SRobert Watson }
1277a0a89d2SRobert Watson 
1287a0a89d2SRobert Watson /*
1297a0a89d2SRobert Watson  * Get the auditing state from the kernel and cache it.
1307a0a89d2SRobert Watson  */
1317a0a89d2SRobert Watson static void
init_audit_state(void)1327a0a89d2SRobert Watson init_audit_state(void)
1337a0a89d2SRobert Watson {
134c0020399SRobert Watson 	int au_cond;
1357a0a89d2SRobert Watson 
136c0020399SRobert Watson 	if (audit_get_cond(&au_cond) < 0) {
1377a0a89d2SRobert Watson 		if (errno != ENOSYS) {
1387a0a89d2SRobert Watson 			auditd_log_err("Audit status check failed (%s)",
1397a0a89d2SRobert Watson 			    strerror(errno));
1407a0a89d2SRobert Watson 		}
1417a0a89d2SRobert Watson 		auditing_state = AUD_STATE_DISABLED;
1427a0a89d2SRobert Watson 	} else
1437a0a89d2SRobert Watson 		if (au_cond == AUC_NOAUDIT || au_cond == AUC_DISABLED)
1447a0a89d2SRobert Watson 			auditing_state = AUD_STATE_DISABLED;
1457a0a89d2SRobert Watson 		else
1467a0a89d2SRobert Watson 			auditing_state = AUD_STATE_ENABLED;
1477a0a89d2SRobert Watson }
1487a0a89d2SRobert Watson 
1497a0a89d2SRobert Watson /*
1507a0a89d2SRobert Watson  * Update the cached auditing state.
1517a0a89d2SRobert Watson  */
1527a0a89d2SRobert Watson void
auditd_set_state(int state)1537a0a89d2SRobert Watson auditd_set_state(int state)
1547a0a89d2SRobert Watson {
1557a0a89d2SRobert Watson 	int old_auditing_state = auditing_state;
1567a0a89d2SRobert Watson 
1577a0a89d2SRobert Watson 	if (state == AUD_STATE_INIT)
1587a0a89d2SRobert Watson 		init_audit_state();
1597a0a89d2SRobert Watson 	else
1607a0a89d2SRobert Watson 		auditing_state = state;
1617a0a89d2SRobert Watson 
1627a0a89d2SRobert Watson 	if (auditing_state != old_auditing_state) {
1637a0a89d2SRobert Watson 		if (auditing_state == AUD_STATE_ENABLED)
1647a0a89d2SRobert Watson 			auditd_log_notice("Auditing enabled");
1657a0a89d2SRobert Watson 		if (auditing_state == AUD_STATE_DISABLED)
1667a0a89d2SRobert Watson 			auditd_log_notice("Auditing disabled");
1677a0a89d2SRobert Watson 	}
1687a0a89d2SRobert Watson }
1697a0a89d2SRobert Watson 
1707a0a89d2SRobert Watson /*
1717a0a89d2SRobert Watson  * Get the cached auditing state.
1727a0a89d2SRobert Watson  */
1737a0a89d2SRobert Watson int
auditd_get_state(void)1747a0a89d2SRobert Watson auditd_get_state(void)
1757a0a89d2SRobert Watson {
1767a0a89d2SRobert Watson 
1777a0a89d2SRobert Watson 	if (auditing_state == AUD_STATE_INIT)
1787a0a89d2SRobert Watson 		init_audit_state();
1797a0a89d2SRobert Watson 
1807a0a89d2SRobert Watson 	return (auditing_state);
1817a0a89d2SRobert Watson }
1827a0a89d2SRobert Watson 
1837a0a89d2SRobert Watson /*
1847a0a89d2SRobert Watson  * Open the trigger messaging mechanism.
1857a0a89d2SRobert Watson  */
1867a0a89d2SRobert Watson int
auditd_open_trigger(int __unused launchd_flag)1877a0a89d2SRobert Watson auditd_open_trigger(int __unused launchd_flag)
1887a0a89d2SRobert Watson {
1897a0a89d2SRobert Watson 
1907a0a89d2SRobert Watson 	return ((triggerfd = open(AUDIT_TRIGGER_FILE, O_RDONLY, 0)));
1917a0a89d2SRobert Watson }
1927a0a89d2SRobert Watson 
1937a0a89d2SRobert Watson /*
1947a0a89d2SRobert Watson  * Close the trigger messaging mechanism.
1957a0a89d2SRobert Watson  */
1967a0a89d2SRobert Watson int
auditd_close_trigger(void)1977a0a89d2SRobert Watson auditd_close_trigger(void)
1987a0a89d2SRobert Watson {
1997a0a89d2SRobert Watson 
2007a0a89d2SRobert Watson 	return (close(triggerfd));
2017a0a89d2SRobert Watson }
2027a0a89d2SRobert Watson 
2037a0a89d2SRobert Watson /*
2047a0a89d2SRobert Watson  * The main event loop.  Wait for trigger messages or signals and handle them.
2057a0a89d2SRobert Watson  * It should not return unless there is a problem.
2067a0a89d2SRobert Watson  */
2077a0a89d2SRobert Watson void
auditd_wait_for_events(void)2087a0a89d2SRobert Watson auditd_wait_for_events(void)
2097a0a89d2SRobert Watson {
2107a0a89d2SRobert Watson 	int num;
2117a0a89d2SRobert Watson 	unsigned int trigger;
2127a0a89d2SRobert Watson 
2137a0a89d2SRobert Watson 	for (;;) {
2147a0a89d2SRobert Watson 		num = read(triggerfd, &trigger, sizeof(trigger));
2157a0a89d2SRobert Watson 		if ((num == -1) && (errno != EINTR)) {
2167a0a89d2SRobert Watson 			auditd_log_err("%s: error %d", __FUNCTION__, errno);
2177a0a89d2SRobert Watson 			return;
2187a0a89d2SRobert Watson 		}
2197a0a89d2SRobert Watson 
2207a0a89d2SRobert Watson 		/* Reset the idle time alarm, if used. */
2217a0a89d2SRobert Watson 		if (max_idletime)
2227a0a89d2SRobert Watson 			alarm(max_idletime);
2237a0a89d2SRobert Watson 
2247a0a89d2SRobert Watson 		if (sigterms != sigterms_handled) {
2257a0a89d2SRobert Watson 			auditd_log_debug("%s: SIGTERM", __FUNCTION__);
2267a0a89d2SRobert Watson 			auditd_terminate();
2277a0a89d2SRobert Watson 			/* not reached */
2287a0a89d2SRobert Watson 		}
2297a0a89d2SRobert Watson 		if (sigalrms != sigalrms_handled) {
2307a0a89d2SRobert Watson 			auditd_log_debug("%s: SIGALRM", __FUNCTION__);
2317a0a89d2SRobert Watson 			auditd_terminate();
2327a0a89d2SRobert Watson 			/* not reached */
2337a0a89d2SRobert Watson 		}
2347a0a89d2SRobert Watson  		if (sigchlds != sigchlds_handled) {
2357a0a89d2SRobert Watson 			sigchlds_handled = sigchlds;
2367a0a89d2SRobert Watson 			auditd_reap_children();
2377a0a89d2SRobert Watson 		}
2387a0a89d2SRobert Watson 		if (sighups != sighups_handled) {
2397a0a89d2SRobert Watson 			auditd_log_debug("%s: SIGHUP", __FUNCTION__);
2407a0a89d2SRobert Watson 			sighups_handled = sighups;
2417a0a89d2SRobert Watson 			auditd_config_controls();
2427a0a89d2SRobert Watson 		}
2437a0a89d2SRobert Watson 
244*8dd74db7SConrad Meyer 		if (num == -1)
2457a0a89d2SRobert Watson 			continue;
2467a0a89d2SRobert Watson 		if (num == 0) {
2477a0a89d2SRobert Watson 			auditd_log_err("%s: read EOF", __FUNCTION__);
2487a0a89d2SRobert Watson 			return;
2497a0a89d2SRobert Watson 		}
2507a0a89d2SRobert Watson 		auditd_handle_trigger(trigger);
2517a0a89d2SRobert Watson 	}
2527a0a89d2SRobert Watson }
2537a0a89d2SRobert Watson 
2547a0a89d2SRobert Watson /*
2557a0a89d2SRobert Watson  * When we get a signal, we are often not at a clean point.  So, little can
2567a0a89d2SRobert Watson  * be done in the signal handler itself.  Instead,  we send a message to the
2577a0a89d2SRobert Watson  * main servicing loop to do proper handling from a non-signal-handler
2587a0a89d2SRobert Watson  * context.
2597a0a89d2SRobert Watson  */
2607a0a89d2SRobert Watson void
auditd_relay_signal(int signal)2617a0a89d2SRobert Watson auditd_relay_signal(int signal)
2627a0a89d2SRobert Watson {
2637a0a89d2SRobert Watson         if (signal == SIGHUP)
2647a0a89d2SRobert Watson                 sighups++;
2657a0a89d2SRobert Watson         if (signal == SIGTERM)
2667a0a89d2SRobert Watson                 sigterms++;
2677a0a89d2SRobert Watson         if (signal == SIGCHLD)
2687a0a89d2SRobert Watson                 sigchlds++;
2697a0a89d2SRobert Watson 	if (signal == SIGALRM)
2707a0a89d2SRobert Watson 		sigalrms++;
2717a0a89d2SRobert Watson }
2727a0a89d2SRobert Watson 
273