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