17a0a89d2SRobert Watson /*-
2*c0020399SRobert 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 <stdarg.h>
367a0a89d2SRobert Watson #include <stdlib.h>
377a0a89d2SRobert Watson #include <unistd.h>
387a0a89d2SRobert Watson 
397a0a89d2SRobert Watson #include <bsm/audit.h>
407a0a89d2SRobert Watson #include <bsm/audit_uevents.h>
417a0a89d2SRobert Watson #include <bsm/auditd_lib.h>
427a0a89d2SRobert Watson #include <bsm/libbsm.h>
437a0a89d2SRobert Watson 
447a0a89d2SRobert Watson #include <asl.h>
457a0a89d2SRobert Watson #include <launch.h>
467a0a89d2SRobert Watson #include <notify.h>
477a0a89d2SRobert Watson #include <mach/port.h>
487a0a89d2SRobert Watson #include <mach/mach_error.h>
497a0a89d2SRobert Watson #include <mach/mach_traps.h>
507a0a89d2SRobert Watson #include <mach/mach.h>
517a0a89d2SRobert Watson #include <mach/host_special_ports.h>
527a0a89d2SRobert Watson 
537a0a89d2SRobert Watson #include "auditd.h"
547a0a89d2SRobert Watson 
557a0a89d2SRobert Watson #include "auditd_controlServer.h"
567a0a89d2SRobert Watson #include "audit_triggersServer.h"
577a0a89d2SRobert Watson 
587a0a89d2SRobert Watson /*
597a0a89d2SRobert Watson  * Apple System Logger Handles.
607a0a89d2SRobert Watson  */
617a0a89d2SRobert Watson static aslmsg 		au_aslmsg = NULL;
627a0a89d2SRobert Watson static aslclient	au_aslclient = NULL;
637a0a89d2SRobert Watson 
647a0a89d2SRobert Watson static mach_port_t	control_port = MACH_PORT_NULL;
657a0a89d2SRobert Watson static mach_port_t	signal_port = MACH_PORT_NULL;
667a0a89d2SRobert Watson static mach_port_t	port_set = MACH_PORT_NULL;
677a0a89d2SRobert Watson 
687a0a89d2SRobert Watson /*
697a0a89d2SRobert Watson  * Current auditing state (cache).
707a0a89d2SRobert Watson  */
717a0a89d2SRobert Watson static int		auditing_state = AUD_STATE_INIT;
727a0a89d2SRobert Watson 
737a0a89d2SRobert Watson /*
747a0a89d2SRobert Watson  * Maximum idle time before auditd terminates under launchd.
757a0a89d2SRobert Watson  * If it is zero then auditd does not timeout while idle.
767a0a89d2SRobert Watson  */
777a0a89d2SRobert Watson static int		max_idletime = 0;
787a0a89d2SRobert Watson 
797a0a89d2SRobert Watson #ifndef	__BSM_INTERNAL_NOTIFY_KEY
807a0a89d2SRobert Watson #define	__BSM_INTERNAL_NOTIFY_KEY	"com.apple.audit.change"
817a0a89d2SRobert Watson #endif /* __BSM_INTERNAL_NOTIFY_KEY */
827a0a89d2SRobert Watson 
837a0a89d2SRobert Watson #ifndef	__AUDIT_LAUNCHD_LABEL
84c74c7b73SRobert Watson #define	__AUDIT_LAUNCHD_LABEL		"com.apple.auditd"
857a0a89d2SRobert Watson #endif /* __AUDIT_LAUNCHD_LABEL */
867a0a89d2SRobert Watson 
877a0a89d2SRobert Watson #define	MAX_MSG_SIZE	4096
887a0a89d2SRobert Watson 
897a0a89d2SRobert Watson /*
907a0a89d2SRobert Watson  * Open and set up system logging.
917a0a89d2SRobert Watson  */
927a0a89d2SRobert Watson void
auditd_openlog(int debug,gid_t gid)937a0a89d2SRobert Watson auditd_openlog(int debug, gid_t gid)
947a0a89d2SRobert Watson {
957a0a89d2SRobert Watson 	uint32_t opt = 0;
967a0a89d2SRobert Watson 	char *cp = NULL;
977a0a89d2SRobert Watson 
987a0a89d2SRobert Watson 	if (debug)
997a0a89d2SRobert Watson 		opt = ASL_OPT_STDERR;
1007a0a89d2SRobert Watson 
101c74c7b73SRobert Watson 	au_aslclient = asl_open("auditd", "com.apple.auditd", opt);
1027a0a89d2SRobert Watson 	au_aslmsg = asl_new(ASL_TYPE_MSG);
1037a0a89d2SRobert Watson 
1047a0a89d2SRobert Watson #ifdef ASL_KEY_READ_UID
1057a0a89d2SRobert Watson 	/*
1067a0a89d2SRobert Watson 	 * Make it only so the audit administrator and members of the audit
1077a0a89d2SRobert Watson 	 * review group (if used) have access to the auditd system log messages.
1087a0a89d2SRobert Watson 	 */
1097a0a89d2SRobert Watson 	asl_set(au_aslmsg, ASL_KEY_READ_UID, "0");
1107a0a89d2SRobert Watson 	asprintf(&cp, "%u", gid);
1117a0a89d2SRobert Watson 	if (cp != NULL) {
1127a0a89d2SRobert Watson #ifdef ASL_KEY_READ_GID
1137a0a89d2SRobert Watson 		asl_set(au_aslmsg, ASL_KEY_READ_GID, cp);
1147a0a89d2SRobert Watson #endif
1157a0a89d2SRobert Watson 		free(cp);
1167a0a89d2SRobert Watson 	}
1177a0a89d2SRobert Watson #endif
1187a0a89d2SRobert Watson 
1197a0a89d2SRobert Watson 	/*
1207a0a89d2SRobert Watson 	 * Set the client-side system log filtering.
1217a0a89d2SRobert Watson 	 */
1227a0a89d2SRobert Watson 	if (debug)
1237a0a89d2SRobert Watson 		asl_set_filter(au_aslclient,
1247a0a89d2SRobert Watson 		    ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
1257a0a89d2SRobert Watson 	else
1267a0a89d2SRobert Watson 		asl_set_filter(au_aslclient,
1277a0a89d2SRobert Watson 		    ASL_FILTER_MASK_UPTO(ASL_LEVEL_INFO));
1287a0a89d2SRobert Watson }
1297a0a89d2SRobert Watson 
1307a0a89d2SRobert Watson /*
1317a0a89d2SRobert Watson  * Log messages at different priority levels.
1327a0a89d2SRobert Watson  */
1337a0a89d2SRobert Watson void
auditd_log_err(const char * fmt,...)1347a0a89d2SRobert Watson auditd_log_err(const char *fmt, ...)
1357a0a89d2SRobert Watson {
1367a0a89d2SRobert Watson 	va_list ap;
1377a0a89d2SRobert Watson 
1387a0a89d2SRobert Watson 	va_start(ap, fmt);
1397a0a89d2SRobert Watson 	asl_vlog(au_aslclient, au_aslmsg, ASL_LEVEL_ERR, fmt, ap);
1407a0a89d2SRobert Watson 	va_end(ap);
1417a0a89d2SRobert Watson }
1427a0a89d2SRobert Watson 
1437a0a89d2SRobert Watson void
auditd_log_notice(const char * fmt,...)1447a0a89d2SRobert Watson auditd_log_notice(const char *fmt, ...)
1457a0a89d2SRobert Watson {
1467a0a89d2SRobert Watson 	va_list ap;
1477a0a89d2SRobert Watson 
1487a0a89d2SRobert Watson 	va_start(ap, fmt);
1497a0a89d2SRobert Watson 	asl_vlog(au_aslclient, au_aslmsg, ASL_LEVEL_NOTICE, fmt, ap);
1507a0a89d2SRobert Watson 	va_end(ap);
1517a0a89d2SRobert Watson }
1527a0a89d2SRobert Watson 
1537a0a89d2SRobert Watson void
auditd_log_info(const char * fmt,...)1547a0a89d2SRobert Watson auditd_log_info(const char *fmt, ...)
1557a0a89d2SRobert Watson {
1567a0a89d2SRobert Watson 	va_list ap;
1577a0a89d2SRobert Watson 
1587a0a89d2SRobert Watson 	va_start(ap, fmt);
1597a0a89d2SRobert Watson 	asl_vlog(au_aslclient, au_aslmsg, ASL_LEVEL_INFO, fmt, ap);
1607a0a89d2SRobert Watson 	va_end(ap);
1617a0a89d2SRobert Watson }
1627a0a89d2SRobert Watson 
1637a0a89d2SRobert Watson void
auditd_log_debug(const char * fmt,...)1647a0a89d2SRobert Watson auditd_log_debug(const char *fmt, ...)
1657a0a89d2SRobert Watson {
1667a0a89d2SRobert Watson 	va_list ap;
1677a0a89d2SRobert Watson 
1687a0a89d2SRobert Watson 	va_start(ap, fmt);
1697a0a89d2SRobert Watson 	asl_vlog(au_aslclient, au_aslmsg, ASL_LEVEL_DEBUG, fmt, ap);
1707a0a89d2SRobert Watson 	va_end(ap);
1717a0a89d2SRobert Watson }
1727a0a89d2SRobert Watson 
1737a0a89d2SRobert Watson /*
1747a0a89d2SRobert Watson  * Get the auditing state from the kernel and cache it.
1757a0a89d2SRobert Watson  */
1767a0a89d2SRobert Watson static void
init_audit_state(void)1777a0a89d2SRobert Watson init_audit_state(void)
1787a0a89d2SRobert Watson {
179*c0020399SRobert Watson 	int au_cond;
1807a0a89d2SRobert Watson 
181*c0020399SRobert Watson 	if (audit_get_cond(&au_cond) < 0) {
1827a0a89d2SRobert Watson 		if (errno != ENOSYS) {
1837a0a89d2SRobert Watson 			auditd_log_err("Audit status check failed (%s)",
1847a0a89d2SRobert Watson 			    strerror(errno));
1857a0a89d2SRobert Watson 		}
1867a0a89d2SRobert Watson 		auditing_state = AUD_STATE_DISABLED;
1877a0a89d2SRobert Watson 	} else
1887a0a89d2SRobert Watson 		if (au_cond == AUC_NOAUDIT || au_cond == AUC_DISABLED)
1897a0a89d2SRobert Watson 			auditing_state = AUD_STATE_DISABLED;
1907a0a89d2SRobert Watson 		else
1917a0a89d2SRobert Watson 			auditing_state = AUD_STATE_ENABLED;
1927a0a89d2SRobert Watson }
1937a0a89d2SRobert Watson 
1947a0a89d2SRobert Watson /*
1957a0a89d2SRobert Watson  * Update the cached auditing state.  Let other tasks that may be caching it
1967a0a89d2SRobert Watson  * as well to update their state via notify(3).
1977a0a89d2SRobert Watson  */
1987a0a89d2SRobert Watson void
auditd_set_state(int state)1997a0a89d2SRobert Watson auditd_set_state(int state)
2007a0a89d2SRobert Watson {
2017a0a89d2SRobert Watson 	int old_auditing_state = auditing_state;
2027a0a89d2SRobert Watson 
2037a0a89d2SRobert Watson 	if (state == AUD_STATE_INIT)
2047a0a89d2SRobert Watson 		init_audit_state();
2057a0a89d2SRobert Watson 	else
2067a0a89d2SRobert Watson 		auditing_state = state;
2077a0a89d2SRobert Watson 
2087a0a89d2SRobert Watson 	if (auditing_state != old_auditing_state) {
2097a0a89d2SRobert Watson 		notify_post(__BSM_INTERNAL_NOTIFY_KEY);
2107a0a89d2SRobert Watson 
2117a0a89d2SRobert Watson 		if (auditing_state == AUD_STATE_ENABLED)
2127a0a89d2SRobert Watson 			auditd_log_notice("Auditing enabled");
2137a0a89d2SRobert Watson 		if (auditing_state == AUD_STATE_DISABLED)
2147a0a89d2SRobert Watson 			auditd_log_notice("Auditing disabled");
2157a0a89d2SRobert Watson 	}
2167a0a89d2SRobert Watson }
2177a0a89d2SRobert Watson 
2187a0a89d2SRobert Watson /*
2197a0a89d2SRobert Watson  * Get the cached auditing state.
2207a0a89d2SRobert Watson  */
2217a0a89d2SRobert Watson int
auditd_get_state(void)2227a0a89d2SRobert Watson auditd_get_state(void)
2237a0a89d2SRobert Watson {
2247a0a89d2SRobert Watson 
2257a0a89d2SRobert Watson 	if (auditing_state == AUD_STATE_INIT) {
2267a0a89d2SRobert Watson 		init_audit_state();
2277a0a89d2SRobert Watson 		notify_post(__BSM_INTERNAL_NOTIFY_KEY);
2287a0a89d2SRobert Watson 	}
2297a0a89d2SRobert Watson 
2307a0a89d2SRobert Watson 	return (auditing_state);
2317a0a89d2SRobert Watson }
2327a0a89d2SRobert Watson 
2337a0a89d2SRobert Watson /*
2347a0a89d2SRobert Watson  * Lookup the audit mach port in the launchd dictionary.
2357a0a89d2SRobert Watson  */
2367a0a89d2SRobert Watson static mach_port_t
lookup_machport(const char * label)2377a0a89d2SRobert Watson lookup_machport(const char *label)
2387a0a89d2SRobert Watson {
2397a0a89d2SRobert Watson 	launch_data_t msg, msd, ld, cdict, to;
2407a0a89d2SRobert Watson 	mach_port_t mp = MACH_PORT_NULL;
2417a0a89d2SRobert Watson 
2427a0a89d2SRobert Watson 	msg = launch_data_new_string(LAUNCH_KEY_CHECKIN);
2437a0a89d2SRobert Watson 
2447a0a89d2SRobert Watson 	cdict = launch_msg(msg);
2457a0a89d2SRobert Watson 	if (cdict == NULL) {
2467a0a89d2SRobert Watson 		auditd_log_err("launch_msg(\"" LAUNCH_KEY_CHECKIN
2477a0a89d2SRobert Watson 		    "\") IPC failure: %m");
2487a0a89d2SRobert Watson                 return (MACH_PORT_NULL);
2497a0a89d2SRobert Watson         }
2507a0a89d2SRobert Watson 
2517a0a89d2SRobert Watson 	if (launch_data_get_type(cdict) == LAUNCH_DATA_ERRNO) {
2527a0a89d2SRobert Watson 		errno = launch_data_get_errno(cdict);
2537a0a89d2SRobert Watson 		auditd_log_err("launch_data_get_type() can't get dict: %m");
2547a0a89d2SRobert Watson 		return (MACH_PORT_NULL);
2557a0a89d2SRobert Watson 	}
2567a0a89d2SRobert Watson 
2577a0a89d2SRobert Watson 	to = launch_data_dict_lookup(cdict, LAUNCH_JOBKEY_TIMEOUT);
2587a0a89d2SRobert Watson 	if (to) {
2597a0a89d2SRobert Watson 		max_idletime = launch_data_get_integer(to);
2607a0a89d2SRobert Watson 		auditd_log_debug("launchd timeout set to %d", max_idletime);
2617a0a89d2SRobert Watson 	} else {
2627a0a89d2SRobert Watson 		auditd_log_debug("launchd timeout not set, setting to 60");
2637a0a89d2SRobert Watson 		max_idletime = 60;
2647a0a89d2SRobert Watson 	}
2657a0a89d2SRobert Watson 
2667a0a89d2SRobert Watson 	msd = launch_data_dict_lookup(cdict, LAUNCH_JOBKEY_MACHSERVICES);
2677a0a89d2SRobert Watson 	if (msd == NULL) {
2687a0a89d2SRobert Watson 		auditd_log_err(
2697a0a89d2SRobert Watson 		    "launch_data_dict_lookup() can't get mach services");
2707a0a89d2SRobert Watson 		return (MACH_PORT_NULL);
2717a0a89d2SRobert Watson 	}
2727a0a89d2SRobert Watson 
2737a0a89d2SRobert Watson 	ld = launch_data_dict_lookup(msd, label);
2747a0a89d2SRobert Watson 	if (ld == NULL) {
2757a0a89d2SRobert Watson 		auditd_log_err("launch_data_dict_lookup can't find %s", label);
2767a0a89d2SRobert Watson 		return (MACH_PORT_NULL);
2777a0a89d2SRobert Watson 	}
2787a0a89d2SRobert Watson 
2797a0a89d2SRobert Watson 	mp = launch_data_get_machport(ld);
2807a0a89d2SRobert Watson 
2817a0a89d2SRobert Watson 	return (mp);
2827a0a89d2SRobert Watson }
2837a0a89d2SRobert Watson 
2847a0a89d2SRobert Watson static int
mach_setup(int launchd_flag)2857a0a89d2SRobert Watson mach_setup(int launchd_flag)
2867a0a89d2SRobert Watson {
2877a0a89d2SRobert Watson 	mach_msg_type_name_t poly;
2887a0a89d2SRobert Watson 
2897a0a89d2SRobert Watson 	/*
2907a0a89d2SRobert Watson 	 * Allocate a port set.
2917a0a89d2SRobert Watson 	 */
2927a0a89d2SRobert Watson 	if (mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET,
2937a0a89d2SRobert Watson 	    &port_set) != KERN_SUCCESS)  {
2947a0a89d2SRobert Watson 		auditd_log_err("Allocation of port set failed");
2957a0a89d2SRobert Watson 		return (-1);
2967a0a89d2SRobert Watson 	}
2977a0a89d2SRobert Watson 
2987a0a89d2SRobert Watson 
2997a0a89d2SRobert Watson 	/*
3007a0a89d2SRobert Watson 	 * Allocate a signal reflection port.
3017a0a89d2SRobert Watson 	 */
3027a0a89d2SRobert Watson 	if (mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE,
3037a0a89d2SRobert Watson 	    &signal_port) != KERN_SUCCESS ||
3047a0a89d2SRobert Watson 	    mach_port_move_member(mach_task_self(), signal_port, port_set) !=
3057a0a89d2SRobert Watson 	    KERN_SUCCESS)  {
3067a0a89d2SRobert Watson 		auditd_log_err("Allocation of signal port failed");
3077a0a89d2SRobert Watson 		return (-1);
3087a0a89d2SRobert Watson 	}
3097a0a89d2SRobert Watson 
3107a0a89d2SRobert Watson 	/*
3117a0a89d2SRobert Watson 	 * Allocate a trigger port.
3127a0a89d2SRobert Watson 	 */
3137a0a89d2SRobert Watson 	if (launchd_flag) {
3147a0a89d2SRobert Watson 		/*
3157a0a89d2SRobert Watson 		 * If started under launchd, lookup port in launchd dictionary.
3167a0a89d2SRobert Watson 		 */
3177a0a89d2SRobert Watson 		if ((control_port = lookup_machport(__AUDIT_LAUNCHD_LABEL)) ==
3187a0a89d2SRobert Watson 		    MACH_PORT_NULL || mach_port_move_member(mach_task_self(),
3197a0a89d2SRobert Watson 		    control_port, port_set) != KERN_SUCCESS) {
3207a0a89d2SRobert Watson 			auditd_log_err("Cannot get Mach control port"
3217a0a89d2SRobert Watson                             " via launchd");
3227a0a89d2SRobert Watson 			return (-1);
3237a0a89d2SRobert Watson 		} else
3247a0a89d2SRobert Watson 			auditd_log_debug("Mach control port registered"
3257a0a89d2SRobert Watson 			    " via launchd");
3267a0a89d2SRobert Watson 	} else {
3277a0a89d2SRobert Watson 		/*
3287a0a89d2SRobert Watson 		 * If not started under launchd, allocate port and register.
3297a0a89d2SRobert Watson 		 */
3307a0a89d2SRobert Watson 		if (mach_port_allocate(mach_task_self(),
3317a0a89d2SRobert Watson 		    MACH_PORT_RIGHT_RECEIVE, &control_port) != KERN_SUCCESS ||
3327a0a89d2SRobert Watson 		    mach_port_move_member(mach_task_self(), control_port,
3337a0a89d2SRobert Watson 		    port_set) != KERN_SUCCESS)
3347a0a89d2SRobert Watson 			auditd_log_err("Allocation of trigger port failed");
3357a0a89d2SRobert Watson 
3367a0a89d2SRobert Watson 		/*
3377a0a89d2SRobert Watson 		 * Create a send right on our trigger port.
3387a0a89d2SRobert Watson 		 */
3397a0a89d2SRobert Watson 		mach_port_extract_right(mach_task_self(), control_port,
3407a0a89d2SRobert Watson 		    MACH_MSG_TYPE_MAKE_SEND, &control_port, &poly);
3417a0a89d2SRobert Watson 
3427a0a89d2SRobert Watson 		/*
3437a0a89d2SRobert Watson 		 * Register the trigger port with the kernel.
3447a0a89d2SRobert Watson 		 */
3457a0a89d2SRobert Watson 		if (host_set_audit_control_port(mach_host_self(),
3467a0a89d2SRobert Watson 		    control_port) != KERN_SUCCESS) {
3477a0a89d2SRobert Watson                         auditd_log_err("Cannot set Mach control port");
3487a0a89d2SRobert Watson 			return (-1);
3497a0a89d2SRobert Watson 		} else
3507a0a89d2SRobert Watson 			auditd_log_debug("Mach control port registered");
3517a0a89d2SRobert Watson 	}
3527a0a89d2SRobert Watson 
3537a0a89d2SRobert Watson 	return (0);
3547a0a89d2SRobert Watson }
3557a0a89d2SRobert Watson 
3567a0a89d2SRobert Watson /*
3577a0a89d2SRobert Watson  * Open the trigger messaging mechanism.
3587a0a89d2SRobert Watson  */
3597a0a89d2SRobert Watson int
auditd_open_trigger(int launchd_flag)3607a0a89d2SRobert Watson auditd_open_trigger(int launchd_flag)
3617a0a89d2SRobert Watson {
3627a0a89d2SRobert Watson 
3637a0a89d2SRobert Watson 	return (mach_setup(launchd_flag));
3647a0a89d2SRobert Watson }
3657a0a89d2SRobert Watson 
3667a0a89d2SRobert Watson /*
3677a0a89d2SRobert Watson  * Close the trigger messaging mechanism.
3687a0a89d2SRobert Watson  */
3697a0a89d2SRobert Watson int
auditd_close_trigger(void)3707a0a89d2SRobert Watson auditd_close_trigger(void)
3717a0a89d2SRobert Watson {
3727a0a89d2SRobert Watson 
3737a0a89d2SRobert Watson 	return (0);
3747a0a89d2SRobert Watson }
3757a0a89d2SRobert Watson 
3767a0a89d2SRobert Watson /*
3777a0a89d2SRobert Watson  * Combined server handler.  Called by the mach message loop when there is
3787a0a89d2SRobert Watson  * a trigger or signal message.
3797a0a89d2SRobert Watson  */
3807a0a89d2SRobert Watson static boolean_t
auditd_combined_server(mach_msg_header_t * InHeadP,mach_msg_header_t * OutHeadP)3817a0a89d2SRobert Watson auditd_combined_server(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
3827a0a89d2SRobert Watson {
3837a0a89d2SRobert Watson 	mach_port_t local_port = InHeadP->msgh_local_port;
3847a0a89d2SRobert Watson 
3857a0a89d2SRobert Watson 	/* Reset the idle time alarm, if used. */
3867a0a89d2SRobert Watson 	if (max_idletime)
3877a0a89d2SRobert Watson 		alarm(max_idletime);
3887a0a89d2SRobert Watson 
3897a0a89d2SRobert Watson 	if (local_port == signal_port) {
3907a0a89d2SRobert Watson 		int signo = InHeadP->msgh_id;
3917a0a89d2SRobert Watson 
3927a0a89d2SRobert Watson 		switch(signo) {
3937a0a89d2SRobert Watson 		case SIGTERM:
3947a0a89d2SRobert Watson 		case SIGALRM:
3957a0a89d2SRobert Watson 			auditd_terminate();
3967a0a89d2SRobert Watson 			/* Not reached. */
3977a0a89d2SRobert Watson 
3987a0a89d2SRobert Watson 		case SIGCHLD:
3997a0a89d2SRobert Watson 			auditd_reap_children();
4007a0a89d2SRobert Watson 			return (TRUE);
4017a0a89d2SRobert Watson 
4027a0a89d2SRobert Watson 		case SIGHUP:
4037a0a89d2SRobert Watson 			auditd_config_controls();
4047a0a89d2SRobert Watson 			return (TRUE);
4057a0a89d2SRobert Watson 
4067a0a89d2SRobert Watson 		default:
4077a0a89d2SRobert Watson 			auditd_log_info("Received signal %d", signo);
4087a0a89d2SRobert Watson 			return (TRUE);
4097a0a89d2SRobert Watson 		}
4107a0a89d2SRobert Watson 	} else if (local_port == control_port) {
4117a0a89d2SRobert Watson 		boolean_t result;
4127a0a89d2SRobert Watson 
4137a0a89d2SRobert Watson 		result = audit_triggers_server(InHeadP, OutHeadP);
4147a0a89d2SRobert Watson 		if (!result)
4157a0a89d2SRobert Watson 			result = auditd_control_server(InHeadP, OutHeadP);
4167a0a89d2SRobert Watson 			return (result);
4177a0a89d2SRobert Watson 	}
4187a0a89d2SRobert Watson 	auditd_log_info("Recevied msg on bad port 0x%x.", local_port);
4197a0a89d2SRobert Watson 	return (FALSE);
4207a0a89d2SRobert Watson }
4217a0a89d2SRobert Watson 
4227a0a89d2SRobert Watson /*
4237a0a89d2SRobert Watson  * The main event loop.  Wait for trigger messages or signals and handle them.
4247a0a89d2SRobert Watson  * It should not return unless there is a problem.
4257a0a89d2SRobert Watson  */
4267a0a89d2SRobert Watson void
auditd_wait_for_events(void)4277a0a89d2SRobert Watson auditd_wait_for_events(void)
4287a0a89d2SRobert Watson {
4297a0a89d2SRobert Watson 	kern_return_t   result;
4307a0a89d2SRobert Watson 
4317a0a89d2SRobert Watson 	/*
4327a0a89d2SRobert Watson 	 * Call the mach messaging server loop.
4337a0a89d2SRobert Watson  	 */
4347a0a89d2SRobert Watson 	result = mach_msg_server(auditd_combined_server, MAX_MSG_SIZE,
4357a0a89d2SRobert Watson 	    port_set, MACH_MSG_OPTION_NONE);
4367a0a89d2SRobert Watson }
4377a0a89d2SRobert Watson 
4387a0a89d2SRobert Watson /*
4397a0a89d2SRobert Watson  * Implementation of the audit_triggers() MIG simpleroutine.  Simply a
4407a0a89d2SRobert Watson  * wrapper function.  This handles input from the kernel on the host
4417a0a89d2SRobert Watson  * special mach port.
4427a0a89d2SRobert Watson  */
4437a0a89d2SRobert Watson kern_return_t
audit_triggers(mach_port_t __unused audit_port,int trigger)4447a0a89d2SRobert Watson audit_triggers(mach_port_t __unused audit_port, int trigger)
4457a0a89d2SRobert Watson {
4467a0a89d2SRobert Watson 
4477a0a89d2SRobert Watson 	auditd_handle_trigger(trigger);
4487a0a89d2SRobert Watson 
4497a0a89d2SRobert Watson 	return (KERN_SUCCESS);
4507a0a89d2SRobert Watson }
4517a0a89d2SRobert Watson 
4527a0a89d2SRobert Watson /*
4537a0a89d2SRobert Watson  * Implementation of the auditd_control() MIG simpleroutine.  Simply a
4547a0a89d2SRobert Watson  * wrapper function.  This handles input from the audit(1) tool.
4557a0a89d2SRobert Watson  */
4567a0a89d2SRobert Watson kern_return_t
auditd_control(mach_port_t __unused auditd_port,int trigger)4577a0a89d2SRobert Watson auditd_control(mach_port_t __unused auditd_port, int trigger)
4587a0a89d2SRobert Watson {
4597a0a89d2SRobert Watson 
4607a0a89d2SRobert Watson 	auditd_handle_trigger(trigger);
4617a0a89d2SRobert Watson 
4627a0a89d2SRobert Watson 	return (KERN_SUCCESS);
4637a0a89d2SRobert Watson }
4647a0a89d2SRobert Watson 
4657a0a89d2SRobert Watson /*
4667a0a89d2SRobert Watson  * When we get a signal, we are often not at a clean point.  So, little can
4677a0a89d2SRobert Watson  * be done in the signal handler itself.  Instead,  we send a message to the
4687a0a89d2SRobert Watson  * main servicing loop to do proper handling from a non-signal-handler
4697a0a89d2SRobert Watson  * context.
4707a0a89d2SRobert Watson  */
4717a0a89d2SRobert Watson void
auditd_relay_signal(int signal)4727a0a89d2SRobert Watson auditd_relay_signal(int signal)
4737a0a89d2SRobert Watson {
4747a0a89d2SRobert Watson 	mach_msg_empty_send_t msg;
4757a0a89d2SRobert Watson 
4767a0a89d2SRobert Watson 	msg.header.msgh_id = signal;
4777a0a89d2SRobert Watson 	msg.header.msgh_remote_port = signal_port;
4787a0a89d2SRobert Watson 	msg.header.msgh_local_port = MACH_PORT_NULL;
4797a0a89d2SRobert Watson 	msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
4807a0a89d2SRobert Watson 	mach_msg(&(msg.header), MACH_SEND_MSG|MACH_SEND_TIMEOUT, sizeof(msg),
4817a0a89d2SRobert Watson 	    0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
4827a0a89d2SRobert Watson }
483