1ca0716f5SRobert Watson /* 2ca0716f5SRobert Watson * Copyright (c) 2004 Apple Computer, Inc. 3ca0716f5SRobert Watson * All rights reserved. 4ca0716f5SRobert Watson * 5ca0716f5SRobert Watson * @APPLE_BSD_LICENSE_HEADER_START@ 6ca0716f5SRobert Watson * 7ca0716f5SRobert Watson * Redistribution and use in source and binary forms, with or without 8ca0716f5SRobert Watson * modification, are permitted provided that the following conditions 9ca0716f5SRobert Watson * are met: 10ca0716f5SRobert Watson * 11ca0716f5SRobert Watson * 1. Redistributions of source code must retain the above copyright 12ca0716f5SRobert Watson * notice, this list of conditions and the following disclaimer. 13ca0716f5SRobert Watson * 2. Redistributions in binary form must reproduce the above copyright 14ca0716f5SRobert Watson * notice, this list of conditions and the following disclaimer in the 15ca0716f5SRobert Watson * documentation and/or other materials provided with the distribution. 16ca0716f5SRobert Watson * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 17ca0716f5SRobert Watson * its contributors may be used to endorse or promote products derived 18ca0716f5SRobert Watson * from this software without specific prior written permission. 19ca0716f5SRobert Watson * 20ca0716f5SRobert Watson * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 21ca0716f5SRobert Watson * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22ca0716f5SRobert Watson * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23ca0716f5SRobert Watson * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 24ca0716f5SRobert Watson * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25ca0716f5SRobert Watson * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26ca0716f5SRobert Watson * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27ca0716f5SRobert Watson * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28ca0716f5SRobert Watson * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29ca0716f5SRobert Watson * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30ca0716f5SRobert Watson * 31ca0716f5SRobert Watson * @APPLE_BSD_LICENSE_HEADER_END@ 32ca0716f5SRobert Watson * 334bd0c025SRobert Watson * $P4: //depot/projects/trustedbsd/openbsm/bin/auditd/auditd.c#23 $ 34ca0716f5SRobert Watson */ 35ca0716f5SRobert Watson 36f4e380b0SRobert Watson #include <sys/types.h> 37ca0716f5SRobert Watson #include <sys/dirent.h> 38ca0716f5SRobert Watson #include <sys/mman.h> 39ca0716f5SRobert Watson #include <sys/queue.h> 40ca0716f5SRobert Watson #include <sys/stat.h> 41ca0716f5SRobert Watson #include <sys/wait.h> 42ca0716f5SRobert Watson 43ca0716f5SRobert Watson #include <bsm/audit.h> 44ca0716f5SRobert Watson #include <bsm/audit_uevents.h> 45ca0716f5SRobert Watson #include <bsm/libbsm.h> 46ca0716f5SRobert Watson 47506764c6SRobert Watson #include <err.h> 48ca0716f5SRobert Watson #include <errno.h> 49ca0716f5SRobert Watson #include <fcntl.h> 5023bf6e20SRobert Watson #include <grp.h> 51ca0716f5SRobert Watson #include <stdio.h> 52ca0716f5SRobert Watson #include <stdlib.h> 53ca0716f5SRobert Watson #include <time.h> 54ca0716f5SRobert Watson #include <unistd.h> 55ca0716f5SRobert Watson #include <signal.h> 56ca0716f5SRobert Watson #include <string.h> 57ca0716f5SRobert Watson #include <syslog.h> 58ca0716f5SRobert Watson 59ca0716f5SRobert Watson #include "auditd.h" 60ca0716f5SRobert Watson 61ca0716f5SRobert Watson #define NA_EVENT_STR_SIZE 25 62bb97b418SRobert Watson #define POL_STR_SIZE 128 63ca0716f5SRobert Watson 64ca0716f5SRobert Watson static int ret, minval; 65ca0716f5SRobert Watson static char *lastfile = NULL; 66ca0716f5SRobert Watson static int allhardcount = 0; 67ca0716f5SRobert Watson static int triggerfd = 0; 68506764c6SRobert Watson static int sigchlds, sigchlds_handled; 69ca0716f5SRobert Watson static int sighups, sighups_handled; 70ca0716f5SRobert Watson static int sigterms, sigterms_handled; 71ca0716f5SRobert Watson 72ca0716f5SRobert Watson static TAILQ_HEAD(, dir_ent) dir_q; 73ca0716f5SRobert Watson 74ca0716f5SRobert Watson static int config_audit_controls(void); 75ca0716f5SRobert Watson 76ca0716f5SRobert Watson /* 77ca0716f5SRobert Watson * Error starting auditd 78ca0716f5SRobert Watson */ 79ca0716f5SRobert Watson static void 80ca0716f5SRobert Watson fail_exit(void) 81ca0716f5SRobert Watson { 82ca0716f5SRobert Watson 83ca0716f5SRobert Watson audit_warn_nostart(); 84ca0716f5SRobert Watson exit(1); 85ca0716f5SRobert Watson } 86ca0716f5SRobert Watson 87ca0716f5SRobert Watson /* 88ca0716f5SRobert Watson * Free our local list of directory names. 89ca0716f5SRobert Watson */ 90ca0716f5SRobert Watson static void 9122ccb20dSRobert Watson free_dir_q(void) 92ca0716f5SRobert Watson { 93ca0716f5SRobert Watson struct dir_ent *dirent; 94ca0716f5SRobert Watson 95ca0716f5SRobert Watson while ((dirent = TAILQ_FIRST(&dir_q))) { 96ca0716f5SRobert Watson TAILQ_REMOVE(&dir_q, dirent, dirs); 97ca0716f5SRobert Watson free(dirent->dirname); 98ca0716f5SRobert Watson free(dirent); 99ca0716f5SRobert Watson } 100ca0716f5SRobert Watson } 101ca0716f5SRobert Watson 102ca0716f5SRobert Watson /* 103ca0716f5SRobert Watson * Generate the timestamp string. 104ca0716f5SRobert Watson */ 105ca0716f5SRobert Watson static int 106ca0716f5SRobert Watson getTSstr(char *buf, int len) 107ca0716f5SRobert Watson { 108ca0716f5SRobert Watson struct timeval ts; 109ca0716f5SRobert Watson struct timezone tzp; 110ca0716f5SRobert Watson time_t tt; 111ca0716f5SRobert Watson 112ca0716f5SRobert Watson if (gettimeofday(&ts, &tzp) != 0) 113ca0716f5SRobert Watson return (-1); 114ca0716f5SRobert Watson tt = (time_t)ts.tv_sec; 115ca0716f5SRobert Watson if (!strftime(buf, len, "%Y%m%d%H%M%S", gmtime(&tt))) 116ca0716f5SRobert Watson return (-1); 117ca0716f5SRobert Watson return (0); 118ca0716f5SRobert Watson } 119ca0716f5SRobert Watson 120ca0716f5SRobert Watson /* 121ca0716f5SRobert Watson * Concat the directory name to the given file name. 122ca0716f5SRobert Watson * XXX We should affix the hostname also 123ca0716f5SRobert Watson */ 124ca0716f5SRobert Watson static char * 125ca0716f5SRobert Watson affixdir(char *name, struct dir_ent *dirent) 126ca0716f5SRobert Watson { 127ca0716f5SRobert Watson char *fn; 128ca0716f5SRobert Watson char *curdir; 129ca0716f5SRobert Watson const char *sep = "/"; 130ca0716f5SRobert Watson 131ca0716f5SRobert Watson curdir = dirent->dirname; 132506764c6SRobert Watson syslog(LOG_DEBUG, "dir = %s", dirent->dirname); 133ca0716f5SRobert Watson 134ca0716f5SRobert Watson fn = malloc(strlen(curdir) + strlen(sep) + (2 * POSTFIX_LEN) + 1); 135ca0716f5SRobert Watson if (fn == NULL) 136ca0716f5SRobert Watson return (NULL); 137ca0716f5SRobert Watson strcpy(fn, curdir); 138ca0716f5SRobert Watson strcat(fn, sep); 139ca0716f5SRobert Watson strcat(fn, name); 140ca0716f5SRobert Watson return (fn); 141ca0716f5SRobert Watson } 142ca0716f5SRobert Watson 143ca0716f5SRobert Watson /* 144ca0716f5SRobert Watson * Close the previous audit trail file. 145ca0716f5SRobert Watson */ 146ca0716f5SRobert Watson static int 147ca0716f5SRobert Watson close_lastfile(char *TS) 148ca0716f5SRobert Watson { 149ca0716f5SRobert Watson char *ptr; 150ca0716f5SRobert Watson char *oldname; 151ca0716f5SRobert Watson 152ca0716f5SRobert Watson if (lastfile != NULL) { 153ca0716f5SRobert Watson oldname = (char *)malloc(strlen(lastfile) + 1); 154ca0716f5SRobert Watson if (oldname == NULL) 155ca0716f5SRobert Watson return (-1); 156ca0716f5SRobert Watson strcpy(oldname, lastfile); 157ca0716f5SRobert Watson 158ca0716f5SRobert Watson /* Rename the last file -- append timestamp. */ 159ca0716f5SRobert Watson if ((ptr = strstr(lastfile, NOT_TERMINATED)) != NULL) { 160ca0716f5SRobert Watson *ptr = '.'; 161ca0716f5SRobert Watson strcpy(ptr+1, TS); 162ca0716f5SRobert Watson if (rename(oldname, lastfile) != 0) 163bb97b418SRobert Watson syslog(LOG_ERR, 164bb97b418SRobert Watson "Could not rename %s to %s: %m", oldname, 165bb97b418SRobert Watson lastfile); 1664bd0c025SRobert Watson else { 167506764c6SRobert Watson syslog(LOG_INFO, "renamed %s to %s", 168ca0716f5SRobert Watson oldname, lastfile); 1694bd0c025SRobert Watson audit_warn_closefile(lastfile); 1704bd0c025SRobert Watson } 171ca0716f5SRobert Watson } 172ca0716f5SRobert Watson free(lastfile); 173ca0716f5SRobert Watson free(oldname); 174ca0716f5SRobert Watson lastfile = NULL; 175ca0716f5SRobert Watson } 176ca0716f5SRobert Watson return (0); 177ca0716f5SRobert Watson } 178ca0716f5SRobert Watson 179ca0716f5SRobert Watson /* 18023bf6e20SRobert Watson * Create the new audit file with appropriate permissions and ownership. Try 18123bf6e20SRobert Watson * to clean up if something goes wrong. 18223bf6e20SRobert Watson */ 18323bf6e20SRobert Watson static int 18423bf6e20SRobert Watson #ifdef AUDIT_REVIEW_GROUP 18523bf6e20SRobert Watson open_trail(const char *fname, uid_t uid, gid_t gid) 18623bf6e20SRobert Watson #else 18723bf6e20SRobert Watson open_trail(const char *fname) 18823bf6e20SRobert Watson #endif 18923bf6e20SRobert Watson { 19023bf6e20SRobert Watson int error, fd; 19123bf6e20SRobert Watson 19223bf6e20SRobert Watson fd = open(fname, O_RDONLY | O_CREAT, S_IRUSR | S_IRGRP); 19323bf6e20SRobert Watson if (fd < 0) 19423bf6e20SRobert Watson return (-1); 19523bf6e20SRobert Watson #ifdef AUDIT_REVIEW_GROUP 19623bf6e20SRobert Watson if (fchown(fd, uid, gid) < 0) { 19723bf6e20SRobert Watson error = errno; 19823bf6e20SRobert Watson close(fd); 19923bf6e20SRobert Watson (void)unlink(fname); 20023bf6e20SRobert Watson errno = error; 20123bf6e20SRobert Watson return (-1); 20223bf6e20SRobert Watson } 20323bf6e20SRobert Watson #endif 20423bf6e20SRobert Watson return (fd); 20523bf6e20SRobert Watson } 20623bf6e20SRobert Watson 20723bf6e20SRobert Watson /* 208ca0716f5SRobert Watson * Create the new file name, swap with existing audit file. 209ca0716f5SRobert Watson */ 210ca0716f5SRobert Watson static int 211ca0716f5SRobert Watson swap_audit_file(void) 212ca0716f5SRobert Watson { 213ca0716f5SRobert Watson char timestr[2 * POSTFIX_LEN]; 214ca0716f5SRobert Watson char *fn; 215ca0716f5SRobert Watson char TS[POSTFIX_LEN]; 216ca0716f5SRobert Watson struct dir_ent *dirent; 21723bf6e20SRobert Watson #ifdef AUDIT_REVIEW_GROUP 21823bf6e20SRobert Watson struct group *grp; 21923bf6e20SRobert Watson gid_t gid; 22023bf6e20SRobert Watson uid_t uid; 22123bf6e20SRobert Watson #endif 22223bf6e20SRobert Watson int error, fd; 223ca0716f5SRobert Watson 224ca0716f5SRobert Watson if (getTSstr(TS, POSTFIX_LEN) != 0) 225ca0716f5SRobert Watson return (-1); 226ca0716f5SRobert Watson 227ca0716f5SRobert Watson strcpy(timestr, TS); 228ca0716f5SRobert Watson strcat(timestr, NOT_TERMINATED); 229ca0716f5SRobert Watson 23023bf6e20SRobert Watson #ifdef AUDIT_REVIEW_GROUP 23123bf6e20SRobert Watson /* 23223bf6e20SRobert Watson * XXXRW: Currently, this code falls back to the daemon gid, which is 23323bf6e20SRobert Watson * likely the wheel group. Is there a better way to deal with this? 23423bf6e20SRobert Watson */ 23523bf6e20SRobert Watson grp = getgrnam(AUDIT_REVIEW_GROUP); 23623bf6e20SRobert Watson if (grp == NULL) { 23723bf6e20SRobert Watson syslog(LOG_INFO, 23823bf6e20SRobert Watson "Audit review group '%s' not available, using daemon gid", 23923bf6e20SRobert Watson AUDIT_REVIEW_GROUP); 24023bf6e20SRobert Watson gid = -1; 24123bf6e20SRobert Watson } else 24223bf6e20SRobert Watson gid = grp->gr_gid; 24323bf6e20SRobert Watson uid = getuid(); 24423bf6e20SRobert Watson #endif 24523bf6e20SRobert Watson 246ca0716f5SRobert Watson /* Try until we succeed. */ 247ca0716f5SRobert Watson while ((dirent = TAILQ_FIRST(&dir_q))) { 248ca0716f5SRobert Watson if ((fn = affixdir(timestr, dirent)) == NULL) { 249506764c6SRobert Watson syslog(LOG_INFO, "Failed to swap log at time %s", 250ca0716f5SRobert Watson timestr); 251ca0716f5SRobert Watson return (-1); 252ca0716f5SRobert Watson } 253ca0716f5SRobert Watson 254ca0716f5SRobert Watson /* 255ca0716f5SRobert Watson * Create and open the file; then close and pass to the 256ca0716f5SRobert Watson * kernel if all went well. 257ca0716f5SRobert Watson */ 258506764c6SRobert Watson syslog(LOG_INFO, "New audit file is %s", fn); 25923bf6e20SRobert Watson #ifdef AUDIT_REVIEW_GROUP 26023bf6e20SRobert Watson fd = open_trail(fn, uid, gid); 26123bf6e20SRobert Watson #else 26223bf6e20SRobert Watson fd = open_trail(fn); 26323bf6e20SRobert Watson #endif 264ca0716f5SRobert Watson if (fd < 0) 26523bf6e20SRobert Watson warn("open(%s)", fn); 26623bf6e20SRobert Watson if (fd >= 0) { 26723bf6e20SRobert Watson error = auditctl(fn); 26823bf6e20SRobert Watson if (error) { 269ca0716f5SRobert Watson syslog(LOG_ERR, 270506764c6SRobert Watson "auditctl failed setting log file! : %s", 271ca0716f5SRobert Watson strerror(errno)); 272ca0716f5SRobert Watson close(fd); 273ca0716f5SRobert Watson } else { 274ca0716f5SRobert Watson /* Success. */ 275ca0716f5SRobert Watson close_lastfile(TS); 276ca0716f5SRobert Watson lastfile = fn; 277ca0716f5SRobert Watson close(fd); 278ca0716f5SRobert Watson return (0); 279ca0716f5SRobert Watson } 28023bf6e20SRobert Watson } 281ca0716f5SRobert Watson 282ca0716f5SRobert Watson /* 283ca0716f5SRobert Watson * Tell the administrator about lack of permissions for dir. 284ca0716f5SRobert Watson */ 285ca0716f5SRobert Watson audit_warn_getacdir(dirent->dirname); 286ca0716f5SRobert Watson 287ca0716f5SRobert Watson /* Try again with a different directory. */ 288ca0716f5SRobert Watson TAILQ_REMOVE(&dir_q, dirent, dirs); 289ca0716f5SRobert Watson free(dirent->dirname); 290ca0716f5SRobert Watson free(dirent); 291ca0716f5SRobert Watson } 292bb97b418SRobert Watson syslog(LOG_ERR, "Log directories exhausted"); 293ca0716f5SRobert Watson return (-1); 294ca0716f5SRobert Watson } 295ca0716f5SRobert Watson 296ca0716f5SRobert Watson /* 297ca0716f5SRobert Watson * Read the audit_control file contents. 298ca0716f5SRobert Watson */ 299ca0716f5SRobert Watson static int 300ca0716f5SRobert Watson read_control_file(void) 301ca0716f5SRobert Watson { 302ca0716f5SRobert Watson char cur_dir[MAXNAMLEN]; 303ca0716f5SRobert Watson struct dir_ent *dirent; 304ca0716f5SRobert Watson au_qctrl_t qctrl; 305ca0716f5SRobert Watson 306ca0716f5SRobert Watson /* 307ca0716f5SRobert Watson * Clear old values. Force a re-read of the file the next time. 308ca0716f5SRobert Watson */ 309ca0716f5SRobert Watson free_dir_q(); 310ca0716f5SRobert Watson endac(); 311ca0716f5SRobert Watson 312ca0716f5SRobert Watson /* 313ca0716f5SRobert Watson * Read the list of directories into a local linked list. 314ca0716f5SRobert Watson * 315ca0716f5SRobert Watson * XXX We should use the reentrant interfaces once they are 316ca0716f5SRobert Watson * available. 317ca0716f5SRobert Watson */ 318ca0716f5SRobert Watson while (getacdir(cur_dir, MAXNAMLEN) >= 0) { 319ca0716f5SRobert Watson dirent = (struct dir_ent *) malloc(sizeof(struct dir_ent)); 320ca0716f5SRobert Watson if (dirent == NULL) 321ca0716f5SRobert Watson return (-1); 322ca0716f5SRobert Watson dirent->softlim = 0; 323ca0716f5SRobert Watson dirent->dirname = (char *) malloc(MAXNAMLEN); 324ca0716f5SRobert Watson if (dirent->dirname == NULL) { 325ca0716f5SRobert Watson free(dirent); 326ca0716f5SRobert Watson return (-1); 327ca0716f5SRobert Watson } 328ca0716f5SRobert Watson strcpy(dirent->dirname, cur_dir); 329ca0716f5SRobert Watson TAILQ_INSERT_TAIL(&dir_q, dirent, dirs); 330ca0716f5SRobert Watson } 331ca0716f5SRobert Watson 332ca0716f5SRobert Watson allhardcount = 0; 333ca0716f5SRobert Watson if (swap_audit_file() == -1) { 334506764c6SRobert Watson syslog(LOG_ERR, "Could not swap audit file"); 335ca0716f5SRobert Watson /* 336ca0716f5SRobert Watson * XXX Faulty directory listing? - user should be given 337ca0716f5SRobert Watson * XXX an opportunity to change the audit_control file 338ca0716f5SRobert Watson * XXX switch to a reduced mode of auditing? 339ca0716f5SRobert Watson */ 340ca0716f5SRobert Watson return (-1); 341ca0716f5SRobert Watson } 342ca0716f5SRobert Watson 343ca0716f5SRobert Watson /* 344ca0716f5SRobert Watson * XXX There are synchronization problems here 345ca0716f5SRobert Watson * XXX what should we do if a trigger for the earlier limit 346ca0716f5SRobert Watson * XXX is generated here? 347ca0716f5SRobert Watson */ 348ca0716f5SRobert Watson if (0 == (ret = getacmin(&minval))) { 349bb97b418SRobert Watson syslog(LOG_DEBUG, "min free = %d", minval); 350ca0716f5SRobert Watson if (auditon(A_GETQCTRL, &qctrl, sizeof(qctrl)) != 0) { 351ca0716f5SRobert Watson syslog(LOG_ERR, 352506764c6SRobert Watson "could not get audit queue settings"); 353ca0716f5SRobert Watson return (-1); 354ca0716f5SRobert Watson } 355ca0716f5SRobert Watson qctrl.aq_minfree = minval; 356ca0716f5SRobert Watson if (auditon(A_SETQCTRL, &qctrl, sizeof(qctrl)) != 0) { 357ca0716f5SRobert Watson syslog(LOG_ERR, 358506764c6SRobert Watson "could not set audit queue settings"); 359ca0716f5SRobert Watson return (-1); 360ca0716f5SRobert Watson } 361ca0716f5SRobert Watson } 362ca0716f5SRobert Watson 363ca0716f5SRobert Watson return (0); 364ca0716f5SRobert Watson } 365ca0716f5SRobert Watson 366ca0716f5SRobert Watson /* 367ca0716f5SRobert Watson * Close all log files, control files, and tell the audit system. 368ca0716f5SRobert Watson */ 369ca0716f5SRobert Watson static int 370ca0716f5SRobert Watson close_all(void) 371ca0716f5SRobert Watson { 372fdb4472cSRobert Watson struct auditinfo ai; 373ca0716f5SRobert Watson int err_ret = 0; 374ca0716f5SRobert Watson char TS[POSTFIX_LEN]; 375ca0716f5SRobert Watson int aufd; 376ca0716f5SRobert Watson token_t *tok; 377ca0716f5SRobert Watson long cond; 378ca0716f5SRobert Watson 379ca0716f5SRobert Watson /* Generate an audit record. */ 380ca0716f5SRobert Watson if ((aufd = au_open()) == -1) 381506764c6SRobert Watson syslog(LOG_ERR, "Could not create audit shutdown event."); 382ca0716f5SRobert Watson else { 383ca0716f5SRobert Watson if ((tok = au_to_text("auditd::Audit shutdown")) != NULL) 384ca0716f5SRobert Watson au_write(aufd, tok); 385fdb4472cSRobert Watson /* 386fdb4472cSRobert Watson * XXX we need to implement extended subject tokens so we can 387fdb4472cSRobert Watson * effectively represent terminal lines with this token type. 388fdb4472cSRobert Watson */ 389fdb4472cSRobert Watson bzero(&ai, sizeof(ai)); 390fdb4472cSRobert Watson if ((tok = au_to_subject32(getuid(), geteuid(), getegid(), 391fdb4472cSRobert Watson getuid(), getgid(), getpid(), getpid(), &ai.ai_termid)) 392fdb4472cSRobert Watson != NULL) 393fdb4472cSRobert Watson au_write(aufd, tok); 394fdb4472cSRobert Watson if ((tok = au_to_return32(0, 0)) != NULL) 395fdb4472cSRobert Watson au_write(aufd, tok); 396ca0716f5SRobert Watson if (au_close(aufd, 1, AUE_audit_shutdown) == -1) 397ca0716f5SRobert Watson syslog(LOG_ERR, 398506764c6SRobert Watson "Could not close audit shutdown event."); 399ca0716f5SRobert Watson } 400ca0716f5SRobert Watson 401ca0716f5SRobert Watson /* Flush contents. */ 402ca0716f5SRobert Watson cond = AUC_DISABLED; 403ca0716f5SRobert Watson err_ret = auditon(A_SETCOND, &cond, sizeof(cond)); 404ca0716f5SRobert Watson if (err_ret != 0) { 405506764c6SRobert Watson syslog(LOG_ERR, "Disabling audit failed! : %s", 406ca0716f5SRobert Watson strerror(errno)); 407ca0716f5SRobert Watson err_ret = 1; 408ca0716f5SRobert Watson } 409ca0716f5SRobert Watson if (getTSstr(TS, POSTFIX_LEN) == 0) 410ca0716f5SRobert Watson close_lastfile(TS); 411ca0716f5SRobert Watson if (lastfile != NULL) 412ca0716f5SRobert Watson free(lastfile); 413ca0716f5SRobert Watson 414ca0716f5SRobert Watson free_dir_q(); 415ca0716f5SRobert Watson if ((remove(AUDITD_PIDFILE) == -1) || err_ret) { 416506764c6SRobert Watson syslog(LOG_ERR, "Could not unregister"); 417ca0716f5SRobert Watson audit_warn_postsigterm(); 418ca0716f5SRobert Watson return (1); 419ca0716f5SRobert Watson } 420ca0716f5SRobert Watson endac(); 421ca0716f5SRobert Watson 422ca0716f5SRobert Watson if (close(triggerfd) != 0) 423506764c6SRobert Watson syslog(LOG_ERR, "Error closing control file"); 424506764c6SRobert Watson syslog(LOG_INFO, "Finished"); 425ca0716f5SRobert Watson return (0); 426ca0716f5SRobert Watson } 427ca0716f5SRobert Watson 428ca0716f5SRobert Watson /* 429ca0716f5SRobert Watson * When we get a signal, we are often not at a clean point. So, little can 430ca0716f5SRobert Watson * be done in the signal handler itself. Instead, we send a message to the 431ca0716f5SRobert Watson * main servicing loop to do proper handling from a non-signal-handler 432ca0716f5SRobert Watson * context. 433ca0716f5SRobert Watson */ 434ca0716f5SRobert Watson static void 435ca0716f5SRobert Watson relay_signal(int signal) 436ca0716f5SRobert Watson { 437ca0716f5SRobert Watson 438ca0716f5SRobert Watson if (signal == SIGHUP) 439ca0716f5SRobert Watson sighups++; 440ca0716f5SRobert Watson if (signal == SIGTERM) 441ca0716f5SRobert Watson sigterms++; 442506764c6SRobert Watson if (signal == SIGCHLD) 443506764c6SRobert Watson sigchlds++; 444ca0716f5SRobert Watson } 445ca0716f5SRobert Watson 446ca0716f5SRobert Watson /* 447ca0716f5SRobert Watson * Registering the daemon. 448ca0716f5SRobert Watson */ 449ca0716f5SRobert Watson static int 450ca0716f5SRobert Watson register_daemon(void) 451ca0716f5SRobert Watson { 452ca0716f5SRobert Watson FILE * pidfile; 453ca0716f5SRobert Watson int fd; 454ca0716f5SRobert Watson pid_t pid; 455ca0716f5SRobert Watson 456ca0716f5SRobert Watson /* Set up the signal hander. */ 457ca0716f5SRobert Watson if (signal(SIGTERM, relay_signal) == SIG_ERR) { 458ca0716f5SRobert Watson syslog(LOG_ERR, 459506764c6SRobert Watson "Could not set signal handler for SIGTERM"); 460ca0716f5SRobert Watson fail_exit(); 461ca0716f5SRobert Watson } 462ca0716f5SRobert Watson if (signal(SIGCHLD, relay_signal) == SIG_ERR) { 463ca0716f5SRobert Watson syslog(LOG_ERR, 464506764c6SRobert Watson "Could not set signal handler for SIGCHLD"); 465ca0716f5SRobert Watson fail_exit(); 466ca0716f5SRobert Watson } 467ca0716f5SRobert Watson if (signal(SIGHUP, relay_signal) == SIG_ERR) { 468ca0716f5SRobert Watson syslog(LOG_ERR, 469506764c6SRobert Watson "Could not set signal handler for SIGHUP"); 470ca0716f5SRobert Watson fail_exit(); 471ca0716f5SRobert Watson } 472ca0716f5SRobert Watson 473ca0716f5SRobert Watson if ((pidfile = fopen(AUDITD_PIDFILE, "a")) == NULL) { 474506764c6SRobert Watson syslog(LOG_ERR, "Could not open PID file"); 475ca0716f5SRobert Watson audit_warn_tmpfile(); 476ca0716f5SRobert Watson return (-1); 477ca0716f5SRobert Watson } 478ca0716f5SRobert Watson 479ca0716f5SRobert Watson /* Attempt to lock the pid file; if a lock is present, exit. */ 480ca0716f5SRobert Watson fd = fileno(pidfile); 481ca0716f5SRobert Watson if (flock(fd, LOCK_EX | LOCK_NB) < 0) { 482ca0716f5SRobert Watson syslog(LOG_ERR, 483506764c6SRobert Watson "PID file is locked (is another auditd running?)."); 484ca0716f5SRobert Watson audit_warn_ebusy(); 485ca0716f5SRobert Watson return (-1); 486ca0716f5SRobert Watson } 487ca0716f5SRobert Watson 488ca0716f5SRobert Watson pid = getpid(); 489ca0716f5SRobert Watson ftruncate(fd, 0); 490ca0716f5SRobert Watson if (fprintf(pidfile, "%u\n", pid) < 0) { 491ca0716f5SRobert Watson /* Should not start the daemon. */ 492ca0716f5SRobert Watson fail_exit(); 493ca0716f5SRobert Watson } 494ca0716f5SRobert Watson 495ca0716f5SRobert Watson fflush(pidfile); 496ca0716f5SRobert Watson return (0); 497ca0716f5SRobert Watson } 498ca0716f5SRobert Watson 499ca0716f5SRobert Watson /* 500bb97b418SRobert Watson * Handle the audit trigger event. 501bb97b418SRobert Watson * 502bb97b418SRobert Watson * We suppress (ignore) duplicated triggers in close succession in order to 503bb97b418SRobert Watson * try to avoid thrashing-like behavior. However, not all triggers can be 504bb97b418SRobert Watson * ignored, as triggers generally represent edge triggers, not level 505bb97b418SRobert Watson * triggers, and won't be retransmitted if the condition persists. Of 506bb97b418SRobert Watson * specific concern is the rotate trigger -- if one is dropped, then it will 507bb97b418SRobert Watson * not be retransmitted, and the log file will grow in an unbounded fashion. 508ca0716f5SRobert Watson */ 509ca0716f5SRobert Watson #define DUPLICATE_INTERVAL 30 510ca0716f5SRobert Watson static void 511ca0716f5SRobert Watson handle_audit_trigger(int trigger) 512ca0716f5SRobert Watson { 513bb97b418SRobert Watson static int last_trigger, last_warning; 514ca0716f5SRobert Watson static time_t last_time; 515ca0716f5SRobert Watson struct dir_ent *dirent; 516ca0716f5SRobert Watson struct timeval ts; 517ca0716f5SRobert Watson struct timezone tzp; 518ca0716f5SRobert Watson time_t tt; 519ca0716f5SRobert Watson 520bb97b418SRobert Watson /* 521bb97b418SRobert Watson * Suppress duplicate messages from the kernel within the specified 522bb97b418SRobert Watson * interval. 523bb97b418SRobert Watson */ 524ca0716f5SRobert Watson if (gettimeofday(&ts, &tzp) == 0) { 525ca0716f5SRobert Watson tt = (time_t)ts.tv_sec; 526bb97b418SRobert Watson switch (trigger) { 527bb97b418SRobert Watson case AUDIT_TRIGGER_LOW_SPACE: 528bb97b418SRobert Watson case AUDIT_TRIGGER_NO_SPACE: 529bb97b418SRobert Watson /* 530bb97b418SRobert Watson * Triggers we can suppress. Of course, we also need 531bb97b418SRobert Watson * to rate limit the warnings, so apply the same 532bb97b418SRobert Watson * interval limit on syslog messages. 533bb97b418SRobert Watson */ 534ca0716f5SRobert Watson if ((trigger == last_trigger) && 535bb97b418SRobert Watson (tt < (last_time + DUPLICATE_INTERVAL))) { 536bb97b418SRobert Watson if (tt >= (last_warning + DUPLICATE_INTERVAL)) 537bb97b418SRobert Watson syslog(LOG_INFO, 538bb97b418SRobert Watson "Suppressing duplicate trigger %d", 539bb97b418SRobert Watson trigger); 540ca0716f5SRobert Watson return; 541bb97b418SRobert Watson } 542bb97b418SRobert Watson last_warning = tt; 543bb97b418SRobert Watson break; 544bb97b418SRobert Watson 545bb97b418SRobert Watson case AUDIT_TRIGGER_ROTATE_KERNEL: 546bb97b418SRobert Watson case AUDIT_TRIGGER_ROTATE_USER: 547bb97b418SRobert Watson case AUDIT_TRIGGER_READ_FILE: 548bb97b418SRobert Watson /* 549bb97b418SRobert Watson * Triggers that we cannot suppress. 550bb97b418SRobert Watson */ 551bb97b418SRobert Watson break; 552bb97b418SRobert Watson } 553bb97b418SRobert Watson 554bb97b418SRobert Watson /* 555bb97b418SRobert Watson * Only update last_trigger after aborting due to a duplicate 556bb97b418SRobert Watson * trigger, not before, or we will never allow that trigger 557bb97b418SRobert Watson * again. 558bb97b418SRobert Watson */ 559ca0716f5SRobert Watson last_trigger = trigger; 560ca0716f5SRobert Watson last_time = tt; 561ca0716f5SRobert Watson } 562ca0716f5SRobert Watson 563ca0716f5SRobert Watson /* 564ca0716f5SRobert Watson * Message processing is done here. 565ca0716f5SRobert Watson */ 566ca0716f5SRobert Watson dirent = TAILQ_FIRST(&dir_q); 567ca0716f5SRobert Watson switch(trigger) { 568ca0716f5SRobert Watson case AUDIT_TRIGGER_LOW_SPACE: 569506764c6SRobert Watson syslog(LOG_INFO, "Got low space trigger"); 570ca0716f5SRobert Watson if (dirent && (dirent->softlim != 1)) { 571ca0716f5SRobert Watson TAILQ_REMOVE(&dir_q, dirent, dirs); 572ca0716f5SRobert Watson /* Add this node to the end of the list. */ 573ca0716f5SRobert Watson TAILQ_INSERT_TAIL(&dir_q, dirent, dirs); 574ca0716f5SRobert Watson audit_warn_soft(dirent->dirname); 575ca0716f5SRobert Watson dirent->softlim = 1; 576ca0716f5SRobert Watson 577ca0716f5SRobert Watson if (TAILQ_NEXT(TAILQ_FIRST(&dir_q), dirs) != NULL && 578ca0716f5SRobert Watson swap_audit_file() == -1) 579506764c6SRobert Watson syslog(LOG_ERR, "Error swapping audit file"); 580ca0716f5SRobert Watson 581ca0716f5SRobert Watson /* 582ca0716f5SRobert Watson * Check if the next dir has already reached its soft 583ca0716f5SRobert Watson * limit. 584ca0716f5SRobert Watson */ 585ca0716f5SRobert Watson dirent = TAILQ_FIRST(&dir_q); 586ca0716f5SRobert Watson if (dirent->softlim == 1) { 587ca0716f5SRobert Watson /* All dirs have reached their soft limit. */ 588ca0716f5SRobert Watson audit_warn_allsoft(); 589ca0716f5SRobert Watson } 590ca0716f5SRobert Watson } else { 591ca0716f5SRobert Watson /* 592ca0716f5SRobert Watson * Continue auditing to the current file. Also 593ca0716f5SRobert Watson * generate an allsoft warning. 594bb97b418SRobert Watson * 595ca0716f5SRobert Watson * XXX do we want to do this ? 596ca0716f5SRobert Watson */ 597ca0716f5SRobert Watson audit_warn_allsoft(); 598ca0716f5SRobert Watson } 599ca0716f5SRobert Watson break; 600ca0716f5SRobert Watson 601ca0716f5SRobert Watson case AUDIT_TRIGGER_NO_SPACE: 602506764c6SRobert Watson syslog(LOG_INFO, "Got no space trigger"); 603ca0716f5SRobert Watson 604ca0716f5SRobert Watson /* Delete current dir, go on to next. */ 605ca0716f5SRobert Watson TAILQ_REMOVE(&dir_q, dirent, dirs); 606ca0716f5SRobert Watson audit_warn_hard(dirent->dirname); 607ca0716f5SRobert Watson free(dirent->dirname); 608ca0716f5SRobert Watson free(dirent); 609ca0716f5SRobert Watson 610ca0716f5SRobert Watson if (swap_audit_file() == -1) 611506764c6SRobert Watson syslog(LOG_ERR, "Error swapping audit file"); 612ca0716f5SRobert Watson 613ca0716f5SRobert Watson /* We are out of log directories. */ 614ca0716f5SRobert Watson audit_warn_allhard(++allhardcount); 615ca0716f5SRobert Watson break; 616ca0716f5SRobert Watson 617bb97b418SRobert Watson case AUDIT_TRIGGER_ROTATE_KERNEL: 618bb97b418SRobert Watson case AUDIT_TRIGGER_ROTATE_USER: 619ca0716f5SRobert Watson /* 620ca0716f5SRobert Watson * Create a new file and swap with the one being used in 621ca0716f5SRobert Watson * kernel 622ca0716f5SRobert Watson */ 623bb97b418SRobert Watson syslog(LOG_INFO, "Got open new trigger from %s", trigger == 624bb97b418SRobert Watson AUDIT_TRIGGER_ROTATE_KERNEL ? "kernel" : "user"); 625ca0716f5SRobert Watson if (swap_audit_file() == -1) 626506764c6SRobert Watson syslog(LOG_ERR, "Error swapping audit file"); 627ca0716f5SRobert Watson break; 628ca0716f5SRobert Watson 629ca0716f5SRobert Watson case AUDIT_TRIGGER_READ_FILE: 630506764c6SRobert Watson syslog(LOG_INFO, "Got read file trigger"); 631ca0716f5SRobert Watson if (read_control_file() == -1) 632506764c6SRobert Watson syslog(LOG_ERR, "Error in audit control file"); 633ca0716f5SRobert Watson if (config_audit_controls() == -1) 634506764c6SRobert Watson syslog(LOG_ERR, "Error setting audit controls"); 635ca0716f5SRobert Watson break; 636ca0716f5SRobert Watson 637ca0716f5SRobert Watson default: 638506764c6SRobert Watson syslog(LOG_ERR, "Got unknown trigger %d", trigger); 639ca0716f5SRobert Watson break; 640ca0716f5SRobert Watson } 641ca0716f5SRobert Watson } 642ca0716f5SRobert Watson 643ca0716f5SRobert Watson static void 644ca0716f5SRobert Watson handle_sighup(void) 645ca0716f5SRobert Watson { 646ca0716f5SRobert Watson 647ca0716f5SRobert Watson sighups_handled = sighups; 648ca0716f5SRobert Watson config_audit_controls(); 649ca0716f5SRobert Watson } 650ca0716f5SRobert Watson 651ca0716f5SRobert Watson /* 652ca0716f5SRobert Watson * Reap our children. 653ca0716f5SRobert Watson */ 654ca0716f5SRobert Watson static void 655ca0716f5SRobert Watson reap_children(void) 656ca0716f5SRobert Watson { 657ca0716f5SRobert Watson pid_t child; 658ca0716f5SRobert Watson int wstatus; 659ca0716f5SRobert Watson 660ca0716f5SRobert Watson while ((child = waitpid(-1, &wstatus, WNOHANG)) > 0) { 661ca0716f5SRobert Watson if (!wstatus) 662ca0716f5SRobert Watson continue; 663506764c6SRobert Watson syslog(LOG_INFO, "warn process [pid=%d] %s %d.", child, 664ca0716f5SRobert Watson ((WIFEXITED(wstatus)) ? "exited with non-zero status" : 665ca0716f5SRobert Watson "exited as a result of signal"), 666ca0716f5SRobert Watson ((WIFEXITED(wstatus)) ? WEXITSTATUS(wstatus) : 667ca0716f5SRobert Watson WTERMSIG(wstatus))); 668ca0716f5SRobert Watson } 669ca0716f5SRobert Watson } 670ca0716f5SRobert Watson 671506764c6SRobert Watson static void 672506764c6SRobert Watson handle_sigchld(void) 673506764c6SRobert Watson { 674506764c6SRobert Watson 675506764c6SRobert Watson sigchlds_handled = sigchlds; 676506764c6SRobert Watson reap_children(); 677506764c6SRobert Watson } 678506764c6SRobert Watson 679506764c6SRobert Watson /* 680506764c6SRobert Watson * Read the control file for triggers/signals and handle appropriately. 681506764c6SRobert Watson */ 682506764c6SRobert Watson static int 683506764c6SRobert Watson wait_for_events(void) 684506764c6SRobert Watson { 685506764c6SRobert Watson int num; 686506764c6SRobert Watson unsigned int trigger; 687506764c6SRobert Watson 688506764c6SRobert Watson for (;;) { 689506764c6SRobert Watson num = read(triggerfd, &trigger, sizeof(trigger)); 690506764c6SRobert Watson if ((num == -1) && (errno != EINTR)) { 691506764c6SRobert Watson syslog(LOG_ERR, "%s: error %d", __FUNCTION__, errno); 692506764c6SRobert Watson return (-1); 693506764c6SRobert Watson } 694506764c6SRobert Watson if (sigterms != sigterms_handled) { 695506764c6SRobert Watson syslog(LOG_DEBUG, "%s: SIGTERM", __FUNCTION__); 696506764c6SRobert Watson break; 697506764c6SRobert Watson } 698bb97b418SRobert Watson if (sigchlds != sigchlds_handled) 699506764c6SRobert Watson handle_sigchld(); 700506764c6SRobert Watson if (sighups != sighups_handled) { 701506764c6SRobert Watson syslog(LOG_DEBUG, "%s: SIGHUP", __FUNCTION__); 702506764c6SRobert Watson handle_sighup(); 703506764c6SRobert Watson } 704506764c6SRobert Watson if ((num == -1) && (errno == EINTR)) 705506764c6SRobert Watson continue; 706506764c6SRobert Watson if (num == 0) { 707506764c6SRobert Watson syslog(LOG_ERR, "%s: read EOF", __FUNCTION__); 708506764c6SRobert Watson return (-1); 709506764c6SRobert Watson } 710506764c6SRobert Watson if (trigger == AUDIT_TRIGGER_CLOSE_AND_DIE) 711506764c6SRobert Watson break; 712506764c6SRobert Watson else 713506764c6SRobert Watson handle_audit_trigger(trigger); 714506764c6SRobert Watson } 715506764c6SRobert Watson return (close_all()); 716506764c6SRobert Watson } 717506764c6SRobert Watson 718ca0716f5SRobert Watson /* 719ca0716f5SRobert Watson * Configure the audit controls in the kernel: the event to class mapping, 720ca0716f5SRobert Watson * kernel preselection mask, etc. 721ca0716f5SRobert Watson */ 722ca0716f5SRobert Watson static int 723ca0716f5SRobert Watson config_audit_controls(void) 724ca0716f5SRobert Watson { 725ca0716f5SRobert Watson au_event_ent_t ev, *evp; 726ca0716f5SRobert Watson au_evclass_map_t evc_map; 727ca0716f5SRobert Watson au_mask_t aumask; 728ca0716f5SRobert Watson int ctr = 0; 729ca0716f5SRobert Watson char naeventstr[NA_EVENT_STR_SIZE]; 730bb97b418SRobert Watson char polstr[POL_STR_SIZE]; 731bb97b418SRobert Watson long policy; 7324bd0c025SRobert Watson au_fstat_t au_fstat; 7334bd0c025SRobert Watson size_t filesz; 734ca0716f5SRobert Watson 735ca0716f5SRobert Watson /* 736ca0716f5SRobert Watson * Process the audit event file, obtaining a class mapping for each 737ca0716f5SRobert Watson * event, and send that mapping into the kernel. 738bb97b418SRobert Watson * 739ca0716f5SRobert Watson * XXX There's a risk here that the BSM library will return NULL 740ca0716f5SRobert Watson * for an event when it can't properly map it to a class. In that 741ca0716f5SRobert Watson * case, we will not process any events beyond the one that failed, 742ca0716f5SRobert Watson * but should. We need a way to get a count of the events. 743ca0716f5SRobert Watson */ 744ca0716f5SRobert Watson ev.ae_name = (char *)malloc(AU_EVENT_NAME_MAX); 745ca0716f5SRobert Watson ev.ae_desc = (char *)malloc(AU_EVENT_DESC_MAX); 746ca0716f5SRobert Watson if ((ev.ae_name == NULL) || (ev.ae_desc == NULL)) { 747bb97b418SRobert Watson if (ev.ae_name != NULL) 748bb97b418SRobert Watson free(ev.ae_name); 749ca0716f5SRobert Watson syslog(LOG_ERR, 750ca0716f5SRobert Watson "Memory allocation error when configuring audit controls."); 751ca0716f5SRobert Watson return (-1); 752ca0716f5SRobert Watson } 753bb97b418SRobert Watson 754bb97b418SRobert Watson /* 755bb97b418SRobert Watson * XXXRW: Currently we have no way to remove mappings from the kernel 756bb97b418SRobert Watson * when they are removed from the file-based mappings. 757bb97b418SRobert Watson */ 758ca0716f5SRobert Watson evp = &ev; 759ca0716f5SRobert Watson setauevent(); 760ca0716f5SRobert Watson while ((evp = getauevent_r(evp)) != NULL) { 761ca0716f5SRobert Watson evc_map.ec_number = evp->ae_number; 762ca0716f5SRobert Watson evc_map.ec_class = evp->ae_class; 763ca0716f5SRobert Watson if (auditon(A_SETCLASS, &evc_map, sizeof(au_evclass_map_t)) 764ca0716f5SRobert Watson != 0) 765ca0716f5SRobert Watson syslog(LOG_ERR, 766ca0716f5SRobert Watson "Failed to register class mapping for event %s", 767ca0716f5SRobert Watson evp->ae_name); 768ca0716f5SRobert Watson else 769ca0716f5SRobert Watson ctr++; 770ca0716f5SRobert Watson } 771ca0716f5SRobert Watson endauevent(); 772ca0716f5SRobert Watson free(ev.ae_name); 773ca0716f5SRobert Watson free(ev.ae_desc); 774ca0716f5SRobert Watson if (ctr == 0) 775ca0716f5SRobert Watson syslog(LOG_ERR, "No events to class mappings registered."); 776ca0716f5SRobert Watson else 777506764c6SRobert Watson syslog(LOG_DEBUG, "Registered %d event to class mappings.", 778ca0716f5SRobert Watson ctr); 779ca0716f5SRobert Watson 780ca0716f5SRobert Watson /* 781ca0716f5SRobert Watson * Get the non-attributable event string and set the kernel mask from 782ca0716f5SRobert Watson * that. 783ca0716f5SRobert Watson */ 784ca0716f5SRobert Watson if ((getacna(naeventstr, NA_EVENT_STR_SIZE) == 0) && 785ca0716f5SRobert Watson (getauditflagsbin(naeventstr, &aumask) == 0)) { 786ca0716f5SRobert Watson if (auditon(A_SETKMASK, &aumask, sizeof(au_mask_t))) 787ca0716f5SRobert Watson syslog(LOG_ERR, 788ca0716f5SRobert Watson "Failed to register non-attributable event mask."); 789ca0716f5SRobert Watson else 790506764c6SRobert Watson syslog(LOG_DEBUG, 791ca0716f5SRobert Watson "Registered non-attributable event mask."); 792ca0716f5SRobert Watson } else 793ca0716f5SRobert Watson syslog(LOG_ERR, 794ca0716f5SRobert Watson "Failed to obtain non-attributable event mask."); 795ca0716f5SRobert Watson 796ca0716f5SRobert Watson /* 797bb97b418SRobert Watson * If a policy is configured in audit_control(5), implement the 798bb97b418SRobert Watson * policy. However, if one isn't defined, set AUDIT_CNT to avoid 799bb97b418SRobert Watson * leaving the system in a fragile state. 800ca0716f5SRobert Watson */ 801bb97b418SRobert Watson if ((getacpol(polstr, POL_STR_SIZE) == 0) && 802bb97b418SRobert Watson (au_strtopol(polstr, &policy) == 0)) { 803bb97b418SRobert Watson if (auditon(A_SETPOLICY, &policy, sizeof(policy))) 804bb97b418SRobert Watson syslog(LOG_ERR, "Failed to set audit policy: %m"); 805bb97b418SRobert Watson } else { 806bb97b418SRobert Watson syslog(LOG_ERR, "Failed to obtain policy flags: %m"); 807bb97b418SRobert Watson policy = AUDIT_CNT; 808bb97b418SRobert Watson if (auditon(A_SETPOLICY, &policy, sizeof(policy))) 809bb97b418SRobert Watson syslog(LOG_ERR, 810bb97b418SRobert Watson "Failed to set default audit policy: %m"); 811bb97b418SRobert Watson } 812ca0716f5SRobert Watson 8134bd0c025SRobert Watson /* 8144bd0c025SRobert Watson * Set trail rotation size. 8154bd0c025SRobert Watson */ 8164bd0c025SRobert Watson if (getacfilesz(&filesz) == 0) { 8174bd0c025SRobert Watson bzero(&au_fstat, sizeof(au_fstat)); 8184bd0c025SRobert Watson au_fstat.af_filesz = filesz; 8194bd0c025SRobert Watson if (auditon(A_SETFSIZE, &au_fstat, sizeof(au_fstat)) < 0) 8204bd0c025SRobert Watson syslog(LOG_ERR, "Failed to set filesz: %m"); 8214bd0c025SRobert Watson } else 8224bd0c025SRobert Watson syslog(LOG_ERR, "Failed to obtain filesz: %m"); 8234bd0c025SRobert Watson 824ca0716f5SRobert Watson return (0); 825ca0716f5SRobert Watson } 826ca0716f5SRobert Watson 827ca0716f5SRobert Watson static void 828ca0716f5SRobert Watson setup(void) 829ca0716f5SRobert Watson { 830fdb4472cSRobert Watson struct auditinfo ai; 831506764c6SRobert Watson auditinfo_t auinfo; 832ca0716f5SRobert Watson int aufd; 833ca0716f5SRobert Watson token_t *tok; 834ca0716f5SRobert Watson 835ca0716f5SRobert Watson if ((triggerfd = open(AUDIT_TRIGGER_FILE, O_RDONLY, 0)) < 0) { 836506764c6SRobert Watson syslog(LOG_ERR, "Error opening trigger file"); 837506764c6SRobert Watson fail_exit(); 838506764c6SRobert Watson } 839506764c6SRobert Watson 840506764c6SRobert Watson /* 841506764c6SRobert Watson * To provide event feedback cycles and avoid auditd becoming 842506764c6SRobert Watson * stalled if auditing is suspended, auditd and its children run 843506764c6SRobert Watson * without their events being audited. We allow the uid, tid, and 844506764c6SRobert Watson * mask fields to be implicitly set to zero, but do set the pid. We 845506764c6SRobert Watson * run this after opening the trigger device to avoid configuring 846506764c6SRobert Watson * audit state without audit present in the system. 847506764c6SRobert Watson * 848506764c6SRobert Watson * XXXRW: Is there more to it than this? 849506764c6SRobert Watson */ 850506764c6SRobert Watson bzero(&auinfo, sizeof(auinfo)); 851506764c6SRobert Watson auinfo.ai_asid = getpid(); 852506764c6SRobert Watson if (setaudit(&auinfo) == -1) { 853506764c6SRobert Watson syslog(LOG_ERR, "Error setting audit stat"); 854ca0716f5SRobert Watson fail_exit(); 855ca0716f5SRobert Watson } 856ca0716f5SRobert Watson 857ca0716f5SRobert Watson TAILQ_INIT(&dir_q); 858ca0716f5SRobert Watson if (read_control_file() == -1) { 859506764c6SRobert Watson syslog(LOG_ERR, "Error reading control file"); 860ca0716f5SRobert Watson fail_exit(); 861ca0716f5SRobert Watson } 862ca0716f5SRobert Watson 863ca0716f5SRobert Watson /* Generate an audit record. */ 864ca0716f5SRobert Watson if ((aufd = au_open()) == -1) 865506764c6SRobert Watson syslog(LOG_ERR, "Could not create audit startup event."); 866ca0716f5SRobert Watson else { 867fdb4472cSRobert Watson /* 868fdb4472cSRobert Watson * XXXCSJP Perhaps we wan't more robust audit records for 869fdb4472cSRobert Watson * audit start up and shutdown. This might include capturing 870fdb4472cSRobert Watson * failures to initialize the audit subsystem? 871fdb4472cSRobert Watson */ 872fdb4472cSRobert Watson bzero(&ai, sizeof(ai)); 873fdb4472cSRobert Watson if ((tok = au_to_subject32(getuid(), geteuid(), getegid(), 874fdb4472cSRobert Watson getuid(), getgid(), getpid(), getpid(), &ai.ai_termid)) 875fdb4472cSRobert Watson != NULL) 876fdb4472cSRobert Watson au_write(aufd, tok); 877ca0716f5SRobert Watson if ((tok = au_to_text("auditd::Audit startup")) != NULL) 878ca0716f5SRobert Watson au_write(aufd, tok); 879fdb4472cSRobert Watson if ((tok = au_to_return32(0, 0)) != NULL) 880fdb4472cSRobert Watson au_write(aufd, tok); 881ca0716f5SRobert Watson if (au_close(aufd, 1, AUE_audit_startup) == -1) 882ca0716f5SRobert Watson syslog(LOG_ERR, 883506764c6SRobert Watson "Could not close audit startup event."); 884ca0716f5SRobert Watson } 885ca0716f5SRobert Watson 886ca0716f5SRobert Watson if (config_audit_controls() == 0) 887506764c6SRobert Watson syslog(LOG_INFO, "Audit controls init successful"); 888ca0716f5SRobert Watson else 889506764c6SRobert Watson syslog(LOG_ERR, "Audit controls init failed"); 890ca0716f5SRobert Watson } 891ca0716f5SRobert Watson 892ca0716f5SRobert Watson int 893ca0716f5SRobert Watson main(int argc, char **argv) 894ca0716f5SRobert Watson { 89523bf6e20SRobert Watson int ch; 896ca0716f5SRobert Watson int debug = 0; 897ca0716f5SRobert Watson int rc; 898ca0716f5SRobert Watson 899ca0716f5SRobert Watson while ((ch = getopt(argc, argv, "dhs")) != -1) { 900ca0716f5SRobert Watson switch(ch) { 901ca0716f5SRobert Watson case 'd': 902ca0716f5SRobert Watson /* Debug option. */ 903ca0716f5SRobert Watson debug = 1; 904ca0716f5SRobert Watson break; 905ca0716f5SRobert Watson 906ca0716f5SRobert Watson case '?': 907ca0716f5SRobert Watson default: 908ca0716f5SRobert Watson (void)fprintf(stderr, 909bb97b418SRobert Watson "usage: auditd [-d] \n"); 910ca0716f5SRobert Watson exit(1); 911ca0716f5SRobert Watson } 912ca0716f5SRobert Watson } 913ca0716f5SRobert Watson 9143b97a967SRobert Watson #ifdef LOG_SECURITY 915ca0716f5SRobert Watson openlog("auditd", LOG_CONS | LOG_PID, LOG_SECURITY); 9163b97a967SRobert Watson #else 9173b97a967SRobert Watson openlog("auditd", LOG_CONS | LOG_PID, LOG_AUTH); 9183b97a967SRobert Watson #endif 919506764c6SRobert Watson syslog(LOG_INFO, "starting..."); 920ca0716f5SRobert Watson 921ca0716f5SRobert Watson if (debug == 0 && daemon(0, 0) == -1) { 922506764c6SRobert Watson syslog(LOG_ERR, "Failed to daemonize"); 923ca0716f5SRobert Watson exit(1); 924ca0716f5SRobert Watson } 925ca0716f5SRobert Watson 926ca0716f5SRobert Watson if (register_daemon() == -1) { 927506764c6SRobert Watson syslog(LOG_ERR, "Could not register as daemon"); 928ca0716f5SRobert Watson exit(1); 929ca0716f5SRobert Watson } 930ca0716f5SRobert Watson 931ca0716f5SRobert Watson setup(); 932ca0716f5SRobert Watson 933506764c6SRobert Watson rc = wait_for_events(); 934506764c6SRobert Watson syslog(LOG_INFO, "auditd exiting."); 935ca0716f5SRobert Watson 936ca0716f5SRobert Watson exit(rc); 937ca0716f5SRobert Watson } 938