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