]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/openbsm/bin/auditd/auditd_darwin.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / openbsm / bin / auditd / auditd_darwin.c
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 }