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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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