xref: /freebsd/contrib/openbsm/bin/auditd/auditd.c (revision 884a2a699669ec61e2366e3e358342dbc94be24a)
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.c#46 $
30  */
31 
32 #include <sys/types.h>
33 
34 #include <config/config.h>
35 
36 #include <sys/dirent.h>
37 #ifdef HAVE_FULL_QUEUE_H
38 #include <sys/queue.h>
39 #else /* !HAVE_FULL_QUEUE_H */
40 #include <compat/queue.h>
41 #endif /* !HAVE_FULL_QUEUE_H */
42 #include <sys/mman.h>
43 #include <sys/param.h>
44 #include <sys/stat.h>
45 #include <sys/wait.h>
46 
47 #include <bsm/audit.h>
48 #include <bsm/audit_uevents.h>
49 #include <bsm/auditd_lib.h>
50 #include <bsm/libbsm.h>
51 
52 #include <err.h>
53 #include <errno.h>
54 #include <fcntl.h>
55 #include <grp.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <time.h>
59 #include <unistd.h>
60 #include <signal.h>
61 #include <string.h>
62 
63 #include "auditd.h"
64 
65 #ifndef HAVE_STRLCPY
66 #include <compat/strlcpy.h>
67 #endif
68 
69 /*
70  * XXX The following are temporary until these can be added to the kernel
71  * audit.h header.
72  */
73 #ifndef	AUDIT_TRIGGER_INITIALIZE
74 #define	AUDIT_TRIGGER_INITIALIZE	7
75 #endif
76 #ifndef	AUDIT_TRIGGER_EXPIRE_TRAILS
77 #define	AUDIT_TRIGGER_EXPIRE_TRAILS	8
78 #endif
79 
80 
81 /*
82  * LaunchD flag (Mac OS X and, maybe, FreeBSD only.)  See launchd(8) and
83  * http://wiki.freebsd.org/launchd for more information.
84  *
85  *      In order for auditd to work "on demand" with launchd(8) it can't:
86  *              call daemon(3)
87  *              call fork and having the parent process exit
88  *              change uids or gids.
89  *              set up the current working directory or chroot.
90  *              set the session id
91  *              change stdio to /dev/null.
92  *              call setrusage(2)
93  *              call setpriority(2)
94  *              Ignore SIGTERM.
95  *      auditd (in 'launchd mode') is launched on demand so it must catch
96  *      SIGTERM to exit cleanly.
97  */
98 static int	launchd_flag = 0;
99 
100 /*
101  * The GID of the audit review group (if used).  The audit trail files and
102  * system logs (Mac OS X only) can only be reviewed by members of this group
103  * or the audit administrator (aka. "root").
104  */
105 static gid_t	audit_review_gid = -1;
106 
107 /*
108  * The path and file name of the last audit trail file.
109  */
110 static char	*lastfile = NULL;
111 
112 /*
113  * Error starting auditd. Run warn script and exit.
114  */
115 static void
116 fail_exit(void)
117 {
118 
119 	audit_warn_nostart();
120 	exit(1);
121 }
122 
123 /*
124  * Follow the 'current' symlink to get the active trail file name.
125  */
126 static char *
127 get_curfile(void)
128 {
129 	char *cf;
130 	int len;
131 
132 	cf = malloc(MAXPATHLEN);
133 	if (cf == NULL) {
134 		auditd_log_err("malloc failed: %m");
135 		return (NULL);
136 	}
137 
138 	len = readlink(AUDIT_CURRENT_LINK, cf, MAXPATHLEN - 1);
139 	if (len < 0) {
140 		free(cf);
141 		return (NULL);
142 	}
143 
144 	/* readlink() doesn't terminate string. */
145 	cf[len] = '\0';
146 
147 	return (cf);
148 }
149 
150 /*
151  * Close the previous audit trail file.
152  */
153 static int
154 close_lastfile(char *TS)
155 {
156 	char *ptr;
157 	char *oldname;
158 	size_t len;
159 
160 	/* If lastfile is NULL try to get it from the 'current' link.  */
161 	if (lastfile == NULL)
162 		lastfile = get_curfile();
163 
164 	if (lastfile != NULL) {
165 		len = strlen(lastfile) + 1;
166 		oldname = (char *)malloc(len);
167 		if (oldname == NULL)
168 			return (-1);
169 		strlcpy(oldname, lastfile, len);
170 
171 		/* Rename the last file -- append timestamp. */
172 		if ((ptr = strstr(lastfile, NOT_TERMINATED)) != NULL) {
173 			memcpy(ptr, TS, POSTFIX_LEN);
174 			if (rename(oldname, lastfile) != 0)
175 				auditd_log_err(
176 				    "Could not rename %s to %s: %m", oldname,
177 				    lastfile);
178 			else {
179 				/*
180 				 * Remove the 'current' symlink since the link
181 				 * is now invalid.
182 				 */
183 				(void) unlink(AUDIT_CURRENT_LINK);
184 				auditd_log_notice( "renamed %s to %s",
185 				    oldname, lastfile);
186 				audit_warn_closefile(lastfile);
187 			}
188 		} else
189 			auditd_log_err( "Could not rename %s to %s", oldname,
190 			    lastfile);
191 		free(lastfile);
192 		free(oldname);
193 		lastfile = NULL;
194 	}
195 	return (0);
196 }
197 
198 /*
199  * Create the new file name, swap with existing audit file.
200  */
201 static int
202 swap_audit_file(void)
203 {
204 	int err;
205 	char *newfile;
206 	char TS[TIMESTAMP_LEN];
207 	time_t tt;
208 
209 	if (getTSstr(tt, TS, TIMESTAMP_LEN) != 0)
210 		return (-1);
211 	err = auditd_swap_trail(TS, &newfile, audit_review_gid,
212 	    audit_warn_getacdir);
213 	if (err != ADE_NOERR) {
214 		auditd_log_err( "%s: %m", auditd_strerror(err));
215 		if (err != ADE_ACTL)
216 			return (-1);
217 	}
218 
219 	/*
220 	 * Only close the last file if were in an auditing state before
221 	 * calling swap_audit_file().  We may need to recover from a crash.
222 	 */
223 	if (auditd_get_state() == AUD_STATE_ENABLED)
224 		close_lastfile(TS);
225 
226 
227 	/*
228 	 * auditd_swap_trail() potentially enables auditing (if not already
229 	 * enabled) so updated the cached state as well.
230 	 */
231 	auditd_set_state(AUD_STATE_ENABLED);
232 
233 	/*
234 	 *  Create 'current' symlink.  Recover from crash, if needed.
235 	 */
236 	if (auditd_new_curlink(newfile) != 0)
237                	auditd_log_err("auditd_new_curlink(\"%s\") failed: %s: %m",
238 		     newfile, auditd_strerror(err));
239 
240 	lastfile = newfile;
241 	auditd_log_notice("New audit file is %s", newfile);
242 
243 	return (0);
244 }
245 
246 /*
247  * Create a new audit log trail file and swap with the current one, if any.
248  */
249 static int
250 do_trail_file(void)
251 {
252 	int err;
253 
254 	/*
255 	 * First, refresh the list of audit log directories.
256 	 */
257 	err = auditd_read_dirs(audit_warn_soft, audit_warn_hard);
258 	if (err) {
259 		auditd_log_err("auditd_read_dirs(): %s",
260 		    auditd_strerror(err));
261 		if (err == ADE_HARDLIM)
262 			audit_warn_allhard();
263 		if (err != ADE_SOFTLIM)
264 			return (-1);
265 		else
266 			audit_warn_allsoft();
267 			/* continue on with soft limit error */
268 	}
269 
270 	/*
271 	 * Create a new file and swap with the one being used in kernel.
272 	 */
273 	if (swap_audit_file() == -1) {
274 		/*
275 		 * XXX Faulty directory listing? - user should be given
276 		 * XXX an opportunity to change the audit_control file
277 		 * XXX switch to a reduced mode of auditing?
278 		 */
279 		return (-1);
280 	}
281 
282 	/*
283 	 * Finally, see if there are any trail files to expire.
284 	 */
285 	err = auditd_expire_trails(audit_warn_expired);
286 	if (err)
287 		auditd_log_err("auditd_expire_trails(): %s",
288 		    auditd_strerror(err));
289 
290 	return (0);
291 }
292 
293 /*
294  * Start up auditing.
295  */
296 static void
297 audit_setup(void)
298 {
299 	int err;
300 
301 	if (do_trail_file() == -1) {
302 		auditd_log_err("Error creating audit trail file");
303 		fail_exit();
304 	}
305 
306 	/* Generate an audit record. */
307 	err = auditd_gen_record(AUE_audit_startup, NULL);
308 	if (err)
309 		auditd_log_err("auditd_gen_record(AUE_audit_startup) %s: %m",
310 		    auditd_strerror(err));
311 
312 	if (auditd_config_controls() == 0)
313 		auditd_log_info("Audit controls init successful");
314 	else
315 		auditd_log_err("Audit controls init failed");
316 
317 }
318 
319 
320 /*
321  * Close auditd pid file and trigger mechanism.
322  */
323 static int
324 close_misc(void)
325 {
326 
327 	auditd_close_dirs();
328 	if (unlink(AUDITD_PIDFILE) == -1 && errno != ENOENT) {
329 		auditd_log_err("Couldn't remove %s: %m", AUDITD_PIDFILE);
330 		return (1);
331 	}
332 	endac();
333 
334 	if (auditd_close_trigger() != 0) {
335 		auditd_log_err("Error closing trigger messaging mechanism");
336 		return (1);
337 	}
338 	return (0);
339 }
340 
341 /*
342  * Close all log files, control files, and tell the audit system.
343  */
344 static int
345 close_all(void)
346 {
347 	int err_ret = 0;
348 	char TS[TIMESTAMP_LEN];
349 	int err;
350 	int cond;
351 	time_t tt;
352 
353 	err = auditd_gen_record(AUE_audit_shutdown, NULL);
354 	if (err)
355 		auditd_log_err("auditd_gen_record(AUE_audit_shutdown) %s: %m",
356 		    auditd_strerror(err));
357 
358 	/* Flush contents. */
359 	cond = AUC_DISABLED;
360 	err_ret = audit_set_cond(&cond);
361 	if (err_ret != 0) {
362 		auditd_log_err("Disabling audit failed! : %s", strerror(errno));
363 		err_ret = 1;
364 	}
365 
366 	/*
367 	 * Updated the cached state that auditing has been disabled.
368 	 */
369 	auditd_set_state(AUD_STATE_DISABLED);
370 
371 	if (getTSstr(tt, TS, TIMESTAMP_LEN) == 0)
372 		close_lastfile(TS);
373 	if (lastfile != NULL)
374 		free(lastfile);
375 
376 	err_ret += close_misc();
377 
378 	if (err_ret) {
379 		auditd_log_err("Could not unregister");
380 		audit_warn_postsigterm();
381 	}
382 
383 	auditd_log_info("Finished");
384 	return (err_ret);
385 }
386 
387 /*
388  * Register the daemon with the signal handler and the auditd pid file.
389  */
390 static int
391 register_daemon(void)
392 {
393 	FILE * pidfile;
394 	int fd;
395 	pid_t pid;
396 
397 	/* Set up the signal hander. */
398 	if (signal(SIGTERM, auditd_relay_signal) == SIG_ERR) {
399 		auditd_log_err(
400 		    "Could not set signal handler for SIGTERM");
401 		fail_exit();
402 	}
403 	if (signal(SIGCHLD, auditd_relay_signal) == SIG_ERR) {
404 		auditd_log_err(
405 		    "Could not set signal handler for SIGCHLD");
406 		fail_exit();
407 	}
408 	if (signal(SIGHUP, auditd_relay_signal) == SIG_ERR) {
409 		auditd_log_err(
410 		    "Could not set signal handler for SIGHUP");
411 		fail_exit();
412 	}
413 	if (signal(SIGALRM, auditd_relay_signal) == SIG_ERR) {
414 		auditd_log_err(
415 		    "Could not set signal handler for SIGALRM");
416 		fail_exit();
417 	}
418 
419 	if ((pidfile = fopen(AUDITD_PIDFILE, "a")) == NULL) {
420 		auditd_log_err("Could not open PID file");
421 		audit_warn_tmpfile();
422 		return (-1);
423 	}
424 
425 	/* Attempt to lock the pid file; if a lock is present, exit. */
426 	fd = fileno(pidfile);
427 	if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
428 		auditd_log_err(
429 		    "PID file is locked (is another auditd running?).");
430 		audit_warn_ebusy();
431 		return (-1);
432 	}
433 
434 	pid = getpid();
435 	ftruncate(fd, 0);
436 	if (fprintf(pidfile, "%u\n", pid) < 0) {
437 		/* Should not start the daemon. */
438 		fail_exit();
439 	}
440 
441 	fflush(pidfile);
442 	return (0);
443 }
444 
445 /*
446  * Handle the audit trigger event.
447  *
448  * We suppress (ignore) duplicated triggers in close succession in order to
449  * try to avoid thrashing-like behavior.  However, not all triggers can be
450  * ignored, as triggers generally represent edge triggers, not level
451  * triggers, and won't be retransmitted if the condition persists.  Of
452  * specific concern is the rotate trigger -- if one is dropped, then it will
453  * not be retransmitted, and the log file will grow in an unbounded fashion.
454  */
455 #define	DUPLICATE_INTERVAL	30
456 void
457 auditd_handle_trigger(int trigger)
458 {
459 	static int last_trigger, last_warning;
460 	static time_t last_time;
461 	struct timeval ts;
462 	struct timezone tzp;
463 	time_t tt;
464 	int au_state;
465 	int err = 0;
466 
467 	/*
468 	 * Suppress duplicate messages from the kernel within the specified
469 	 * interval.
470 	 */
471 	if (gettimeofday(&ts, &tzp) == 0) {
472 		tt = (time_t)ts.tv_sec;
473 		switch (trigger) {
474 		case AUDIT_TRIGGER_LOW_SPACE:
475 		case AUDIT_TRIGGER_NO_SPACE:
476 			/*
477 			 * Triggers we can suppress.  Of course, we also need
478 			 * to rate limit the warnings, so apply the same
479 			 * interval limit on syslog messages.
480 			 */
481 			if ((trigger == last_trigger) &&
482 			    (tt < (last_time + DUPLICATE_INTERVAL))) {
483 				if (tt >= (last_warning + DUPLICATE_INTERVAL))
484 					auditd_log_info(
485 					    "Suppressing duplicate trigger %d",
486 					    trigger);
487 				return;
488 			}
489 			last_warning = tt;
490 			break;
491 
492 		case AUDIT_TRIGGER_ROTATE_KERNEL:
493 		case AUDIT_TRIGGER_ROTATE_USER:
494 		case AUDIT_TRIGGER_READ_FILE:
495 		case AUDIT_TRIGGER_CLOSE_AND_DIE:
496 		case AUDIT_TRIGGER_INITIALIZE:
497 			/*
498 			 * Triggers that we cannot suppress.
499 			 */
500 			break;
501 		}
502 
503 		/*
504 		 * Only update last_trigger after aborting due to a duplicate
505 		 * trigger, not before, or we will never allow that trigger
506 		 * again.
507 		 */
508 		last_trigger = trigger;
509 		last_time = tt;
510 	}
511 
512 	au_state = auditd_get_state();
513 
514 	/*
515 	 * Message processing is done here.
516  	 */
517 	switch(trigger) {
518 	case AUDIT_TRIGGER_LOW_SPACE:
519 		auditd_log_notice("Got low space trigger");
520 		if (do_trail_file() == -1)
521 			auditd_log_err("Error swapping audit file");
522 		break;
523 
524 	case AUDIT_TRIGGER_NO_SPACE:
525 		auditd_log_notice("Got no space trigger");
526 		if (do_trail_file() == -1)
527 			auditd_log_err("Error swapping audit file");
528 		break;
529 
530 	case AUDIT_TRIGGER_ROTATE_KERNEL:
531 	case AUDIT_TRIGGER_ROTATE_USER:
532 		auditd_log_info("Got open new trigger from %s", trigger ==
533 		    AUDIT_TRIGGER_ROTATE_KERNEL ? "kernel" : "user");
534 		if (au_state == AUD_STATE_ENABLED && do_trail_file() == -1)
535 			auditd_log_err("Error swapping audit file");
536 		break;
537 
538 	case AUDIT_TRIGGER_READ_FILE:
539 		auditd_log_info("Got read file trigger");
540 		if (au_state == AUD_STATE_ENABLED) {
541 			if (auditd_config_controls() == -1)
542 				auditd_log_err("Error setting audit controls");
543 			else if (do_trail_file() == -1)
544 				auditd_log_err("Error swapping audit file");
545 		}
546 		break;
547 
548 	case AUDIT_TRIGGER_CLOSE_AND_DIE:
549 		auditd_log_info("Got close and die trigger");
550 		if (au_state == AUD_STATE_ENABLED)
551 			err = close_all();
552 		/*
553 		 * Running under launchd don't exit.  Wait for launchd to
554 		 * send SIGTERM.
555 		 */
556 		if (!launchd_flag) {
557 			auditd_log_info("auditd exiting.");
558 			exit (err);
559 		}
560 		break;
561 
562 	case AUDIT_TRIGGER_INITIALIZE:
563 		auditd_log_info("Got audit initialize trigger");
564 		if (au_state == AUD_STATE_DISABLED)
565 			audit_setup();
566 		break;
567 
568 	case AUDIT_TRIGGER_EXPIRE_TRAILS:
569 		auditd_log_info("Got audit expire trails trigger");
570 		err = auditd_expire_trails(audit_warn_expired);
571 		if (err)
572 			auditd_log_err("auditd_expire_trails(): %s",
573 		    	    auditd_strerror(err));
574 		break;
575 
576 	default:
577 		auditd_log_err("Got unknown trigger %d", trigger);
578 		break;
579 	}
580 }
581 
582 /*
583  * Reap our children.
584  */
585 void
586 auditd_reap_children(void)
587 {
588 	pid_t child;
589 	int wstatus;
590 
591 	while ((child = waitpid(-1, &wstatus, WNOHANG)) > 0) {
592 		if (!wstatus)
593 			continue;
594 		auditd_log_info("warn process [pid=%d] %s %d.", child,
595 		    ((WIFEXITED(wstatus)) ? "exited with non-zero status" :
596 		    "exited as a result of signal"),
597 		    ((WIFEXITED(wstatus)) ? WEXITSTATUS(wstatus) :
598 		    WTERMSIG(wstatus)));
599 	}
600 }
601 
602 /*
603  * Reap any children and terminate.  If under launchd don't shutdown auditing
604  * but just the other stuff.
605  */
606 void
607 auditd_terminate(void)
608 {
609 	int ret;
610 
611 	auditd_reap_children();
612 
613 	if (launchd_flag)
614 		ret = close_misc();
615 	else
616 		ret = close_all();
617 
618 	exit(ret);
619 }
620 
621 /*
622  * Configure the audit controls in the kernel: the event to class mapping,
623  * kernel preselection mask, etc.
624  */
625 int
626 auditd_config_controls(void)
627 {
628 	int cnt, err;
629 	int ret = 0;
630 
631 	/*
632 	 * Configure event to class mappings in kernel.
633 	 */
634 	cnt = auditd_set_evcmap();
635 	if (cnt < 0) {
636 		auditd_log_err("auditd_set_evcmap() failed: %m");
637 		ret = -1;
638 	} else if (cnt == 0) {
639 		auditd_log_err("No events to class mappings registered.");
640 		ret = -1;
641 	} else
642 		auditd_log_debug("Registered %d event to class mappings.", cnt);
643 
644 	/*
645 	 * Configure non-attributable event mask in kernel.
646 	 */
647 	err = auditd_set_namask();
648 	if (err) {
649 		auditd_log_err("auditd_set_namask() %s: %m",
650 		    auditd_strerror(err));
651 		ret = -1;
652 	} else
653 		auditd_log_debug("Registered non-attributable event mask.");
654 
655 	/*
656 	 * Configure audit policy in kernel.
657 	 */
658 	err = auditd_set_policy();
659 	if (err) {
660 		auditd_log_err("auditd_set_policy() %s: %m",
661 		    auditd_strerror(err));
662 		ret = -1;
663 	} else
664 		auditd_log_debug("Set audit policy in kernel.");
665 
666 	/*
667 	 * Configure audit trail log size in kernel.
668 	 */
669 	err = auditd_set_fsize();
670 	if (err) {
671 		auditd_log_err("audit_set_fsize() %s: %m",
672 		    auditd_strerror(err));
673 		ret = -1;
674 	} else
675 		auditd_log_debug("Set audit trail size in kernel.");
676 
677 	/*
678 	 * Configure audit trail volume minimum free percentage of blocks in
679 	 * kernel.
680 	 */
681 	err = auditd_set_minfree();
682 	if (err) {
683 		auditd_log_err("auditd_set_minfree() %s: %m",
684 		    auditd_strerror(err));
685 		ret = -1;
686 	} else
687 		auditd_log_debug(
688 		    "Set audit trail min free percent in kernel.");
689 
690 	/*
691 	 * Configure host address in the audit kernel information.
692 	 */
693 	err = auditd_set_host();
694 	if (err) {
695 		if (err == ADE_PARSE) {
696 			auditd_log_notice(
697 			    "audit_control(5) may be missing 'host:' field");
698 		} else {
699 			auditd_log_err("auditd_set_host() %s: %m",
700 			    auditd_strerror(err));
701 			ret = -1;
702 		}
703 	} else
704 		auditd_log_debug(
705 		    "Set audit host address information in kernel.");
706 
707 	return (ret);
708 }
709 
710 /*
711  * Setup and initialize auditd.
712  */
713 static void
714 setup(void)
715 {
716 	int err;
717 
718 	if (auditd_open_trigger(launchd_flag) < 0) {
719 		auditd_log_err("Error opening trigger messaging mechanism");
720 		fail_exit();
721 	}
722 
723 	/*
724 	 * To prevent event feedback cycles and avoid auditd becoming
725 	 * stalled if auditing is suspended, auditd and its children run
726 	 * without their events being audited.  We allow the uid, tid, and
727 	 * mask fields to be implicitly set to zero, but do set the pid.  We
728 	 * run this after opening the trigger device to avoid configuring
729 	 * audit state without audit present in the system.
730 	 */
731 	err = auditd_prevent_audit();
732 	if (err) {
733 		auditd_log_err("auditd_prevent_audit() %s: %m",
734 		    auditd_strerror(err));
735 		fail_exit();
736 	}
737 
738 	/*
739 	 * Make sure auditd auditing state is correct.
740 	 */
741 	auditd_set_state(AUD_STATE_INIT);
742 
743 	/*
744 	 * If under launchd, don't start auditing.  Wait for a trigger to
745 	 * do so.
746 	 */
747 	if (!launchd_flag)
748 		audit_setup();
749 }
750 
751 int
752 main(int argc, char **argv)
753 {
754 	int ch;
755 	int debug = 0;
756 #ifdef AUDIT_REVIEW_GROUP
757 	struct group *grp;
758 #endif
759 
760 	while ((ch = getopt(argc, argv, "dl")) != -1) {
761 		switch(ch) {
762 		case 'd':
763 			/* Debug option. */
764 			debug = 1;
765 			break;
766 
767 		case 'l':
768 			/* Be launchd friendly. */
769 			launchd_flag = 1;
770 			break;
771 
772 		case '?':
773 		default:
774 			(void)fprintf(stderr,
775 			    "usage: auditd [-d] [-l]\n");
776 			exit(1);
777 		}
778 	}
779 
780 	audit_review_gid = getgid();
781 
782 #ifdef AUDIT_REVIEW_GROUP
783 	/*
784 	 * XXXRW: Currently, this code falls back to the daemon gid, which is
785 	 * likely the wheel group.  Is there a better way to deal with this?
786 	 */
787 	grp = getgrnam(AUDIT_REVIEW_GROUP);
788 	if (grp != NULL)
789 		audit_review_gid = grp->gr_gid;
790 #endif
791 
792 	auditd_openlog(debug, audit_review_gid);
793 
794 	if (launchd_flag)
795 		auditd_log_info("started by launchd...");
796 	else
797 		auditd_log_info("starting...");
798 
799 #ifdef AUDIT_REVIEW_GROUP
800 	if (grp == NULL)
801 		auditd_log_info(
802 		    "Audit review group '%s' not available, using daemon gid (%d)",
803 		    AUDIT_REVIEW_GROUP, audit_review_gid);
804 #endif
805 	if (debug == 0 && launchd_flag == 0 && daemon(0, 0) == -1) {
806 		auditd_log_err("Failed to daemonize");
807 		exit(1);
808 	}
809 
810 	if (register_daemon() == -1) {
811 		auditd_log_err("Could not register as daemon");
812 		exit(1);
813 	}
814 
815 	setup();
816 
817 	/*
818 	 * auditd_wait_for_events() shouldn't return unless something is wrong.
819 	 */
820 	auditd_wait_for_events();
821 
822 	auditd_log_err("abnormal exit.");
823 	close_all();
824 	exit(-1);
825 }
826