2 * Copyright (c) 2004 Apple Computer, Inc.
5 * @APPLE_BSD_LICENSE_HEADER_START@
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
31 * @APPLE_BSD_LICENSE_HEADER_END@
33 * $P4: //depot/projects/trustedbsd/openbsm/bin/auditd/auditd.c#13 $
36 #include <sys/types.h>
37 #include <sys/dirent.h>
39 #include <sys/queue.h>
43 #include <bsm/audit.h>
44 #include <bsm/audit_uevents.h>
45 #include <bsm/libbsm.h>
60 #define NA_EVENT_STR_SIZE 25
62 static int ret, minval;
63 static char *lastfile = NULL;
64 static int allhardcount = 0;
65 static int triggerfd = 0;
66 static int sighups, sighups_handled;
67 static int sigterms, sigterms_handled;
68 static long global_flags;
70 static TAILQ_HEAD(, dir_ent) dir_q;
72 static int config_audit_controls(void);
75 * Error starting auditd
86 * Free our local list of directory names.
91 struct dir_ent *dirent;
93 while ((dirent = TAILQ_FIRST(&dir_q))) {
94 TAILQ_REMOVE(&dir_q, dirent, dirs);
95 free(dirent->dirname);
101 * Generate the timestamp string.
104 getTSstr(char *buf, int len)
110 if (gettimeofday(&ts, &tzp) != 0)
112 tt = (time_t)ts.tv_sec;
113 if (!strftime(buf, len, "%Y%m%d%H%M%S", gmtime(&tt)))
119 * Concat the directory name to the given file name.
120 * XXX We should affix the hostname also
123 affixdir(char *name, struct dir_ent *dirent)
127 const char *sep = "/";
129 curdir = dirent->dirname;
130 syslog(LOG_INFO, "dir = %s\n", dirent->dirname);
132 fn = malloc(strlen(curdir) + strlen(sep) + (2 * POSTFIX_LEN) + 1);
142 * Close the previous audit trail file.
145 close_lastfile(char *TS)
150 if (lastfile != NULL) {
151 oldname = (char *)malloc(strlen(lastfile) + 1);
154 strcpy(oldname, lastfile);
156 /* Rename the last file -- append timestamp. */
157 if ((ptr = strstr(lastfile, NOT_TERMINATED)) != NULL) {
160 if (rename(oldname, lastfile) != 0)
161 syslog(LOG_ERR, "Could not rename %s to %s \n",
164 syslog(LOG_INFO, "renamed %s to %s \n",
175 * Create the new audit file with appropriate permissions and ownership. Try
176 * to clean up if something goes wrong.
179 #ifdef AUDIT_REVIEW_GROUP
180 open_trail(const char *fname, uid_t uid, gid_t gid)
182 open_trail(const char *fname)
187 fd = open(fname, O_RDONLY | O_CREAT, S_IRUSR | S_IRGRP);
190 #ifdef AUDIT_REVIEW_GROUP
191 if (fchown(fd, uid, gid) < 0) {
203 * Create the new file name, swap with existing audit file.
206 swap_audit_file(void)
208 char timestr[2 * POSTFIX_LEN];
210 char TS[POSTFIX_LEN];
211 struct dir_ent *dirent;
212 #ifdef AUDIT_REVIEW_GROUP
219 if (getTSstr(TS, POSTFIX_LEN) != 0)
223 strcat(timestr, NOT_TERMINATED);
225 #ifdef AUDIT_REVIEW_GROUP
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?
230 grp = getgrnam(AUDIT_REVIEW_GROUP);
233 "Audit review group '%s' not available, using daemon gid",
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",
250 * Create and open the file; then close and pass to the
251 * kernel if all went well.
253 syslog(LOG_INFO, "New audit file is %s\n", fn);
254 #ifdef AUDIT_REVIEW_GROUP
255 fd = open_trail(fn, uid, gid);
260 warn("open(%s)", fn);
262 error = auditctl(fn);
265 "auditctl failed setting log file! : %s\n",
278 * Tell the administrator about lack of permissions for dir.
280 audit_warn_getacdir(dirent->dirname);
282 /* Try again with a different directory. */
283 TAILQ_REMOVE(&dir_q, dirent, dirs);
284 free(dirent->dirname);
287 syslog(LOG_INFO, "Log directories exhausted\n");
292 * Read the audit_control file contents.
295 read_control_file(void)
297 char cur_dir[MAXNAMLEN];
298 struct dir_ent *dirent;
302 * Clear old values. Force a re-read of the file the next time.
308 * Read the list of directories into a local linked list.
310 * XXX We should use the reentrant interfaces once they are
313 while (getacdir(cur_dir, MAXNAMLEN) >= 0) {
314 dirent = (struct dir_ent *) malloc(sizeof(struct dir_ent));
318 dirent->dirname = (char *) malloc(MAXNAMLEN);
319 if (dirent->dirname == NULL) {
323 strcpy(dirent->dirname, cur_dir);
324 TAILQ_INSERT_TAIL(&dir_q, dirent, dirs);
328 if (swap_audit_file() == -1) {
329 syslog(LOG_ERR, "Could not swap audit file\n");
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?
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?
343 if (0 == (ret = getacmin(&minval))) {
344 syslog(LOG_INFO, "min free = %d\n", minval);
345 if (auditon(A_GETQCTRL, &qctrl, sizeof(qctrl)) != 0) {
347 "could not get audit queue settings\n");
350 qctrl.aq_minfree = minval;
351 if (auditon(A_SETQCTRL, &qctrl, sizeof(qctrl)) != 0) {
353 "could not set audit queue settings\n");
362 * Close all log files, control files, and tell the audit system.
368 char TS[POSTFIX_LEN];
373 /* Generate an audit record. */
374 if ((aufd = au_open()) == -1)
375 syslog(LOG_ERR, "Could not create audit shutdown event.\n");
377 if ((tok = au_to_text("auditd::Audit shutdown")) != NULL)
379 if (au_close(aufd, 1, AUE_audit_shutdown) == -1)
381 "Could not close audit shutdown event.\n");
384 /* Flush contents. */
386 err_ret = auditon(A_SETCOND, &cond, sizeof(cond));
388 syslog(LOG_ERR, "Disabling audit failed! : %s\n",
392 if (getTSstr(TS, POSTFIX_LEN) == 0)
394 if (lastfile != NULL)
398 if ((remove(AUDITD_PIDFILE) == -1) || err_ret) {
399 syslog(LOG_ERR, "Could not unregister\n");
400 audit_warn_postsigterm();
405 if (close(triggerfd) != 0)
406 syslog(LOG_ERR, "Error closing control file\n");
407 syslog(LOG_INFO, "Finished.\n");
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
418 relay_signal(int signal)
421 if (signal == SIGHUP)
423 if (signal == SIGTERM)
428 * Registering the daemon.
431 register_daemon(void)
437 /* Set up the signal hander. */
438 if (signal(SIGTERM, relay_signal) == SIG_ERR) {
440 "Could not set signal handler for SIGTERM\n");
443 if (signal(SIGCHLD, relay_signal) == SIG_ERR) {
445 "Could not set signal handler for SIGCHLD\n");
448 if (signal(SIGHUP, relay_signal) == SIG_ERR) {
450 "Could not set signal handler for SIGHUP\n");
454 if ((pidfile = fopen(AUDITD_PIDFILE, "a")) == NULL) {
456 "Could not open PID file\n");
457 audit_warn_tmpfile();
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) {
465 "PID file is locked (is another auditd running?).\n");
472 if (fprintf(pidfile, "%u\n", pid) < 0) {
473 /* Should not start the daemon. */
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.
486 #define DUPLICATE_INTERVAL 30
488 handle_audit_trigger(int trigger)
490 static int last_trigger;
491 static time_t last_time;
492 struct dir_ent *dirent;
496 * Suppres duplicate messages from the kernel within the specified
503 if (gettimeofday(&ts, &tzp) == 0) {
504 tt = (time_t)ts.tv_sec;
505 if ((trigger == last_trigger) &&
506 (tt < (last_time + DUPLICATE_INTERVAL)))
508 last_trigger = trigger;
513 * Message processing is done here.
515 dirent = TAILQ_FIRST(&dir_q);
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);
527 if (TAILQ_NEXT(TAILQ_FIRST(&dir_q), dirs) != NULL &&
528 swap_audit_file() == -1)
529 syslog(LOG_ERR, "Error swapping audit file\n");
532 * Check if the next dir has already reached its soft
535 dirent = TAILQ_FIRST(&dir_q);
536 if (dirent->softlim == 1) {
537 /* All dirs have reached their soft limit. */
538 audit_warn_allsoft();
542 * Continue auditing to the current file. Also
543 * generate an allsoft warning.
544 * XXX do we want to do this ?
546 audit_warn_allsoft();
550 case AUDIT_TRIGGER_NO_SPACE:
551 syslog(LOG_INFO, "Got no space trigger\n");
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);
559 if (swap_audit_file() == -1)
560 syslog(LOG_ERR, "Error swapping audit file\n");
562 /* We are out of log directories. */
563 audit_warn_allhard(++allhardcount);
566 case AUDIT_TRIGGER_OPEN_NEW:
568 * Create a new file and swap with the one being used in
571 syslog(LOG_INFO, "Got open new trigger\n");
572 if (swap_audit_file() == -1)
573 syslog(LOG_ERR, "Error swapping audit file\n");
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");
585 syslog(LOG_ERR, "Got unknown trigger %d\n", trigger);
594 sighups_handled = sighups;
595 config_audit_controls();
599 * Read the control file for triggers and handle appropriately.
602 wait_for_triggers(void)
605 unsigned int trigger;
608 num = read(triggerfd, &trigger, sizeof(trigger));
609 if ((num == -1) && (errno != EINTR)) {
610 syslog(LOG_ERR, "%s: error %d\n", __FUNCTION__, errno);
613 if (sigterms != sigterms_handled) {
614 syslog(LOG_INFO, "%s: SIGTERM", __FUNCTION__);
617 if (sighups != sighups_handled) {
618 syslog(LOG_INFO, "%s: SIGHUP", __FUNCTION__);
621 if ((num == -1) && (errno == EINTR))
624 syslog(LOG_INFO, "%s: read EOF\n", __FUNCTION__);
627 syslog(LOG_INFO, "%s: read %d\n", __FUNCTION__, trigger);
628 if (trigger == AUDIT_TRIGGER_CLOSE_AND_DIE)
631 handle_audit_trigger(trigger);
633 return (close_all());
645 while ((child = waitpid(-1, &wstatus, WNOHANG)) > 0) {
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) :
657 * Configure the audit controls in the kernel: the event to class mapping,
658 * kernel preselection mask, etc.
661 config_audit_controls(void)
663 au_event_ent_t ev, *evp;
664 au_evclass_map_t evc_map;
667 char naeventstr[NA_EVENT_STR_SIZE];
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.
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)) {
681 "Memory allocation error when configuring audit controls.");
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))
692 "Failed to register class mapping for event %s",
701 syslog(LOG_ERR, "No events to class mappings registered.");
703 syslog(LOG_INFO, "Registered %d event to class mappings.",
707 * Get the non-attributable event string and set the kernel mask from
710 if ((getacna(naeventstr, NA_EVENT_STR_SIZE) == 0) &&
711 (getauditflagsbin(naeventstr, &aumask) == 0)) {
712 if (auditon(A_SETKMASK, &aumask, sizeof(au_mask_t)))
714 "Failed to register non-attributable event mask.");
717 "Registered non-attributable event mask.");
720 "Failed to obtain non-attributable event mask.");
723 * Set the audit policy flags based on passed in parameter values.
725 if (auditon(A_SETPOLICY, &global_flags, sizeof(global_flags)))
726 syslog(LOG_ERR, "Failed to set audit policy.");
737 if ((triggerfd = open(AUDIT_TRIGGER_FILE, O_RDONLY, 0)) < 0) {
738 syslog(LOG_ERR, "Error opening trigger file\n");
743 if (read_control_file() == -1) {
744 syslog(LOG_ERR, "Error reading control file\n");
748 /* Generate an audit record. */
749 if ((aufd = au_open()) == -1)
750 syslog(LOG_ERR, "Could not create audit startup event.\n");
752 if ((tok = au_to_text("auditd::Audit startup")) != NULL)
754 if (au_close(aufd, 1, AUE_audit_startup) == -1)
756 "Could not close audit startup event.\n");
759 if (config_audit_controls() == 0)
760 syslog(LOG_INFO, "Audit controls init successful\n");
762 syslog(LOG_INFO, "Audit controls init failed\n");
766 main(int argc, char **argv)
772 global_flags |= AUDIT_CNT;
773 while ((ch = getopt(argc, argv, "dhs")) != -1) {
781 /* Fail-stop option. */
782 global_flags &= ~(AUDIT_CNT);
786 /* Halt-stop option. */
787 global_flags |= AUDIT_AHLT;
792 (void)fprintf(stderr,
793 "usage: auditd [-h | -s] [-d] \n");
799 openlog("auditd", LOG_CONS | LOG_PID, LOG_SECURITY);
801 openlog("auditd", LOG_CONS | LOG_PID, LOG_AUTH);
803 syslog(LOG_INFO, "starting...\n");
805 if (debug == 0 && daemon(0, 0) == -1) {
806 syslog(LOG_ERR, "Failed to daemonize\n");
810 if (register_daemon() == -1) {
811 syslog(LOG_ERR, "Could not register as daemon\n");
817 rc = wait_for_triggers();
818 syslog(LOG_INFO, "auditd exiting.\n");