17a0a89d2SRobert Watson /*- 206edd2f1SRobert Watson * Copyright (c) 2008-2009 Apple Inc. 37a0a89d2SRobert Watson * All rights reserved. 47a0a89d2SRobert Watson * 57a0a89d2SRobert Watson * Redistribution and use in source and binary forms, with or without 67a0a89d2SRobert Watson * modification, are permitted provided that the following conditions 77a0a89d2SRobert Watson * are met: 87a0a89d2SRobert Watson * 1. Redistributions of source code must retain the above copyright 97a0a89d2SRobert Watson * notice, this list of conditions and the following disclaimer. 107a0a89d2SRobert Watson * 2. Redistributions in binary form must reproduce the above copyright 117a0a89d2SRobert Watson * notice, this list of conditions and the following disclaimer in the 127a0a89d2SRobert Watson * documentation and/or other materials provided with the distribution. 137a0a89d2SRobert Watson * 3. Neither the name of Apple Inc. ("Apple") nor the names of 147a0a89d2SRobert Watson * its contributors may be used to endorse or promote products derived 157a0a89d2SRobert Watson * from this software without specific prior written permission. 167a0a89d2SRobert Watson * 177a0a89d2SRobert Watson * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND 187a0a89d2SRobert Watson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 197a0a89d2SRobert Watson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 207a0a89d2SRobert Watson * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR 217a0a89d2SRobert Watson * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 227a0a89d2SRobert Watson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 237a0a89d2SRobert Watson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 247a0a89d2SRobert Watson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 257a0a89d2SRobert Watson * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 267a0a89d2SRobert Watson * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 277a0a89d2SRobert Watson * POSSIBILITY OF SUCH DAMAGE. 287a0a89d2SRobert Watson */ 297a0a89d2SRobert Watson 307a0a89d2SRobert Watson #include <sys/param.h> 317a0a89d2SRobert Watson 327a0a89d2SRobert Watson #include <config/config.h> 337a0a89d2SRobert Watson 347a0a89d2SRobert Watson #include <sys/dirent.h> 357a0a89d2SRobert Watson #ifdef HAVE_FULL_QUEUE_H 367a0a89d2SRobert Watson #include <sys/queue.h> 377a0a89d2SRobert Watson #else /* !HAVE_FULL_QUEUE_H */ 387a0a89d2SRobert Watson #include <compat/queue.h> 397a0a89d2SRobert Watson #endif /* !HAVE_FULL_QUEUE_H */ 40c0020399SRobert Watson #include <sys/mount.h> 41c0020399SRobert Watson #include <sys/socket.h> 427a0a89d2SRobert Watson 437a0a89d2SRobert Watson #include <sys/stat.h> 447a0a89d2SRobert Watson #include <sys/time.h> 457a0a89d2SRobert Watson 467a0a89d2SRobert Watson #include <netinet/in.h> 477a0a89d2SRobert Watson 487a0a89d2SRobert Watson #include <bsm/audit.h> 497a0a89d2SRobert Watson #include <bsm/audit_uevents.h> 507a0a89d2SRobert Watson #include <bsm/auditd_lib.h> 517a0a89d2SRobert Watson #include <bsm/libbsm.h> 527a0a89d2SRobert Watson 53aa772005SRobert Watson #include <assert.h> 5406edd2f1SRobert Watson #include <dirent.h> 557a0a89d2SRobert Watson #include <err.h> 567a0a89d2SRobert Watson #include <errno.h> 577a0a89d2SRobert Watson #include <fcntl.h> 587a0a89d2SRobert Watson #include <stdio.h> 597a0a89d2SRobert Watson #include <string.h> 607a0a89d2SRobert Watson #include <stdlib.h> 617a0a89d2SRobert Watson #include <time.h> 627a0a89d2SRobert Watson #include <unistd.h> 637a0a89d2SRobert Watson #include <netdb.h> 647a0a89d2SRobert Watson 657a0a89d2SRobert Watson #ifdef __APPLE__ 667a0a89d2SRobert Watson #include <notify.h> 677a0a89d2SRobert Watson #ifndef __BSM_INTERNAL_NOTIFY_KEY 687a0a89d2SRobert Watson #define __BSM_INTERNAL_NOTIFY_KEY "com.apple.audit.change" 697a0a89d2SRobert Watson #endif /* __BSM_INTERNAL_NOTIFY_KEY */ 707a0a89d2SRobert Watson #endif /* __APPLE__ */ 717a0a89d2SRobert Watson 727a0a89d2SRobert Watson /* 737a0a89d2SRobert Watson * XXX This is temporary until this is moved to <bsm/audit.h> and shared with 747a0a89d2SRobert Watson * the kernel. 757a0a89d2SRobert Watson */ 767a0a89d2SRobert Watson #ifndef AUDIT_HARD_LIMIT_FREE_BLOCKS 777a0a89d2SRobert Watson #define AUDIT_HARD_LIMIT_FREE_BLOCKS 4 787a0a89d2SRobert Watson #endif 797a0a89d2SRobert Watson 8006edd2f1SRobert Watson /* 8106edd2f1SRobert Watson * Number of seconds to January 1, 2000 8206edd2f1SRobert Watson */ 8306edd2f1SRobert Watson #define JAN_01_2000 946598400 8406edd2f1SRobert Watson 857a0a89d2SRobert Watson struct dir_ent { 867a0a89d2SRobert Watson char *dirname; 877a0a89d2SRobert Watson uint8_t softlim; 887a0a89d2SRobert Watson uint8_t hardlim; 897a0a89d2SRobert Watson TAILQ_ENTRY(dir_ent) dirs; 907a0a89d2SRobert Watson }; 917a0a89d2SRobert Watson 927a0a89d2SRobert Watson static TAILQ_HEAD(, dir_ent) dir_q; 9306edd2f1SRobert Watson 9406edd2f1SRobert Watson struct audit_trail { 9506edd2f1SRobert Watson time_t at_time; 9606edd2f1SRobert Watson char *at_path; 9706edd2f1SRobert Watson off_t at_size; 9806edd2f1SRobert Watson 9906edd2f1SRobert Watson TAILQ_ENTRY(audit_trail) at_trls; 10006edd2f1SRobert Watson }; 10106edd2f1SRobert Watson 10206edd2f1SRobert Watson static int auditd_minval = -1; 103aa772005SRobert Watson static int auditd_dist = 0; 10406edd2f1SRobert Watson 10506edd2f1SRobert Watson static char auditd_host[MAXHOSTNAMELEN]; 10606edd2f1SRobert Watson static int auditd_hostlen = -1; 1077a0a89d2SRobert Watson 1087a0a89d2SRobert Watson static char *auditd_errmsg[] = { 1097a0a89d2SRobert Watson "no error", /* ADE_NOERR ( 0) */ 1107a0a89d2SRobert Watson "could not parse audit_control(5) file", /* ADE_PARSE ( 1) */ 1117a0a89d2SRobert Watson "auditon(2) failed", /* ADE_AUDITON ( 2) */ 1127a0a89d2SRobert Watson "malloc(3) failed", /* ADE_NOMEM ( 3) */ 1137a0a89d2SRobert Watson "all audit log directories over soft limit", /* ADE_SOFTLIM ( 4) */ 1147a0a89d2SRobert Watson "all audit log directories over hard limit", /* ADE_HARDLIM ( 5) */ 1157a0a89d2SRobert Watson "could not create file name string", /* ADE_STRERR ( 6) */ 1167a0a89d2SRobert Watson "could not open audit record", /* ADE_AU_OPEN ( 7) */ 1177a0a89d2SRobert Watson "could not close audit record", /* ADE_AU_CLOSE ( 8) */ 1187a0a89d2SRobert Watson "could not set active audit session state", /* ADE_SETAUDIT ( 9) */ 1197a0a89d2SRobert Watson "auditctl(2) failed (trail still swapped)", /* ADE_ACTL (10) */ 1207a0a89d2SRobert Watson "auditctl(2) failed (trail not swapped)", /* ADE_ACTLERR (11) */ 1217a0a89d2SRobert Watson "could not swap audit trail file", /* ADE_SWAPERR (12) */ 1227a0a89d2SRobert Watson "could not rename crash recovery file", /* ADE_RENAME (13) */ 1237a0a89d2SRobert Watson "could not read 'current' link file", /* ADE_READLINK (14) */ 1247a0a89d2SRobert Watson "could not create 'current' link file", /* ADE_SYMLINK (15) */ 1257a0a89d2SRobert Watson "invalid argument", /* ADE_INVAL (16) */ 1267a0a89d2SRobert Watson "could not resolve hostname to address", /* ADE_GETADDR (17) */ 1277a0a89d2SRobert Watson "address family not supported", /* ADE_ADDRFAM (18) */ 12806edd2f1SRobert Watson "error expiring audit trail files", /* ADE_EXPIRE (19) */ 1297a0a89d2SRobert Watson }; 1307a0a89d2SRobert Watson 1317a0a89d2SRobert Watson #define MAXERRCODE (sizeof(auditd_errmsg) / sizeof(auditd_errmsg[0])) 1327a0a89d2SRobert Watson 133597df30eSRobert Watson #define NA_EVENT_STR_SIZE 128 1347a0a89d2SRobert Watson #define POL_STR_SIZE 128 1357a0a89d2SRobert Watson 1367a0a89d2SRobert Watson 1377a0a89d2SRobert Watson /* 1387a0a89d2SRobert Watson * Look up and return the error string for the given audit error code. 1397a0a89d2SRobert Watson */ 1407a0a89d2SRobert Watson const char * 1417a0a89d2SRobert Watson auditd_strerror(int errcode) 1427a0a89d2SRobert Watson { 1437a0a89d2SRobert Watson int idx = -errcode; 1447a0a89d2SRobert Watson 1457a0a89d2SRobert Watson if (idx < 0 || idx > (int)MAXERRCODE) 1467a0a89d2SRobert Watson return ("Invalid auditd error code"); 1477a0a89d2SRobert Watson 1487a0a89d2SRobert Watson return (auditd_errmsg[idx]); 1497a0a89d2SRobert Watson } 1507a0a89d2SRobert Watson 1517a0a89d2SRobert Watson 1527a0a89d2SRobert Watson /* 153aa772005SRobert Watson * Free our local list of directory names and init list. 1547a0a89d2SRobert Watson */ 1557a0a89d2SRobert Watson static void 1567a0a89d2SRobert Watson free_dir_q(void) 1577a0a89d2SRobert Watson { 1587a0a89d2SRobert Watson struct dir_ent *d1, *d2; 1597a0a89d2SRobert Watson 1607a0a89d2SRobert Watson d1 = TAILQ_FIRST(&dir_q); 1617a0a89d2SRobert Watson while (d1 != NULL) { 1627a0a89d2SRobert Watson d2 = TAILQ_NEXT(d1, dirs); 1637a0a89d2SRobert Watson free(d1->dirname); 1647a0a89d2SRobert Watson free(d1); 1657a0a89d2SRobert Watson d1 = d2; 1667a0a89d2SRobert Watson } 1677a0a89d2SRobert Watson TAILQ_INIT(&dir_q); 1687a0a89d2SRobert Watson } 1697a0a89d2SRobert Watson 1707a0a89d2SRobert Watson /* 1717a0a89d2SRobert Watson * Concat the directory name to the given file name. 1727a0a89d2SRobert Watson * XXX We should affix the hostname also 1737a0a89d2SRobert Watson */ 1747a0a89d2SRobert Watson static char * 1757a0a89d2SRobert Watson affixdir(char *name, struct dir_ent *dirent) 1767a0a89d2SRobert Watson { 1777a0a89d2SRobert Watson char *fn = NULL; 1787a0a89d2SRobert Watson 1797a0a89d2SRobert Watson /* 1807a0a89d2SRobert Watson * Sanity check on file name. 1817a0a89d2SRobert Watson */ 182aa772005SRobert Watson if (strlen(name) != FILENAME_LEN) { 1837a0a89d2SRobert Watson errno = EINVAL; 1847a0a89d2SRobert Watson return (NULL); 1857a0a89d2SRobert Watson } 1867a0a89d2SRobert Watson 18706edd2f1SRobert Watson /* 18806edd2f1SRobert Watson * If the host is set then also add the hostname to the filename. 18906edd2f1SRobert Watson */ 19006edd2f1SRobert Watson if (auditd_hostlen != -1) 19106edd2f1SRobert Watson asprintf(&fn, "%s/%s.%s", dirent->dirname, name, auditd_host); 19206edd2f1SRobert Watson else 1937a0a89d2SRobert Watson asprintf(&fn, "%s/%s", dirent->dirname, name); 1947a0a89d2SRobert Watson return (fn); 1957a0a89d2SRobert Watson } 1967a0a89d2SRobert Watson 1977a0a89d2SRobert Watson /* 1987a0a89d2SRobert Watson * Insert the directory entry in the list by the way they are ordered in 1997a0a89d2SRobert Watson * audit_control(5). Move the entries that are over the soft and hard limits 2007a0a89d2SRobert Watson * toward the tail. 2017a0a89d2SRobert Watson */ 2027a0a89d2SRobert Watson static void 2037a0a89d2SRobert Watson insert_orderly(struct dir_ent *denew) 2047a0a89d2SRobert Watson { 2057a0a89d2SRobert Watson struct dir_ent *dep; 2067a0a89d2SRobert Watson 2077a0a89d2SRobert Watson TAILQ_FOREACH(dep, &dir_q, dirs) { 2087a0a89d2SRobert Watson if (dep->softlim == 1 && denew->softlim == 0) { 2097a0a89d2SRobert Watson TAILQ_INSERT_BEFORE(dep, denew, dirs); 2107a0a89d2SRobert Watson return; 2117a0a89d2SRobert Watson } 2127a0a89d2SRobert Watson if (dep->hardlim == 1 && denew->hardlim == 0) { 2137a0a89d2SRobert Watson TAILQ_INSERT_BEFORE(dep, denew, dirs); 2147a0a89d2SRobert Watson return; 2157a0a89d2SRobert Watson } 2167a0a89d2SRobert Watson } 2177a0a89d2SRobert Watson TAILQ_INSERT_TAIL(&dir_q, denew, dirs); 2187a0a89d2SRobert Watson } 2197a0a89d2SRobert Watson 2207a0a89d2SRobert Watson /* 221aa772005SRobert Watson * Get the min percentage of free blocks from audit_control(5) and that 222aa772005SRobert Watson * value in the kernel. Return: 223aa772005SRobert Watson * ADE_NOERR on success, 224aa772005SRobert Watson * ADE_PARSE error parsing audit_control(5), 225aa772005SRobert Watson */ 226aa772005SRobert Watson int 227aa772005SRobert Watson auditd_set_dist(void) 228aa772005SRobert Watson { 229aa772005SRobert Watson int ret; 230aa772005SRobert Watson 231aa772005SRobert Watson ret = getacdist(); 232aa772005SRobert Watson if (ret < 0) 233aa772005SRobert Watson return (ADE_PARSE); 234aa772005SRobert Watson 235aa772005SRobert Watson auditd_dist = ret; 236aa772005SRobert Watson 237aa772005SRobert Watson return (ADE_NOERR); 238aa772005SRobert Watson } 239aa772005SRobert Watson 240aa772005SRobert Watson /* 2417a0a89d2SRobert Watson * Get the host from audit_control(5) and set it in the audit kernel 2427a0a89d2SRobert Watson * information. Return: 2437a0a89d2SRobert Watson * ADE_NOERR on success. 2447a0a89d2SRobert Watson * ADE_PARSE error parsing audit_control(5). 2457a0a89d2SRobert Watson * ADE_AUDITON error getting/setting auditon(2) value. 2467a0a89d2SRobert Watson * ADE_GETADDR error getting address info for host. 2477a0a89d2SRobert Watson * ADE_ADDRFAM un-supported address family. 2487a0a89d2SRobert Watson */ 2497a0a89d2SRobert Watson int 2507a0a89d2SRobert Watson auditd_set_host(void) 2517a0a89d2SRobert Watson { 2527a0a89d2SRobert Watson struct sockaddr_in6 *sin6; 2537a0a89d2SRobert Watson struct sockaddr_in *sin; 2547a0a89d2SRobert Watson struct addrinfo *res; 2557a0a89d2SRobert Watson struct auditinfo_addr aia; 2567a0a89d2SRobert Watson int error, ret = ADE_NOERR; 2577a0a89d2SRobert Watson 25806edd2f1SRobert Watson if (getachost(auditd_host, sizeof(auditd_host)) != 0) { 2597a0a89d2SRobert Watson ret = ADE_PARSE; 2607a0a89d2SRobert Watson 2617a0a89d2SRobert Watson /* 2627a0a89d2SRobert Watson * To maintain reverse compatability with older audit_control 2637a0a89d2SRobert Watson * files, simply drop a warning if the host parameter has not 2647a0a89d2SRobert Watson * been set. However, we will explicitly disable the 2657a0a89d2SRobert Watson * generation of extended audit header by passing in a zeroed 2667a0a89d2SRobert Watson * termid structure. 2677a0a89d2SRobert Watson */ 2687a0a89d2SRobert Watson bzero(&aia, sizeof(aia)); 2697a0a89d2SRobert Watson aia.ai_termid.at_type = AU_IPv4; 270c0020399SRobert Watson error = audit_set_kaudit(&aia, sizeof(aia)); 2717a0a89d2SRobert Watson if (error < 0 && errno != ENOSYS) 2727a0a89d2SRobert Watson ret = ADE_AUDITON; 2737a0a89d2SRobert Watson return (ret); 2747a0a89d2SRobert Watson } 27506edd2f1SRobert Watson auditd_hostlen = strlen(auditd_host); 27606edd2f1SRobert Watson error = getaddrinfo(auditd_host, NULL, NULL, &res); 2777a0a89d2SRobert Watson if (error) 2787a0a89d2SRobert Watson return (ADE_GETADDR); 2797a0a89d2SRobert Watson switch (res->ai_family) { 2807a0a89d2SRobert Watson case PF_INET6: 2817a0a89d2SRobert Watson sin6 = (struct sockaddr_in6 *) res->ai_addr; 2827a0a89d2SRobert Watson bcopy(&sin6->sin6_addr.s6_addr, 2837a0a89d2SRobert Watson &aia.ai_termid.at_addr[0], sizeof(struct in6_addr)); 2847a0a89d2SRobert Watson aia.ai_termid.at_type = AU_IPv6; 2857a0a89d2SRobert Watson break; 2867a0a89d2SRobert Watson 2877a0a89d2SRobert Watson case PF_INET: 2887a0a89d2SRobert Watson sin = (struct sockaddr_in *) res->ai_addr; 2897a0a89d2SRobert Watson bcopy(&sin->sin_addr.s_addr, 2907a0a89d2SRobert Watson &aia.ai_termid.at_addr[0], sizeof(struct in_addr)); 2917a0a89d2SRobert Watson aia.ai_termid.at_type = AU_IPv4; 2927a0a89d2SRobert Watson break; 2937a0a89d2SRobert Watson 2947a0a89d2SRobert Watson default: 2957a0a89d2SRobert Watson /* Un-supported address family in host parameter. */ 2967a0a89d2SRobert Watson errno = EAFNOSUPPORT; 2977a0a89d2SRobert Watson return (ADE_ADDRFAM); 2987a0a89d2SRobert Watson } 2997a0a89d2SRobert Watson 300c0020399SRobert Watson if (audit_set_kaudit(&aia, sizeof(aia)) < 0) 3017a0a89d2SRobert Watson ret = ADE_AUDITON; 3027a0a89d2SRobert Watson 3037a0a89d2SRobert Watson return (ret); 3047a0a89d2SRobert Watson } 3057a0a89d2SRobert Watson 3067a0a89d2SRobert Watson /* 3077a0a89d2SRobert Watson * Get the min percentage of free blocks from audit_control(5) and that 3087a0a89d2SRobert Watson * value in the kernel. Return: 3097a0a89d2SRobert Watson * ADE_NOERR on success, 3107a0a89d2SRobert Watson * ADE_PARSE error parsing audit_control(5), 3117a0a89d2SRobert Watson * ADE_AUDITON error getting/setting auditon(2) value. 3127a0a89d2SRobert Watson */ 3137a0a89d2SRobert Watson int 3147a0a89d2SRobert Watson auditd_set_minfree(void) 3157a0a89d2SRobert Watson { 3167a0a89d2SRobert Watson au_qctrl_t qctrl; 3177a0a89d2SRobert Watson 31806edd2f1SRobert Watson if (getacmin(&auditd_minval) != 0) 3197a0a89d2SRobert Watson return (ADE_PARSE); 3207a0a89d2SRobert Watson 321c0020399SRobert Watson if (audit_get_qctrl(&qctrl, sizeof(qctrl)) != 0) 3227a0a89d2SRobert Watson return (ADE_AUDITON); 3237a0a89d2SRobert Watson 32406edd2f1SRobert Watson if (qctrl.aq_minfree != auditd_minval) { 32506edd2f1SRobert Watson qctrl.aq_minfree = auditd_minval; 326c0020399SRobert Watson if (audit_set_qctrl(&qctrl, sizeof(qctrl)) != 0) 3277a0a89d2SRobert Watson return (ADE_AUDITON); 3287a0a89d2SRobert Watson } 3297a0a89d2SRobert Watson 3307a0a89d2SRobert Watson return (0); 3317a0a89d2SRobert Watson } 3327a0a89d2SRobert Watson 3337a0a89d2SRobert Watson /* 33406edd2f1SRobert Watson * Convert a trailname into a timestamp (seconds). Return 0 if the conversion 33506edd2f1SRobert Watson * was successful. 33606edd2f1SRobert Watson */ 33706edd2f1SRobert Watson static int 33806edd2f1SRobert Watson trailname_to_tstamp(char *fn, time_t *tstamp) 33906edd2f1SRobert Watson { 34006edd2f1SRobert Watson struct tm tm; 341aa772005SRobert Watson char ts[TIMESTAMP_LEN + 1]; 34206edd2f1SRobert Watson char *p; 34306edd2f1SRobert Watson 34406edd2f1SRobert Watson *tstamp = 0; 34506edd2f1SRobert Watson 34606edd2f1SRobert Watson /* 34706edd2f1SRobert Watson * Get the ending time stamp. 34806edd2f1SRobert Watson */ 34906edd2f1SRobert Watson if ((p = strchr(fn, '.')) == NULL) 35006edd2f1SRobert Watson return (1); 351aa772005SRobert Watson strlcpy(ts, ++p, sizeof(ts)); 35206edd2f1SRobert Watson if (strlen(ts) != POSTFIX_LEN) 35306edd2f1SRobert Watson return (1); 35406edd2f1SRobert Watson 35506edd2f1SRobert Watson bzero(&tm, sizeof(tm)); 35606edd2f1SRobert Watson 35706edd2f1SRobert Watson /* seconds (0-60) */ 35806edd2f1SRobert Watson p = ts + POSTFIX_LEN - 2; 35906edd2f1SRobert Watson tm.tm_sec = atol(p); 36006edd2f1SRobert Watson if (tm.tm_sec < 0 || tm.tm_sec > 60) 36106edd2f1SRobert Watson return (1); 36206edd2f1SRobert Watson 36306edd2f1SRobert Watson /* minutes (0-59) */ 36406edd2f1SRobert Watson *p = '\0'; p -= 2; 36506edd2f1SRobert Watson tm.tm_min = atol(p); 36606edd2f1SRobert Watson if (tm.tm_min < 0 || tm.tm_min > 59) 36706edd2f1SRobert Watson return (1); 36806edd2f1SRobert Watson 36906edd2f1SRobert Watson /* hours (0 - 23) */ 37006edd2f1SRobert Watson *p = '\0'; p -= 2; 37106edd2f1SRobert Watson tm.tm_hour = atol(p); 37206edd2f1SRobert Watson if (tm.tm_hour < 0 || tm.tm_hour > 23) 37306edd2f1SRobert Watson return (1); 37406edd2f1SRobert Watson 37506edd2f1SRobert Watson /* day of month (1-31) */ 37606edd2f1SRobert Watson *p = '\0'; p -= 2; 37706edd2f1SRobert Watson tm.tm_mday = atol(p); 37806edd2f1SRobert Watson if (tm.tm_mday < 1 || tm.tm_mday > 31) 37906edd2f1SRobert Watson return (1); 38006edd2f1SRobert Watson 38106edd2f1SRobert Watson /* month (0 - 11) */ 38206edd2f1SRobert Watson *p = '\0'; p -= 2; 38306edd2f1SRobert Watson tm.tm_mon = atol(p) - 1; 38406edd2f1SRobert Watson if (tm.tm_mon < 0 || tm.tm_mon > 11) 38506edd2f1SRobert Watson return (1); 38606edd2f1SRobert Watson 38706edd2f1SRobert Watson /* year (year - 1900) */ 38806edd2f1SRobert Watson *p = '\0'; p -= 4; 38906edd2f1SRobert Watson tm.tm_year = atol(p) - 1900; 39006edd2f1SRobert Watson if (tm.tm_year < 0) 39106edd2f1SRobert Watson return (1); 39206edd2f1SRobert Watson 39306edd2f1SRobert Watson *tstamp = timegm(&tm); 39406edd2f1SRobert Watson 39506edd2f1SRobert Watson return (0); 39606edd2f1SRobert Watson } 39706edd2f1SRobert Watson 39806edd2f1SRobert Watson /* 39906edd2f1SRobert Watson * Remove audit trails files according to the expiration conditions. Returns: 40006edd2f1SRobert Watson * ADE_NOERR on success or there is nothing to do. 40106edd2f1SRobert Watson * ADE_PARSE if error parsing audit_control(5). 40206edd2f1SRobert Watson * ADE_NOMEM if could not allocate memory. 403*b6a05070SChristian Brueffer * ADE_READLINK if could not read link file. 404*b6a05070SChristian Brueffer * ADE_EXPIRE if there was an unexpected error. 40506edd2f1SRobert Watson */ 40606edd2f1SRobert Watson int 40706edd2f1SRobert Watson auditd_expire_trails(int (*warn_expired)(char *)) 40806edd2f1SRobert Watson { 409*b6a05070SChristian Brueffer int andflg, len, ret = ADE_NOERR; 41006edd2f1SRobert Watson size_t expire_size, total_size = 0L; 41106edd2f1SRobert Watson time_t expire_age, oldest_time, current_time = time(NULL); 41206edd2f1SRobert Watson struct dir_ent *traildir; 41306edd2f1SRobert Watson struct audit_trail *at; 41406edd2f1SRobert Watson char *afnp, *pn; 41506edd2f1SRobert Watson TAILQ_HEAD(au_trls_head, audit_trail) head = 41606edd2f1SRobert Watson TAILQ_HEAD_INITIALIZER(head); 41706edd2f1SRobert Watson struct stat stbuf; 41806edd2f1SRobert Watson char activefn[MAXPATHLEN]; 41906edd2f1SRobert Watson 42006edd2f1SRobert Watson /* 42106edd2f1SRobert Watson * Read the expiration conditions. If no conditions then return no 42206edd2f1SRobert Watson * error. 42306edd2f1SRobert Watson */ 42406edd2f1SRobert Watson if (getacexpire(&andflg, &expire_age, &expire_size) < 0) 42506edd2f1SRobert Watson return (ADE_PARSE); 42606edd2f1SRobert Watson if (!expire_age && !expire_size) 42706edd2f1SRobert Watson return (ADE_NOERR); 42806edd2f1SRobert Watson 42906edd2f1SRobert Watson /* 43006edd2f1SRobert Watson * Read the 'current' trail file name. Trim off directory path. 43106edd2f1SRobert Watson */ 43206edd2f1SRobert Watson activefn[0] = '\0'; 433*b6a05070SChristian Brueffer len = readlink(AUDIT_CURRENT_LINK, activefn, MAXPATHLEN - 1); 434*b6a05070SChristian Brueffer if (len < 0) 435*b6a05070SChristian Brueffer return (ADE_READLINK); 43606edd2f1SRobert Watson if ((afnp = strrchr(activefn, '/')) != NULL) 43706edd2f1SRobert Watson afnp++; 43806edd2f1SRobert Watson 43906edd2f1SRobert Watson 44006edd2f1SRobert Watson /* 44106edd2f1SRobert Watson * Build tail queue of the trail files. 44206edd2f1SRobert Watson */ 44306edd2f1SRobert Watson TAILQ_FOREACH(traildir, &dir_q, dirs) { 44406edd2f1SRobert Watson DIR *dirp; 44506edd2f1SRobert Watson struct dirent *dp; 44606edd2f1SRobert Watson 44706edd2f1SRobert Watson dirp = opendir(traildir->dirname); 44806edd2f1SRobert Watson while ((dp = readdir(dirp)) != NULL) { 44906edd2f1SRobert Watson time_t tstamp = 0; 45006edd2f1SRobert Watson struct audit_trail *new; 45106edd2f1SRobert Watson 45206edd2f1SRobert Watson /* 45306edd2f1SRobert Watson * Quickly filter non-trail files. 45406edd2f1SRobert Watson */ 455aa772005SRobert Watson if (dp->d_namlen < FILENAME_LEN || 45606edd2f1SRobert Watson dp->d_name[POSTFIX_LEN] != '.') 45706edd2f1SRobert Watson continue; 45806edd2f1SRobert Watson 45906edd2f1SRobert Watson if (asprintf(&pn, "%s/%s", traildir->dirname, 46006edd2f1SRobert Watson dp->d_name) < 0) { 46106edd2f1SRobert Watson ret = ADE_NOMEM; 46206edd2f1SRobert Watson break; 46306edd2f1SRobert Watson } 46406edd2f1SRobert Watson 46506edd2f1SRobert Watson if (stat(pn, &stbuf) < 0 || !S_ISREG(stbuf.st_mode)) { 46606edd2f1SRobert Watson free(pn); 46706edd2f1SRobert Watson continue; 46806edd2f1SRobert Watson } 46906edd2f1SRobert Watson 47006edd2f1SRobert Watson total_size += stbuf.st_size; 47106edd2f1SRobert Watson 47206edd2f1SRobert Watson /* 47306edd2f1SRobert Watson * If this is the 'current' audit trail then 47406edd2f1SRobert Watson * don't add it to the tail queue. 47506edd2f1SRobert Watson */ 476aa772005SRobert Watson if (NULL != afnp && strcmp(dp->d_name, afnp) == 0) { 47706edd2f1SRobert Watson free(pn); 47806edd2f1SRobert Watson continue; 47906edd2f1SRobert Watson } 48006edd2f1SRobert Watson 48106edd2f1SRobert Watson /* 48206edd2f1SRobert Watson * Get the ending time stamp encoded in the trail 48306edd2f1SRobert Watson * name. If we can't read it or if it is older 48406edd2f1SRobert Watson * than Jan 1, 2000 then use the mtime. 48506edd2f1SRobert Watson */ 48606edd2f1SRobert Watson if (trailname_to_tstamp(dp->d_name, &tstamp) != 0 || 48706edd2f1SRobert Watson tstamp < JAN_01_2000) 48806edd2f1SRobert Watson tstamp = stbuf.st_mtime; 48906edd2f1SRobert Watson 49006edd2f1SRobert Watson /* 49106edd2f1SRobert Watson * If the time stamp is older than Jan 1, 2000 then 49206edd2f1SRobert Watson * update the mtime of the trail file to the current 49306edd2f1SRobert Watson * time. This is so we don't prematurely remove a trail 49406edd2f1SRobert Watson * file that was created while the system clock reset 49506edd2f1SRobert Watson * to the * "beginning of time" but later the system 49606edd2f1SRobert Watson * clock is set to the correct current time. 49706edd2f1SRobert Watson */ 49806edd2f1SRobert Watson if (current_time >= JAN_01_2000 && 49906edd2f1SRobert Watson tstamp < JAN_01_2000) { 50006edd2f1SRobert Watson struct timeval tv[2]; 50106edd2f1SRobert Watson 50206edd2f1SRobert Watson tstamp = stbuf.st_mtime = current_time; 50306edd2f1SRobert Watson TIMESPEC_TO_TIMEVAL(&tv[0], 50406edd2f1SRobert Watson &stbuf.st_atimespec); 50506edd2f1SRobert Watson TIMESPEC_TO_TIMEVAL(&tv[1], 50606edd2f1SRobert Watson &stbuf.st_mtimespec); 50706edd2f1SRobert Watson utimes(pn, tv); 50806edd2f1SRobert Watson } 50906edd2f1SRobert Watson 51006edd2f1SRobert Watson /* 51106edd2f1SRobert Watson * Allocate and populate the new entry. 51206edd2f1SRobert Watson */ 51306edd2f1SRobert Watson new = malloc(sizeof(*new)); 51406edd2f1SRobert Watson if (NULL == new) { 51506edd2f1SRobert Watson free(pn); 51606edd2f1SRobert Watson ret = ADE_NOMEM; 51706edd2f1SRobert Watson break; 51806edd2f1SRobert Watson } 51906edd2f1SRobert Watson new->at_time = tstamp; 52006edd2f1SRobert Watson new->at_size = stbuf.st_size; 52106edd2f1SRobert Watson new->at_path = pn; 52206edd2f1SRobert Watson 52306edd2f1SRobert Watson /* 52406edd2f1SRobert Watson * Check to see if we have a new head. Otherwise, 52506edd2f1SRobert Watson * walk the tailq from the tail first and do a simple 52606edd2f1SRobert Watson * insertion sort. 52706edd2f1SRobert Watson */ 52806edd2f1SRobert Watson if (TAILQ_EMPTY(&head) || 529aa772005SRobert Watson new->at_time <= TAILQ_FIRST(&head)->at_time) { 53006edd2f1SRobert Watson TAILQ_INSERT_HEAD(&head, new, at_trls); 53106edd2f1SRobert Watson continue; 53206edd2f1SRobert Watson } 53306edd2f1SRobert Watson 53406edd2f1SRobert Watson TAILQ_FOREACH_REVERSE(at, &head, au_trls_head, at_trls) 53506edd2f1SRobert Watson if (new->at_time >= at->at_time) { 53606edd2f1SRobert Watson TAILQ_INSERT_AFTER(&head, at, new, 53706edd2f1SRobert Watson at_trls); 53806edd2f1SRobert Watson break; 53906edd2f1SRobert Watson } 54006edd2f1SRobert Watson 54106edd2f1SRobert Watson } 5423ee3cd17SRobert Watson closedir(dirp); 54306edd2f1SRobert Watson } 54406edd2f1SRobert Watson 54506edd2f1SRobert Watson oldest_time = current_time - expire_age; 54606edd2f1SRobert Watson 54706edd2f1SRobert Watson /* 54806edd2f1SRobert Watson * Expire trail files, oldest (mtime) first, if the given 54906edd2f1SRobert Watson * conditions are met. 55006edd2f1SRobert Watson */ 55106edd2f1SRobert Watson at = TAILQ_FIRST(&head); 55206edd2f1SRobert Watson while (NULL != at) { 55306edd2f1SRobert Watson struct audit_trail *at_next = TAILQ_NEXT(at, at_trls); 55406edd2f1SRobert Watson 55506edd2f1SRobert Watson if (andflg) { 55606edd2f1SRobert Watson if ((expire_size && total_size > expire_size) && 55706edd2f1SRobert Watson (expire_age && at->at_time < oldest_time)) { 55806edd2f1SRobert Watson if (warn_expired) 55906edd2f1SRobert Watson (*warn_expired)(at->at_path); 56006edd2f1SRobert Watson if (unlink(at->at_path) < 0) 56106edd2f1SRobert Watson ret = ADE_EXPIRE; 56206edd2f1SRobert Watson total_size -= at->at_size; 56306edd2f1SRobert Watson } 56406edd2f1SRobert Watson } else { 56506edd2f1SRobert Watson if ((expire_size && total_size > expire_size) || 56606edd2f1SRobert Watson (expire_age && at->at_time < oldest_time)) { 56706edd2f1SRobert Watson if (warn_expired) 56806edd2f1SRobert Watson (*warn_expired)(at->at_path); 56906edd2f1SRobert Watson if (unlink(at->at_path) < 0) 57006edd2f1SRobert Watson ret = ADE_EXPIRE; 57106edd2f1SRobert Watson total_size -= at->at_size; 57206edd2f1SRobert Watson } 57306edd2f1SRobert Watson } 57406edd2f1SRobert Watson 57506edd2f1SRobert Watson free(at->at_path); 57606edd2f1SRobert Watson free(at); 57706edd2f1SRobert Watson at = at_next; 57806edd2f1SRobert Watson } 57906edd2f1SRobert Watson 58006edd2f1SRobert Watson return (ret); 58106edd2f1SRobert Watson } 58206edd2f1SRobert Watson 58306edd2f1SRobert Watson /* 5847a0a89d2SRobert Watson * Parses the "dir" entry in audit_control(5) into an ordered list. Also, will 58506edd2f1SRobert Watson * set the minfree and host values if not already set. Arguments include 58606edd2f1SRobert Watson * function pointers to audit_warn functions for soft and hard limits. Returns: 5877a0a89d2SRobert Watson * ADE_NOERR on success, 5887a0a89d2SRobert Watson * ADE_PARSE error parsing audit_control(5), 5897a0a89d2SRobert Watson * ADE_AUDITON error getting/setting auditon(2) value, 5907a0a89d2SRobert Watson * ADE_NOMEM error allocating memory, 5917a0a89d2SRobert Watson * ADE_SOFTLIM if all the directories are over the soft limit, 5927a0a89d2SRobert Watson * ADE_HARDLIM if all the directories are over the hard limit, 5937a0a89d2SRobert Watson */ 5947a0a89d2SRobert Watson int 5957a0a89d2SRobert Watson auditd_read_dirs(int (*warn_soft)(char *), int (*warn_hard)(char *)) 5967a0a89d2SRobert Watson { 5977a0a89d2SRobert Watson char cur_dir[MAXNAMLEN]; 5987a0a89d2SRobert Watson struct dir_ent *dirent; 5997a0a89d2SRobert Watson struct statfs sfs; 6007a0a89d2SRobert Watson int err; 6017a0a89d2SRobert Watson char soft, hard; 6027a0a89d2SRobert Watson int tcnt = 0; 6037a0a89d2SRobert Watson int scnt = 0; 6047a0a89d2SRobert Watson int hcnt = 0; 6057a0a89d2SRobert Watson 60606edd2f1SRobert Watson if (auditd_minval == -1 && (err = auditd_set_minfree()) != 0) 6077a0a89d2SRobert Watson return (err); 6087a0a89d2SRobert Watson 60906edd2f1SRobert Watson if (auditd_hostlen == -1) 61006edd2f1SRobert Watson auditd_set_host(); 61106edd2f1SRobert Watson 6127a0a89d2SRobert Watson /* 6137a0a89d2SRobert Watson * Init directory q. Force a re-read of the file the next time. 6147a0a89d2SRobert Watson */ 6157a0a89d2SRobert Watson free_dir_q(); 6167a0a89d2SRobert Watson endac(); 6177a0a89d2SRobert Watson 6187a0a89d2SRobert Watson /* 6197a0a89d2SRobert Watson * Read the list of directories into an ordered linked list 6207a0a89d2SRobert Watson * admin's preference, then those over soft limit and, finally, 6217a0a89d2SRobert Watson * those over the hard limit. 6227a0a89d2SRobert Watson * 6237a0a89d2SRobert Watson * XXX We should use the reentrant interfaces once they are 6247a0a89d2SRobert Watson * available. 6257a0a89d2SRobert Watson */ 6267a0a89d2SRobert Watson while (getacdir(cur_dir, MAXNAMLEN) >= 0) { 6277a0a89d2SRobert Watson if (statfs(cur_dir, &sfs) < 0) 6287a0a89d2SRobert Watson continue; /* XXX should warn */ 629aa772005SRobert Watson soft = (sfs.f_bfree < (sfs.f_blocks * auditd_minval / 100 )) ? 63006edd2f1SRobert Watson 1 : 0; 6317a0a89d2SRobert Watson hard = (sfs.f_bfree < AUDIT_HARD_LIMIT_FREE_BLOCKS) ? 1 : 0; 6327a0a89d2SRobert Watson if (soft) { 6337a0a89d2SRobert Watson if (warn_soft) 6347a0a89d2SRobert Watson (*warn_soft)(cur_dir); 6357a0a89d2SRobert Watson scnt++; 6367a0a89d2SRobert Watson } 6377a0a89d2SRobert Watson if (hard) { 6387a0a89d2SRobert Watson if (warn_hard) 6397a0a89d2SRobert Watson (*warn_hard)(cur_dir); 6407a0a89d2SRobert Watson hcnt++; 6417a0a89d2SRobert Watson } 6427a0a89d2SRobert Watson dirent = (struct dir_ent *) malloc(sizeof(struct dir_ent)); 6437a0a89d2SRobert Watson if (dirent == NULL) 6447a0a89d2SRobert Watson return (ADE_NOMEM); 6457a0a89d2SRobert Watson dirent->softlim = soft; 6467a0a89d2SRobert Watson dirent->hardlim = hard; 6477a0a89d2SRobert Watson dirent->dirname = (char *) malloc(MAXNAMLEN); 6487a0a89d2SRobert Watson if (dirent->dirname == NULL) { 6497a0a89d2SRobert Watson free(dirent); 6507a0a89d2SRobert Watson return (ADE_NOMEM); 6517a0a89d2SRobert Watson } 6527a0a89d2SRobert Watson strlcpy(dirent->dirname, cur_dir, MAXNAMLEN); 6537a0a89d2SRobert Watson insert_orderly(dirent); 6547a0a89d2SRobert Watson tcnt++; 6557a0a89d2SRobert Watson } 6567a0a89d2SRobert Watson 6577a0a89d2SRobert Watson if (hcnt == tcnt) 6587a0a89d2SRobert Watson return (ADE_HARDLIM); 6597a0a89d2SRobert Watson if (scnt == tcnt) 6607a0a89d2SRobert Watson return (ADE_SOFTLIM); 6617a0a89d2SRobert Watson return (0); 6627a0a89d2SRobert Watson } 6637a0a89d2SRobert Watson 6647a0a89d2SRobert Watson void 6657a0a89d2SRobert Watson auditd_close_dirs(void) 6667a0a89d2SRobert Watson { 6677a0a89d2SRobert Watson free_dir_q(); 66806edd2f1SRobert Watson auditd_minval = -1; 66906edd2f1SRobert Watson auditd_hostlen = -1; 6707a0a89d2SRobert Watson } 6717a0a89d2SRobert Watson 6727a0a89d2SRobert Watson 6737a0a89d2SRobert Watson /* 6747a0a89d2SRobert Watson * Process the audit event file, obtaining a class mapping for each event, and 6757a0a89d2SRobert Watson * set that mapping into the kernel. Return: 6767a0a89d2SRobert Watson * n number of event mappings that were successfully processed, 6777a0a89d2SRobert Watson * ADE_NOMEM if there was an error allocating memory. 6787a0a89d2SRobert Watson */ 6797a0a89d2SRobert Watson int 6807a0a89d2SRobert Watson auditd_set_evcmap(void) 6817a0a89d2SRobert Watson { 6827a0a89d2SRobert Watson au_event_ent_t ev, *evp; 6837a0a89d2SRobert Watson au_evclass_map_t evc_map; 6847a0a89d2SRobert Watson int ctr = 0; 6857a0a89d2SRobert Watson 6867a0a89d2SRobert Watson /* 6877a0a89d2SRobert Watson * XXX There's a risk here that the BSM library will return NULL 6887a0a89d2SRobert Watson * for an event when it can't properly map it to a class. In that 6897a0a89d2SRobert Watson * case, we will not process any events beyond the one that failed, 6907a0a89d2SRobert Watson * but should. We need a way to get a count of the events. 6917a0a89d2SRobert Watson */ 6927a0a89d2SRobert Watson ev.ae_name = (char *)malloc(AU_EVENT_NAME_MAX); 6937a0a89d2SRobert Watson ev.ae_desc = (char *)malloc(AU_EVENT_DESC_MAX); 694aa772005SRobert Watson if (ev.ae_name == NULL || ev.ae_desc == NULL) { 6957a0a89d2SRobert Watson if (ev.ae_name != NULL) 6967a0a89d2SRobert Watson free(ev.ae_name); 6977a0a89d2SRobert Watson return (ADE_NOMEM); 6987a0a89d2SRobert Watson } 6997a0a89d2SRobert Watson 7007a0a89d2SRobert Watson /* 7017a0a89d2SRobert Watson * XXXRW: Currently we have no way to remove mappings from the kernel 7027a0a89d2SRobert Watson * when they are removed from the file-based mappings. 7037a0a89d2SRobert Watson */ 7047a0a89d2SRobert Watson evp = &ev; 7057a0a89d2SRobert Watson setauevent(); 7067a0a89d2SRobert Watson while ((evp = getauevent_r(evp)) != NULL) { 7077a0a89d2SRobert Watson evc_map.ec_number = evp->ae_number; 7087a0a89d2SRobert Watson evc_map.ec_class = evp->ae_class; 709c0020399SRobert Watson if (audit_set_class(&evc_map, sizeof(evc_map)) == 0) 7107a0a89d2SRobert Watson ctr++; 7117a0a89d2SRobert Watson } 7127a0a89d2SRobert Watson endauevent(); 7137a0a89d2SRobert Watson free(ev.ae_name); 7147a0a89d2SRobert Watson free(ev.ae_desc); 7157a0a89d2SRobert Watson 7167a0a89d2SRobert Watson return (ctr); 7177a0a89d2SRobert Watson } 7187a0a89d2SRobert Watson 7197a0a89d2SRobert Watson /* 7207a0a89d2SRobert Watson * Get the non-attributable event string and set the kernel mask. Return: 7217a0a89d2SRobert Watson * ADE_NOERR on success, 7227a0a89d2SRobert Watson * ADE_PARSE error parsing audit_control(5), 7237a0a89d2SRobert Watson * ADE_AUDITON error setting the mask using auditon(2). 7247a0a89d2SRobert Watson */ 7257a0a89d2SRobert Watson int 7267a0a89d2SRobert Watson auditd_set_namask(void) 7277a0a89d2SRobert Watson { 7287a0a89d2SRobert Watson au_mask_t aumask; 7297a0a89d2SRobert Watson char naeventstr[NA_EVENT_STR_SIZE]; 7307a0a89d2SRobert Watson 731aa772005SRobert Watson if (getacna(naeventstr, NA_EVENT_STR_SIZE) != 0 || 732aa772005SRobert Watson getauditflagsbin(naeventstr, &aumask) != 0) 7337a0a89d2SRobert Watson return (ADE_PARSE); 7347a0a89d2SRobert Watson 735c0020399SRobert Watson if (audit_set_kmask(&aumask, sizeof(aumask)) != 0) 7367a0a89d2SRobert Watson return (ADE_AUDITON); 7377a0a89d2SRobert Watson 7387a0a89d2SRobert Watson return (ADE_NOERR); 7397a0a89d2SRobert Watson } 7407a0a89d2SRobert Watson 7417a0a89d2SRobert Watson /* 7427a0a89d2SRobert Watson * Set the audit control policy if a policy is configured in audit_control(5), 7437a0a89d2SRobert Watson * implement the policy. However, if one isn't defined or if there is an error 7447a0a89d2SRobert Watson * parsing the control file, set AUDIT_CNT to avoid leaving the system in a 7457a0a89d2SRobert Watson * fragile state. Return: 7467a0a89d2SRobert Watson * ADE_NOERR on success, 7477a0a89d2SRobert Watson * ADE_PARSE error parsing audit_control(5), 7487a0a89d2SRobert Watson * ADE_AUDITON error setting policy using auditon(2). 7497a0a89d2SRobert Watson */ 7507a0a89d2SRobert Watson int 7517a0a89d2SRobert Watson auditd_set_policy(void) 7527a0a89d2SRobert Watson { 753c0020399SRobert Watson int policy; 7547a0a89d2SRobert Watson char polstr[POL_STR_SIZE]; 7557a0a89d2SRobert Watson 756aa772005SRobert Watson if (getacpol(polstr, POL_STR_SIZE) != 0 || 757aa772005SRobert Watson au_strtopol(polstr, &policy) != 0) { 7587a0a89d2SRobert Watson policy = AUDIT_CNT; 759c0020399SRobert Watson if (audit_set_policy(&policy) != 0) 7607a0a89d2SRobert Watson return (ADE_AUDITON); 7617a0a89d2SRobert Watson return (ADE_PARSE); 7627a0a89d2SRobert Watson } 7637a0a89d2SRobert Watson 764c0020399SRobert Watson if (audit_set_policy(&policy) != 0) 7657a0a89d2SRobert Watson return (ADE_AUDITON); 7667a0a89d2SRobert Watson 7677a0a89d2SRobert Watson return (ADE_NOERR); 7687a0a89d2SRobert Watson } 7697a0a89d2SRobert Watson 7707a0a89d2SRobert Watson /* 7717a0a89d2SRobert Watson * Set trail rotation size. Return: 7727a0a89d2SRobert Watson * ADE_NOERR on success, 7737a0a89d2SRobert Watson * ADE_PARSE error parsing audit_control(5), 7747a0a89d2SRobert Watson * ADE_AUDITON error setting file size using auditon(2). 7757a0a89d2SRobert Watson */ 7767a0a89d2SRobert Watson int 7777a0a89d2SRobert Watson auditd_set_fsize(void) 7787a0a89d2SRobert Watson { 7797a0a89d2SRobert Watson size_t filesz; 7807a0a89d2SRobert Watson au_fstat_t au_fstat; 7817a0a89d2SRobert Watson 7827a0a89d2SRobert Watson /* 7837a0a89d2SRobert Watson * Set trail rotation size. 7847a0a89d2SRobert Watson */ 7857a0a89d2SRobert Watson if (getacfilesz(&filesz) != 0) 7867a0a89d2SRobert Watson return (ADE_PARSE); 7877a0a89d2SRobert Watson 7887a0a89d2SRobert Watson bzero(&au_fstat, sizeof(au_fstat)); 7897a0a89d2SRobert Watson au_fstat.af_filesz = filesz; 790c0020399SRobert Watson if (audit_set_fsize(&au_fstat, sizeof(au_fstat)) != 0) 7917a0a89d2SRobert Watson return (ADE_AUDITON); 7927a0a89d2SRobert Watson 7937a0a89d2SRobert Watson return (ADE_NOERR); 7947a0a89d2SRobert Watson } 7957a0a89d2SRobert Watson 796aa772005SRobert Watson static void 797aa772005SRobert Watson inject_dist(const char *fromname, char *toname, size_t tonamesize) 798aa772005SRobert Watson { 799aa772005SRobert Watson char *ptr; 800aa772005SRobert Watson 801aa772005SRobert Watson ptr = strrchr(fromname, '/'); 802aa772005SRobert Watson assert(ptr != NULL); 803aa772005SRobert Watson assert(ptr - fromname < (ssize_t)tonamesize); 804aa772005SRobert Watson strlcpy(toname, fromname, ptr - fromname + 1); 805aa772005SRobert Watson strlcat(toname, "/dist/", tonamesize); 806aa772005SRobert Watson strlcat(toname, ptr + 1, tonamesize); 807aa772005SRobert Watson } 808aa772005SRobert Watson 809aa772005SRobert Watson static int 810aa772005SRobert Watson auditdist_link(const char *filename) 811aa772005SRobert Watson { 812aa772005SRobert Watson char fname[MAXPATHLEN]; 813aa772005SRobert Watson 814aa772005SRobert Watson if (auditd_dist) { 815aa772005SRobert Watson inject_dist(filename, fname, sizeof(fname)); 816aa772005SRobert Watson /* Ignore errors. */ 817aa772005SRobert Watson (void) link(filename, fname); 818aa772005SRobert Watson } 819aa772005SRobert Watson 820aa772005SRobert Watson return (0); 821aa772005SRobert Watson } 822aa772005SRobert Watson 823aa772005SRobert Watson int 824aa772005SRobert Watson auditd_rename(const char *fromname, const char *toname) 825aa772005SRobert Watson { 826aa772005SRobert Watson char fname[MAXPATHLEN], tname[MAXPATHLEN]; 827aa772005SRobert Watson 828aa772005SRobert Watson if (auditd_dist) { 829aa772005SRobert Watson inject_dist(fromname, fname, sizeof(fname)); 830aa772005SRobert Watson inject_dist(toname, tname, sizeof(tname)); 831aa772005SRobert Watson /* Ignore errors. */ 832aa772005SRobert Watson (void) rename(fname, tname); 833aa772005SRobert Watson } 834aa772005SRobert Watson 835aa772005SRobert Watson return (rename(fromname, toname)); 836aa772005SRobert Watson } 837aa772005SRobert Watson 8387a0a89d2SRobert Watson /* 839aa772005SRobert Watson * Create the new audit file with appropriate permissions and ownership. 840aa772005SRobert Watson * Call auditctl(2) for this file. 841aa772005SRobert Watson * Try to clean up if something goes wrong. 842aa772005SRobert Watson * *errorp is modified only on auditctl(2) failure. 8437a0a89d2SRobert Watson */ 8447a0a89d2SRobert Watson static int 845aa772005SRobert Watson open_trail(char *fname, gid_t gid, int *errorp) 8467a0a89d2SRobert Watson { 847aa772005SRobert Watson int fd; 8487a0a89d2SRobert Watson 849aa772005SRobert Watson /* XXXPJD: What should we do if the file already exists? */ 850aa772005SRobert Watson fd = open(fname, O_RDONLY | O_CREAT, S_IRUSR); 8517a0a89d2SRobert Watson if (fd < 0) 8527a0a89d2SRobert Watson return (-1); 853aa772005SRobert Watson if (fchown(fd, -1, gid) < 0 || fchmod(fd, S_IRUSR | S_IRGRP) < 0) { 854aa772005SRobert Watson (void) close(fd); 8557a0a89d2SRobert Watson (void) unlink(fname); 8567a0a89d2SRobert Watson return (-1); 8577a0a89d2SRobert Watson } 858aa772005SRobert Watson (void) close(fd); 859aa772005SRobert Watson if (auditctl(fname) < 0) { 860aa772005SRobert Watson *errorp = errno; 861aa772005SRobert Watson (void) unlink(fname); 862aa772005SRobert Watson return (-1); 863aa772005SRobert Watson } 864aa772005SRobert Watson (void) auditdist_link(fname); 865aa772005SRobert Watson return (0); 8667a0a89d2SRobert Watson } 8677a0a89d2SRobert Watson 8687a0a89d2SRobert Watson /* 8697a0a89d2SRobert Watson * Create the new audit trail file, swap with existing audit file. Arguments 8707a0a89d2SRobert Watson * include timestamp for the filename, a pointer to a string for returning the 8717a0a89d2SRobert Watson * new file name, GID for trail file, and audit_warn function pointer for 8727a0a89d2SRobert Watson * 'getacdir()' errors. Returns: 8737a0a89d2SRobert Watson * ADE_NOERR on success, 8747a0a89d2SRobert Watson * ADE_STRERR if the file name string could not be created, 8757a0a89d2SRobert Watson * ADE_SWAPERR if the audit trail file could not be swapped, 8767a0a89d2SRobert Watson * ADE_ACTL if the auditctl(2) call failed but file swap still 8777a0a89d2SRobert Watson * successful. 8787a0a89d2SRobert Watson * ADE_ACTLERR if the auditctl(2) call failed and file swap failed. 8797a0a89d2SRobert Watson * ADE_SYMLINK if symlink(2) failed updating the current link. 8807a0a89d2SRobert Watson */ 8817a0a89d2SRobert Watson int 8827a0a89d2SRobert Watson auditd_swap_trail(char *TS, char **newfile, gid_t gid, 8837a0a89d2SRobert Watson int (*warn_getacdir)(char *)) 8847a0a89d2SRobert Watson { 885aa772005SRobert Watson char timestr[FILENAME_LEN + 1]; 8867a0a89d2SRobert Watson char *fn; 8877a0a89d2SRobert Watson struct dir_ent *dirent; 8887a0a89d2SRobert Watson int saverrno = 0; 8897a0a89d2SRobert Watson 890aa772005SRobert Watson if (strlen(TS) != TIMESTAMP_LEN || 891aa772005SRobert Watson snprintf(timestr, sizeof(timestr), "%s.%s", TS, 892aa772005SRobert Watson NOT_TERMINATED) < 0) { 8937a0a89d2SRobert Watson errno = EINVAL; 8947a0a89d2SRobert Watson return (ADE_STRERR); 8957a0a89d2SRobert Watson } 8967a0a89d2SRobert Watson 8977a0a89d2SRobert Watson /* Try until we succeed. */ 89806edd2f1SRobert Watson TAILQ_FOREACH(dirent, &dir_q, dirs) { 8997a0a89d2SRobert Watson if (dirent->hardlim) 9007a0a89d2SRobert Watson continue; 9017a0a89d2SRobert Watson if ((fn = affixdir(timestr, dirent)) == NULL) 9027a0a89d2SRobert Watson return (ADE_STRERR); 9037a0a89d2SRobert Watson 9047a0a89d2SRobert Watson /* 905aa772005SRobert Watson * Create the file and pass to the kernel if all went well. 9067a0a89d2SRobert Watson */ 907aa772005SRobert Watson if (open_trail(fn, gid, &saverrno) == 0) { 9087a0a89d2SRobert Watson /* Success. */ 9097a0a89d2SRobert Watson *newfile = fn; 9107a0a89d2SRobert Watson if (saverrno) { 9117a0a89d2SRobert Watson /* 9127a0a89d2SRobert Watson * auditctl() failed but still 9137a0a89d2SRobert Watson * successful. Return errno and "soft" 9147a0a89d2SRobert Watson * error. 9157a0a89d2SRobert Watson */ 9167a0a89d2SRobert Watson errno = saverrno; 9177a0a89d2SRobert Watson return (ADE_ACTL); 9187a0a89d2SRobert Watson } 9197a0a89d2SRobert Watson return (ADE_NOERR); 9207a0a89d2SRobert Watson } 921aa772005SRobert Watson /* 922aa772005SRobert Watson * auditctl failed setting log file. Try again. 923aa772005SRobert Watson */ 9247a0a89d2SRobert Watson /* 9257a0a89d2SRobert Watson * Tell the administrator about lack of permissions for dir. 9267a0a89d2SRobert Watson */ 9277a0a89d2SRobert Watson if (warn_getacdir != NULL) 9287a0a89d2SRobert Watson (*warn_getacdir)(dirent->dirname); 9297a0a89d2SRobert Watson } 9307a0a89d2SRobert Watson if (saverrno) { 9317a0a89d2SRobert Watson errno = saverrno; 9327a0a89d2SRobert Watson return (ADE_ACTLERR); 9337a0a89d2SRobert Watson } else 9347a0a89d2SRobert Watson return (ADE_SWAPERR); 9357a0a89d2SRobert Watson } 9367a0a89d2SRobert Watson 9377a0a89d2SRobert Watson /* 9387a0a89d2SRobert Watson * Mask calling process from being audited. Returns: 9397a0a89d2SRobert Watson * ADE_NOERR on success, 9407a0a89d2SRobert Watson * ADE_SETAUDIT if setaudit(2) fails. 9417a0a89d2SRobert Watson */ 94206edd2f1SRobert Watson #ifdef __APPLE__ 94306edd2f1SRobert Watson int 94406edd2f1SRobert Watson auditd_prevent_audit(void) 94506edd2f1SRobert Watson { 94606edd2f1SRobert Watson auditinfo_addr_t aia; 94706edd2f1SRobert Watson 94806edd2f1SRobert Watson /* 94906edd2f1SRobert Watson * To prevent event feedback cycles and avoid audit becoming stalled if 95006edd2f1SRobert Watson * auditing is suspended we mask this processes events from being 95106edd2f1SRobert Watson * audited. We allow the uid, tid, and mask fields to be implicitly 95206edd2f1SRobert Watson * set to zero, but do set the audit session ID to the PID. 95306edd2f1SRobert Watson * 95406edd2f1SRobert Watson * XXXRW: Is there more to it than this? 95506edd2f1SRobert Watson */ 95606edd2f1SRobert Watson bzero(&aia, sizeof(aia)); 95706edd2f1SRobert Watson aia.ai_asid = AU_ASSIGN_ASID; 95806edd2f1SRobert Watson aia.ai_termid.at_type = AU_IPv4; 95906edd2f1SRobert Watson if (setaudit_addr(&aia, sizeof(aia)) != 0) 96006edd2f1SRobert Watson return (ADE_SETAUDIT); 96106edd2f1SRobert Watson return (ADE_NOERR); 96206edd2f1SRobert Watson } 96306edd2f1SRobert Watson #else 9647a0a89d2SRobert Watson int 9657a0a89d2SRobert Watson auditd_prevent_audit(void) 9667a0a89d2SRobert Watson { 9677a0a89d2SRobert Watson auditinfo_t ai; 9687a0a89d2SRobert Watson 9697a0a89d2SRobert Watson /* 9707a0a89d2SRobert Watson * To prevent event feedback cycles and avoid audit becoming stalled if 9717a0a89d2SRobert Watson * auditing is suspended we mask this processes events from being 9727a0a89d2SRobert Watson * audited. We allow the uid, tid, and mask fields to be implicitly 9737a0a89d2SRobert Watson * set to zero, but do set the audit session ID to the PID. 9747a0a89d2SRobert Watson * 9757a0a89d2SRobert Watson * XXXRW: Is there more to it than this? 9767a0a89d2SRobert Watson */ 9777a0a89d2SRobert Watson bzero(&ai, sizeof(ai)); 9787a0a89d2SRobert Watson ai.ai_asid = getpid(); 9797a0a89d2SRobert Watson if (setaudit(&ai) != 0) 9807a0a89d2SRobert Watson return (ADE_SETAUDIT); 9817a0a89d2SRobert Watson return (ADE_NOERR); 9827a0a89d2SRobert Watson } 983aa772005SRobert Watson #endif /* !__APPLE__ */ 9847a0a89d2SRobert Watson 9857a0a89d2SRobert Watson /* 9867a0a89d2SRobert Watson * Generate and submit audit record for audit startup or shutdown. The event 9877a0a89d2SRobert Watson * argument can be AUE_audit_recovery, AUE_audit_startup or 9887a0a89d2SRobert Watson * AUE_audit_shutdown. The path argument will add a path token, if not NULL. 9897a0a89d2SRobert Watson * Returns: 9907a0a89d2SRobert Watson * AUE_NOERR on success, 9917a0a89d2SRobert Watson * ADE_NOMEM if memory allocation fails, 9927a0a89d2SRobert Watson * ADE_AU_OPEN if au_open(3) fails, 9937a0a89d2SRobert Watson * ADE_AU_CLOSE if au_close(3) fails. 9947a0a89d2SRobert Watson */ 9957a0a89d2SRobert Watson int 9967a0a89d2SRobert Watson auditd_gen_record(int event, char *path) 9977a0a89d2SRobert Watson { 9987a0a89d2SRobert Watson int aufd; 9997a0a89d2SRobert Watson uid_t uid; 10007a0a89d2SRobert Watson pid_t pid; 10017a0a89d2SRobert Watson char *autext = NULL; 10027a0a89d2SRobert Watson token_t *tok; 10037a0a89d2SRobert Watson struct auditinfo_addr aia; 10047a0a89d2SRobert Watson 10057a0a89d2SRobert Watson if (event == AUE_audit_startup) 10067a0a89d2SRobert Watson asprintf(&autext, "%s::Audit startup", getprogname()); 10077a0a89d2SRobert Watson else if (event == AUE_audit_shutdown) 10087a0a89d2SRobert Watson asprintf(&autext, "%s::Audit shutdown", getprogname()); 10097a0a89d2SRobert Watson else if (event == AUE_audit_recovery) 10107a0a89d2SRobert Watson asprintf(&autext, "%s::Audit recovery", getprogname()); 10117a0a89d2SRobert Watson else 10127a0a89d2SRobert Watson return (ADE_INVAL); 10137a0a89d2SRobert Watson if (autext == NULL) 10147a0a89d2SRobert Watson return (ADE_NOMEM); 10157a0a89d2SRobert Watson 10167a0a89d2SRobert Watson if ((aufd = au_open()) == -1) { 10177a0a89d2SRobert Watson free(autext); 10187a0a89d2SRobert Watson return (ADE_AU_OPEN); 10197a0a89d2SRobert Watson } 10207a0a89d2SRobert Watson bzero(&aia, sizeof(aia)); 10217a0a89d2SRobert Watson uid = getuid(); pid = getpid(); 10227a0a89d2SRobert Watson if ((tok = au_to_subject32_ex(uid, geteuid(), getegid(), uid, getgid(), 10237a0a89d2SRobert Watson pid, pid, &aia.ai_termid)) != NULL) 10247a0a89d2SRobert Watson au_write(aufd, tok); 10257a0a89d2SRobert Watson if ((tok = au_to_text(autext)) != NULL) 10267a0a89d2SRobert Watson au_write(aufd, tok); 10277a0a89d2SRobert Watson free(autext); 10287a0a89d2SRobert Watson if (path != NULL && (tok = au_to_path(path)) != NULL) 10297a0a89d2SRobert Watson au_write(aufd, tok); 10307a0a89d2SRobert Watson if ((tok = au_to_return32(0, 0)) != NULL) 10317a0a89d2SRobert Watson au_write(aufd, tok); 10327a0a89d2SRobert Watson if (au_close(aufd, 1, event) == -1) 10337a0a89d2SRobert Watson return (ADE_AU_CLOSE); 10347a0a89d2SRobert Watson 10357a0a89d2SRobert Watson return (ADE_NOERR); 10367a0a89d2SRobert Watson } 10377a0a89d2SRobert Watson 10387a0a89d2SRobert Watson /* 10397a0a89d2SRobert Watson * Check for a 'current' symlink and do crash recovery, if needed. Create a new 10407a0a89d2SRobert Watson * 'current' symlink. The argument 'curfile' is the file the 'current' symlink 10417a0a89d2SRobert Watson * should point to. Returns: 10427a0a89d2SRobert Watson * ADE_NOERR on success, 10437a0a89d2SRobert Watson * ADE_AU_OPEN if au_open(3) fails, 10447a0a89d2SRobert Watson * ADE_AU_CLOSE if au_close(3) fails. 10457a0a89d2SRobert Watson * ADE_RENAME if error renaming audit trail file, 10467a0a89d2SRobert Watson * ADE_READLINK if error reading the 'current' link, 10477a0a89d2SRobert Watson * ADE_SYMLINK if error creating 'current' link. 10487a0a89d2SRobert Watson */ 10497a0a89d2SRobert Watson int 10507a0a89d2SRobert Watson auditd_new_curlink(char *curfile) 10517a0a89d2SRobert Watson { 10527a0a89d2SRobert Watson int len, err; 10537a0a89d2SRobert Watson char *ptr; 10547a0a89d2SRobert Watson char *path = NULL; 10557a0a89d2SRobert Watson struct stat sb; 10567a0a89d2SRobert Watson char recoveredname[MAXPATHLEN]; 10577a0a89d2SRobert Watson char newname[MAXPATHLEN]; 10587a0a89d2SRobert Watson 10597a0a89d2SRobert Watson /* 10607a0a89d2SRobert Watson * Check to see if audit was shutdown properly. If not, clean up, 10617a0a89d2SRobert Watson * recover previous audit trail file, and generate audit record. 10627a0a89d2SRobert Watson */ 1063aa772005SRobert Watson len = readlink(AUDIT_CURRENT_LINK, recoveredname, 1064aa772005SRobert Watson sizeof(recoveredname) - 1); 10657a0a89d2SRobert Watson if (len > 0) { 10667a0a89d2SRobert Watson /* 'current' exist but is it pointing at a valid file? */ 10677a0a89d2SRobert Watson recoveredname[len++] = '\0'; 10687a0a89d2SRobert Watson if (stat(recoveredname, &sb) == 0) { 10697a0a89d2SRobert Watson /* Yes, rename it to a crash recovery file. */ 1070aa772005SRobert Watson strlcpy(newname, recoveredname, sizeof(newname)); 10717a0a89d2SRobert Watson 10727a0a89d2SRobert Watson if ((ptr = strstr(newname, NOT_TERMINATED)) != NULL) { 107306edd2f1SRobert Watson memcpy(ptr, CRASH_RECOVERY, POSTFIX_LEN); 1074aa772005SRobert Watson if (auditd_rename(recoveredname, newname) != 0) 10757a0a89d2SRobert Watson return (ADE_RENAME); 10767a0a89d2SRobert Watson } else 10777a0a89d2SRobert Watson return (ADE_STRERR); 10787a0a89d2SRobert Watson 10797a0a89d2SRobert Watson path = newname; 10807a0a89d2SRobert Watson } 10817a0a89d2SRobert Watson 10827a0a89d2SRobert Watson /* 'current' symlink is (now) invalid so remove it. */ 10837a0a89d2SRobert Watson (void) unlink(AUDIT_CURRENT_LINK); 10847a0a89d2SRobert Watson 10857a0a89d2SRobert Watson /* Note the crash recovery in current audit trail */ 10867a0a89d2SRobert Watson err = auditd_gen_record(AUE_audit_recovery, path); 10877a0a89d2SRobert Watson if (err) 10887a0a89d2SRobert Watson return (err); 10897a0a89d2SRobert Watson } 10907a0a89d2SRobert Watson 10917a0a89d2SRobert Watson if (len < 0 && errno != ENOENT) 10927a0a89d2SRobert Watson return (ADE_READLINK); 10937a0a89d2SRobert Watson 10947a0a89d2SRobert Watson if (symlink(curfile, AUDIT_CURRENT_LINK) != 0) 10957a0a89d2SRobert Watson return (ADE_SYMLINK); 10967a0a89d2SRobert Watson 10977a0a89d2SRobert Watson return (0); 10987a0a89d2SRobert Watson } 10997a0a89d2SRobert Watson 11007a0a89d2SRobert Watson /* 11017a0a89d2SRobert Watson * Do just what we need to quickly start auditing. Assume no system logging or 11027a0a89d2SRobert Watson * notify. Return: 11037a0a89d2SRobert Watson * 0 on success, 11047a0a89d2SRobert Watson * -1 on failure. 11057a0a89d2SRobert Watson */ 11067a0a89d2SRobert Watson int 11077a0a89d2SRobert Watson audit_quick_start(void) 11087a0a89d2SRobert Watson { 11097a0a89d2SRobert Watson int err; 111006edd2f1SRobert Watson char *newfile = NULL; 11117a0a89d2SRobert Watson time_t tt; 1112aa772005SRobert Watson char TS[TIMESTAMP_LEN + 1]; 111306edd2f1SRobert Watson int ret = 0; 11147a0a89d2SRobert Watson 11157a0a89d2SRobert Watson /* 11167a0a89d2SRobert Watson * Mask auditing of this process. 11177a0a89d2SRobert Watson */ 11187a0a89d2SRobert Watson if (auditd_prevent_audit() != 0) 11197a0a89d2SRobert Watson return (-1); 11207a0a89d2SRobert Watson 11217a0a89d2SRobert Watson /* 11227a0a89d2SRobert Watson * Read audit_control and get log directories. 11237a0a89d2SRobert Watson */ 11247a0a89d2SRobert Watson err = auditd_read_dirs(NULL, NULL); 11257a0a89d2SRobert Watson if (err != ADE_NOERR && err != ADE_SOFTLIM) 11267a0a89d2SRobert Watson return (-1); 11277a0a89d2SRobert Watson 11287a0a89d2SRobert Watson /* 1129aa772005SRobert Watson * Setup trail file distribution. 1130aa772005SRobert Watson */ 1131aa772005SRobert Watson (void) auditd_set_dist(); 1132aa772005SRobert Watson 1133aa772005SRobert Watson /* 11347a0a89d2SRobert Watson * Create a new audit trail log. 11357a0a89d2SRobert Watson */ 1136aa772005SRobert Watson if (getTSstr(tt, TS, sizeof(TS)) != 0) 11377a0a89d2SRobert Watson return (-1); 11387a0a89d2SRobert Watson err = auditd_swap_trail(TS, &newfile, getgid(), NULL); 113906edd2f1SRobert Watson if (err != ADE_NOERR && err != ADE_ACTL) { 114006edd2f1SRobert Watson ret = -1; 114106edd2f1SRobert Watson goto out; 114206edd2f1SRobert Watson } 11437a0a89d2SRobert Watson 11447a0a89d2SRobert Watson /* 11457a0a89d2SRobert Watson * Add the current symlink and recover from crash, if needed. 11467a0a89d2SRobert Watson */ 114706edd2f1SRobert Watson if (auditd_new_curlink(newfile) != 0) { 114806edd2f1SRobert Watson ret = -1; 114906edd2f1SRobert Watson goto out; 115006edd2f1SRobert Watson } 11517a0a89d2SRobert Watson 11527a0a89d2SRobert Watson /* 11537a0a89d2SRobert Watson * At this point auditing has started so generate audit start-up record. 11547a0a89d2SRobert Watson */ 115506edd2f1SRobert Watson if (auditd_gen_record(AUE_audit_startup, NULL) != 0) { 115606edd2f1SRobert Watson ret = -1; 115706edd2f1SRobert Watson goto out; 115806edd2f1SRobert Watson } 11597a0a89d2SRobert Watson 11607a0a89d2SRobert Watson /* 11617a0a89d2SRobert Watson * Configure the audit controls. 11627a0a89d2SRobert Watson */ 11637a0a89d2SRobert Watson (void) auditd_set_evcmap(); 11647a0a89d2SRobert Watson (void) auditd_set_namask(); 11657a0a89d2SRobert Watson (void) auditd_set_policy(); 11667a0a89d2SRobert Watson (void) auditd_set_fsize(); 11677a0a89d2SRobert Watson (void) auditd_set_minfree(); 11687a0a89d2SRobert Watson (void) auditd_set_host(); 11697a0a89d2SRobert Watson 117006edd2f1SRobert Watson out: 117106edd2f1SRobert Watson if (newfile != NULL) 117206edd2f1SRobert Watson free(newfile); 117306edd2f1SRobert Watson 117406edd2f1SRobert Watson return (ret); 11757a0a89d2SRobert Watson } 11767a0a89d2SRobert Watson 11777a0a89d2SRobert Watson /* 11787a0a89d2SRobert Watson * Shut down auditing quickly. Assumes that is only called on system shutdown. 11797a0a89d2SRobert Watson * Returns: 11807a0a89d2SRobert Watson * 0 on success, 11817a0a89d2SRobert Watson * -1 on failure. 11827a0a89d2SRobert Watson */ 11837a0a89d2SRobert Watson int 11847a0a89d2SRobert Watson audit_quick_stop(void) 11857a0a89d2SRobert Watson { 11867a0a89d2SRobert Watson int len; 1187c0020399SRobert Watson int cond; 11887a0a89d2SRobert Watson char *ptr; 11897a0a89d2SRobert Watson time_t tt; 11907a0a89d2SRobert Watson char oldname[MAXPATHLEN]; 11917a0a89d2SRobert Watson char newname[MAXPATHLEN]; 1192aa772005SRobert Watson char TS[TIMESTAMP_LEN + 1]; 11937a0a89d2SRobert Watson 11947a0a89d2SRobert Watson /* 11957a0a89d2SRobert Watson * Auditing already disabled? 11967a0a89d2SRobert Watson */ 1197c0020399SRobert Watson if (audit_get_cond(&cond) != 0) 11987a0a89d2SRobert Watson return (-1); 1199c74c7b73SRobert Watson if (cond == AUC_NOAUDIT) 12007a0a89d2SRobert Watson return (0); 12017a0a89d2SRobert Watson 12027a0a89d2SRobert Watson /* 12037a0a89d2SRobert Watson * Generate audit shutdown record. 12047a0a89d2SRobert Watson */ 12057a0a89d2SRobert Watson (void) auditd_gen_record(AUE_audit_shutdown, NULL); 12067a0a89d2SRobert Watson 12077a0a89d2SRobert Watson /* 12087a0a89d2SRobert Watson * Shutdown auditing in the kernel. 12097a0a89d2SRobert Watson */ 12107a0a89d2SRobert Watson cond = AUC_DISABLED; 1211c0020399SRobert Watson if (audit_set_cond(&cond) != 0) 12127a0a89d2SRobert Watson return (-1); 12137a0a89d2SRobert Watson #ifdef __BSM_INTERNAL_NOTIFY_KEY 12147a0a89d2SRobert Watson notify_post(__BSM_INTERNAL_NOTIFY_KEY); 12157a0a89d2SRobert Watson #endif 12167a0a89d2SRobert Watson 12177a0a89d2SRobert Watson /* 12187a0a89d2SRobert Watson * Rename last audit trail and remove 'current' link. 12197a0a89d2SRobert Watson */ 1220aa772005SRobert Watson len = readlink(AUDIT_CURRENT_LINK, oldname, sizeof(oldname) - 1); 12217a0a89d2SRobert Watson if (len < 0) 12227a0a89d2SRobert Watson return (-1); 12237a0a89d2SRobert Watson oldname[len++] = '\0'; 12247a0a89d2SRobert Watson 1225aa772005SRobert Watson if (getTSstr(tt, TS, sizeof(TS)) != 0) 12267a0a89d2SRobert Watson return (-1); 12277a0a89d2SRobert Watson 1228aa772005SRobert Watson strlcpy(newname, oldname, sizeof(newname)); 12297a0a89d2SRobert Watson 12307a0a89d2SRobert Watson if ((ptr = strstr(newname, NOT_TERMINATED)) != NULL) { 123106edd2f1SRobert Watson memcpy(ptr, TS, POSTFIX_LEN); 1232aa772005SRobert Watson if (auditd_rename(oldname, newname) != 0) 12337a0a89d2SRobert Watson return (-1); 12347a0a89d2SRobert Watson } else 12357a0a89d2SRobert Watson return (-1); 12367a0a89d2SRobert Watson 12377a0a89d2SRobert Watson (void) unlink(AUDIT_CURRENT_LINK); 12387a0a89d2SRobert Watson 12397a0a89d2SRobert Watson return (0); 12407a0a89d2SRobert Watson } 1241