2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * "Portions Copyright (c) 2004 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
25 #include <mach/port.h>
26 #include <mach/mach_error.h>
27 #include <mach/mach_traps.h>
28 #include <mach/mach.h>
29 #include <mach/host_special_ports.h>
31 #include <sys/types.h>
33 #include <sys/queue.h>
49 #include <bsm/audit.h>
50 #include <bsm/audit_uevents.h>
51 #include <bsm/libbsm.h>
54 #include "auditd_control_server.h"
55 #include "audit_triggers_server.h"
56 #define NA_EVENT_STR_SIZE 25
58 static int ret
, minval
;
59 static char *lastfile
= NULL
;
61 static int allhardcount
= 0;
63 mach_port_t bp
= MACH_PORT_NULL
;
64 mach_port_t control_port
= MACH_PORT_NULL
;
65 mach_port_t signal_port
= MACH_PORT_NULL
;
66 mach_port_t port_set
= MACH_PORT_NULL
;
68 #ifndef __BSM_INTERNAL_NOTIFY_KEY
69 #define __BSM_INTERNAL_NOTIFY_KEY "com.apple.audit.change"
70 #endif /* __BSM_INTERNAL_NOTIFY_KEY */
72 TAILQ_HEAD(, dir_ent
) dir_q
;
75 /* Error starting auditd */
83 * Free our local list of directory names
87 struct dir_ent
*dirent
;
89 while ((dirent
= TAILQ_FIRST(&dir_q
))) {
90 TAILQ_REMOVE(&dir_q
, dirent
, dirs
);
91 free(dirent
->dirname
);
97 * generate the timestamp string
99 int getTSstr(char *buf
, int len
)
105 if(gettimeofday(&ts
, &tzp
) != 0) {
108 tt
= (time_t)ts
.tv_sec
;
109 if(!strftime(buf
, len
, "%Y%m%d%H%M%S", gmtime(&tt
))) {
117 * Concat the directory name to the given file name
118 * XXX We should affix the hostname also
120 char *affixdir(char *name
, struct dir_ent
*dirent
)
124 const char *sep
= "/";
126 curdir
= dirent
->dirname
;
127 syslog(LOG_INFO
, "dir = %s\n", dirent
->dirname
);
129 fn
= (char *) malloc (strlen(curdir
) + strlen(sep
)
130 + (2 * POSTFIX_LEN
) + 1);
141 /* Close the previous audit trail file */
142 int close_lastfile(char *TS
)
147 if(lastfile
!= NULL
) {
148 oldname
= (char *)malloc(strlen(lastfile
) + 1);
149 if(oldname
== NULL
) {
152 strcpy(oldname
, lastfile
);
154 /* rename the last file -- append timestamp */
156 if((ptr
= strstr(lastfile
, NOT_TERMINATED
)) != NULL
) {
159 if(rename(oldname
, lastfile
) != 0) {
160 syslog(LOG_ERR
, "Could not rename %s to %s \n",
164 syslog(LOG_INFO
, "renamed %s to %s \n",
179 * Create the new file name, swap with existing audit file
181 int swap_audit_file()
183 char timestr
[2 * POSTFIX_LEN
];
185 char TS
[POSTFIX_LEN
];
186 struct dir_ent
*dirent
;
188 if(getTSstr(TS
, POSTFIX_LEN
) != 0) {
193 strcat(timestr
, NOT_TERMINATED
);
195 /* try until we succeed */
196 while((dirent
= TAILQ_FIRST(&dir_q
))) {
197 if((fn
= affixdir(timestr
, dirent
)) == NULL
) {
201 syslog(LOG_INFO
, "New audit file is %s\n", fn
);
202 if (open(fn
, O_RDONLY
| O_CREAT
, S_IRUSR
| S_IRGRP
) < 0) {
205 else if (auditctl(fn
) != 0) {
206 syslog(LOG_ERR
, "auditctl failed! : %s\n",
216 /* Tell the administrator about lack of permissions for dirent */
217 audit_warn_getacdir(dirent
->dirname
);
219 /* Try again with a different directory */
220 TAILQ_REMOVE(&dir_q
, dirent
, dirs
);
221 free(dirent
->dirname
);
228 * Read the audit_control file contents
230 int read_control_file()
232 char cur_dir
[MAX_DIR_SIZE
];
233 struct dir_ent
*dirent
;
236 /* Clear old values */
238 endac(); // force a re-read of the file the next time
240 /* Post that the audit config changed */
241 notify_post(__BSM_INTERNAL_NOTIFY_KEY
);
243 /* Read the list of directories into a local linked list */
244 /* XXX We should use the reentrant interfaces once they are available */
245 while(getacdir(cur_dir
, MAX_DIR_SIZE
) >= 0) {
246 dirent
= (struct dir_ent
*) malloc (sizeof(struct dir_ent
));
252 dirent
->dirname
= (char *) malloc (MAX_DIR_SIZE
);
253 if(dirent
->dirname
== NULL
) {
258 strcpy(dirent
->dirname
, cur_dir
);
259 TAILQ_INSERT_TAIL(&dir_q
, dirent
, dirs
);
264 if(swap_audit_file() == -1) {
265 syslog(LOG_ERR
, "Could not swap audit file\n");
267 * XXX Faulty directory listing? - user should be given
268 * XXX an opportunity to change the audit_control file
269 * XXX switch to a reduced mode of auditing?
275 * XXX There are synchronization problems here
276 * XXX what should we do if a trigger for the earlier limit
277 * XXX is generated here?
279 if(0 == (ret
= getacmin(&minval
))) {
281 syslog(LOG_INFO
, "min free = %d\n", minval
);
283 if (auditon(A_GETQCTRL
, &qctrl
, sizeof(qctrl
)) != 0) {
285 "could not get audit queue settings\n");
288 qctrl
.aq_minfree
= minval
;
289 if (auditon(A_SETQCTRL
, &qctrl
, sizeof(qctrl
)) != 0) {
291 "could not set audit queue settings\n");
300 * Close all log files, control files, and tell the audit system.
305 char TS
[POSTFIX_LEN
];
309 /* Generate an audit record */
310 if((aufd
= au_open()) == -1) {
311 syslog(LOG_ERR
, "Could not create audit shutdown event.\n");
314 if((tok
= au_to_text("auditd::Audit shutdown")) != NULL
) {
318 if(au_close(aufd
, 1, AUE_audit_shutdown
) == -1) {
319 syslog(LOG_ERR
, "Could not close audit shutdown event.\n");
324 err_ret
= auditctl(NULL
);
326 syslog(LOG_ERR
, "auditctl failed! : %s\n",
330 if(getTSstr(TS
, POSTFIX_LEN
) == 0) {
337 if((remove(AUDITD_PIDFILE
) == -1) || err_ret
) {
338 syslog(LOG_ERR
, "Could not unregister\n");
339 audit_warn_postsigterm();
343 syslog(LOG_INFO
, "Finished.\n");
348 * When we get a signal, we are often not at a clean point.
349 * So, little can be done in the signal handler itself. Instead,
350 * we send a message to the main servicing loop to do proper
351 * handling from a non-signal-handler context.
354 relay_signal(int signal
)
356 mach_msg_empty_send_t msg
;
358 msg
.header
.msgh_id
= signal
;
359 msg
.header
.msgh_remote_port
= signal_port
;
360 msg
.header
.msgh_local_port
= MACH_PORT_NULL
;
361 msg
.header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND
, 0);
362 mach_msg(&(msg
.header
), MACH_SEND_MSG
|MACH_SEND_TIMEOUT
, sizeof(msg
),
363 0, MACH_PORT_NULL
, MACH_MSG_TIMEOUT_NONE
, MACH_PORT_NULL
);
366 /* registering the daemon */
367 int register_daemon()
373 /* Set up the signal hander */
374 if (signal(SIGTERM
, relay_signal
) == SIG_ERR
) {
377 if (signal(SIGCHLD
, relay_signal
) == SIG_ERR
) {
381 if ((pidfile
= fopen(AUDITD_PIDFILE
, "a")) == NULL
) {
382 audit_warn_tmpfile();
386 /* attempt to lock the pid file; if a lock is present, exit */
387 fd
= fileno(pidfile
);
388 if(flock(fd
, LOCK_EX
| LOCK_NB
) < 0) {
389 syslog(LOG_ERR
, "PID file is locked (is another auditd running?).\n");
396 if(fprintf(pidfile
, "%u\n", pid
) < 0) {
397 /* should not start the daemon */
406 * React to input from the audit tool
408 kern_return_t
auditd_control(auditd_port
, flags
)
409 mach_port_t auditd_port
;
417 /* create a new file and swap with the one being used in kernel */
418 if(swap_audit_file() == -1) {
419 syslog(LOG_ERR
, "Error swapping audit file\n");
424 if(read_control_file() == -1) {
425 syslog(LOG_ERR
, "Error in audit control file\n");
430 err_ret
= close_all();
442 * Suppress duplicate messages within a 30 second interval.
443 * This should be enough to time to rotate log files without
444 * thrashing from soft warnings generated before the log is
447 #define DUPLICATE_INTERVAL 30
449 * Implementation of the audit_triggers() MIG routine.
451 kern_return_t
audit_triggers(audit_port
, flags
)
452 mach_port_t audit_port
;
455 static int last_flags
;
456 static time_t last_time
;
457 struct dir_ent
*dirent
;
460 * Suppres duplicate messages from the kernel within the specified interval
466 if(gettimeofday(&ts
, &tzp
) == 0) {
467 tt
= (time_t)ts
.tv_sec
;
468 if ((flags
== last_flags
) && (tt
< (last_time
+ DUPLICATE_INTERVAL
))) {
476 "audit_triggers() called within auditd with flags = %d\n",
479 * XXX Message processing is done here
481 dirent
= TAILQ_FIRST(&dir_q
);
482 if(flags
== AUDIT_TRIGGER_LOW_SPACE
) {
483 if(dirent
&& (dirent
->softlim
!= 1)) {
484 TAILQ_REMOVE(&dir_q
, dirent
, dirs
);
485 /* add this node to the end of the list */
486 TAILQ_INSERT_TAIL(&dir_q
, dirent
, dirs
);
487 audit_warn_soft(dirent
->dirname
);
490 if (TAILQ_NEXT(TAILQ_FIRST(&dir_q
), dirs
) != NULL
&& swap_audit_file() == -1) {
491 syslog(LOG_ERR
, "Error swapping audit file\n");
495 * check if the next dir has already reached its
498 dirent
= TAILQ_FIRST(&dir_q
);
499 if(dirent
->softlim
== 1) {
500 /* all dirs have reached their soft limit */
501 audit_warn_allsoft();
506 * Continue auditing to the current file
507 * Also generate an allsoft warning
508 * XXX do we want to do this ?
510 audit_warn_allsoft();
513 else if (flags
== AUDIT_TRIGGER_FILE_FULL
) {
515 /* delete current dir, go on to next */
516 TAILQ_REMOVE(&dir_q
, dirent
, dirs
);
517 audit_warn_hard(dirent
->dirname
);
518 free(dirent
->dirname
);
521 if(swap_audit_file() == -1) {
522 syslog(LOG_ERR
, "Error swapping audit file in response to AUDIT_TRIGGER_FILE_FULL message\n");
524 /* Nowhere to write to */
525 audit_warn_allhard(++allhardcount
);
540 while ((child
= waitpid(-1, &wstatus
, WNOHANG
)) > 0) {
542 syslog(LOG_INFO
, "warn process [pid=%d] %s %d.\n", child
,
543 ((WIFEXITED(wstatus
)) ?
544 "exited with non-zero status" :
545 "exited as a result of signal"),
546 ((WIFEXITED(wstatus
)) ?
547 WEXITSTATUS(wstatus
) :
556 boolean_t
auditd_combined_server(
557 mach_msg_header_t
*InHeadP
,
558 mach_msg_header_t
*OutHeadP
)
560 mach_port_t local_port
= InHeadP
->msgh_local_port
;
562 if (local_port
== signal_port
) {
563 int signo
= InHeadP
->msgh_id
;
566 if (SIGTERM
== signo
) {
569 } else if (SIGCHLD
== signo
) {
573 syslog(LOG_INFO
, "Recevied signal %d.\n", signo
);
576 } else if (local_port
== control_port
) {
579 result
= audit_triggers_server(InHeadP
, OutHeadP
);
581 result
= auditd_control_server(InHeadP
, OutHeadP
);
584 syslog(LOG_INFO
, "Recevied msg on bad port 0x%x.\n", local_port
);
588 void wait_on_audit_trigger(port_set
)
589 mach_port_t port_set
;
591 kern_return_t result
;
592 result
= mach_msg_server(auditd_combined_server
, 4096, port_set
, MACH_MSG_OPTION_NONE
);
593 syslog(LOG_ERR
, "abnormal exit\n");
597 * Configure the audit controls in the kernel: the event to class mapping,
598 * kernel preselection mask, etc.
600 int config_audit_controls(long flags
)
603 au_evclass_map_t evc_map
;
606 char naeventstr
[NA_EVENT_STR_SIZE
];
608 /* Process the audit event file, obtaining a class mapping for each
609 * event, and send that mapping into the kernel.
610 * XXX There's a risk here that the BSM library will return NULL
611 * for an event when it can't properly map it to a class. In that
612 * case, we will not process any events beyond the one that failed,
613 * but should. We need a way to get a count of the events.
617 while((ev
= getauevent()) != NULL
) {
618 evc_map
.ec_number
= ev
->ae_number
;
619 evc_map
.ec_class
= ev
->ae_class
;
620 if (auditon(A_SETCLASS
, &evc_map
, sizeof(au_evclass_map_t
)) != 0) {
622 "Failed to register class mapping for event %s",
633 syslog(LOG_ERR
, "No events to class mappings registered.");
635 syslog(LOG_INFO
, "Registered %d event to class mappings.", ctr
);
637 /* Get the non-attributable event string and set the kernel mask
640 if ((getacna(naeventstr
, NA_EVENT_STR_SIZE
) == 0)
641 && ( getauditflagsbin(naeventstr
, &aumask
) == 0)) {
643 if (auditon(A_SETKMASK
, &aumask
, sizeof(au_mask_t
))){
645 "Failed to register non-attributable event mask.");
647 syslog(LOG_INFO
, "Registered non-attributable event mask.");
651 syslog(LOG_ERR
,"Failed to obtain non-attributable event mask.");
655 * Set the audit policy flags based on passed in parameter values.
657 if (auditon(A_SETPOLICY
, &flags
, sizeof(flags
))) {
659 "Failed to set audit policy.");
665 void setup(long flags
)
667 mach_msg_type_name_t poly
;
671 /* Allocate a port set */
672 if (mach_port_allocate(mach_task_self(),
673 MACH_PORT_RIGHT_PORT_SET
,
674 &port_set
) != KERN_SUCCESS
) {
675 syslog(LOG_ERR
, "allocation of port set failed\n");
679 /* Allocate a signal reflection port */
680 if (mach_port_allocate(mach_task_self(),
681 MACH_PORT_RIGHT_RECEIVE
,
682 &signal_port
) != KERN_SUCCESS
||
683 mach_port_move_member(mach_task_self(),
685 port_set
) != KERN_SUCCESS
) {
686 syslog(LOG_ERR
, "allocation of signal port failed\n");
690 /* Allocate a trigger port */
691 if (mach_port_allocate(mach_task_self(),
692 MACH_PORT_RIGHT_RECEIVE
,
693 &control_port
) != KERN_SUCCESS
||
694 mach_port_move_member(mach_task_self(),
696 port_set
) != KERN_SUCCESS
) {
697 syslog(LOG_ERR
, "allocation of trigger port failed\n");
701 /* create a send right on our trigger port */
702 mach_port_extract_right(mach_task_self(), control_port
,
703 MACH_MSG_TYPE_MAKE_SEND
, &control_port
, &poly
);
707 /* register the trigger port with the kernel */
708 if(host_set_audit_control_port(mach_host_self(), control_port
) != KERN_SUCCESS
) {
709 syslog(LOG_ERR
, "Cannot set Mach control port\n");
713 syslog(LOG_ERR
, "Mach control port registered\n");
716 if(read_control_file() == -1) {
717 syslog(LOG_ERR
, "Error reading control file\n");
721 /* Generate an audit record */
722 if((aufd
= au_open()) == -1) {
723 syslog(LOG_ERR
, "Could not create audit startup event.\n");
726 if((tok
= au_to_text("auditd::Audit startup")) != NULL
) {
730 if(au_close(aufd
, 1, AUE_audit_startup
) == -1) {
731 syslog(LOG_ERR
, "Could not close audit startup event.\n");
735 if (config_audit_controls(flags
) == 0)
736 syslog(LOG_INFO
, "Initialization successful\n");
738 syslog(LOG_INFO
, "Initialization failed\n");
742 int main(int argc
, char **argv
)
745 long flags
= AUDIT_CNT
;
748 while ((ch
= getopt(argc
, argv
, "dhs")) != -1) {
756 /* fail-stop option */
758 flags
&= ~(AUDIT_CNT
);
761 /* halt-stop option */
768 (void)fprintf(stderr
,
769 "usage: auditd [-h | -s]\n");
774 openlog("auditd", LOG_CONS
| LOG_PID
, LOG_DAEMON
);
775 syslog(LOG_INFO
, "starting...\n");
777 if (debug
== 0 && daemon(0, 0) == -1) {
778 syslog(LOG_ERR
, "Failed to daemonize\n");
782 if(register_daemon() == -1) {
783 syslog(LOG_ERR
, "Could not register as daemon\n");
788 wait_on_audit_trigger(port_set
);
789 syslog(LOG_INFO
, "exiting.\n");