1 /*-
2  * Copyright (c) 2004-2009 Apple Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
15  *     its contributors may be used to endorse or promote products derived
16  *     from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  * $P4: //depot/projects/trustedbsd/openbsm/bin/auditd/auditd_darwin.c#5 $
30  */
31 
32 #include <sys/types.h>
33 
34 #include <config/config.h>
35 
36 #include <errno.h>
37 #include <stdarg.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 
41 #include <bsm/audit.h>
42 #include <bsm/audit_uevents.h>
43 #include <bsm/auditd_lib.h>
44 #include <bsm/libbsm.h>
45 
46 #include <asl.h>
47 #include <launch.h>
48 #include <notify.h>
49 #include <mach/port.h>
50 #include <mach/mach_error.h>
51 #include <mach/mach_traps.h>
52 #include <mach/mach.h>
53 #include <mach/host_special_ports.h>
54 
55 #include "auditd.h"
56 
57 #include "auditd_controlServer.h"
58 #include "audit_triggersServer.h"
59 
60 /*
61  * Apple System Logger Handles.
62  */
63 static aslmsg 		au_aslmsg = NULL;
64 static aslclient	au_aslclient = NULL;
65 
66 static mach_port_t	control_port = MACH_PORT_NULL;
67 static mach_port_t	signal_port = MACH_PORT_NULL;
68 static mach_port_t	port_set = MACH_PORT_NULL;
69 
70 /*
71  * Current auditing state (cache).
72  */
73 static int		auditing_state = AUD_STATE_INIT;
74 
75 /*
76  * Maximum idle time before auditd terminates under launchd.
77  * If it is zero then auditd does not timeout while idle.
78  */
79 static int		max_idletime = 0;
80 
81 #ifndef	__BSM_INTERNAL_NOTIFY_KEY
82 #define	__BSM_INTERNAL_NOTIFY_KEY	"com.apple.audit.change"
83 #endif /* __BSM_INTERNAL_NOTIFY_KEY */
84 
85 #ifndef	__AUDIT_LAUNCHD_LABEL
86 #define	__AUDIT_LAUNCHD_LABEL		"com.apple.auditd"
87 #endif /* __AUDIT_LAUNCHD_LABEL */
88 
89 #define	MAX_MSG_SIZE	4096
90 
91 /*
92  * Open and set up system logging.
93  */
94 void
95 auditd_openlog(int debug, gid_t gid)
96 {
97 	uint32_t opt = 0;
98 	char *cp = NULL;
99 
100 	if (debug)
101 		opt = ASL_OPT_STDERR;
102 
103 	au_aslclient = asl_open("auditd", "com.apple.auditd", opt);
104 	au_aslmsg = asl_new(ASL_TYPE_MSG);
105 
106 #ifdef ASL_KEY_READ_UID
107 	/*
108 	 * Make it only so the audit administrator and members of the audit
109 	 * review group (if used) have access to the auditd system log messages.
110 	 */
111 	asl_set(au_aslmsg, ASL_KEY_READ_UID, "0");
112 	asprintf(&cp, "%u", gid);
113 	if (cp != NULL) {
114 #ifdef ASL_KEY_READ_GID
115 		asl_set(au_aslmsg, ASL_KEY_READ_GID, cp);
116 #endif
117 		free(cp);
118 	}
119 #endif
120 
121 	/*
122 	 * Set the client-side system log filtering.
123 	 */
124 	if (debug)
125 		asl_set_filter(au_aslclient,
126 		    ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
127 	else
128 		asl_set_filter(au_aslclient,
129 		    ASL_FILTER_MASK_UPTO(ASL_LEVEL_INFO));
130 }
131 
132 /*
133  * Log messages at different priority levels.
134  */
135 void
136 auditd_log_err(const char *fmt, ...)
137 {
138 	va_list ap;
139 
140 	va_start(ap, fmt);
141 	asl_vlog(au_aslclient, au_aslmsg, ASL_LEVEL_ERR, fmt, ap);
142 	va_end(ap);
143 }
144 
145 void
146 auditd_log_notice(const char *fmt, ...)
147 {
148 	va_list ap;
149 
150 	va_start(ap, fmt);
151 	asl_vlog(au_aslclient, au_aslmsg, ASL_LEVEL_NOTICE, fmt, ap);
152 	va_end(ap);
153 }
154 
155 void
156 auditd_log_info(const char *fmt, ...)
157 {
158 	va_list ap;
159 
160 	va_start(ap, fmt);
161 	asl_vlog(au_aslclient, au_aslmsg, ASL_LEVEL_INFO, fmt, ap);
162 	va_end(ap);
163 }
164 
165 void
166 auditd_log_debug(const char *fmt, ...)
167 {
168 	va_list ap;
169 
170 	va_start(ap, fmt);
171 	asl_vlog(au_aslclient, au_aslmsg, ASL_LEVEL_DEBUG, fmt, ap);
172 	va_end(ap);
173 }
174 
175 /*
176  * Get the auditing state from the kernel and cache it.
177  */
178 static void
179 init_audit_state(void)
180 {
181 	int au_cond;
182 
183 	if (audit_get_cond(&au_cond) < 0) {
184 		if (errno != ENOSYS) {
185 			auditd_log_err("Audit status check failed (%s)",
186 			    strerror(errno));
187 		}
188 		auditing_state = AUD_STATE_DISABLED;
189 	} else
190 		if (au_cond == AUC_NOAUDIT || au_cond == AUC_DISABLED)
191 			auditing_state = AUD_STATE_DISABLED;
192 		else
193 			auditing_state = AUD_STATE_ENABLED;
194 }
195 
196 /*
197  * Update the cached auditing state.  Let other tasks that may be caching it
198  * as well to update their state via notify(3).
199  */
200 void
201 auditd_set_state(int state)
202 {
203 	int old_auditing_state = auditing_state;
204 
205 	if (state == AUD_STATE_INIT)
206 		init_audit_state();
207 	else
208 		auditing_state = state;
209 
210 	if (auditing_state != old_auditing_state) {
211 		notify_post(__BSM_INTERNAL_NOTIFY_KEY);
212 
213 		if (auditing_state == AUD_STATE_ENABLED)
214 			auditd_log_notice("Auditing enabled");
215 		if (auditing_state == AUD_STATE_DISABLED)
216 			auditd_log_notice("Auditing disabled");
217 	}
218 }
219 
220 /*
221  * Get the cached auditing state.
222  */
223 int
224 auditd_get_state(void)
225 {
226 
227 	if (auditing_state == AUD_STATE_INIT) {
228 		init_audit_state();
229 		notify_post(__BSM_INTERNAL_NOTIFY_KEY);
230 	}
231 
232 	return (auditing_state);
233 }
234 
235 /*
236  * Lookup the audit mach port in the launchd dictionary.
237  */
238 static mach_port_t
239 lookup_machport(const char *label)
240 {
241 	launch_data_t msg, msd, ld, cdict, to;
242 	mach_port_t mp = MACH_PORT_NULL;
243 
244 	msg = launch_data_new_string(LAUNCH_KEY_CHECKIN);
245 
246 	cdict = launch_msg(msg);
247 	if (cdict == NULL) {
248 		auditd_log_err("launch_msg(\"" LAUNCH_KEY_CHECKIN
249 		    "\") IPC failure: %m");
250                 return (MACH_PORT_NULL);
251         }
252 
253 	if (launch_data_get_type(cdict) == LAUNCH_DATA_ERRNO) {
254 		errno = launch_data_get_errno(cdict);
255 		auditd_log_err("launch_data_get_type() can't get dict: %m");
256 		return (MACH_PORT_NULL);
257 	}
258 
259 	to = launch_data_dict_lookup(cdict, LAUNCH_JOBKEY_TIMEOUT);
260 	if (to) {
261 		max_idletime = launch_data_get_integer(to);
262 		auditd_log_debug("launchd timeout set to %d", max_idletime);
263 	} else {
264 		auditd_log_debug("launchd timeout not set, setting to 60");
265 		max_idletime = 60;
266 	}
267 
268 	msd = launch_data_dict_lookup(cdict, LAUNCH_JOBKEY_MACHSERVICES);
269 	if (msd == NULL) {
270 		auditd_log_err(
271 		    "launch_data_dict_lookup() can't get mach services");
272 		return (MACH_PORT_NULL);
273 	}
274 
275 	ld = launch_data_dict_lookup(msd, label);
276 	if (ld == NULL) {
277 		auditd_log_err("launch_data_dict_lookup can't find %s", label);
278 		return (MACH_PORT_NULL);
279 	}
280 
281 	mp = launch_data_get_machport(ld);
282 
283 	return (mp);
284 }
285 
286 static int
287 mach_setup(int launchd_flag)
288 {
289 	mach_msg_type_name_t poly;
290 
291 	/*
292 	 * Allocate a port set.
293 	 */
294 	if (mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET,
295 	    &port_set) != KERN_SUCCESS)  {
296 		auditd_log_err("Allocation of port set failed");
297 		return (-1);
298 	}
299 
300 
301 	/*
302 	 * Allocate a signal reflection port.
303 	 */
304 	if (mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE,
305 	    &signal_port) != KERN_SUCCESS ||
306 	    mach_port_move_member(mach_task_self(), signal_port, port_set) !=
307 	    KERN_SUCCESS)  {
308 		auditd_log_err("Allocation of signal port failed");
309 		return (-1);
310 	}
311 
312 	/*
313 	 * Allocate a trigger port.
314 	 */
315 	if (launchd_flag) {
316 		/*
317 		 * If started under launchd, lookup port in launchd dictionary.
318 		 */
319 		if ((control_port = lookup_machport(__AUDIT_LAUNCHD_LABEL)) ==
320 		    MACH_PORT_NULL || mach_port_move_member(mach_task_self(),
321 		    control_port, port_set) != KERN_SUCCESS) {
322 			auditd_log_err("Cannot get Mach control port"
323                             " via launchd");
324 			return (-1);
325 		} else
326 			auditd_log_debug("Mach control port registered"
327 			    " via launchd");
328 	} else {
329 		/*
330 		 * If not started under launchd, allocate port and register.
331 		 */
332 		if (mach_port_allocate(mach_task_self(),
333 		    MACH_PORT_RIGHT_RECEIVE, &control_port) != KERN_SUCCESS ||
334 		    mach_port_move_member(mach_task_self(), control_port,
335 		    port_set) != KERN_SUCCESS)
336 			auditd_log_err("Allocation of trigger port failed");
337 
338 		/*
339 		 * Create a send right on our trigger port.
340 		 */
341 		mach_port_extract_right(mach_task_self(), control_port,
342 		    MACH_MSG_TYPE_MAKE_SEND, &control_port, &poly);
343 
344 		/*
345 		 * Register the trigger port with the kernel.
346 		 */
347 		if (host_set_audit_control_port(mach_host_self(),
348 		    control_port) != KERN_SUCCESS) {
349                         auditd_log_err("Cannot set Mach control port");
350 			return (-1);
351 		} else
352 			auditd_log_debug("Mach control port registered");
353 	}
354 
355 	return (0);
356 }
357 
358 /*
359  * Open the trigger messaging mechanism.
360  */
361 int
362 auditd_open_trigger(int launchd_flag)
363 {
364 
365 	return (mach_setup(launchd_flag));
366 }
367 
368 /*
369  * Close the trigger messaging mechanism.
370  */
371 int
372 auditd_close_trigger(void)
373 {
374 
375 	return (0);
376 }
377 
378 /*
379  * Combined server handler.  Called by the mach message loop when there is
380  * a trigger or signal message.
381  */
382 static boolean_t
383 auditd_combined_server(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
384 {
385 	mach_port_t local_port = InHeadP->msgh_local_port;
386 
387 	/* Reset the idle time alarm, if used. */
388 	if (max_idletime)
389 		alarm(max_idletime);
390 
391 	if (local_port == signal_port) {
392 		int signo = InHeadP->msgh_id;
393 
394 		switch(signo) {
395 		case SIGTERM:
396 		case SIGALRM:
397 			auditd_terminate();
398 			/* Not reached. */
399 
400 		case SIGCHLD:
401 			auditd_reap_children();
402 			return (TRUE);
403 
404 		case SIGHUP:
405 			auditd_config_controls();
406 			return (TRUE);
407 
408 		default:
409 			auditd_log_info("Received signal %d", signo);
410 			return (TRUE);
411 		}
412 	} else if (local_port == control_port) {
413 		boolean_t result;
414 
415 		result = audit_triggers_server(InHeadP, OutHeadP);
416 		if (!result)
417 			result = auditd_control_server(InHeadP, OutHeadP);
418 			return (result);
419 	}
420 	auditd_log_info("Recevied msg on bad port 0x%x.", local_port);
421 	return (FALSE);
422 }
423 
424 /*
425  * The main event loop.  Wait for trigger messages or signals and handle them.
426  * It should not return unless there is a problem.
427  */
428 void
429 auditd_wait_for_events(void)
430 {
431 	kern_return_t   result;
432 
433 	/*
434 	 * Call the mach messaging server loop.
435  	 */
436 	result = mach_msg_server(auditd_combined_server, MAX_MSG_SIZE,
437 	    port_set, MACH_MSG_OPTION_NONE);
438 }
439 
440 /*
441  * Implementation of the audit_triggers() MIG simpleroutine.  Simply a
442  * wrapper function.  This handles input from the kernel on the host
443  * special mach port.
444  */
445 kern_return_t
446 audit_triggers(mach_port_t __unused audit_port, int trigger)
447 {
448 
449 	auditd_handle_trigger(trigger);
450 
451 	return (KERN_SUCCESS);
452 }
453 
454 /*
455  * Implementation of the auditd_control() MIG simpleroutine.  Simply a
456  * wrapper function.  This handles input from the audit(1) tool.
457  */
458 kern_return_t
459 auditd_control(mach_port_t __unused auditd_port, int trigger)
460 {
461 
462 	auditd_handle_trigger(trigger);
463 
464 	return (KERN_SUCCESS);
465 }
466 
467 /*
468  * When we get a signal, we are often not at a clean point.  So, little can
469  * be done in the signal handler itself.  Instead,  we send a message to the
470  * main servicing loop to do proper handling from a non-signal-handler
471  * context.
472  */
473 void
474 auditd_relay_signal(int signal)
475 {
476 	mach_msg_empty_send_t msg;
477 
478 	msg.header.msgh_id = signal;
479 	msg.header.msgh_remote_port = signal_port;
480 	msg.header.msgh_local_port = MACH_PORT_NULL;
481 	msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
482 	mach_msg(&(msg.header), MACH_SEND_MSG|MACH_SEND_TIMEOUT, sizeof(msg),
483 	    0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
484 }
485