17a0a89d2SRobert Watson /*- 206edd2f1SRobert Watson * Copyright (c) 2008-2009 Apple Inc. 35e386598SRobert Watson * Copyright (c) 2016 Robert N. M. Watson 47a0a89d2SRobert Watson * All rights reserved. 57a0a89d2SRobert Watson * 65e386598SRobert Watson * Portions of this software were developed by BAE Systems, the University of 75e386598SRobert Watson * Cambridge Computer Laboratory, and Memorial University under DARPA/AFRL 85e386598SRobert Watson * contract FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent 95e386598SRobert Watson * Computing (TC) research program. 105e386598SRobert Watson * 117a0a89d2SRobert Watson * Redistribution and use in source and binary forms, with or without 127a0a89d2SRobert Watson * modification, are permitted provided that the following conditions 137a0a89d2SRobert Watson * are met: 147a0a89d2SRobert Watson * 1. Redistributions of source code must retain the above copyright 157a0a89d2SRobert Watson * notice, this list of conditions and the following disclaimer. 167a0a89d2SRobert Watson * 2. Redistributions in binary form must reproduce the above copyright 177a0a89d2SRobert Watson * notice, this list of conditions and the following disclaimer in the 187a0a89d2SRobert Watson * documentation and/or other materials provided with the distribution. 197a0a89d2SRobert Watson * 3. Neither the name of Apple Inc. ("Apple") nor the names of 207a0a89d2SRobert Watson * its contributors may be used to endorse or promote products derived 217a0a89d2SRobert Watson * from this software without specific prior written permission. 227a0a89d2SRobert Watson * 237a0a89d2SRobert Watson * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND 247a0a89d2SRobert Watson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 257a0a89d2SRobert Watson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 267a0a89d2SRobert Watson * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR 277a0a89d2SRobert Watson * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 287a0a89d2SRobert Watson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 297a0a89d2SRobert Watson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 307a0a89d2SRobert Watson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 317a0a89d2SRobert Watson * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 327a0a89d2SRobert Watson * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 337a0a89d2SRobert Watson * POSSIBILITY OF SUCH DAMAGE. 347a0a89d2SRobert Watson */ 357a0a89d2SRobert Watson 367a0a89d2SRobert Watson #include <sys/param.h> 377a0a89d2SRobert Watson 387a0a89d2SRobert Watson #include <config/config.h> 397a0a89d2SRobert Watson 407a0a89d2SRobert Watson #include <sys/dirent.h> 417a0a89d2SRobert Watson #ifdef HAVE_FULL_QUEUE_H 427a0a89d2SRobert Watson #include <sys/queue.h> 437a0a89d2SRobert Watson #else /* !HAVE_FULL_QUEUE_H */ 447a0a89d2SRobert Watson #include <compat/queue.h> 457a0a89d2SRobert Watson #endif /* !HAVE_FULL_QUEUE_H */ 46c0020399SRobert Watson #include <sys/mount.h> 47c0020399SRobert Watson #include <sys/socket.h> 487a0a89d2SRobert Watson 497a0a89d2SRobert Watson #include <sys/stat.h> 507a0a89d2SRobert Watson #include <sys/time.h> 517a0a89d2SRobert Watson 527a0a89d2SRobert Watson #include <netinet/in.h> 537a0a89d2SRobert Watson 547a0a89d2SRobert Watson #include <bsm/audit.h> 557a0a89d2SRobert Watson #include <bsm/audit_uevents.h> 567a0a89d2SRobert Watson #include <bsm/auditd_lib.h> 577a0a89d2SRobert Watson #include <bsm/libbsm.h> 587a0a89d2SRobert Watson 59aa772005SRobert Watson #include <assert.h> 6006edd2f1SRobert Watson #include <dirent.h> 617a0a89d2SRobert Watson #include <err.h> 627a0a89d2SRobert Watson #include <errno.h> 637a0a89d2SRobert Watson #include <fcntl.h> 647a0a89d2SRobert Watson #include <stdio.h> 657a0a89d2SRobert Watson #include <string.h> 667a0a89d2SRobert Watson #include <stdlib.h> 677a0a89d2SRobert Watson #include <time.h> 687a0a89d2SRobert Watson #include <unistd.h> 697a0a89d2SRobert Watson #include <netdb.h> 707a0a89d2SRobert Watson 717a0a89d2SRobert Watson #ifdef __APPLE__ 727a0a89d2SRobert Watson #include <notify.h> 737a0a89d2SRobert Watson #ifndef __BSM_INTERNAL_NOTIFY_KEY 747a0a89d2SRobert Watson #define __BSM_INTERNAL_NOTIFY_KEY "com.apple.audit.change" 757a0a89d2SRobert Watson #endif /* __BSM_INTERNAL_NOTIFY_KEY */ 767a0a89d2SRobert Watson #endif /* __APPLE__ */ 777a0a89d2SRobert Watson 787a0a89d2SRobert Watson /* 797a0a89d2SRobert Watson * XXX This is temporary until this is moved to <bsm/audit.h> and shared with 807a0a89d2SRobert Watson * the kernel. 817a0a89d2SRobert Watson */ 827a0a89d2SRobert Watson #ifndef AUDIT_HARD_LIMIT_FREE_BLOCKS 837a0a89d2SRobert Watson #define AUDIT_HARD_LIMIT_FREE_BLOCKS 4 847a0a89d2SRobert Watson #endif 857a0a89d2SRobert Watson 8606edd2f1SRobert Watson /* 8706edd2f1SRobert Watson * Number of seconds to January 1, 2000 8806edd2f1SRobert Watson */ 8906edd2f1SRobert Watson #define JAN_01_2000 946598400 9006edd2f1SRobert Watson 917a0a89d2SRobert Watson struct dir_ent { 927a0a89d2SRobert Watson char *dirname; 937a0a89d2SRobert Watson uint8_t softlim; 947a0a89d2SRobert Watson uint8_t hardlim; 957a0a89d2SRobert Watson TAILQ_ENTRY(dir_ent) dirs; 967a0a89d2SRobert Watson }; 977a0a89d2SRobert Watson 987a0a89d2SRobert Watson static TAILQ_HEAD(, dir_ent) dir_q; 9906edd2f1SRobert Watson 10006edd2f1SRobert Watson struct audit_trail { 10106edd2f1SRobert Watson time_t at_time; 10206edd2f1SRobert Watson char *at_path; 10306edd2f1SRobert Watson off_t at_size; 10406edd2f1SRobert Watson 10506edd2f1SRobert Watson TAILQ_ENTRY(audit_trail) at_trls; 10606edd2f1SRobert Watson }; 10706edd2f1SRobert Watson 10806edd2f1SRobert Watson static int auditd_minval = -1; 109aa772005SRobert Watson static int auditd_dist = 0; 11006edd2f1SRobert Watson 11106edd2f1SRobert Watson static char auditd_host[MAXHOSTNAMELEN]; 11206edd2f1SRobert Watson static int auditd_hostlen = -1; 1137a0a89d2SRobert Watson 1147a0a89d2SRobert Watson static char *auditd_errmsg[] = { 1157a0a89d2SRobert Watson "no error", /* ADE_NOERR ( 0) */ 1167a0a89d2SRobert Watson "could not parse audit_control(5) file", /* ADE_PARSE ( 1) */ 1177a0a89d2SRobert Watson "auditon(2) failed", /* ADE_AUDITON ( 2) */ 1187a0a89d2SRobert Watson "malloc(3) failed", /* ADE_NOMEM ( 3) */ 1197a0a89d2SRobert Watson "all audit log directories over soft limit", /* ADE_SOFTLIM ( 4) */ 1207a0a89d2SRobert Watson "all audit log directories over hard limit", /* ADE_HARDLIM ( 5) */ 1217a0a89d2SRobert Watson "could not create file name string", /* ADE_STRERR ( 6) */ 1227a0a89d2SRobert Watson "could not open audit record", /* ADE_AU_OPEN ( 7) */ 1237a0a89d2SRobert Watson "could not close audit record", /* ADE_AU_CLOSE ( 8) */ 1247a0a89d2SRobert Watson "could not set active audit session state", /* ADE_SETAUDIT ( 9) */ 1257a0a89d2SRobert Watson "auditctl(2) failed (trail still swapped)", /* ADE_ACTL (10) */ 1267a0a89d2SRobert Watson "auditctl(2) failed (trail not swapped)", /* ADE_ACTLERR (11) */ 1277a0a89d2SRobert Watson "could not swap audit trail file", /* ADE_SWAPERR (12) */ 1287a0a89d2SRobert Watson "could not rename crash recovery file", /* ADE_RENAME (13) */ 1297a0a89d2SRobert Watson "could not read 'current' link file", /* ADE_READLINK (14) */ 1307a0a89d2SRobert Watson "could not create 'current' link file", /* ADE_SYMLINK (15) */ 1317a0a89d2SRobert Watson "invalid argument", /* ADE_INVAL (16) */ 1327a0a89d2SRobert Watson "could not resolve hostname to address", /* ADE_GETADDR (17) */ 1337a0a89d2SRobert Watson "address family not supported", /* ADE_ADDRFAM (18) */ 13406edd2f1SRobert Watson "error expiring audit trail files", /* ADE_EXPIRE (19) */ 1357a0a89d2SRobert Watson }; 1367a0a89d2SRobert Watson 1377a0a89d2SRobert Watson #define MAXERRCODE (sizeof(auditd_errmsg) / sizeof(auditd_errmsg[0])) 1387a0a89d2SRobert Watson 139597df30eSRobert Watson #define NA_EVENT_STR_SIZE 128 1407a0a89d2SRobert Watson #define POL_STR_SIZE 128 1417a0a89d2SRobert Watson 1427a0a89d2SRobert Watson 1437a0a89d2SRobert Watson /* 1447a0a89d2SRobert Watson * Look up and return the error string for the given audit error code. 1457a0a89d2SRobert Watson */ 1467a0a89d2SRobert Watson const char * 1477a0a89d2SRobert Watson auditd_strerror(int errcode) 1487a0a89d2SRobert Watson { 1497a0a89d2SRobert Watson int idx = -errcode; 1507a0a89d2SRobert Watson 1517a0a89d2SRobert Watson if (idx < 0 || idx > (int)MAXERRCODE) 1527a0a89d2SRobert Watson return ("Invalid auditd error code"); 1537a0a89d2SRobert Watson 1547a0a89d2SRobert Watson return (auditd_errmsg[idx]); 1557a0a89d2SRobert Watson } 1567a0a89d2SRobert Watson 1577a0a89d2SRobert Watson 1587a0a89d2SRobert Watson /* 159aa772005SRobert Watson * Free our local list of directory names and init list. 1607a0a89d2SRobert Watson */ 1617a0a89d2SRobert Watson static void 1627a0a89d2SRobert Watson free_dir_q(void) 1637a0a89d2SRobert Watson { 1647a0a89d2SRobert Watson struct dir_ent *d1, *d2; 1657a0a89d2SRobert Watson 1667a0a89d2SRobert Watson d1 = TAILQ_FIRST(&dir_q); 1677a0a89d2SRobert Watson while (d1 != NULL) { 1687a0a89d2SRobert Watson d2 = TAILQ_NEXT(d1, dirs); 1697a0a89d2SRobert Watson free(d1->dirname); 1707a0a89d2SRobert Watson free(d1); 1717a0a89d2SRobert Watson d1 = d2; 1727a0a89d2SRobert Watson } 1737a0a89d2SRobert Watson TAILQ_INIT(&dir_q); 1747a0a89d2SRobert Watson } 1757a0a89d2SRobert Watson 1767a0a89d2SRobert Watson /* 1777a0a89d2SRobert Watson * Concat the directory name to the given file name. 1787a0a89d2SRobert Watson * XXX We should affix the hostname also 1797a0a89d2SRobert Watson */ 1807a0a89d2SRobert Watson static char * 1817a0a89d2SRobert Watson affixdir(char *name, struct dir_ent *dirent) 1827a0a89d2SRobert Watson { 1837a0a89d2SRobert Watson char *fn = NULL; 1847a0a89d2SRobert Watson 1857a0a89d2SRobert Watson /* 1867a0a89d2SRobert Watson * Sanity check on file name. 1877a0a89d2SRobert Watson */ 188aa772005SRobert Watson if (strlen(name) != FILENAME_LEN) { 1897a0a89d2SRobert Watson errno = EINVAL; 1907a0a89d2SRobert Watson return (NULL); 1917a0a89d2SRobert Watson } 1927a0a89d2SRobert Watson 19306edd2f1SRobert Watson /* 19406edd2f1SRobert Watson * If the host is set then also add the hostname to the filename. 19506edd2f1SRobert Watson */ 196*6d4db583SPawel Jakub Dawidek if (auditd_hostlen > 0) 19706edd2f1SRobert Watson asprintf(&fn, "%s/%s.%s", dirent->dirname, name, auditd_host); 19806edd2f1SRobert Watson else 1997a0a89d2SRobert Watson asprintf(&fn, "%s/%s", dirent->dirname, name); 2007a0a89d2SRobert Watson return (fn); 2017a0a89d2SRobert Watson } 2027a0a89d2SRobert Watson 2037a0a89d2SRobert Watson /* 2047a0a89d2SRobert Watson * Insert the directory entry in the list by the way they are ordered in 2057a0a89d2SRobert Watson * audit_control(5). Move the entries that are over the soft and hard limits 2067a0a89d2SRobert Watson * toward the tail. 2077a0a89d2SRobert Watson */ 2087a0a89d2SRobert Watson static void 2097a0a89d2SRobert Watson insert_orderly(struct dir_ent *denew) 2107a0a89d2SRobert Watson { 2117a0a89d2SRobert Watson struct dir_ent *dep; 2127a0a89d2SRobert Watson 2137a0a89d2SRobert Watson TAILQ_FOREACH(dep, &dir_q, dirs) { 2147a0a89d2SRobert Watson if (dep->softlim == 1 && denew->softlim == 0) { 2157a0a89d2SRobert Watson TAILQ_INSERT_BEFORE(dep, denew, dirs); 2167a0a89d2SRobert Watson return; 2177a0a89d2SRobert Watson } 2187a0a89d2SRobert Watson if (dep->hardlim == 1 && denew->hardlim == 0) { 2197a0a89d2SRobert Watson TAILQ_INSERT_BEFORE(dep, denew, dirs); 2207a0a89d2SRobert Watson return; 2217a0a89d2SRobert Watson } 2227a0a89d2SRobert Watson } 2237a0a89d2SRobert Watson TAILQ_INSERT_TAIL(&dir_q, denew, dirs); 2247a0a89d2SRobert Watson } 2257a0a89d2SRobert Watson 2267a0a89d2SRobert Watson /* 227aa772005SRobert Watson * Get the min percentage of free blocks from audit_control(5) and that 228aa772005SRobert Watson * value in the kernel. Return: 229aa772005SRobert Watson * ADE_NOERR on success, 230aa772005SRobert Watson * ADE_PARSE error parsing audit_control(5), 231aa772005SRobert Watson */ 232aa772005SRobert Watson int 233aa772005SRobert Watson auditd_set_dist(void) 234aa772005SRobert Watson { 235aa772005SRobert Watson int ret; 236aa772005SRobert Watson 237aa772005SRobert Watson ret = getacdist(); 238aa772005SRobert Watson if (ret < 0) 239aa772005SRobert Watson return (ADE_PARSE); 240aa772005SRobert Watson 241aa772005SRobert Watson auditd_dist = ret; 242aa772005SRobert Watson 243aa772005SRobert Watson return (ADE_NOERR); 244aa772005SRobert Watson } 245aa772005SRobert Watson 246aa772005SRobert Watson /* 2477a0a89d2SRobert Watson * Get the host from audit_control(5) and set it in the audit kernel 2487a0a89d2SRobert Watson * information. Return: 2497a0a89d2SRobert Watson * ADE_NOERR on success. 2507a0a89d2SRobert Watson * ADE_PARSE error parsing audit_control(5). 2517a0a89d2SRobert Watson * ADE_AUDITON error getting/setting auditon(2) value. 2527a0a89d2SRobert Watson * ADE_GETADDR error getting address info for host. 2537a0a89d2SRobert Watson * ADE_ADDRFAM un-supported address family. 2547a0a89d2SRobert Watson */ 2557a0a89d2SRobert Watson int 2567a0a89d2SRobert Watson auditd_set_host(void) 2577a0a89d2SRobert Watson { 2587a0a89d2SRobert Watson struct sockaddr_in6 *sin6; 2597a0a89d2SRobert Watson struct sockaddr_in *sin; 2607a0a89d2SRobert Watson struct addrinfo *res; 2617a0a89d2SRobert Watson struct auditinfo_addr aia; 2627a0a89d2SRobert Watson int error, ret = ADE_NOERR; 2637a0a89d2SRobert Watson 2646e3b0894SAlan Somers if ((getachost(auditd_host, sizeof(auditd_host)) != 0) || 2656e3b0894SAlan Somers ((auditd_hostlen = strlen(auditd_host)) == 0)) { 2667a0a89d2SRobert Watson ret = ADE_PARSE; 2677a0a89d2SRobert Watson 2687a0a89d2SRobert Watson /* 2697a0a89d2SRobert Watson * To maintain reverse compatability with older audit_control 2707a0a89d2SRobert Watson * files, simply drop a warning if the host parameter has not 2717a0a89d2SRobert Watson * been set. However, we will explicitly disable the 2727a0a89d2SRobert Watson * generation of extended audit header by passing in a zeroed 2737a0a89d2SRobert Watson * termid structure. 2747a0a89d2SRobert Watson */ 2757a0a89d2SRobert Watson bzero(&aia, sizeof(aia)); 2767a0a89d2SRobert Watson aia.ai_termid.at_type = AU_IPv4; 277c0020399SRobert Watson error = audit_set_kaudit(&aia, sizeof(aia)); 2787a0a89d2SRobert Watson if (error < 0 && errno != ENOSYS) 2797a0a89d2SRobert Watson ret = ADE_AUDITON; 2807a0a89d2SRobert Watson return (ret); 2817a0a89d2SRobert Watson } 28206edd2f1SRobert Watson error = getaddrinfo(auditd_host, NULL, NULL, &res); 2837a0a89d2SRobert Watson if (error) 2847a0a89d2SRobert Watson return (ADE_GETADDR); 2857a0a89d2SRobert Watson switch (res->ai_family) { 2867a0a89d2SRobert Watson case PF_INET6: 2877a0a89d2SRobert Watson sin6 = (struct sockaddr_in6 *) res->ai_addr; 2887a0a89d2SRobert Watson bcopy(&sin6->sin6_addr.s6_addr, 2897a0a89d2SRobert Watson &aia.ai_termid.at_addr[0], sizeof(struct in6_addr)); 2907a0a89d2SRobert Watson aia.ai_termid.at_type = AU_IPv6; 2917a0a89d2SRobert Watson break; 2927a0a89d2SRobert Watson 2937a0a89d2SRobert Watson case PF_INET: 2947a0a89d2SRobert Watson sin = (struct sockaddr_in *) res->ai_addr; 2957a0a89d2SRobert Watson bcopy(&sin->sin_addr.s_addr, 2967a0a89d2SRobert Watson &aia.ai_termid.at_addr[0], sizeof(struct in_addr)); 2977a0a89d2SRobert Watson aia.ai_termid.at_type = AU_IPv4; 2987a0a89d2SRobert Watson break; 2997a0a89d2SRobert Watson 3007a0a89d2SRobert Watson default: 3017a0a89d2SRobert Watson /* Un-supported address family in host parameter. */ 3027a0a89d2SRobert Watson errno = EAFNOSUPPORT; 3037a0a89d2SRobert Watson return (ADE_ADDRFAM); 3047a0a89d2SRobert Watson } 3057a0a89d2SRobert Watson 306c0020399SRobert Watson if (audit_set_kaudit(&aia, sizeof(aia)) < 0) 3077a0a89d2SRobert Watson ret = ADE_AUDITON; 3087a0a89d2SRobert Watson 3097a0a89d2SRobert Watson return (ret); 3107a0a89d2SRobert Watson } 3117a0a89d2SRobert Watson 3127a0a89d2SRobert Watson /* 3137a0a89d2SRobert Watson * Get the min percentage of free blocks from audit_control(5) and that 3147a0a89d2SRobert Watson * value in the kernel. Return: 3157a0a89d2SRobert Watson * ADE_NOERR on success, 3167a0a89d2SRobert Watson * ADE_PARSE error parsing audit_control(5), 3177a0a89d2SRobert Watson * ADE_AUDITON error getting/setting auditon(2) value. 3187a0a89d2SRobert Watson */ 3197a0a89d2SRobert Watson int 3207a0a89d2SRobert Watson auditd_set_minfree(void) 3217a0a89d2SRobert Watson { 3227a0a89d2SRobert Watson au_qctrl_t qctrl; 3237a0a89d2SRobert Watson 32406edd2f1SRobert Watson if (getacmin(&auditd_minval) != 0) 3257a0a89d2SRobert Watson return (ADE_PARSE); 3267a0a89d2SRobert Watson 327c0020399SRobert Watson if (audit_get_qctrl(&qctrl, sizeof(qctrl)) != 0) 3287a0a89d2SRobert Watson return (ADE_AUDITON); 3297a0a89d2SRobert Watson 33006edd2f1SRobert Watson if (qctrl.aq_minfree != auditd_minval) { 33106edd2f1SRobert Watson qctrl.aq_minfree = auditd_minval; 332c0020399SRobert Watson if (audit_set_qctrl(&qctrl, sizeof(qctrl)) != 0) 3337a0a89d2SRobert Watson return (ADE_AUDITON); 3347a0a89d2SRobert Watson } 3357a0a89d2SRobert Watson 3367a0a89d2SRobert Watson return (0); 3377a0a89d2SRobert Watson } 3387a0a89d2SRobert Watson 3397a0a89d2SRobert Watson /* 34006edd2f1SRobert Watson * Convert a trailname into a timestamp (seconds). Return 0 if the conversion 34106edd2f1SRobert Watson * was successful. 34206edd2f1SRobert Watson */ 34306edd2f1SRobert Watson static int 34406edd2f1SRobert Watson trailname_to_tstamp(char *fn, time_t *tstamp) 34506edd2f1SRobert Watson { 34606edd2f1SRobert Watson struct tm tm; 347aa772005SRobert Watson char ts[TIMESTAMP_LEN + 1]; 34806edd2f1SRobert Watson char *p; 34906edd2f1SRobert Watson 35006edd2f1SRobert Watson *tstamp = 0; 35106edd2f1SRobert Watson 35206edd2f1SRobert Watson /* 35306edd2f1SRobert Watson * Get the ending time stamp. 35406edd2f1SRobert Watson */ 35506edd2f1SRobert Watson if ((p = strchr(fn, '.')) == NULL) 35606edd2f1SRobert Watson return (1); 357aa772005SRobert Watson strlcpy(ts, ++p, sizeof(ts)); 35806edd2f1SRobert Watson if (strlen(ts) != POSTFIX_LEN) 35906edd2f1SRobert Watson return (1); 36006edd2f1SRobert Watson 36106edd2f1SRobert Watson bzero(&tm, sizeof(tm)); 36206edd2f1SRobert Watson 36306edd2f1SRobert Watson /* seconds (0-60) */ 36406edd2f1SRobert Watson p = ts + POSTFIX_LEN - 2; 36506edd2f1SRobert Watson tm.tm_sec = atol(p); 36606edd2f1SRobert Watson if (tm.tm_sec < 0 || tm.tm_sec > 60) 36706edd2f1SRobert Watson return (1); 36806edd2f1SRobert Watson 36906edd2f1SRobert Watson /* minutes (0-59) */ 37006edd2f1SRobert Watson *p = '\0'; p -= 2; 37106edd2f1SRobert Watson tm.tm_min = atol(p); 37206edd2f1SRobert Watson if (tm.tm_min < 0 || tm.tm_min > 59) 37306edd2f1SRobert Watson return (1); 37406edd2f1SRobert Watson 37506edd2f1SRobert Watson /* hours (0 - 23) */ 37606edd2f1SRobert Watson *p = '\0'; p -= 2; 37706edd2f1SRobert Watson tm.tm_hour = atol(p); 37806edd2f1SRobert Watson if (tm.tm_hour < 0 || tm.tm_hour > 23) 37906edd2f1SRobert Watson return (1); 38006edd2f1SRobert Watson 38106edd2f1SRobert Watson /* day of month (1-31) */ 38206edd2f1SRobert Watson *p = '\0'; p -= 2; 38306edd2f1SRobert Watson tm.tm_mday = atol(p); 38406edd2f1SRobert Watson if (tm.tm_mday < 1 || tm.tm_mday > 31) 38506edd2f1SRobert Watson return (1); 38606edd2f1SRobert Watson 38706edd2f1SRobert Watson /* month (0 - 11) */ 38806edd2f1SRobert Watson *p = '\0'; p -= 2; 38906edd2f1SRobert Watson tm.tm_mon = atol(p) - 1; 39006edd2f1SRobert Watson if (tm.tm_mon < 0 || tm.tm_mon > 11) 39106edd2f1SRobert Watson return (1); 39206edd2f1SRobert Watson 39306edd2f1SRobert Watson /* year (year - 1900) */ 39406edd2f1SRobert Watson *p = '\0'; p -= 4; 39506edd2f1SRobert Watson tm.tm_year = atol(p) - 1900; 39606edd2f1SRobert Watson if (tm.tm_year < 0) 39706edd2f1SRobert Watson return (1); 39806edd2f1SRobert Watson 39906edd2f1SRobert Watson *tstamp = timegm(&tm); 40006edd2f1SRobert Watson 40106edd2f1SRobert Watson return (0); 40206edd2f1SRobert Watson } 40306edd2f1SRobert Watson 40406edd2f1SRobert Watson /* 40506edd2f1SRobert Watson * Remove audit trails files according to the expiration conditions. Returns: 40606edd2f1SRobert Watson * ADE_NOERR on success or there is nothing to do. 40706edd2f1SRobert Watson * ADE_PARSE if error parsing audit_control(5). 40806edd2f1SRobert Watson * ADE_NOMEM if could not allocate memory. 409b6a05070SChristian Brueffer * ADE_READLINK if could not read link file. 410b6a05070SChristian Brueffer * ADE_EXPIRE if there was an unexpected error. 41106edd2f1SRobert Watson */ 41206edd2f1SRobert Watson int 41306edd2f1SRobert Watson auditd_expire_trails(int (*warn_expired)(char *)) 41406edd2f1SRobert Watson { 415b6a05070SChristian Brueffer int andflg, len, ret = ADE_NOERR; 41606edd2f1SRobert Watson size_t expire_size, total_size = 0L; 41706edd2f1SRobert Watson time_t expire_age, oldest_time, current_time = time(NULL); 41806edd2f1SRobert Watson struct dir_ent *traildir; 41906edd2f1SRobert Watson struct audit_trail *at; 42006edd2f1SRobert Watson char *afnp, *pn; 42106edd2f1SRobert Watson TAILQ_HEAD(au_trls_head, audit_trail) head = 42206edd2f1SRobert Watson TAILQ_HEAD_INITIALIZER(head); 42306edd2f1SRobert Watson struct stat stbuf; 42406edd2f1SRobert Watson char activefn[MAXPATHLEN]; 42506edd2f1SRobert Watson 42606edd2f1SRobert Watson /* 42706edd2f1SRobert Watson * Read the expiration conditions. If no conditions then return no 42806edd2f1SRobert Watson * error. 42906edd2f1SRobert Watson */ 43006edd2f1SRobert Watson if (getacexpire(&andflg, &expire_age, &expire_size) < 0) 43106edd2f1SRobert Watson return (ADE_PARSE); 43206edd2f1SRobert Watson if (!expire_age && !expire_size) 43306edd2f1SRobert Watson return (ADE_NOERR); 43406edd2f1SRobert Watson 43506edd2f1SRobert Watson /* 43606edd2f1SRobert Watson * Read the 'current' trail file name. Trim off directory path. 43706edd2f1SRobert Watson */ 43806edd2f1SRobert Watson activefn[0] = '\0'; 439b6a05070SChristian Brueffer len = readlink(AUDIT_CURRENT_LINK, activefn, MAXPATHLEN - 1); 440b6a05070SChristian Brueffer if (len < 0) 441b6a05070SChristian Brueffer return (ADE_READLINK); 44206edd2f1SRobert Watson if ((afnp = strrchr(activefn, '/')) != NULL) 44306edd2f1SRobert Watson afnp++; 44406edd2f1SRobert Watson 44506edd2f1SRobert Watson 44606edd2f1SRobert Watson /* 44706edd2f1SRobert Watson * Build tail queue of the trail files. 44806edd2f1SRobert Watson */ 44906edd2f1SRobert Watson TAILQ_FOREACH(traildir, &dir_q, dirs) { 45006edd2f1SRobert Watson DIR *dirp; 45106edd2f1SRobert Watson struct dirent *dp; 45206edd2f1SRobert Watson 45306edd2f1SRobert Watson dirp = opendir(traildir->dirname); 45406edd2f1SRobert Watson while ((dp = readdir(dirp)) != NULL) { 45506edd2f1SRobert Watson time_t tstamp = 0; 45606edd2f1SRobert Watson struct audit_trail *new; 45706edd2f1SRobert Watson 45806edd2f1SRobert Watson /* 45906edd2f1SRobert Watson * Quickly filter non-trail files. 46006edd2f1SRobert Watson */ 461aa772005SRobert Watson if (dp->d_namlen < FILENAME_LEN || 46206edd2f1SRobert Watson dp->d_name[POSTFIX_LEN] != '.') 46306edd2f1SRobert Watson continue; 46406edd2f1SRobert Watson 46506edd2f1SRobert Watson if (asprintf(&pn, "%s/%s", traildir->dirname, 46606edd2f1SRobert Watson dp->d_name) < 0) { 46706edd2f1SRobert Watson ret = ADE_NOMEM; 46806edd2f1SRobert Watson break; 46906edd2f1SRobert Watson } 47006edd2f1SRobert Watson 47106edd2f1SRobert Watson if (stat(pn, &stbuf) < 0 || !S_ISREG(stbuf.st_mode)) { 47206edd2f1SRobert Watson free(pn); 47306edd2f1SRobert Watson continue; 47406edd2f1SRobert Watson } 47506edd2f1SRobert Watson 47606edd2f1SRobert Watson total_size += stbuf.st_size; 47706edd2f1SRobert Watson 47806edd2f1SRobert Watson /* 47906edd2f1SRobert Watson * If this is the 'current' audit trail then 48006edd2f1SRobert Watson * don't add it to the tail queue. 48106edd2f1SRobert Watson */ 482aa772005SRobert Watson if (NULL != afnp && strcmp(dp->d_name, afnp) == 0) { 48306edd2f1SRobert Watson free(pn); 48406edd2f1SRobert Watson continue; 48506edd2f1SRobert Watson } 48606edd2f1SRobert Watson 48706edd2f1SRobert Watson /* 48806edd2f1SRobert Watson * Get the ending time stamp encoded in the trail 48906edd2f1SRobert Watson * name. If we can't read it or if it is older 49006edd2f1SRobert Watson * than Jan 1, 2000 then use the mtime. 49106edd2f1SRobert Watson */ 49206edd2f1SRobert Watson if (trailname_to_tstamp(dp->d_name, &tstamp) != 0 || 49306edd2f1SRobert Watson tstamp < JAN_01_2000) 49406edd2f1SRobert Watson tstamp = stbuf.st_mtime; 49506edd2f1SRobert Watson 49606edd2f1SRobert Watson /* 49706edd2f1SRobert Watson * If the time stamp is older than Jan 1, 2000 then 49806edd2f1SRobert Watson * update the mtime of the trail file to the current 49906edd2f1SRobert Watson * time. This is so we don't prematurely remove a trail 50006edd2f1SRobert Watson * file that was created while the system clock reset 50106edd2f1SRobert Watson * to the * "beginning of time" but later the system 50206edd2f1SRobert Watson * clock is set to the correct current time. 50306edd2f1SRobert Watson */ 50406edd2f1SRobert Watson if (current_time >= JAN_01_2000 && 50506edd2f1SRobert Watson tstamp < JAN_01_2000) { 50606edd2f1SRobert Watson struct timeval tv[2]; 50706edd2f1SRobert Watson 50806edd2f1SRobert Watson tstamp = stbuf.st_mtime = current_time; 50906edd2f1SRobert Watson TIMESPEC_TO_TIMEVAL(&tv[0], 51006edd2f1SRobert Watson &stbuf.st_atimespec); 51106edd2f1SRobert Watson TIMESPEC_TO_TIMEVAL(&tv[1], 51206edd2f1SRobert Watson &stbuf.st_mtimespec); 51306edd2f1SRobert Watson utimes(pn, tv); 51406edd2f1SRobert Watson } 51506edd2f1SRobert Watson 51606edd2f1SRobert Watson /* 51706edd2f1SRobert Watson * Allocate and populate the new entry. 51806edd2f1SRobert Watson */ 51906edd2f1SRobert Watson new = malloc(sizeof(*new)); 52006edd2f1SRobert Watson if (NULL == new) { 52106edd2f1SRobert Watson free(pn); 52206edd2f1SRobert Watson ret = ADE_NOMEM; 52306edd2f1SRobert Watson break; 52406edd2f1SRobert Watson } 52506edd2f1SRobert Watson new->at_time = tstamp; 52606edd2f1SRobert Watson new->at_size = stbuf.st_size; 52706edd2f1SRobert Watson new->at_path = pn; 52806edd2f1SRobert Watson 52906edd2f1SRobert Watson /* 53006edd2f1SRobert Watson * Check to see if we have a new head. Otherwise, 53106edd2f1SRobert Watson * walk the tailq from the tail first and do a simple 53206edd2f1SRobert Watson * insertion sort. 53306edd2f1SRobert Watson */ 53406edd2f1SRobert Watson if (TAILQ_EMPTY(&head) || 535aa772005SRobert Watson new->at_time <= TAILQ_FIRST(&head)->at_time) { 53606edd2f1SRobert Watson TAILQ_INSERT_HEAD(&head, new, at_trls); 53706edd2f1SRobert Watson continue; 53806edd2f1SRobert Watson } 53906edd2f1SRobert Watson 54006edd2f1SRobert Watson TAILQ_FOREACH_REVERSE(at, &head, au_trls_head, at_trls) 54106edd2f1SRobert Watson if (new->at_time >= at->at_time) { 54206edd2f1SRobert Watson TAILQ_INSERT_AFTER(&head, at, new, 54306edd2f1SRobert Watson at_trls); 54406edd2f1SRobert Watson break; 54506edd2f1SRobert Watson } 54606edd2f1SRobert Watson 54706edd2f1SRobert Watson } 5483ee3cd17SRobert Watson closedir(dirp); 54906edd2f1SRobert Watson } 55006edd2f1SRobert Watson 55106edd2f1SRobert Watson oldest_time = current_time - expire_age; 55206edd2f1SRobert Watson 55306edd2f1SRobert Watson /* 55406edd2f1SRobert Watson * Expire trail files, oldest (mtime) first, if the given 55506edd2f1SRobert Watson * conditions are met. 55606edd2f1SRobert Watson */ 55706edd2f1SRobert Watson at = TAILQ_FIRST(&head); 55806edd2f1SRobert Watson while (NULL != at) { 55906edd2f1SRobert Watson struct audit_trail *at_next = TAILQ_NEXT(at, at_trls); 56006edd2f1SRobert Watson 56106edd2f1SRobert Watson if (andflg) { 56206edd2f1SRobert Watson if ((expire_size && total_size > expire_size) && 56306edd2f1SRobert Watson (expire_age && at->at_time < oldest_time)) { 56406edd2f1SRobert Watson if (warn_expired) 56506edd2f1SRobert Watson (*warn_expired)(at->at_path); 56606edd2f1SRobert Watson if (unlink(at->at_path) < 0) 56706edd2f1SRobert Watson ret = ADE_EXPIRE; 56806edd2f1SRobert Watson total_size -= at->at_size; 56906edd2f1SRobert Watson } 57006edd2f1SRobert Watson } else { 57106edd2f1SRobert Watson if ((expire_size && total_size > expire_size) || 57206edd2f1SRobert Watson (expire_age && at->at_time < oldest_time)) { 57306edd2f1SRobert Watson if (warn_expired) 57406edd2f1SRobert Watson (*warn_expired)(at->at_path); 57506edd2f1SRobert Watson if (unlink(at->at_path) < 0) 57606edd2f1SRobert Watson ret = ADE_EXPIRE; 57706edd2f1SRobert Watson total_size -= at->at_size; 57806edd2f1SRobert Watson } 57906edd2f1SRobert Watson } 58006edd2f1SRobert Watson 58106edd2f1SRobert Watson free(at->at_path); 58206edd2f1SRobert Watson free(at); 58306edd2f1SRobert Watson at = at_next; 58406edd2f1SRobert Watson } 58506edd2f1SRobert Watson 58606edd2f1SRobert Watson return (ret); 58706edd2f1SRobert Watson } 58806edd2f1SRobert Watson 58906edd2f1SRobert Watson /* 5907a0a89d2SRobert Watson * Parses the "dir" entry in audit_control(5) into an ordered list. Also, will 59106edd2f1SRobert Watson * set the minfree and host values if not already set. Arguments include 59206edd2f1SRobert Watson * function pointers to audit_warn functions for soft and hard limits. Returns: 5937a0a89d2SRobert Watson * ADE_NOERR on success, 5947a0a89d2SRobert Watson * ADE_PARSE error parsing audit_control(5), 5957a0a89d2SRobert Watson * ADE_AUDITON error getting/setting auditon(2) value, 5967a0a89d2SRobert Watson * ADE_NOMEM error allocating memory, 5977a0a89d2SRobert Watson * ADE_SOFTLIM if all the directories are over the soft limit, 5987a0a89d2SRobert Watson * ADE_HARDLIM if all the directories are over the hard limit, 5997a0a89d2SRobert Watson */ 6007a0a89d2SRobert Watson int 6017a0a89d2SRobert Watson auditd_read_dirs(int (*warn_soft)(char *), int (*warn_hard)(char *)) 6027a0a89d2SRobert Watson { 6037a0a89d2SRobert Watson char cur_dir[MAXNAMLEN]; 6047a0a89d2SRobert Watson struct dir_ent *dirent; 6057a0a89d2SRobert Watson struct statfs sfs; 6067a0a89d2SRobert Watson int err; 6077a0a89d2SRobert Watson char soft, hard; 6087a0a89d2SRobert Watson int tcnt = 0; 6097a0a89d2SRobert Watson int scnt = 0; 6107a0a89d2SRobert Watson int hcnt = 0; 6117a0a89d2SRobert Watson 61206edd2f1SRobert Watson if (auditd_minval == -1 && (err = auditd_set_minfree()) != 0) 6137a0a89d2SRobert Watson return (err); 6147a0a89d2SRobert Watson 61506edd2f1SRobert Watson if (auditd_hostlen == -1) 61606edd2f1SRobert Watson auditd_set_host(); 61706edd2f1SRobert Watson 6187a0a89d2SRobert Watson /* 6197a0a89d2SRobert Watson * Init directory q. Force a re-read of the file the next time. 6207a0a89d2SRobert Watson */ 6217a0a89d2SRobert Watson free_dir_q(); 6227a0a89d2SRobert Watson endac(); 6237a0a89d2SRobert Watson 6247a0a89d2SRobert Watson /* 6257a0a89d2SRobert Watson * Read the list of directories into an ordered linked list 6267a0a89d2SRobert Watson * admin's preference, then those over soft limit and, finally, 6277a0a89d2SRobert Watson * those over the hard limit. 6287a0a89d2SRobert Watson * 6297a0a89d2SRobert Watson * XXX We should use the reentrant interfaces once they are 6307a0a89d2SRobert Watson * available. 6317a0a89d2SRobert Watson */ 6327a0a89d2SRobert Watson while (getacdir(cur_dir, MAXNAMLEN) >= 0) { 6337a0a89d2SRobert Watson if (statfs(cur_dir, &sfs) < 0) 6347a0a89d2SRobert Watson continue; /* XXX should warn */ 635aa772005SRobert Watson soft = (sfs.f_bfree < (sfs.f_blocks * auditd_minval / 100 )) ? 63606edd2f1SRobert Watson 1 : 0; 6377a0a89d2SRobert Watson hard = (sfs.f_bfree < AUDIT_HARD_LIMIT_FREE_BLOCKS) ? 1 : 0; 6387a0a89d2SRobert Watson if (soft) { 6397a0a89d2SRobert Watson if (warn_soft) 6407a0a89d2SRobert Watson (*warn_soft)(cur_dir); 6417a0a89d2SRobert Watson scnt++; 6427a0a89d2SRobert Watson } 6437a0a89d2SRobert Watson if (hard) { 6447a0a89d2SRobert Watson if (warn_hard) 6457a0a89d2SRobert Watson (*warn_hard)(cur_dir); 6467a0a89d2SRobert Watson hcnt++; 6477a0a89d2SRobert Watson } 6487a0a89d2SRobert Watson dirent = (struct dir_ent *) malloc(sizeof(struct dir_ent)); 6497a0a89d2SRobert Watson if (dirent == NULL) 6507a0a89d2SRobert Watson return (ADE_NOMEM); 6517a0a89d2SRobert Watson dirent->softlim = soft; 6527a0a89d2SRobert Watson dirent->hardlim = hard; 6537a0a89d2SRobert Watson dirent->dirname = (char *) malloc(MAXNAMLEN); 6547a0a89d2SRobert Watson if (dirent->dirname == NULL) { 6557a0a89d2SRobert Watson free(dirent); 6567a0a89d2SRobert Watson return (ADE_NOMEM); 6577a0a89d2SRobert Watson } 6587a0a89d2SRobert Watson strlcpy(dirent->dirname, cur_dir, MAXNAMLEN); 6597a0a89d2SRobert Watson insert_orderly(dirent); 6607a0a89d2SRobert Watson tcnt++; 6617a0a89d2SRobert Watson } 6627a0a89d2SRobert Watson 6637a0a89d2SRobert Watson if (hcnt == tcnt) 6647a0a89d2SRobert Watson return (ADE_HARDLIM); 6657a0a89d2SRobert Watson if (scnt == tcnt) 6667a0a89d2SRobert Watson return (ADE_SOFTLIM); 6677a0a89d2SRobert Watson return (0); 6687a0a89d2SRobert Watson } 6697a0a89d2SRobert Watson 6707a0a89d2SRobert Watson void 6717a0a89d2SRobert Watson auditd_close_dirs(void) 6727a0a89d2SRobert Watson { 6737a0a89d2SRobert Watson free_dir_q(); 67406edd2f1SRobert Watson auditd_minval = -1; 67506edd2f1SRobert Watson auditd_hostlen = -1; 6767a0a89d2SRobert Watson } 6777a0a89d2SRobert Watson 6787a0a89d2SRobert Watson 6797a0a89d2SRobert Watson /* 6807a0a89d2SRobert Watson * Process the audit event file, obtaining a class mapping for each event, and 6817a0a89d2SRobert Watson * set that mapping into the kernel. Return: 6827a0a89d2SRobert Watson * n number of event mappings that were successfully processed, 6837a0a89d2SRobert Watson * ADE_NOMEM if there was an error allocating memory. 6845e386598SRobert Watson * 6855e386598SRobert Watson * Historically, this code only set up the in-kernel class mapping. On 6865e386598SRobert Watson * systems with an in-kernel event-to-name mapping, it also now installs that, 6875e386598SRobert Watson * as it is iterating over the event list anyway. Failures there will be 6885e386598SRobert Watson * ignored as not all kernels support the feature. 6897a0a89d2SRobert Watson */ 6907a0a89d2SRobert Watson int 6917a0a89d2SRobert Watson auditd_set_evcmap(void) 6927a0a89d2SRobert Watson { 6937a0a89d2SRobert Watson au_event_ent_t ev, *evp; 6947a0a89d2SRobert Watson au_evclass_map_t evc_map; 6955e386598SRobert Watson au_evname_map_t evn_map; 6967a0a89d2SRobert Watson int ctr = 0; 6977a0a89d2SRobert Watson 6987a0a89d2SRobert Watson /* 6997a0a89d2SRobert Watson * XXX There's a risk here that the BSM library will return NULL 7007a0a89d2SRobert Watson * for an event when it can't properly map it to a class. In that 7017a0a89d2SRobert Watson * case, we will not process any events beyond the one that failed, 7027a0a89d2SRobert Watson * but should. We need a way to get a count of the events. 7037a0a89d2SRobert Watson */ 7047a0a89d2SRobert Watson ev.ae_name = (char *)malloc(AU_EVENT_NAME_MAX); 7057a0a89d2SRobert Watson ev.ae_desc = (char *)malloc(AU_EVENT_DESC_MAX); 706aa772005SRobert Watson if (ev.ae_name == NULL || ev.ae_desc == NULL) { 7077a0a89d2SRobert Watson if (ev.ae_name != NULL) 7087a0a89d2SRobert Watson free(ev.ae_name); 7097a0a89d2SRobert Watson return (ADE_NOMEM); 7107a0a89d2SRobert Watson } 7117a0a89d2SRobert Watson 7127a0a89d2SRobert Watson /* 7137a0a89d2SRobert Watson * XXXRW: Currently we have no way to remove mappings from the kernel 7147a0a89d2SRobert Watson * when they are removed from the file-based mappings. 7157a0a89d2SRobert Watson */ 7167a0a89d2SRobert Watson evp = &ev; 7177a0a89d2SRobert Watson setauevent(); 7187a0a89d2SRobert Watson while ((evp = getauevent_r(evp)) != NULL) { 7195e386598SRobert Watson /* 7205e386598SRobert Watson * Set the event-to-name mapping entry. If there's not room 7215e386598SRobert Watson * in the in-kernel string, then we skip the entry. Possibly 7225e386598SRobert Watson * better than truncating...? 7235e386598SRobert Watson */ 7245e386598SRobert Watson if (strlcpy(evn_map.en_name, evp->ae_name, 7255e386598SRobert Watson sizeof(evn_map.en_name)) < sizeof(evn_map.en_name)) { 7265e386598SRobert Watson evn_map.en_number = evp->ae_number; 7275e386598SRobert Watson (void)audit_set_event(&evn_map, sizeof(evn_map)); 7285e386598SRobert Watson } 7295e386598SRobert Watson 7305e386598SRobert Watson /* 7315e386598SRobert Watson * Set the event-to-class mapping entry. 7325e386598SRobert Watson */ 7337a0a89d2SRobert Watson evc_map.ec_number = evp->ae_number; 7347a0a89d2SRobert Watson evc_map.ec_class = evp->ae_class; 735c0020399SRobert Watson if (audit_set_class(&evc_map, sizeof(evc_map)) == 0) 7367a0a89d2SRobert Watson ctr++; 7377a0a89d2SRobert Watson } 7387a0a89d2SRobert Watson endauevent(); 7397a0a89d2SRobert Watson free(ev.ae_name); 7407a0a89d2SRobert Watson free(ev.ae_desc); 7417a0a89d2SRobert Watson 7427a0a89d2SRobert Watson return (ctr); 7437a0a89d2SRobert Watson } 7447a0a89d2SRobert Watson 7457a0a89d2SRobert Watson /* 7467a0a89d2SRobert Watson * Get the non-attributable event string and set the kernel mask. Return: 7477a0a89d2SRobert Watson * ADE_NOERR on success, 7487a0a89d2SRobert Watson * ADE_PARSE error parsing audit_control(5), 7497a0a89d2SRobert Watson * ADE_AUDITON error setting the mask using auditon(2). 7507a0a89d2SRobert Watson */ 7517a0a89d2SRobert Watson int 7527a0a89d2SRobert Watson auditd_set_namask(void) 7537a0a89d2SRobert Watson { 7547a0a89d2SRobert Watson au_mask_t aumask; 7557a0a89d2SRobert Watson char naeventstr[NA_EVENT_STR_SIZE]; 7567a0a89d2SRobert Watson 757aa772005SRobert Watson if (getacna(naeventstr, NA_EVENT_STR_SIZE) != 0 || 758aa772005SRobert Watson getauditflagsbin(naeventstr, &aumask) != 0) 7597a0a89d2SRobert Watson return (ADE_PARSE); 7607a0a89d2SRobert Watson 761c0020399SRobert Watson if (audit_set_kmask(&aumask, sizeof(aumask)) != 0) 7627a0a89d2SRobert Watson return (ADE_AUDITON); 7637a0a89d2SRobert Watson 7647a0a89d2SRobert Watson return (ADE_NOERR); 7657a0a89d2SRobert Watson } 7667a0a89d2SRobert Watson 7677a0a89d2SRobert Watson /* 7687a0a89d2SRobert Watson * Set the audit control policy if a policy is configured in audit_control(5), 7697a0a89d2SRobert Watson * implement the policy. However, if one isn't defined or if there is an error 7707a0a89d2SRobert Watson * parsing the control file, set AUDIT_CNT to avoid leaving the system in a 7717a0a89d2SRobert Watson * fragile state. Return: 7727a0a89d2SRobert Watson * ADE_NOERR on success, 7737a0a89d2SRobert Watson * ADE_PARSE error parsing audit_control(5), 7747a0a89d2SRobert Watson * ADE_AUDITON error setting policy using auditon(2). 7757a0a89d2SRobert Watson */ 7767a0a89d2SRobert Watson int 7777a0a89d2SRobert Watson auditd_set_policy(void) 7787a0a89d2SRobert Watson { 779c0020399SRobert Watson int policy; 7807a0a89d2SRobert Watson char polstr[POL_STR_SIZE]; 7817a0a89d2SRobert Watson 782aa772005SRobert Watson if (getacpol(polstr, POL_STR_SIZE) != 0 || 783aa772005SRobert Watson au_strtopol(polstr, &policy) != 0) { 7847a0a89d2SRobert Watson policy = AUDIT_CNT; 785c0020399SRobert Watson if (audit_set_policy(&policy) != 0) 7867a0a89d2SRobert Watson return (ADE_AUDITON); 7877a0a89d2SRobert Watson return (ADE_PARSE); 7887a0a89d2SRobert Watson } 7897a0a89d2SRobert Watson 790c0020399SRobert Watson if (audit_set_policy(&policy) != 0) 7917a0a89d2SRobert Watson return (ADE_AUDITON); 7927a0a89d2SRobert Watson 7937a0a89d2SRobert Watson return (ADE_NOERR); 7947a0a89d2SRobert Watson } 7957a0a89d2SRobert Watson 7967a0a89d2SRobert Watson /* 7977a0a89d2SRobert Watson * Set trail rotation size. Return: 7987a0a89d2SRobert Watson * ADE_NOERR on success, 7997a0a89d2SRobert Watson * ADE_PARSE error parsing audit_control(5), 8007a0a89d2SRobert Watson * ADE_AUDITON error setting file size using auditon(2). 8017a0a89d2SRobert Watson */ 8027a0a89d2SRobert Watson int 8037a0a89d2SRobert Watson auditd_set_fsize(void) 8047a0a89d2SRobert Watson { 8057a0a89d2SRobert Watson size_t filesz; 8067a0a89d2SRobert Watson au_fstat_t au_fstat; 8077a0a89d2SRobert Watson 8087a0a89d2SRobert Watson /* 8097a0a89d2SRobert Watson * Set trail rotation size. 8107a0a89d2SRobert Watson */ 8117a0a89d2SRobert Watson if (getacfilesz(&filesz) != 0) 8127a0a89d2SRobert Watson return (ADE_PARSE); 8137a0a89d2SRobert Watson 8147a0a89d2SRobert Watson bzero(&au_fstat, sizeof(au_fstat)); 8157a0a89d2SRobert Watson au_fstat.af_filesz = filesz; 816c0020399SRobert Watson if (audit_set_fsize(&au_fstat, sizeof(au_fstat)) != 0) 8177a0a89d2SRobert Watson return (ADE_AUDITON); 8187a0a89d2SRobert Watson 8197a0a89d2SRobert Watson return (ADE_NOERR); 8207a0a89d2SRobert Watson } 8217a0a89d2SRobert Watson 8225e386598SRobert Watson /* 8235e386598SRobert Watson * Set trail rotation size. Return: 8245e386598SRobert Watson * ADE_NOERR on success, 8255e386598SRobert Watson * ADE_PARSE error parsing audit_control(5), 8265e386598SRobert Watson * ADE_AUDITON error setting queue size using auditon(2). 8275e386598SRobert Watson */ 8285e386598SRobert Watson int 8295e386598SRobert Watson auditd_set_qsize(void) 8305e386598SRobert Watson { 8315e386598SRobert Watson int qsz; 8325e386598SRobert Watson au_qctrl_t au_qctrl; 8335e386598SRobert Watson 8345e386598SRobert Watson /* 8355e386598SRobert Watson * Set trail rotation size. 8365e386598SRobert Watson */ 8375e386598SRobert Watson if (getacqsize(&qsz) != 0) 8385e386598SRobert Watson return (ADE_PARSE); 8395e386598SRobert Watson 8405e386598SRobert Watson if (audit_get_qctrl(&au_qctrl, sizeof(au_qctrl)) != 0) 8415e386598SRobert Watson return (ADE_AUDITON); 8425e386598SRobert Watson if (qsz != USE_DEFAULT_QSZ) 8435e386598SRobert Watson au_qctrl.aq_hiwater = qsz; 8445e386598SRobert Watson if (audit_set_qctrl(&au_qctrl, sizeof(au_qctrl)) != 0) 8455e386598SRobert Watson return (ADE_AUDITON); 8465e386598SRobert Watson 8475e386598SRobert Watson return (ADE_NOERR); 8485e386598SRobert Watson } 8495e386598SRobert Watson 850aa772005SRobert Watson static void 851aa772005SRobert Watson inject_dist(const char *fromname, char *toname, size_t tonamesize) 852aa772005SRobert Watson { 853aa772005SRobert Watson char *ptr; 854aa772005SRobert Watson 855aa772005SRobert Watson ptr = strrchr(fromname, '/'); 856aa772005SRobert Watson assert(ptr != NULL); 857aa772005SRobert Watson assert(ptr - fromname < (ssize_t)tonamesize); 858aa772005SRobert Watson strlcpy(toname, fromname, ptr - fromname + 1); 859aa772005SRobert Watson strlcat(toname, "/dist/", tonamesize); 860aa772005SRobert Watson strlcat(toname, ptr + 1, tonamesize); 861aa772005SRobert Watson } 862aa772005SRobert Watson 863aa772005SRobert Watson static int 864aa772005SRobert Watson auditdist_link(const char *filename) 865aa772005SRobert Watson { 866aa772005SRobert Watson char fname[MAXPATHLEN]; 867aa772005SRobert Watson 868aa772005SRobert Watson if (auditd_dist) { 869aa772005SRobert Watson inject_dist(filename, fname, sizeof(fname)); 870aa772005SRobert Watson /* Ignore errors. */ 871aa772005SRobert Watson (void) link(filename, fname); 872aa772005SRobert Watson } 873aa772005SRobert Watson 874aa772005SRobert Watson return (0); 875aa772005SRobert Watson } 876aa772005SRobert Watson 877aa772005SRobert Watson int 878aa772005SRobert Watson auditd_rename(const char *fromname, const char *toname) 879aa772005SRobert Watson { 880aa772005SRobert Watson char fname[MAXPATHLEN], tname[MAXPATHLEN]; 881aa772005SRobert Watson 882aa772005SRobert Watson if (auditd_dist) { 883aa772005SRobert Watson inject_dist(fromname, fname, sizeof(fname)); 884aa772005SRobert Watson inject_dist(toname, tname, sizeof(tname)); 885aa772005SRobert Watson /* Ignore errors. */ 886aa772005SRobert Watson (void) rename(fname, tname); 887aa772005SRobert Watson } 888aa772005SRobert Watson 889aa772005SRobert Watson return (rename(fromname, toname)); 890aa772005SRobert Watson } 891aa772005SRobert Watson 8927a0a89d2SRobert Watson /* 893aa772005SRobert Watson * Create the new audit file with appropriate permissions and ownership. 894aa772005SRobert Watson * Call auditctl(2) for this file. 895aa772005SRobert Watson * Try to clean up if something goes wrong. 896aa772005SRobert Watson * *errorp is modified only on auditctl(2) failure. 8977a0a89d2SRobert Watson */ 8987a0a89d2SRobert Watson static int 899aa772005SRobert Watson open_trail(char *fname, gid_t gid, int *errorp) 9007a0a89d2SRobert Watson { 901aa772005SRobert Watson int fd; 9027a0a89d2SRobert Watson 903aa772005SRobert Watson /* XXXPJD: What should we do if the file already exists? */ 904aa772005SRobert Watson fd = open(fname, O_RDONLY | O_CREAT, S_IRUSR); 9057a0a89d2SRobert Watson if (fd < 0) 9067a0a89d2SRobert Watson return (-1); 907aa772005SRobert Watson if (fchown(fd, -1, gid) < 0 || fchmod(fd, S_IRUSR | S_IRGRP) < 0) { 908aa772005SRobert Watson (void) close(fd); 9097a0a89d2SRobert Watson (void) unlink(fname); 9107a0a89d2SRobert Watson return (-1); 9117a0a89d2SRobert Watson } 912aa772005SRobert Watson (void) close(fd); 913aa772005SRobert Watson if (auditctl(fname) < 0) { 914aa772005SRobert Watson *errorp = errno; 915aa772005SRobert Watson (void) unlink(fname); 916aa772005SRobert Watson return (-1); 917aa772005SRobert Watson } 918aa772005SRobert Watson (void) auditdist_link(fname); 919aa772005SRobert Watson return (0); 9207a0a89d2SRobert Watson } 9217a0a89d2SRobert Watson 9227a0a89d2SRobert Watson /* 9237a0a89d2SRobert Watson * Create the new audit trail file, swap with existing audit file. Arguments 9247a0a89d2SRobert Watson * include timestamp for the filename, a pointer to a string for returning the 9257a0a89d2SRobert Watson * new file name, GID for trail file, and audit_warn function pointer for 9267a0a89d2SRobert Watson * 'getacdir()' errors. Returns: 9277a0a89d2SRobert Watson * ADE_NOERR on success, 9287a0a89d2SRobert Watson * ADE_STRERR if the file name string could not be created, 9297a0a89d2SRobert Watson * ADE_SWAPERR if the audit trail file could not be swapped, 9307a0a89d2SRobert Watson * ADE_ACTL if the auditctl(2) call failed but file swap still 9317a0a89d2SRobert Watson * successful. 9327a0a89d2SRobert Watson * ADE_ACTLERR if the auditctl(2) call failed and file swap failed. 9337a0a89d2SRobert Watson * ADE_SYMLINK if symlink(2) failed updating the current link. 9347a0a89d2SRobert Watson */ 9357a0a89d2SRobert Watson int 9367a0a89d2SRobert Watson auditd_swap_trail(char *TS, char **newfile, gid_t gid, 9377a0a89d2SRobert Watson int (*warn_getacdir)(char *)) 9387a0a89d2SRobert Watson { 939aa772005SRobert Watson char timestr[FILENAME_LEN + 1]; 9407a0a89d2SRobert Watson char *fn; 9417a0a89d2SRobert Watson struct dir_ent *dirent; 9427a0a89d2SRobert Watson int saverrno = 0; 9437a0a89d2SRobert Watson 944aa772005SRobert Watson if (strlen(TS) != TIMESTAMP_LEN || 945aa772005SRobert Watson snprintf(timestr, sizeof(timestr), "%s.%s", TS, 946aa772005SRobert Watson NOT_TERMINATED) < 0) { 9477a0a89d2SRobert Watson errno = EINVAL; 9487a0a89d2SRobert Watson return (ADE_STRERR); 9497a0a89d2SRobert Watson } 9507a0a89d2SRobert Watson 9517a0a89d2SRobert Watson /* Try until we succeed. */ 95206edd2f1SRobert Watson TAILQ_FOREACH(dirent, &dir_q, dirs) { 9537a0a89d2SRobert Watson if (dirent->hardlim) 9547a0a89d2SRobert Watson continue; 9557a0a89d2SRobert Watson if ((fn = affixdir(timestr, dirent)) == NULL) 9567a0a89d2SRobert Watson return (ADE_STRERR); 9577a0a89d2SRobert Watson 9587a0a89d2SRobert Watson /* 959aa772005SRobert Watson * Create the file and pass to the kernel if all went well. 9607a0a89d2SRobert Watson */ 961aa772005SRobert Watson if (open_trail(fn, gid, &saverrno) == 0) { 9627a0a89d2SRobert Watson /* Success. */ 9637a0a89d2SRobert Watson *newfile = fn; 9647a0a89d2SRobert Watson if (saverrno) { 9657a0a89d2SRobert Watson /* 9667a0a89d2SRobert Watson * auditctl() failed but still 9677a0a89d2SRobert Watson * successful. Return errno and "soft" 9687a0a89d2SRobert Watson * error. 9697a0a89d2SRobert Watson */ 9707a0a89d2SRobert Watson errno = saverrno; 9717a0a89d2SRobert Watson return (ADE_ACTL); 9727a0a89d2SRobert Watson } 9737a0a89d2SRobert Watson return (ADE_NOERR); 9747a0a89d2SRobert Watson } 975aa772005SRobert Watson /* 976aa772005SRobert Watson * auditctl failed setting log file. Try again. 977aa772005SRobert Watson */ 9787a0a89d2SRobert Watson /* 9797a0a89d2SRobert Watson * Tell the administrator about lack of permissions for dir. 9807a0a89d2SRobert Watson */ 9817a0a89d2SRobert Watson if (warn_getacdir != NULL) 9827a0a89d2SRobert Watson (*warn_getacdir)(dirent->dirname); 9837a0a89d2SRobert Watson } 9847a0a89d2SRobert Watson if (saverrno) { 9857a0a89d2SRobert Watson errno = saverrno; 9867a0a89d2SRobert Watson return (ADE_ACTLERR); 9877a0a89d2SRobert Watson } else 9887a0a89d2SRobert Watson return (ADE_SWAPERR); 9897a0a89d2SRobert Watson } 9907a0a89d2SRobert Watson 9917a0a89d2SRobert Watson /* 9927a0a89d2SRobert Watson * Mask calling process from being audited. Returns: 9937a0a89d2SRobert Watson * ADE_NOERR on success, 9947a0a89d2SRobert Watson * ADE_SETAUDIT if setaudit(2) fails. 9957a0a89d2SRobert Watson */ 99606edd2f1SRobert Watson #ifdef __APPLE__ 99706edd2f1SRobert Watson int 99806edd2f1SRobert Watson auditd_prevent_audit(void) 99906edd2f1SRobert Watson { 100006edd2f1SRobert Watson auditinfo_addr_t aia; 100106edd2f1SRobert Watson 100206edd2f1SRobert Watson /* 100306edd2f1SRobert Watson * To prevent event feedback cycles and avoid audit becoming stalled if 100406edd2f1SRobert Watson * auditing is suspended we mask this processes events from being 100506edd2f1SRobert Watson * audited. We allow the uid, tid, and mask fields to be implicitly 100606edd2f1SRobert Watson * set to zero, but do set the audit session ID to the PID. 100706edd2f1SRobert Watson * 100806edd2f1SRobert Watson * XXXRW: Is there more to it than this? 100906edd2f1SRobert Watson */ 101006edd2f1SRobert Watson bzero(&aia, sizeof(aia)); 101106edd2f1SRobert Watson aia.ai_asid = AU_ASSIGN_ASID; 101206edd2f1SRobert Watson aia.ai_termid.at_type = AU_IPv4; 101306edd2f1SRobert Watson if (setaudit_addr(&aia, sizeof(aia)) != 0) 101406edd2f1SRobert Watson return (ADE_SETAUDIT); 101506edd2f1SRobert Watson return (ADE_NOERR); 101606edd2f1SRobert Watson } 101706edd2f1SRobert Watson #else 10187a0a89d2SRobert Watson int 10197a0a89d2SRobert Watson auditd_prevent_audit(void) 10207a0a89d2SRobert Watson { 10217a0a89d2SRobert Watson auditinfo_t ai; 10227a0a89d2SRobert Watson 10237a0a89d2SRobert Watson /* 10247a0a89d2SRobert Watson * To prevent event feedback cycles and avoid audit becoming stalled if 10257a0a89d2SRobert Watson * auditing is suspended we mask this processes events from being 10267a0a89d2SRobert Watson * audited. We allow the uid, tid, and mask fields to be implicitly 10277a0a89d2SRobert Watson * set to zero, but do set the audit session ID to the PID. 10287a0a89d2SRobert Watson * 10297a0a89d2SRobert Watson * XXXRW: Is there more to it than this? 10307a0a89d2SRobert Watson */ 10317a0a89d2SRobert Watson bzero(&ai, sizeof(ai)); 10327a0a89d2SRobert Watson ai.ai_asid = getpid(); 10337a0a89d2SRobert Watson if (setaudit(&ai) != 0) 10347a0a89d2SRobert Watson return (ADE_SETAUDIT); 10357a0a89d2SRobert Watson return (ADE_NOERR); 10367a0a89d2SRobert Watson } 1037aa772005SRobert Watson #endif /* !__APPLE__ */ 10387a0a89d2SRobert Watson 10397a0a89d2SRobert Watson /* 10407a0a89d2SRobert Watson * Generate and submit audit record for audit startup or shutdown. The event 10417a0a89d2SRobert Watson * argument can be AUE_audit_recovery, AUE_audit_startup or 10427a0a89d2SRobert Watson * AUE_audit_shutdown. The path argument will add a path token, if not NULL. 10437a0a89d2SRobert Watson * Returns: 10447a0a89d2SRobert Watson * AUE_NOERR on success, 10457a0a89d2SRobert Watson * ADE_NOMEM if memory allocation fails, 10467a0a89d2SRobert Watson * ADE_AU_OPEN if au_open(3) fails, 10477a0a89d2SRobert Watson * ADE_AU_CLOSE if au_close(3) fails. 10487a0a89d2SRobert Watson */ 10497a0a89d2SRobert Watson int 10507a0a89d2SRobert Watson auditd_gen_record(int event, char *path) 10517a0a89d2SRobert Watson { 10527a0a89d2SRobert Watson int aufd; 10537a0a89d2SRobert Watson uid_t uid; 10547a0a89d2SRobert Watson pid_t pid; 10557a0a89d2SRobert Watson char *autext = NULL; 10567a0a89d2SRobert Watson token_t *tok; 10577a0a89d2SRobert Watson struct auditinfo_addr aia; 10587a0a89d2SRobert Watson 10597a0a89d2SRobert Watson if (event == AUE_audit_startup) 10607a0a89d2SRobert Watson asprintf(&autext, "%s::Audit startup", getprogname()); 10617a0a89d2SRobert Watson else if (event == AUE_audit_shutdown) 10627a0a89d2SRobert Watson asprintf(&autext, "%s::Audit shutdown", getprogname()); 10637a0a89d2SRobert Watson else if (event == AUE_audit_recovery) 10647a0a89d2SRobert Watson asprintf(&autext, "%s::Audit recovery", getprogname()); 10657a0a89d2SRobert Watson else 10667a0a89d2SRobert Watson return (ADE_INVAL); 10677a0a89d2SRobert Watson if (autext == NULL) 10687a0a89d2SRobert Watson return (ADE_NOMEM); 10697a0a89d2SRobert Watson 10707a0a89d2SRobert Watson if ((aufd = au_open()) == -1) { 10717a0a89d2SRobert Watson free(autext); 10727a0a89d2SRobert Watson return (ADE_AU_OPEN); 10737a0a89d2SRobert Watson } 10747a0a89d2SRobert Watson bzero(&aia, sizeof(aia)); 10757a0a89d2SRobert Watson uid = getuid(); pid = getpid(); 10767a0a89d2SRobert Watson if ((tok = au_to_subject32_ex(uid, geteuid(), getegid(), uid, getgid(), 10777a0a89d2SRobert Watson pid, pid, &aia.ai_termid)) != NULL) 10787a0a89d2SRobert Watson au_write(aufd, tok); 10797a0a89d2SRobert Watson if ((tok = au_to_text(autext)) != NULL) 10807a0a89d2SRobert Watson au_write(aufd, tok); 10817a0a89d2SRobert Watson free(autext); 10827a0a89d2SRobert Watson if (path != NULL && (tok = au_to_path(path)) != NULL) 10837a0a89d2SRobert Watson au_write(aufd, tok); 10847a0a89d2SRobert Watson if ((tok = au_to_return32(0, 0)) != NULL) 10857a0a89d2SRobert Watson au_write(aufd, tok); 10867a0a89d2SRobert Watson if (au_close(aufd, 1, event) == -1) 10877a0a89d2SRobert Watson return (ADE_AU_CLOSE); 10887a0a89d2SRobert Watson 10897a0a89d2SRobert Watson return (ADE_NOERR); 10907a0a89d2SRobert Watson } 10917a0a89d2SRobert Watson 10927a0a89d2SRobert Watson /* 10937a0a89d2SRobert Watson * Check for a 'current' symlink and do crash recovery, if needed. Create a new 10947a0a89d2SRobert Watson * 'current' symlink. The argument 'curfile' is the file the 'current' symlink 10957a0a89d2SRobert Watson * should point to. Returns: 10967a0a89d2SRobert Watson * ADE_NOERR on success, 10977a0a89d2SRobert Watson * ADE_AU_OPEN if au_open(3) fails, 10987a0a89d2SRobert Watson * ADE_AU_CLOSE if au_close(3) fails. 10997a0a89d2SRobert Watson * ADE_RENAME if error renaming audit trail file, 11007a0a89d2SRobert Watson * ADE_READLINK if error reading the 'current' link, 11017a0a89d2SRobert Watson * ADE_SYMLINK if error creating 'current' link. 11027a0a89d2SRobert Watson */ 11037a0a89d2SRobert Watson int 11047a0a89d2SRobert Watson auditd_new_curlink(char *curfile) 11057a0a89d2SRobert Watson { 11067a0a89d2SRobert Watson int len, err; 11077a0a89d2SRobert Watson char *ptr; 11087a0a89d2SRobert Watson char *path = NULL; 11097a0a89d2SRobert Watson struct stat sb; 11107a0a89d2SRobert Watson char recoveredname[MAXPATHLEN]; 11117a0a89d2SRobert Watson char newname[MAXPATHLEN]; 11127a0a89d2SRobert Watson 11137a0a89d2SRobert Watson /* 11147a0a89d2SRobert Watson * Check to see if audit was shutdown properly. If not, clean up, 11157a0a89d2SRobert Watson * recover previous audit trail file, and generate audit record. 11167a0a89d2SRobert Watson */ 1117aa772005SRobert Watson len = readlink(AUDIT_CURRENT_LINK, recoveredname, 1118aa772005SRobert Watson sizeof(recoveredname) - 1); 11197a0a89d2SRobert Watson if (len > 0) { 11207a0a89d2SRobert Watson /* 'current' exist but is it pointing at a valid file? */ 11217a0a89d2SRobert Watson recoveredname[len++] = '\0'; 11227a0a89d2SRobert Watson if (stat(recoveredname, &sb) == 0) { 11237a0a89d2SRobert Watson /* Yes, rename it to a crash recovery file. */ 1124aa772005SRobert Watson strlcpy(newname, recoveredname, sizeof(newname)); 11257a0a89d2SRobert Watson 11267a0a89d2SRobert Watson if ((ptr = strstr(newname, NOT_TERMINATED)) != NULL) { 112706edd2f1SRobert Watson memcpy(ptr, CRASH_RECOVERY, POSTFIX_LEN); 1128aa772005SRobert Watson if (auditd_rename(recoveredname, newname) != 0) 11297a0a89d2SRobert Watson return (ADE_RENAME); 11307a0a89d2SRobert Watson } else 11317a0a89d2SRobert Watson return (ADE_STRERR); 11327a0a89d2SRobert Watson 11337a0a89d2SRobert Watson path = newname; 11347a0a89d2SRobert Watson } 11357a0a89d2SRobert Watson 11367a0a89d2SRobert Watson /* 'current' symlink is (now) invalid so remove it. */ 11377a0a89d2SRobert Watson (void) unlink(AUDIT_CURRENT_LINK); 11387a0a89d2SRobert Watson 11397a0a89d2SRobert Watson /* Note the crash recovery in current audit trail */ 11407a0a89d2SRobert Watson err = auditd_gen_record(AUE_audit_recovery, path); 11417a0a89d2SRobert Watson if (err) 11427a0a89d2SRobert Watson return (err); 11437a0a89d2SRobert Watson } 11447a0a89d2SRobert Watson 11457a0a89d2SRobert Watson if (len < 0 && errno != ENOENT) 11467a0a89d2SRobert Watson return (ADE_READLINK); 11477a0a89d2SRobert Watson 11487a0a89d2SRobert Watson if (symlink(curfile, AUDIT_CURRENT_LINK) != 0) 11497a0a89d2SRobert Watson return (ADE_SYMLINK); 11507a0a89d2SRobert Watson 11517a0a89d2SRobert Watson return (0); 11527a0a89d2SRobert Watson } 11537a0a89d2SRobert Watson 11547a0a89d2SRobert Watson /* 11557a0a89d2SRobert Watson * Do just what we need to quickly start auditing. Assume no system logging or 11567a0a89d2SRobert Watson * notify. Return: 11577a0a89d2SRobert Watson * 0 on success, 11587a0a89d2SRobert Watson * -1 on failure. 11597a0a89d2SRobert Watson */ 11607a0a89d2SRobert Watson int 11617a0a89d2SRobert Watson audit_quick_start(void) 11627a0a89d2SRobert Watson { 11637a0a89d2SRobert Watson int err; 116406edd2f1SRobert Watson char *newfile = NULL; 11657a0a89d2SRobert Watson time_t tt; 1166aa772005SRobert Watson char TS[TIMESTAMP_LEN + 1]; 116706edd2f1SRobert Watson int ret = 0; 11687a0a89d2SRobert Watson 11697a0a89d2SRobert Watson /* 11707a0a89d2SRobert Watson * Mask auditing of this process. 11717a0a89d2SRobert Watson */ 11727a0a89d2SRobert Watson if (auditd_prevent_audit() != 0) 11737a0a89d2SRobert Watson return (-1); 11747a0a89d2SRobert Watson 11757a0a89d2SRobert Watson /* 11767a0a89d2SRobert Watson * Read audit_control and get log directories. 11777a0a89d2SRobert Watson */ 11787a0a89d2SRobert Watson err = auditd_read_dirs(NULL, NULL); 11797a0a89d2SRobert Watson if (err != ADE_NOERR && err != ADE_SOFTLIM) 11807a0a89d2SRobert Watson return (-1); 11817a0a89d2SRobert Watson 11827a0a89d2SRobert Watson /* 1183aa772005SRobert Watson * Setup trail file distribution. 1184aa772005SRobert Watson */ 1185aa772005SRobert Watson (void) auditd_set_dist(); 1186aa772005SRobert Watson 1187aa772005SRobert Watson /* 11887a0a89d2SRobert Watson * Create a new audit trail log. 11897a0a89d2SRobert Watson */ 1190aa772005SRobert Watson if (getTSstr(tt, TS, sizeof(TS)) != 0) 11917a0a89d2SRobert Watson return (-1); 11927a0a89d2SRobert Watson err = auditd_swap_trail(TS, &newfile, getgid(), NULL); 119306edd2f1SRobert Watson if (err != ADE_NOERR && err != ADE_ACTL) { 119406edd2f1SRobert Watson ret = -1; 119506edd2f1SRobert Watson goto out; 119606edd2f1SRobert Watson } 11977a0a89d2SRobert Watson 11987a0a89d2SRobert Watson /* 11997a0a89d2SRobert Watson * Add the current symlink and recover from crash, if needed. 12007a0a89d2SRobert Watson */ 120106edd2f1SRobert Watson if (auditd_new_curlink(newfile) != 0) { 120206edd2f1SRobert Watson ret = -1; 120306edd2f1SRobert Watson goto out; 120406edd2f1SRobert Watson } 12057a0a89d2SRobert Watson 12067a0a89d2SRobert Watson /* 12077a0a89d2SRobert Watson * At this point auditing has started so generate audit start-up record. 12087a0a89d2SRobert Watson */ 120906edd2f1SRobert Watson if (auditd_gen_record(AUE_audit_startup, NULL) != 0) { 121006edd2f1SRobert Watson ret = -1; 121106edd2f1SRobert Watson goto out; 121206edd2f1SRobert Watson } 12137a0a89d2SRobert Watson 12147a0a89d2SRobert Watson /* 12157a0a89d2SRobert Watson * Configure the audit controls. 12167a0a89d2SRobert Watson */ 12177a0a89d2SRobert Watson (void) auditd_set_evcmap(); 12187a0a89d2SRobert Watson (void) auditd_set_namask(); 12197a0a89d2SRobert Watson (void) auditd_set_policy(); 12207a0a89d2SRobert Watson (void) auditd_set_fsize(); 12217a0a89d2SRobert Watson (void) auditd_set_minfree(); 12227a0a89d2SRobert Watson (void) auditd_set_host(); 12237a0a89d2SRobert Watson 122406edd2f1SRobert Watson out: 122506edd2f1SRobert Watson if (newfile != NULL) 122606edd2f1SRobert Watson free(newfile); 122706edd2f1SRobert Watson 122806edd2f1SRobert Watson return (ret); 12297a0a89d2SRobert Watson } 12307a0a89d2SRobert Watson 12317a0a89d2SRobert Watson /* 12327a0a89d2SRobert Watson * Shut down auditing quickly. Assumes that is only called on system shutdown. 12337a0a89d2SRobert Watson * Returns: 12347a0a89d2SRobert Watson * 0 on success, 12357a0a89d2SRobert Watson * -1 on failure. 12367a0a89d2SRobert Watson */ 12377a0a89d2SRobert Watson int 12387a0a89d2SRobert Watson audit_quick_stop(void) 12397a0a89d2SRobert Watson { 12407a0a89d2SRobert Watson int len; 1241c0020399SRobert Watson int cond; 12427a0a89d2SRobert Watson char *ptr; 12437a0a89d2SRobert Watson time_t tt; 12447a0a89d2SRobert Watson char oldname[MAXPATHLEN]; 12457a0a89d2SRobert Watson char newname[MAXPATHLEN]; 1246aa772005SRobert Watson char TS[TIMESTAMP_LEN + 1]; 12477a0a89d2SRobert Watson 12487a0a89d2SRobert Watson /* 12497a0a89d2SRobert Watson * Auditing already disabled? 12507a0a89d2SRobert Watson */ 1251c0020399SRobert Watson if (audit_get_cond(&cond) != 0) 12527a0a89d2SRobert Watson return (-1); 1253c74c7b73SRobert Watson if (cond == AUC_NOAUDIT) 12547a0a89d2SRobert Watson return (0); 12557a0a89d2SRobert Watson 12567a0a89d2SRobert Watson /* 12577a0a89d2SRobert Watson * Generate audit shutdown record. 12587a0a89d2SRobert Watson */ 12597a0a89d2SRobert Watson (void) auditd_gen_record(AUE_audit_shutdown, NULL); 12607a0a89d2SRobert Watson 12617a0a89d2SRobert Watson /* 12627a0a89d2SRobert Watson * Shutdown auditing in the kernel. 12637a0a89d2SRobert Watson */ 12647a0a89d2SRobert Watson cond = AUC_DISABLED; 1265c0020399SRobert Watson if (audit_set_cond(&cond) != 0) 12667a0a89d2SRobert Watson return (-1); 12677a0a89d2SRobert Watson #ifdef __BSM_INTERNAL_NOTIFY_KEY 12687a0a89d2SRobert Watson notify_post(__BSM_INTERNAL_NOTIFY_KEY); 12697a0a89d2SRobert Watson #endif 12707a0a89d2SRobert Watson 12717a0a89d2SRobert Watson /* 12727a0a89d2SRobert Watson * Rename last audit trail and remove 'current' link. 12737a0a89d2SRobert Watson */ 1274aa772005SRobert Watson len = readlink(AUDIT_CURRENT_LINK, oldname, sizeof(oldname) - 1); 12757a0a89d2SRobert Watson if (len < 0) 12767a0a89d2SRobert Watson return (-1); 12777a0a89d2SRobert Watson oldname[len++] = '\0'; 12787a0a89d2SRobert Watson 1279aa772005SRobert Watson if (getTSstr(tt, TS, sizeof(TS)) != 0) 12807a0a89d2SRobert Watson return (-1); 12817a0a89d2SRobert Watson 1282aa772005SRobert Watson strlcpy(newname, oldname, sizeof(newname)); 12837a0a89d2SRobert Watson 12847a0a89d2SRobert Watson if ((ptr = strstr(newname, NOT_TERMINATED)) != NULL) { 128506edd2f1SRobert Watson memcpy(ptr, TS, POSTFIX_LEN); 1286aa772005SRobert Watson if (auditd_rename(oldname, newname) != 0) 12877a0a89d2SRobert Watson return (-1); 12887a0a89d2SRobert Watson } else 12897a0a89d2SRobert Watson return (-1); 12907a0a89d2SRobert Watson 12917a0a89d2SRobert Watson (void) unlink(AUDIT_CURRENT_LINK); 12927a0a89d2SRobert Watson 12937a0a89d2SRobert Watson return (0); 12947a0a89d2SRobert Watson } 1295