auditd.c (161863) | auditd.c (162503) |
---|---|
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 --- 16 unchanged lines hidden (view full) --- 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 * | 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 --- 16 unchanged lines hidden (view full) --- 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#18 $ | 33 * $P4: //depot/projects/trustedbsd/openbsm/bin/auditd/auditd.c#21 $ |
34 */ 35 36#include <sys/types.h> 37#include <sys/dirent.h> 38#include <sys/mman.h> 39#include <sys/queue.h> 40#include <sys/stat.h> 41#include <sys/wait.h> --- 12 unchanged lines hidden (view full) --- 54#include <unistd.h> 55#include <signal.h> 56#include <string.h> 57#include <syslog.h> 58 59#include "auditd.h" 60 61#define NA_EVENT_STR_SIZE 25 | 34 */ 35 36#include <sys/types.h> 37#include <sys/dirent.h> 38#include <sys/mman.h> 39#include <sys/queue.h> 40#include <sys/stat.h> 41#include <sys/wait.h> --- 12 unchanged lines hidden (view full) --- 54#include <unistd.h> 55#include <signal.h> 56#include <string.h> 57#include <syslog.h> 58 59#include "auditd.h" 60 61#define NA_EVENT_STR_SIZE 25 |
62#define POL_STR_SIZE 128 |
|
62 63static int ret, minval; 64static char *lastfile = NULL; 65static int allhardcount = 0; 66static int triggerfd = 0; 67static int sigchlds, sigchlds_handled; 68static int sighups, sighups_handled; 69static int sigterms, sigterms_handled; | 63 64static int ret, minval; 65static char *lastfile = NULL; 66static int allhardcount = 0; 67static int triggerfd = 0; 68static int sigchlds, sigchlds_handled; 69static int sighups, sighups_handled; 70static int sigterms, sigterms_handled; |
70static long global_flags; | |
71 72static TAILQ_HEAD(, dir_ent) dir_q; 73 74static int config_audit_controls(void); 75 76/* 77 * Error starting auditd 78 */ --- 76 unchanged lines hidden (view full) --- 155 return (-1); 156 strcpy(oldname, lastfile); 157 158 /* Rename the last file -- append timestamp. */ 159 if ((ptr = strstr(lastfile, NOT_TERMINATED)) != NULL) { 160 *ptr = '.'; 161 strcpy(ptr+1, TS); 162 if (rename(oldname, lastfile) != 0) | 71 72static TAILQ_HEAD(, dir_ent) dir_q; 73 74static int config_audit_controls(void); 75 76/* 77 * Error starting auditd 78 */ --- 76 unchanged lines hidden (view full) --- 155 return (-1); 156 strcpy(oldname, lastfile); 157 158 /* Rename the last file -- append timestamp. */ 159 if ((ptr = strstr(lastfile, NOT_TERMINATED)) != NULL) { 160 *ptr = '.'; 161 strcpy(ptr+1, TS); 162 if (rename(oldname, lastfile) != 0) |
163 syslog(LOG_ERR, "Could not rename %s to %s", 164 oldname, lastfile); | 163 syslog(LOG_ERR, 164 "Could not rename %s to %s: %m", oldname, 165 lastfile); |
165 else 166 syslog(LOG_INFO, "renamed %s to %s", 167 oldname, lastfile); 168 } 169 free(lastfile); 170 free(oldname); 171 lastfile = NULL; 172 } --- 108 unchanged lines hidden (view full) --- 281 */ 282 audit_warn_getacdir(dirent->dirname); 283 284 /* Try again with a different directory. */ 285 TAILQ_REMOVE(&dir_q, dirent, dirs); 286 free(dirent->dirname); 287 free(dirent); 288 } | 166 else 167 syslog(LOG_INFO, "renamed %s to %s", 168 oldname, lastfile); 169 } 170 free(lastfile); 171 free(oldname); 172 lastfile = NULL; 173 } --- 108 unchanged lines hidden (view full) --- 282 */ 283 audit_warn_getacdir(dirent->dirname); 284 285 /* Try again with a different directory. */ 286 TAILQ_REMOVE(&dir_q, dirent, dirs); 287 free(dirent->dirname); 288 free(dirent); 289 } |
289 syslog(LOG_ERR, "Log directories exhausted\n"); | 290 syslog(LOG_ERR, "Log directories exhausted"); |
290 return (-1); 291} 292 293/* 294 * Read the audit_control file contents. 295 */ 296static int 297read_control_file(void) --- 40 unchanged lines hidden (view full) --- 338 } 339 340 /* 341 * XXX There are synchronization problems here 342 * XXX what should we do if a trigger for the earlier limit 343 * XXX is generated here? 344 */ 345 if (0 == (ret = getacmin(&minval))) { | 291 return (-1); 292} 293 294/* 295 * Read the audit_control file contents. 296 */ 297static int 298read_control_file(void) --- 40 unchanged lines hidden (view full) --- 339 } 340 341 /* 342 * XXX There are synchronization problems here 343 * XXX what should we do if a trigger for the earlier limit 344 * XXX is generated here? 345 */ 346 if (0 == (ret = getacmin(&minval))) { |
346 syslog(LOG_DEBUG, "min free = %d\n", minval); | 347 syslog(LOG_DEBUG, "min free = %d", minval); |
347 if (auditon(A_GETQCTRL, &qctrl, sizeof(qctrl)) != 0) { 348 syslog(LOG_ERR, 349 "could not get audit queue settings"); 350 return (-1); 351 } 352 qctrl.aq_minfree = minval; 353 if (auditon(A_SETQCTRL, &qctrl, sizeof(qctrl)) != 0) { 354 syslog(LOG_ERR, --- 134 unchanged lines hidden (view full) --- 489 fail_exit(); 490 } 491 492 fflush(pidfile); 493 return (0); 494} 495 496/* | 348 if (auditon(A_GETQCTRL, &qctrl, sizeof(qctrl)) != 0) { 349 syslog(LOG_ERR, 350 "could not get audit queue settings"); 351 return (-1); 352 } 353 qctrl.aq_minfree = minval; 354 if (auditon(A_SETQCTRL, &qctrl, sizeof(qctrl)) != 0) { 355 syslog(LOG_ERR, --- 134 unchanged lines hidden (view full) --- 490 fail_exit(); 491 } 492 493 fflush(pidfile); 494 return (0); 495} 496 497/* |
497 * Suppress duplicate messages within a 30 second interval. This should be 498 * enough to time to rotate log files without thrashing from soft warnings 499 * generated before the log is actually rotated. | 498 * Handle the audit trigger event. 499 * 500 * We suppress (ignore) duplicated triggers in close succession in order to 501 * try to avoid thrashing-like behavior. However, not all triggers can be 502 * ignored, as triggers generally represent edge triggers, not level 503 * triggers, and won't be retransmitted if the condition persists. Of 504 * specific concern is the rotate trigger -- if one is dropped, then it will 505 * not be retransmitted, and the log file will grow in an unbounded fashion. |
500 */ 501#define DUPLICATE_INTERVAL 30 502static void 503handle_audit_trigger(int trigger) 504{ | 506 */ 507#define DUPLICATE_INTERVAL 30 508static void 509handle_audit_trigger(int trigger) 510{ |
505 static int last_trigger; | 511 static int last_trigger, last_warning; |
506 static time_t last_time; 507 struct dir_ent *dirent; | 512 static time_t last_time; 513 struct dir_ent *dirent; |
508 509 /* 510 * Suppres duplicate messages from the kernel within the specified 511 * interval. 512 */ | |
513 struct timeval ts; 514 struct timezone tzp; 515 time_t tt; 516 | 514 struct timeval ts; 515 struct timezone tzp; 516 time_t tt; 517 |
518 /* 519 * Suppress duplicate messages from the kernel within the specified 520 * interval. 521 */ |
|
517 if (gettimeofday(&ts, &tzp) == 0) { 518 tt = (time_t)ts.tv_sec; | 522 if (gettimeofday(&ts, &tzp) == 0) { 523 tt = (time_t)ts.tv_sec; |
519 if ((trigger == last_trigger) && 520 (tt < (last_time + DUPLICATE_INTERVAL))) 521 return; | 524 switch (trigger) { 525 case AUDIT_TRIGGER_LOW_SPACE: 526 case AUDIT_TRIGGER_NO_SPACE: 527 /* 528 * Triggers we can suppress. Of course, we also need 529 * to rate limit the warnings, so apply the same 530 * interval limit on syslog messages. 531 */ 532 if ((trigger == last_trigger) && 533 (tt < (last_time + DUPLICATE_INTERVAL))) { 534 if (tt >= (last_warning + DUPLICATE_INTERVAL)) 535 syslog(LOG_INFO, 536 "Suppressing duplicate trigger %d", 537 trigger); 538 return; 539 } 540 last_warning = tt; 541 break; 542 543 case AUDIT_TRIGGER_ROTATE_KERNEL: 544 case AUDIT_TRIGGER_ROTATE_USER: 545 case AUDIT_TRIGGER_READ_FILE: 546 /* 547 * Triggers that we cannot suppress. 548 */ 549 break; 550 } 551 552 /* 553 * Only update last_trigger after aborting due to a duplicate 554 * trigger, not before, or we will never allow that trigger 555 * again. 556 */ |
522 last_trigger = trigger; 523 last_time = tt; 524 } 525 526 /* 527 * Message processing is done here. 528 */ 529 dirent = TAILQ_FIRST(&dir_q); 530 switch(trigger) { | 557 last_trigger = trigger; 558 last_time = tt; 559 } 560 561 /* 562 * Message processing is done here. 563 */ 564 dirent = TAILQ_FIRST(&dir_q); 565 switch(trigger) { |
531 | |
532 case AUDIT_TRIGGER_LOW_SPACE: 533 syslog(LOG_INFO, "Got low space trigger"); 534 if (dirent && (dirent->softlim != 1)) { 535 TAILQ_REMOVE(&dir_q, dirent, dirs); 536 /* Add this node to the end of the list. */ 537 TAILQ_INSERT_TAIL(&dir_q, dirent, dirs); 538 audit_warn_soft(dirent->dirname); 539 dirent->softlim = 1; --- 9 unchanged lines hidden (view full) --- 549 dirent = TAILQ_FIRST(&dir_q); 550 if (dirent->softlim == 1) { 551 /* All dirs have reached their soft limit. */ 552 audit_warn_allsoft(); 553 } 554 } else { 555 /* 556 * Continue auditing to the current file. Also | 566 case AUDIT_TRIGGER_LOW_SPACE: 567 syslog(LOG_INFO, "Got low space trigger"); 568 if (dirent && (dirent->softlim != 1)) { 569 TAILQ_REMOVE(&dir_q, dirent, dirs); 570 /* Add this node to the end of the list. */ 571 TAILQ_INSERT_TAIL(&dir_q, dirent, dirs); 572 audit_warn_soft(dirent->dirname); 573 dirent->softlim = 1; --- 9 unchanged lines hidden (view full) --- 583 dirent = TAILQ_FIRST(&dir_q); 584 if (dirent->softlim == 1) { 585 /* All dirs have reached their soft limit. */ 586 audit_warn_allsoft(); 587 } 588 } else { 589 /* 590 * Continue auditing to the current file. Also |
557 * generate an allsoft warning. | 591 * generate an allsoft warning. 592 * |
558 * XXX do we want to do this ? 559 */ 560 audit_warn_allsoft(); 561 } 562 break; 563 564 case AUDIT_TRIGGER_NO_SPACE: 565 syslog(LOG_INFO, "Got no space trigger"); --- 6 unchanged lines hidden (view full) --- 572 573 if (swap_audit_file() == -1) 574 syslog(LOG_ERR, "Error swapping audit file"); 575 576 /* We are out of log directories. */ 577 audit_warn_allhard(++allhardcount); 578 break; 579 | 593 * XXX do we want to do this ? 594 */ 595 audit_warn_allsoft(); 596 } 597 break; 598 599 case AUDIT_TRIGGER_NO_SPACE: 600 syslog(LOG_INFO, "Got no space trigger"); --- 6 unchanged lines hidden (view full) --- 607 608 if (swap_audit_file() == -1) 609 syslog(LOG_ERR, "Error swapping audit file"); 610 611 /* We are out of log directories. */ 612 audit_warn_allhard(++allhardcount); 613 break; 614 |
580 case AUDIT_TRIGGER_OPEN_NEW: | 615 case AUDIT_TRIGGER_ROTATE_KERNEL: 616 case AUDIT_TRIGGER_ROTATE_USER: |
581 /* 582 * Create a new file and swap with the one being used in 583 * kernel 584 */ | 617 /* 618 * Create a new file and swap with the one being used in 619 * kernel 620 */ |
585 syslog(LOG_INFO, "Got open new trigger"); | 621 syslog(LOG_INFO, "Got open new trigger from %s", trigger == 622 AUDIT_TRIGGER_ROTATE_KERNEL ? "kernel" : "user"); |
586 if (swap_audit_file() == -1) 587 syslog(LOG_ERR, "Error swapping audit file"); 588 break; 589 590 case AUDIT_TRIGGER_READ_FILE: 591 syslog(LOG_INFO, "Got read file trigger"); 592 if (read_control_file() == -1) 593 syslog(LOG_ERR, "Error in audit control file"); --- 57 unchanged lines hidden (view full) --- 651 if ((num == -1) && (errno != EINTR)) { 652 syslog(LOG_ERR, "%s: error %d", __FUNCTION__, errno); 653 return (-1); 654 } 655 if (sigterms != sigterms_handled) { 656 syslog(LOG_DEBUG, "%s: SIGTERM", __FUNCTION__); 657 break; 658 } | 623 if (swap_audit_file() == -1) 624 syslog(LOG_ERR, "Error swapping audit file"); 625 break; 626 627 case AUDIT_TRIGGER_READ_FILE: 628 syslog(LOG_INFO, "Got read file trigger"); 629 if (read_control_file() == -1) 630 syslog(LOG_ERR, "Error in audit control file"); --- 57 unchanged lines hidden (view full) --- 688 if ((num == -1) && (errno != EINTR)) { 689 syslog(LOG_ERR, "%s: error %d", __FUNCTION__, errno); 690 return (-1); 691 } 692 if (sigterms != sigterms_handled) { 693 syslog(LOG_DEBUG, "%s: SIGTERM", __FUNCTION__); 694 break; 695 } |
659 if (sigchlds != sigchlds_handled) { 660 syslog(LOG_DEBUG, "%s: SIGCHLD", __FUNCTION__); | 696 if (sigchlds != sigchlds_handled) |
661 handle_sigchld(); | 697 handle_sigchld(); |
662 } | |
663 if (sighups != sighups_handled) { 664 syslog(LOG_DEBUG, "%s: SIGHUP", __FUNCTION__); 665 handle_sighup(); 666 } 667 if ((num == -1) && (errno == EINTR)) 668 continue; 669 if (num == 0) { 670 syslog(LOG_ERR, "%s: read EOF", __FUNCTION__); 671 return (-1); 672 } | 698 if (sighups != sighups_handled) { 699 syslog(LOG_DEBUG, "%s: SIGHUP", __FUNCTION__); 700 handle_sighup(); 701 } 702 if ((num == -1) && (errno == EINTR)) 703 continue; 704 if (num == 0) { 705 syslog(LOG_ERR, "%s: read EOF", __FUNCTION__); 706 return (-1); 707 } |
673 syslog(LOG_DEBUG, "%s: read %d", __FUNCTION__, trigger); | |
674 if (trigger == AUDIT_TRIGGER_CLOSE_AND_DIE) 675 break; 676 else 677 handle_audit_trigger(trigger); 678 } 679 return (close_all()); 680} 681 --- 4 unchanged lines hidden (view full) --- 686static int 687config_audit_controls(void) 688{ 689 au_event_ent_t ev, *evp; 690 au_evclass_map_t evc_map; 691 au_mask_t aumask; 692 int ctr = 0; 693 char naeventstr[NA_EVENT_STR_SIZE]; | 708 if (trigger == AUDIT_TRIGGER_CLOSE_AND_DIE) 709 break; 710 else 711 handle_audit_trigger(trigger); 712 } 713 return (close_all()); 714} 715 --- 4 unchanged lines hidden (view full) --- 720static int 721config_audit_controls(void) 722{ 723 au_event_ent_t ev, *evp; 724 au_evclass_map_t evc_map; 725 au_mask_t aumask; 726 int ctr = 0; 727 char naeventstr[NA_EVENT_STR_SIZE]; |
728 char polstr[POL_STR_SIZE]; 729 long policy; |
|
694 695 /* 696 * Process the audit event file, obtaining a class mapping for each 697 * event, and send that mapping into the kernel. | 730 731 /* 732 * Process the audit event file, obtaining a class mapping for each 733 * event, and send that mapping into the kernel. |
734 * |
|
698 * XXX There's a risk here that the BSM library will return NULL 699 * for an event when it can't properly map it to a class. In that 700 * case, we will not process any events beyond the one that failed, 701 * but should. We need a way to get a count of the events. 702 */ 703 ev.ae_name = (char *)malloc(AU_EVENT_NAME_MAX); 704 ev.ae_desc = (char *)malloc(AU_EVENT_DESC_MAX); 705 if ((ev.ae_name == NULL) || (ev.ae_desc == NULL)) { | 735 * XXX There's a risk here that the BSM library will return NULL 736 * for an event when it can't properly map it to a class. In that 737 * case, we will not process any events beyond the one that failed, 738 * but should. We need a way to get a count of the events. 739 */ 740 ev.ae_name = (char *)malloc(AU_EVENT_NAME_MAX); 741 ev.ae_desc = (char *)malloc(AU_EVENT_DESC_MAX); 742 if ((ev.ae_name == NULL) || (ev.ae_desc == NULL)) { |
743 if (ev.ae_name != NULL) 744 free(ev.ae_name); |
|
706 syslog(LOG_ERR, 707 "Memory allocation error when configuring audit controls."); 708 return (-1); 709 } | 745 syslog(LOG_ERR, 746 "Memory allocation error when configuring audit controls."); 747 return (-1); 748 } |
749 750 /* 751 * XXXRW: Currently we have no way to remove mappings from the kernel 752 * when they are removed from the file-based mappings. 753 */ |
|
710 evp = &ev; 711 setauevent(); 712 while ((evp = getauevent_r(evp)) != NULL) { 713 evc_map.ec_number = evp->ae_number; 714 evc_map.ec_class = evp->ae_class; 715 if (auditon(A_SETCLASS, &evc_map, sizeof(au_evclass_map_t)) 716 != 0) 717 syslog(LOG_ERR, --- 23 unchanged lines hidden (view full) --- 741 else 742 syslog(LOG_DEBUG, 743 "Registered non-attributable event mask."); 744 } else 745 syslog(LOG_ERR, 746 "Failed to obtain non-attributable event mask."); 747 748 /* | 754 evp = &ev; 755 setauevent(); 756 while ((evp = getauevent_r(evp)) != NULL) { 757 evc_map.ec_number = evp->ae_number; 758 evc_map.ec_class = evp->ae_class; 759 if (auditon(A_SETCLASS, &evc_map, sizeof(au_evclass_map_t)) 760 != 0) 761 syslog(LOG_ERR, --- 23 unchanged lines hidden (view full) --- 785 else 786 syslog(LOG_DEBUG, 787 "Registered non-attributable event mask."); 788 } else 789 syslog(LOG_ERR, 790 "Failed to obtain non-attributable event mask."); 791 792 /* |
749 * Set the audit policy flags based on passed in parameter values. | 793 * If a policy is configured in audit_control(5), implement the 794 * policy. However, if one isn't defined, set AUDIT_CNT to avoid 795 * leaving the system in a fragile state. |
750 */ | 796 */ |
751 if (auditon(A_SETPOLICY, &global_flags, sizeof(global_flags))) 752 syslog(LOG_ERR, "Failed to set audit policy."); | 797 if ((getacpol(polstr, POL_STR_SIZE) == 0) && 798 (au_strtopol(polstr, &policy) == 0)) { 799 if (auditon(A_SETPOLICY, &policy, sizeof(policy))) 800 syslog(LOG_ERR, "Failed to set audit policy: %m"); 801 } else { 802 syslog(LOG_ERR, "Failed to obtain policy flags: %m"); 803 policy = AUDIT_CNT; 804 if (auditon(A_SETPOLICY, &policy, sizeof(policy))) 805 syslog(LOG_ERR, 806 "Failed to set default audit policy: %m"); 807 } |
753 754 return (0); 755} 756 757static void 758setup(void) 759{ 760 struct auditinfo ai; --- 60 unchanged lines hidden (view full) --- 821 822int 823main(int argc, char **argv) 824{ 825 int ch; 826 int debug = 0; 827 int rc; 828 | 808 809 return (0); 810} 811 812static void 813setup(void) 814{ 815 struct auditinfo ai; --- 60 unchanged lines hidden (view full) --- 876 877int 878main(int argc, char **argv) 879{ 880 int ch; 881 int debug = 0; 882 int rc; 883 |
829 global_flags |= AUDIT_CNT; | |
830 while ((ch = getopt(argc, argv, "dhs")) != -1) { 831 switch(ch) { 832 case 'd': 833 /* Debug option. */ 834 debug = 1; 835 break; 836 | 884 while ((ch = getopt(argc, argv, "dhs")) != -1) { 885 switch(ch) { 886 case 'd': 887 /* Debug option. */ 888 debug = 1; 889 break; 890 |
837 case 's': 838 /* Fail-stop option. */ 839 global_flags &= ~(AUDIT_CNT); 840 break; 841 842 case 'h': 843 /* Halt-stop option. */ 844 global_flags |= AUDIT_AHLT; 845 break; 846 | |
847 case '?': 848 default: 849 (void)fprintf(stderr, | 891 case '?': 892 default: 893 (void)fprintf(stderr, |
850 "usage: auditd [-h | -s] [-d] \n"); | 894 "usage: auditd [-d] \n"); |
851 exit(1); 852 } 853 } 854 855#ifdef LOG_SECURITY 856 openlog("auditd", LOG_CONS | LOG_PID, LOG_SECURITY); 857#else 858 openlog("auditd", LOG_CONS | LOG_PID, LOG_AUTH); --- 20 unchanged lines hidden --- | 895 exit(1); 896 } 897 } 898 899#ifdef LOG_SECURITY 900 openlog("auditd", LOG_CONS | LOG_PID, LOG_SECURITY); 901#else 902 openlog("auditd", LOG_CONS | LOG_PID, LOG_AUTH); --- 20 unchanged lines hidden --- |