auditd.c revision 155364
1/*
2 * Copyright (c) 2004 Apple Computer, Inc.
3 * All rights reserved.
4 *
5 * @APPLE_BSD_LICENSE_HEADER_START@
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1.  Redistributions of source code must retain the above copyright
12 *     notice, this list of conditions and the following disclaimer.
13 * 2.  Redistributions in binary form must reproduce the above copyright
14 *     notice, this list of conditions and the following disclaimer in the
15 *     documentation and/or other materials provided with the distribution.
16 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
17 *     its contributors may be used to endorse or promote products derived
18 *     from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
21 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
24 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * @APPLE_BSD_LICENSE_HEADER_END@
32 *
33 * $P4: //depot/projects/trustedbsd/openbsm/bin/auditd/auditd.c#11 $
34 */
35
36#include <sys/dirent.h>
37#include <sys/mman.h>
38#include <sys/queue.h>
39#include <sys/stat.h>
40#include <sys/types.h>
41#include <sys/wait.h>
42
43#include <bsm/audit.h>
44#include <bsm/audit_uevents.h>
45#include <bsm/libbsm.h>
46
47#include <errno.h>
48#include <fcntl.h>
49#include <grp.h>
50#include <stdio.h>
51#include <stdlib.h>
52#include <time.h>
53#include <unistd.h>
54#include <signal.h>
55#include <string.h>
56#include <syslog.h>
57
58#include "auditd.h"
59
60#define	NA_EVENT_STR_SIZE	25
61
62static int	 ret, minval;
63static char	*lastfile = NULL;
64static int	 allhardcount = 0;
65static int	 triggerfd = 0;
66static int	 sighups, sighups_handled;
67static int	 sigterms, sigterms_handled;
68static long	 global_flags;
69
70static TAILQ_HEAD(, dir_ent)	dir_q;
71
72static int	config_audit_controls(void);
73
74/*
75 * Error starting auditd
76 */
77static void
78fail_exit(void)
79{
80
81	audit_warn_nostart();
82	exit(1);
83}
84
85/*
86 * Free our local list of directory names.
87 */
88static void
89free_dir_q()
90{
91	struct dir_ent *dirent;
92
93	while ((dirent = TAILQ_FIRST(&dir_q))) {
94		TAILQ_REMOVE(&dir_q, dirent, dirs);
95		free(dirent->dirname);
96		free(dirent);
97	}
98}
99
100/*
101 * Generate the timestamp string.
102 */
103static int
104getTSstr(char *buf, int len)
105{
106	struct timeval ts;
107	struct timezone tzp;
108	time_t tt;
109
110	if (gettimeofday(&ts, &tzp) != 0)
111		return (-1);
112	tt = (time_t)ts.tv_sec;
113	if (!strftime(buf, len, "%Y%m%d%H%M%S", gmtime(&tt)))
114		return (-1);
115	return (0);
116}
117
118/*
119 * Concat the directory name to the given file name.
120 * XXX We should affix the hostname also
121 */
122static char *
123affixdir(char *name, struct dir_ent *dirent)
124{
125	char *fn;
126	char *curdir;
127	const char *sep = "/";
128
129	curdir = dirent->dirname;
130	syslog(LOG_INFO, "dir = %s\n", dirent->dirname);
131
132	fn = malloc(strlen(curdir) + strlen(sep) + (2 * POSTFIX_LEN) + 1);
133	if (fn == NULL)
134		return (NULL);
135	strcpy(fn, curdir);
136	strcat(fn, sep);
137	strcat(fn, name);
138	return (fn);
139}
140
141/*
142 * Close the previous audit trail file.
143 */
144static int
145close_lastfile(char *TS)
146{
147	char *ptr;
148	char *oldname;
149
150	if (lastfile != NULL) {
151		oldname = (char *)malloc(strlen(lastfile) + 1);
152		if (oldname == NULL)
153			return (-1);
154		strcpy(oldname, lastfile);
155
156		/* Rename the last file -- append timestamp. */
157		if ((ptr = strstr(lastfile, NOT_TERMINATED)) != NULL) {
158			*ptr = '.';
159			strcpy(ptr+1, TS);
160			if (rename(oldname, lastfile) != 0)
161				syslog(LOG_ERR, "Could not rename %s to %s \n",
162				    oldname, lastfile);
163			else
164				syslog(LOG_INFO, "renamed %s to %s \n",
165				    oldname, lastfile);
166		}
167		free(lastfile);
168		free(oldname);
169		lastfile = NULL;
170	}
171	return (0);
172}
173
174/*
175 * Create the new audit file with appropriate permissions and ownership.  Try
176 * to clean up if something goes wrong.
177 */
178static int
179#ifdef AUDIT_REVIEW_GROUP
180open_trail(const char *fname, uid_t uid, gid_t gid)
181#else
182open_trail(const char *fname)
183#endif
184{
185	int error, fd;
186
187	fd = open(fname, O_RDONLY | O_CREAT, S_IRUSR | S_IRGRP);
188	if (fd < 0)
189		return (-1);
190#ifdef AUDIT_REVIEW_GROUP
191	if (fchown(fd, uid, gid) < 0) {
192		error = errno;
193		close(fd);
194		(void)unlink(fname);
195		errno = error;
196		return (-1);
197	}
198#endif
199	return (fd);
200}
201
202/*
203 * Create the new file name, swap with existing audit file.
204 */
205static int
206swap_audit_file(void)
207{
208	char timestr[2 * POSTFIX_LEN];
209	char *fn;
210	char TS[POSTFIX_LEN];
211	struct dir_ent *dirent;
212#ifdef AUDIT_REVIEW_GROUP
213	struct group *grp;
214	gid_t gid;
215	uid_t uid;
216#endif
217	int error, fd;
218
219	if (getTSstr(TS, POSTFIX_LEN) != 0)
220		return (-1);
221
222	strcpy(timestr, TS);
223	strcat(timestr, NOT_TERMINATED);
224
225#ifdef AUDIT_REVIEW_GROUP
226	/*
227	 * XXXRW: Currently, this code falls back to the daemon gid, which is
228	 * likely the wheel group.  Is there a better way to deal with this?
229	 */
230	grp = getgrnam(AUDIT_REVIEW_GROUP);
231	if (grp == NULL) {
232		syslog(LOG_INFO,
233		    "Audit review group '%s' not available, using daemon gid",
234		    AUDIT_REVIEW_GROUP);
235		gid = -1;
236	} else
237		gid = grp->gr_gid;
238	uid = getuid();
239#endif
240
241	/* Try until we succeed. */
242	while ((dirent = TAILQ_FIRST(&dir_q))) {
243		if ((fn = affixdir(timestr, dirent)) == NULL) {
244			syslog(LOG_INFO, "Failed to swap log  at time %s\n",
245				timestr);
246			return (-1);
247		}
248
249		/*
250		 * Create and open the file; then close and pass to the
251		 * kernel if all went well.
252		 */
253		syslog(LOG_INFO, "New audit file is %s\n", fn);
254#ifdef AUDIT_REVIEW_GROUP
255		fd = open_trail(fn, uid, gid);
256#else
257		fd = open_trail(fn);
258#endif
259		if (fd < 0)
260			warn("open(%s)", fn);
261		if (fd >= 0) {
262			error = auditctl(fn);
263			if (error) {
264				syslog(LOG_ERR,
265				    "auditctl failed setting log file! : %s\n",
266				    strerror(errno));
267				close(fd);
268			} else {
269				/* Success. */
270				close_lastfile(TS);
271				lastfile = fn;
272				close(fd);
273				return (0);
274			}
275		}
276
277		/*
278		 * Tell the administrator about lack of permissions for dir.
279		 */
280		audit_warn_getacdir(dirent->dirname);
281
282		/* Try again with a different directory. */
283		TAILQ_REMOVE(&dir_q, dirent, dirs);
284		free(dirent->dirname);
285		free(dirent);
286	}
287	syslog(LOG_INFO, "Log directories exhausted\n");
288	return (-1);
289}
290
291/*
292 * Read the audit_control file contents.
293 */
294static int
295read_control_file(void)
296{
297	char cur_dir[MAXNAMLEN];
298	struct dir_ent *dirent;
299	au_qctrl_t qctrl;
300
301	/*
302	 * Clear old values.  Force a re-read of the file the next time.
303	 */
304	free_dir_q();
305	endac();
306
307	/*
308	 * Read the list of directories into a local linked list.
309	 *
310	 * XXX We should use the reentrant interfaces once they are
311	 * available.
312	 */
313	while (getacdir(cur_dir, MAXNAMLEN) >= 0) {
314		dirent = (struct dir_ent *) malloc(sizeof(struct dir_ent));
315		if (dirent == NULL)
316			return (-1);
317		dirent->softlim = 0;
318		dirent->dirname = (char *) malloc(MAXNAMLEN);
319		if (dirent->dirname == NULL) {
320			free(dirent);
321			return (-1);
322		}
323		strcpy(dirent->dirname, cur_dir);
324		TAILQ_INSERT_TAIL(&dir_q, dirent, dirs);
325	}
326
327	allhardcount = 0;
328	if (swap_audit_file() == -1) {
329		syslog(LOG_ERR, "Could not swap audit file\n");
330		/*
331		 * XXX Faulty directory listing? - user should be given
332		 * XXX an opportunity to change the audit_control file
333		 * XXX switch to a reduced mode of auditing?
334		 */
335		return (-1);
336	}
337
338	/*
339	 * XXX There are synchronization problems here
340 	 * XXX what should we do if a trigger for the earlier limit
341	 * XXX is generated here?
342	 */
343	if (0 == (ret = getacmin(&minval))) {
344		syslog(LOG_INFO, "min free = %d\n", minval);
345		if (auditon(A_GETQCTRL, &qctrl, sizeof(qctrl)) != 0) {
346			syslog(LOG_ERR,
347			    "could not get audit queue settings\n");
348				return (-1);
349		}
350		qctrl.aq_minfree = minval;
351		if (auditon(A_SETQCTRL, &qctrl, sizeof(qctrl)) != 0) {
352			syslog(LOG_ERR,
353			    "could not set audit queue settings\n");
354			return (-1);
355		}
356	}
357
358	return (0);
359}
360
361/*
362 * Close all log files, control files, and tell the audit system.
363 */
364static int
365close_all(void)
366{
367	int err_ret = 0;
368	char TS[POSTFIX_LEN];
369	int aufd;
370	token_t *tok;
371	long cond;
372
373	/* Generate an audit record. */
374	if ((aufd = au_open()) == -1)
375		syslog(LOG_ERR, "Could not create audit shutdown event.\n");
376	else {
377		if ((tok = au_to_text("auditd::Audit shutdown")) != NULL)
378			au_write(aufd, tok);
379		if (au_close(aufd, 1, AUE_audit_shutdown) == -1)
380			syslog(LOG_ERR,
381			    "Could not close audit shutdown event.\n");
382	}
383
384	/* Flush contents. */
385	cond = AUC_DISABLED;
386	err_ret = auditon(A_SETCOND, &cond, sizeof(cond));
387	if (err_ret != 0) {
388		syslog(LOG_ERR, "Disabling audit failed! : %s\n",
389		    strerror(errno));
390		err_ret = 1;
391	}
392	if (getTSstr(TS, POSTFIX_LEN) == 0)
393		close_lastfile(TS);
394	if (lastfile != NULL)
395		free(lastfile);
396
397	free_dir_q();
398	if ((remove(AUDITD_PIDFILE) == -1) || err_ret) {
399		syslog(LOG_ERR, "Could not unregister\n");
400		audit_warn_postsigterm();
401		return (1);
402	}
403	endac();
404
405	if (close(triggerfd) != 0)
406		syslog(LOG_ERR, "Error closing control file\n");
407	syslog(LOG_INFO, "Finished.\n");
408	return (0);
409}
410
411/*
412 * When we get a signal, we are often not at a clean point.  So, little can
413 * be done in the signal handler itself.  Instead,  we send a message to the
414 * main servicing loop to do proper handling from a non-signal-handler
415 * context.
416 */
417static void
418relay_signal(int signal)
419{
420
421	if (signal == SIGHUP)
422		sighups++;
423	if (signal == SIGTERM)
424		sigterms++;
425}
426
427/*
428 * Registering the daemon.
429 */
430static int
431register_daemon(void)
432{
433	FILE * pidfile;
434	int fd;
435	pid_t pid;
436
437	/* Set up the signal hander. */
438	if (signal(SIGTERM, relay_signal) == SIG_ERR) {
439		syslog(LOG_ERR,
440		    "Could not set signal handler for SIGTERM\n");
441		fail_exit();
442	}
443	if (signal(SIGCHLD, relay_signal) == SIG_ERR) {
444		syslog(LOG_ERR,
445		    "Could not set signal handler for SIGCHLD\n");
446		fail_exit();
447	}
448	if (signal(SIGHUP, relay_signal) == SIG_ERR) {
449		syslog(LOG_ERR,
450		    "Could not set signal handler for SIGHUP\n");
451		fail_exit();
452	}
453
454	if ((pidfile = fopen(AUDITD_PIDFILE, "a")) == NULL) {
455		syslog(LOG_ERR,
456		    "Could not open PID file\n");
457		audit_warn_tmpfile();
458		return (-1);
459	}
460
461	/* Attempt to lock the pid file; if a lock is present, exit. */
462	fd = fileno(pidfile);
463	if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
464		syslog(LOG_ERR,
465		    "PID file is locked (is another auditd running?).\n");
466		audit_warn_ebusy();
467		return (-1);
468	}
469
470	pid = getpid();
471	ftruncate(fd, 0);
472	if (fprintf(pidfile, "%u\n", pid) < 0) {
473		/* Should not start the daemon. */
474		fail_exit();
475	}
476
477	fflush(pidfile);
478	return (0);
479}
480
481/*
482 * Suppress duplicate messages within a 30 second interval.   This should be
483 * enough to time to rotate log files without thrashing from soft warnings
484 * generated before the log is actually rotated.
485 */
486#define	DUPLICATE_INTERVAL	30
487static void
488handle_audit_trigger(int trigger)
489{
490	static int last_trigger;
491	static time_t last_time;
492	struct dir_ent *dirent;
493	int rc;
494
495	/*
496	 * Suppres duplicate messages from the kernel within the specified
497	 * interval.
498	 */
499	struct timeval ts;
500	struct timezone tzp;
501	time_t tt;
502
503	if (gettimeofday(&ts, &tzp) == 0) {
504		tt = (time_t)ts.tv_sec;
505		if ((trigger == last_trigger) &&
506		    (tt < (last_time + DUPLICATE_INTERVAL)))
507			return;
508		last_trigger = trigger;
509		last_time = tt;
510	}
511
512	/*
513	 * Message processing is done here.
514 	 */
515	dirent = TAILQ_FIRST(&dir_q);
516	switch(trigger) {
517
518	case AUDIT_TRIGGER_LOW_SPACE:
519		syslog(LOG_INFO, "Got low space trigger\n");
520		if (dirent && (dirent->softlim != 1)) {
521			TAILQ_REMOVE(&dir_q, dirent, dirs);
522				/* Add this node to the end of the list. */
523				TAILQ_INSERT_TAIL(&dir_q, dirent, dirs);
524				audit_warn_soft(dirent->dirname);
525				dirent->softlim = 1;
526
527			if (TAILQ_NEXT(TAILQ_FIRST(&dir_q), dirs) != NULL &&
528			    swap_audit_file() == -1)
529				syslog(LOG_ERR, "Error swapping audit file\n");
530
531			/*
532			 * Check if the next dir has already reached its soft
533			 * limit.
534			 */
535			dirent = TAILQ_FIRST(&dir_q);
536			if (dirent->softlim == 1)  {
537				/* All dirs have reached their soft limit. */
538				audit_warn_allsoft();
539			}
540		} else {
541			/*
542			 * Continue auditing to the current file.  Also
543			 * generate  an allsoft warning.
544			 * XXX do we want to do this ?
545			 */
546			audit_warn_allsoft();
547		}
548		break;
549
550	case AUDIT_TRIGGER_NO_SPACE:
551		syslog(LOG_INFO, "Got no space trigger\n");
552
553		/* Delete current dir, go on to next. */
554		TAILQ_REMOVE(&dir_q, dirent, dirs);
555		audit_warn_hard(dirent->dirname);
556		free(dirent->dirname);
557		free(dirent);
558
559		if (swap_audit_file() == -1)
560			syslog(LOG_ERR, "Error swapping audit file\n");
561
562		/* We are out of log directories. */
563		audit_warn_allhard(++allhardcount);
564		break;
565
566	case AUDIT_TRIGGER_OPEN_NEW:
567		/*
568		 * Create a new file and swap with the one being used in
569		 * kernel
570		 */
571		syslog(LOG_INFO, "Got open new trigger\n");
572		if (swap_audit_file() == -1)
573			syslog(LOG_ERR, "Error swapping audit file\n");
574		break;
575
576	case AUDIT_TRIGGER_READ_FILE:
577		syslog(LOG_INFO, "Got read file trigger\n");
578		if (read_control_file() == -1)
579			syslog(LOG_ERR, "Error in audit control file\n");
580		if (config_audit_controls() == -1)
581			syslog(LOG_ERR, "Error setting audit controls\n");
582		break;
583
584	default:
585		syslog(LOG_ERR, "Got unknown trigger %d\n", trigger);
586		break;
587	}
588}
589
590static void
591handle_sighup(void)
592{
593
594	sighups_handled = sighups;
595	config_audit_controls();
596}
597
598/*
599 * Read the control file for triggers and handle appropriately.
600 */
601static int
602wait_for_triggers(void)
603{
604	int num;
605	unsigned int trigger;
606
607	for (;;) {
608		num = read(triggerfd, &trigger, sizeof(trigger));
609		if ((num == -1) && (errno != EINTR)) {
610			syslog(LOG_ERR, "%s: error %d\n", __FUNCTION__, errno);
611			return (-1);
612		}
613		if (sigterms != sigterms_handled) {
614			syslog(LOG_INFO, "%s: SIGTERM", __FUNCTION__);
615			break;
616		}
617		if (sighups != sighups_handled) {
618			syslog(LOG_INFO, "%s: SIGHUP", __FUNCTION__);
619			handle_sighup();
620		}
621		if ((num == -1) && (errno == EINTR))
622			continue;
623		if (num == 0) {
624			syslog(LOG_INFO, "%s: read EOF\n", __FUNCTION__);
625			return (-1);
626		}
627		syslog(LOG_INFO, "%s: read %d\n", __FUNCTION__, trigger);
628		if (trigger == AUDIT_TRIGGER_CLOSE_AND_DIE)
629			break;
630		else
631			handle_audit_trigger(trigger);
632	}
633	return (close_all());
634}
635
636/*
637 * Reap our children.
638 */
639static void
640reap_children(void)
641{
642	pid_t child;
643	int wstatus;
644
645	while ((child = waitpid(-1, &wstatus, WNOHANG)) > 0) {
646		if (!wstatus)
647			continue;
648		syslog(LOG_INFO, "warn process [pid=%d] %s %d.\n", child,
649		    ((WIFEXITED(wstatus)) ? "exited with non-zero status" :
650		    "exited as a result of signal"),
651		    ((WIFEXITED(wstatus)) ? WEXITSTATUS(wstatus) :
652		    WTERMSIG(wstatus)));
653	}
654}
655
656/*
657 * Configure the audit controls in the kernel: the event to class mapping,
658 * kernel preselection mask, etc.
659 */
660static int
661config_audit_controls(void)
662{
663	au_event_ent_t ev, *evp;
664	au_evclass_map_t evc_map;
665	au_mask_t aumask;
666	int ctr = 0;
667	char naeventstr[NA_EVENT_STR_SIZE];
668
669	/*
670	 * Process the audit event file, obtaining a class mapping for each
671	 * event, and send that mapping into the kernel.
672	 * XXX There's a risk here that the BSM library will return NULL
673	 * for an event when it can't properly map it to a class. In that
674	 * case, we will not process any events beyond the one that failed,
675	 * but should. We need a way to get a count of the events.
676	*/
677	ev.ae_name = (char *)malloc(AU_EVENT_NAME_MAX);
678	ev.ae_desc = (char *)malloc(AU_EVENT_DESC_MAX);
679	if ((ev.ae_name == NULL) || (ev.ae_desc == NULL)) {
680		syslog(LOG_ERR,
681		    "Memory allocation error when configuring audit controls.");
682		return (-1);
683	}
684	evp = &ev;
685	setauevent();
686	while ((evp = getauevent_r(evp)) != NULL) {
687		evc_map.ec_number = evp->ae_number;
688		evc_map.ec_class = evp->ae_class;
689		if (auditon(A_SETCLASS, &evc_map, sizeof(au_evclass_map_t))
690		    != 0)
691			syslog(LOG_ERR,
692				"Failed to register class mapping for event %s",
693				 evp->ae_name);
694		else
695			ctr++;
696	}
697	endauevent();
698	free(ev.ae_name);
699	free(ev.ae_desc);
700	if (ctr == 0)
701		syslog(LOG_ERR, "No events to class mappings registered.");
702	else
703		syslog(LOG_INFO, "Registered %d event to class mappings.",
704		    ctr);
705
706	/*
707	 * Get the non-attributable event string and set the kernel mask from
708	 * that.
709	 */
710	if ((getacna(naeventstr, NA_EVENT_STR_SIZE) == 0) &&
711	    (getauditflagsbin(naeventstr, &aumask) == 0)) {
712		if (auditon(A_SETKMASK, &aumask, sizeof(au_mask_t)))
713			syslog(LOG_ERR,
714			    "Failed to register non-attributable event mask.");
715		else
716			syslog(LOG_INFO,
717			    "Registered non-attributable event mask.");
718	} else
719		syslog(LOG_ERR,
720		    "Failed to obtain non-attributable event mask.");
721
722	/*
723	 * Set the audit policy flags based on passed in parameter values.
724	 */
725	if (auditon(A_SETPOLICY, &global_flags, sizeof(global_flags)))
726		syslog(LOG_ERR, "Failed to set audit policy.");
727
728	return (0);
729}
730
731static void
732setup(void)
733{
734	int aufd;
735	token_t *tok;
736
737	if ((triggerfd = open(AUDIT_TRIGGER_FILE, O_RDONLY, 0)) < 0) {
738		syslog(LOG_ERR, "Error opening trigger file\n");
739		fail_exit();
740	}
741
742	TAILQ_INIT(&dir_q);
743	if (read_control_file() == -1) {
744		syslog(LOG_ERR, "Error reading control file\n");
745		fail_exit();
746	}
747
748	/* Generate an audit record. */
749	if ((aufd = au_open()) == -1)
750		syslog(LOG_ERR, "Could not create audit startup event.\n");
751	else {
752		if ((tok = au_to_text("auditd::Audit startup")) != NULL)
753			au_write(aufd, tok);
754		if (au_close(aufd, 1, AUE_audit_startup) == -1)
755			syslog(LOG_ERR,
756			    "Could not close audit startup event.\n");
757	}
758
759	if (config_audit_controls() == 0)
760		syslog(LOG_INFO, "Audit controls init successful\n");
761	else
762		syslog(LOG_INFO, "Audit controls init failed\n");
763}
764
765int
766main(int argc, char **argv)
767{
768	int ch;
769	int debug = 0;
770	int rc;
771
772	global_flags |= AUDIT_CNT;
773	while ((ch = getopt(argc, argv, "dhs")) != -1) {
774		switch(ch) {
775		case 'd':
776			/* Debug option. */
777			debug = 1;
778			break;
779
780		case 's':
781			/* Fail-stop option. */
782			global_flags &= ~(AUDIT_CNT);
783			break;
784
785		case 'h':
786			/* Halt-stop option. */
787			global_flags |= AUDIT_AHLT;
788			break;
789
790		case '?':
791		default:
792			(void)fprintf(stderr,
793			    "usage: auditd [-h | -s] [-d] \n");
794			exit(1);
795		}
796	}
797
798	openlog("auditd", LOG_CONS | LOG_PID, LOG_SECURITY);
799	syslog(LOG_INFO, "starting...\n");
800
801	if (debug == 0 && daemon(0, 0) == -1) {
802		syslog(LOG_ERR, "Failed to daemonize\n");
803		exit(1);
804	}
805
806	if (register_daemon() == -1) {
807		syslog(LOG_ERR, "Could not register as daemon\n");
808		exit(1);
809	}
810
811	setup();
812
813	rc = wait_for_triggers();
814	syslog(LOG_INFO, "auditd exiting.\n");
815
816	exit(rc);
817}
818