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 * 29c0020399SRobert Watson * $P4: //depot/projects/trustedbsd/openbsm/libauditd/auditd_lib.c#10 $ 307a0a89d2SRobert Watson */ 317a0a89d2SRobert Watson 327a0a89d2SRobert Watson #include <sys/param.h> 337a0a89d2SRobert Watson 347a0a89d2SRobert Watson #include <config/config.h> 357a0a89d2SRobert Watson 367a0a89d2SRobert Watson #include <sys/dirent.h> 377a0a89d2SRobert Watson #ifdef HAVE_FULL_QUEUE_H 387a0a89d2SRobert Watson #include <sys/queue.h> 397a0a89d2SRobert Watson #else /* !HAVE_FULL_QUEUE_H */ 407a0a89d2SRobert Watson #include <compat/queue.h> 417a0a89d2SRobert Watson #endif /* !HAVE_FULL_QUEUE_H */ 42c0020399SRobert Watson #include <sys/mount.h> 43c0020399SRobert Watson #include <sys/socket.h> 447a0a89d2SRobert Watson 457a0a89d2SRobert Watson #include <sys/stat.h> 467a0a89d2SRobert Watson #include <sys/time.h> 477a0a89d2SRobert Watson 487a0a89d2SRobert Watson #include <netinet/in.h> 497a0a89d2SRobert Watson 507a0a89d2SRobert Watson #include <bsm/audit.h> 517a0a89d2SRobert Watson #include <bsm/audit_uevents.h> 527a0a89d2SRobert Watson #include <bsm/auditd_lib.h> 537a0a89d2SRobert Watson #include <bsm/libbsm.h> 547a0a89d2SRobert Watson 5506edd2f1SRobert Watson #include <dirent.h> 567a0a89d2SRobert Watson #include <err.h> 577a0a89d2SRobert Watson #include <errno.h> 587a0a89d2SRobert Watson #include <fcntl.h> 597a0a89d2SRobert Watson #include <stdio.h> 607a0a89d2SRobert Watson #include <string.h> 617a0a89d2SRobert Watson #include <stdlib.h> 627a0a89d2SRobert Watson #include <time.h> 637a0a89d2SRobert Watson #include <unistd.h> 647a0a89d2SRobert Watson #include <netdb.h> 657a0a89d2SRobert Watson 667a0a89d2SRobert Watson #ifdef __APPLE__ 677a0a89d2SRobert Watson #include <notify.h> 687a0a89d2SRobert Watson #ifndef __BSM_INTERNAL_NOTIFY_KEY 697a0a89d2SRobert Watson #define __BSM_INTERNAL_NOTIFY_KEY "com.apple.audit.change" 707a0a89d2SRobert Watson #endif /* __BSM_INTERNAL_NOTIFY_KEY */ 717a0a89d2SRobert Watson #endif /* __APPLE__ */ 727a0a89d2SRobert Watson 737a0a89d2SRobert Watson /* 747a0a89d2SRobert Watson * XXX This is temporary until this is moved to <bsm/audit.h> and shared with 757a0a89d2SRobert Watson * the kernel. 767a0a89d2SRobert Watson */ 777a0a89d2SRobert Watson #ifndef AUDIT_HARD_LIMIT_FREE_BLOCKS 787a0a89d2SRobert Watson #define AUDIT_HARD_LIMIT_FREE_BLOCKS 4 797a0a89d2SRobert Watson #endif 807a0a89d2SRobert Watson 8106edd2f1SRobert Watson /* 8206edd2f1SRobert Watson * Number of seconds to January 1, 2000 8306edd2f1SRobert Watson */ 8406edd2f1SRobert Watson #define JAN_01_2000 946598400 8506edd2f1SRobert Watson 867a0a89d2SRobert Watson struct dir_ent { 877a0a89d2SRobert Watson char *dirname; 887a0a89d2SRobert Watson uint8_t softlim; 897a0a89d2SRobert Watson uint8_t hardlim; 907a0a89d2SRobert Watson TAILQ_ENTRY(dir_ent) dirs; 917a0a89d2SRobert Watson }; 927a0a89d2SRobert Watson 937a0a89d2SRobert Watson static TAILQ_HEAD(, dir_ent) dir_q; 9406edd2f1SRobert Watson 9506edd2f1SRobert Watson struct audit_trail { 9606edd2f1SRobert Watson time_t at_time; 9706edd2f1SRobert Watson char *at_path; 9806edd2f1SRobert Watson off_t at_size; 9906edd2f1SRobert Watson 10006edd2f1SRobert Watson TAILQ_ENTRY(audit_trail) at_trls; 10106edd2f1SRobert Watson }; 10206edd2f1SRobert Watson 10306edd2f1SRobert Watson static int auditd_minval = -1; 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 1337a0a89d2SRobert Watson #define NA_EVENT_STR_SIZE 25 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 /* 1537a0a89d2SRobert 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 */ 1827a0a89d2SRobert Watson if (strlen(name) != (FILENAME_LEN - 1)) { 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 /* 2217a0a89d2SRobert Watson * Get the host from audit_control(5) and set it in the audit kernel 2227a0a89d2SRobert Watson * information. Return: 2237a0a89d2SRobert Watson * ADE_NOERR on success. 2247a0a89d2SRobert Watson * ADE_PARSE error parsing audit_control(5). 2257a0a89d2SRobert Watson * ADE_AUDITON error getting/setting auditon(2) value. 2267a0a89d2SRobert Watson * ADE_GETADDR error getting address info for host. 2277a0a89d2SRobert Watson * ADE_ADDRFAM un-supported address family. 2287a0a89d2SRobert Watson */ 2297a0a89d2SRobert Watson int 2307a0a89d2SRobert Watson auditd_set_host(void) 2317a0a89d2SRobert Watson { 2327a0a89d2SRobert Watson struct sockaddr_in6 *sin6; 2337a0a89d2SRobert Watson struct sockaddr_in *sin; 2347a0a89d2SRobert Watson struct addrinfo *res; 2357a0a89d2SRobert Watson struct auditinfo_addr aia; 2367a0a89d2SRobert Watson int error, ret = ADE_NOERR; 2377a0a89d2SRobert Watson 23806edd2f1SRobert Watson if (getachost(auditd_host, sizeof(auditd_host)) != 0) { 2397a0a89d2SRobert Watson ret = ADE_PARSE; 2407a0a89d2SRobert Watson 2417a0a89d2SRobert Watson /* 2427a0a89d2SRobert Watson * To maintain reverse compatability with older audit_control 2437a0a89d2SRobert Watson * files, simply drop a warning if the host parameter has not 2447a0a89d2SRobert Watson * been set. However, we will explicitly disable the 2457a0a89d2SRobert Watson * generation of extended audit header by passing in a zeroed 2467a0a89d2SRobert Watson * termid structure. 2477a0a89d2SRobert Watson */ 2487a0a89d2SRobert Watson bzero(&aia, sizeof(aia)); 2497a0a89d2SRobert Watson aia.ai_termid.at_type = AU_IPv4; 250c0020399SRobert Watson error = audit_set_kaudit(&aia, sizeof(aia)); 2517a0a89d2SRobert Watson if (error < 0 && errno != ENOSYS) 2527a0a89d2SRobert Watson ret = ADE_AUDITON; 2537a0a89d2SRobert Watson return (ret); 2547a0a89d2SRobert Watson } 25506edd2f1SRobert Watson auditd_hostlen = strlen(auditd_host); 25606edd2f1SRobert Watson error = getaddrinfo(auditd_host, NULL, NULL, &res); 2577a0a89d2SRobert Watson if (error) 2587a0a89d2SRobert Watson return (ADE_GETADDR); 2597a0a89d2SRobert Watson switch (res->ai_family) { 2607a0a89d2SRobert Watson case PF_INET6: 2617a0a89d2SRobert Watson sin6 = (struct sockaddr_in6 *) res->ai_addr; 2627a0a89d2SRobert Watson bcopy(&sin6->sin6_addr.s6_addr, 2637a0a89d2SRobert Watson &aia.ai_termid.at_addr[0], sizeof(struct in6_addr)); 2647a0a89d2SRobert Watson aia.ai_termid.at_type = AU_IPv6; 2657a0a89d2SRobert Watson break; 2667a0a89d2SRobert Watson 2677a0a89d2SRobert Watson case PF_INET: 2687a0a89d2SRobert Watson sin = (struct sockaddr_in *) res->ai_addr; 2697a0a89d2SRobert Watson bcopy(&sin->sin_addr.s_addr, 2707a0a89d2SRobert Watson &aia.ai_termid.at_addr[0], sizeof(struct in_addr)); 2717a0a89d2SRobert Watson aia.ai_termid.at_type = AU_IPv4; 2727a0a89d2SRobert Watson break; 2737a0a89d2SRobert Watson 2747a0a89d2SRobert Watson default: 2757a0a89d2SRobert Watson /* Un-supported address family in host parameter. */ 2767a0a89d2SRobert Watson errno = EAFNOSUPPORT; 2777a0a89d2SRobert Watson return (ADE_ADDRFAM); 2787a0a89d2SRobert Watson } 2797a0a89d2SRobert Watson 280c0020399SRobert Watson if (audit_set_kaudit(&aia, sizeof(aia)) < 0) 2817a0a89d2SRobert Watson ret = ADE_AUDITON; 2827a0a89d2SRobert Watson 2837a0a89d2SRobert Watson return (ret); 2847a0a89d2SRobert Watson } 2857a0a89d2SRobert Watson 2867a0a89d2SRobert Watson /* 2877a0a89d2SRobert Watson * Get the min percentage of free blocks from audit_control(5) and that 2887a0a89d2SRobert Watson * value in the kernel. Return: 2897a0a89d2SRobert Watson * ADE_NOERR on success, 2907a0a89d2SRobert Watson * ADE_PARSE error parsing audit_control(5), 2917a0a89d2SRobert Watson * ADE_AUDITON error getting/setting auditon(2) value. 2927a0a89d2SRobert Watson */ 2937a0a89d2SRobert Watson int 2947a0a89d2SRobert Watson auditd_set_minfree(void) 2957a0a89d2SRobert Watson { 2967a0a89d2SRobert Watson au_qctrl_t qctrl; 2977a0a89d2SRobert Watson 29806edd2f1SRobert Watson if (getacmin(&auditd_minval) != 0) 2997a0a89d2SRobert Watson return (ADE_PARSE); 3007a0a89d2SRobert Watson 301c0020399SRobert Watson if (audit_get_qctrl(&qctrl, sizeof(qctrl)) != 0) 3027a0a89d2SRobert Watson return (ADE_AUDITON); 3037a0a89d2SRobert Watson 30406edd2f1SRobert Watson if (qctrl.aq_minfree != auditd_minval) { 30506edd2f1SRobert Watson qctrl.aq_minfree = auditd_minval; 306c0020399SRobert Watson if (audit_set_qctrl(&qctrl, sizeof(qctrl)) != 0) 3077a0a89d2SRobert Watson return (ADE_AUDITON); 3087a0a89d2SRobert Watson } 3097a0a89d2SRobert Watson 3107a0a89d2SRobert Watson return (0); 3117a0a89d2SRobert Watson } 3127a0a89d2SRobert Watson 3137a0a89d2SRobert Watson /* 31406edd2f1SRobert Watson * Convert a trailname into a timestamp (seconds). Return 0 if the conversion 31506edd2f1SRobert Watson * was successful. 31606edd2f1SRobert Watson */ 31706edd2f1SRobert Watson static int 31806edd2f1SRobert Watson trailname_to_tstamp(char *fn, time_t *tstamp) 31906edd2f1SRobert Watson { 32006edd2f1SRobert Watson struct tm tm; 32106edd2f1SRobert Watson char ts[TIMESTAMP_LEN]; 32206edd2f1SRobert Watson char *p; 32306edd2f1SRobert Watson 32406edd2f1SRobert Watson *tstamp = 0; 32506edd2f1SRobert Watson 32606edd2f1SRobert Watson /* 32706edd2f1SRobert Watson * Get the ending time stamp. 32806edd2f1SRobert Watson */ 32906edd2f1SRobert Watson if ((p = strchr(fn, '.')) == NULL) 33006edd2f1SRobert Watson return (1); 33106edd2f1SRobert Watson strlcpy(ts, ++p, TIMESTAMP_LEN); 33206edd2f1SRobert Watson if (strlen(ts) != POSTFIX_LEN) 33306edd2f1SRobert Watson return (1); 33406edd2f1SRobert Watson 33506edd2f1SRobert Watson bzero(&tm, sizeof(tm)); 33606edd2f1SRobert Watson 33706edd2f1SRobert Watson /* seconds (0-60) */ 33806edd2f1SRobert Watson p = ts + POSTFIX_LEN - 2; 33906edd2f1SRobert Watson tm.tm_sec = atol(p); 34006edd2f1SRobert Watson if (tm.tm_sec < 0 || tm.tm_sec > 60) 34106edd2f1SRobert Watson return (1); 34206edd2f1SRobert Watson 34306edd2f1SRobert Watson /* minutes (0-59) */ 34406edd2f1SRobert Watson *p = '\0'; p -= 2; 34506edd2f1SRobert Watson tm.tm_min = atol(p); 34606edd2f1SRobert Watson if (tm.tm_min < 0 || tm.tm_min > 59) 34706edd2f1SRobert Watson return (1); 34806edd2f1SRobert Watson 34906edd2f1SRobert Watson /* hours (0 - 23) */ 35006edd2f1SRobert Watson *p = '\0'; p -= 2; 35106edd2f1SRobert Watson tm.tm_hour = atol(p); 35206edd2f1SRobert Watson if (tm.tm_hour < 0 || tm.tm_hour > 23) 35306edd2f1SRobert Watson return (1); 35406edd2f1SRobert Watson 35506edd2f1SRobert Watson /* day of month (1-31) */ 35606edd2f1SRobert Watson *p = '\0'; p -= 2; 35706edd2f1SRobert Watson tm.tm_mday = atol(p); 35806edd2f1SRobert Watson if (tm.tm_mday < 1 || tm.tm_mday > 31) 35906edd2f1SRobert Watson return (1); 36006edd2f1SRobert Watson 36106edd2f1SRobert Watson /* month (0 - 11) */ 36206edd2f1SRobert Watson *p = '\0'; p -= 2; 36306edd2f1SRobert Watson tm.tm_mon = atol(p) - 1; 36406edd2f1SRobert Watson if (tm.tm_mon < 0 || tm.tm_mon > 11) 36506edd2f1SRobert Watson return (1); 36606edd2f1SRobert Watson 36706edd2f1SRobert Watson /* year (year - 1900) */ 36806edd2f1SRobert Watson *p = '\0'; p -= 4; 36906edd2f1SRobert Watson tm.tm_year = atol(p) - 1900; 37006edd2f1SRobert Watson if (tm.tm_year < 0) 37106edd2f1SRobert Watson return (1); 37206edd2f1SRobert Watson 37306edd2f1SRobert Watson *tstamp = timegm(&tm); 37406edd2f1SRobert Watson 37506edd2f1SRobert Watson return (0); 37606edd2f1SRobert Watson } 37706edd2f1SRobert Watson 37806edd2f1SRobert Watson /* 37906edd2f1SRobert Watson * Remove audit trails files according to the expiration conditions. Returns: 38006edd2f1SRobert Watson * ADE_NOERR on success or there is nothing to do. 38106edd2f1SRobert Watson * ADE_PARSE if error parsing audit_control(5). 38206edd2f1SRobert Watson * ADE_NOMEM if could not allocate memory. 38306edd2f1SRobert Watson * ADE_EXPIRE if there was an unespected error. 38406edd2f1SRobert Watson */ 38506edd2f1SRobert Watson int 38606edd2f1SRobert Watson auditd_expire_trails(int (*warn_expired)(char *)) 38706edd2f1SRobert Watson { 38806edd2f1SRobert Watson int andflg, ret = ADE_NOERR; 38906edd2f1SRobert Watson size_t expire_size, total_size = 0L; 39006edd2f1SRobert Watson time_t expire_age, oldest_time, current_time = time(NULL); 39106edd2f1SRobert Watson struct dir_ent *traildir; 39206edd2f1SRobert Watson struct audit_trail *at; 39306edd2f1SRobert Watson char *afnp, *pn; 39406edd2f1SRobert Watson TAILQ_HEAD(au_trls_head, audit_trail) head = 39506edd2f1SRobert Watson TAILQ_HEAD_INITIALIZER(head); 39606edd2f1SRobert Watson struct stat stbuf; 39706edd2f1SRobert Watson char activefn[MAXPATHLEN]; 39806edd2f1SRobert Watson 39906edd2f1SRobert Watson /* 40006edd2f1SRobert Watson * Read the expiration conditions. If no conditions then return no 40106edd2f1SRobert Watson * error. 40206edd2f1SRobert Watson */ 40306edd2f1SRobert Watson if (getacexpire(&andflg, &expire_age, &expire_size) < 0) 40406edd2f1SRobert Watson return (ADE_PARSE); 40506edd2f1SRobert Watson if (!expire_age && !expire_size) 40606edd2f1SRobert Watson return (ADE_NOERR); 40706edd2f1SRobert Watson 40806edd2f1SRobert Watson /* 40906edd2f1SRobert Watson * Read the 'current' trail file name. Trim off directory path. 41006edd2f1SRobert Watson */ 41106edd2f1SRobert Watson activefn[0] = '\0'; 41206edd2f1SRobert Watson readlink(AUDIT_CURRENT_LINK, activefn, MAXPATHLEN - 1); 41306edd2f1SRobert Watson if ((afnp = strrchr(activefn, '/')) != NULL) 41406edd2f1SRobert Watson afnp++; 41506edd2f1SRobert Watson 41606edd2f1SRobert Watson 41706edd2f1SRobert Watson /* 41806edd2f1SRobert Watson * Build tail queue of the trail files. 41906edd2f1SRobert Watson */ 42006edd2f1SRobert Watson TAILQ_FOREACH(traildir, &dir_q, dirs) { 42106edd2f1SRobert Watson DIR *dirp; 42206edd2f1SRobert Watson struct dirent *dp; 42306edd2f1SRobert Watson 42406edd2f1SRobert Watson dirp = opendir(traildir->dirname); 42506edd2f1SRobert Watson while ((dp = readdir(dirp)) != NULL) { 42606edd2f1SRobert Watson time_t tstamp = 0; 42706edd2f1SRobert Watson struct audit_trail *new; 42806edd2f1SRobert Watson 42906edd2f1SRobert Watson /* 43006edd2f1SRobert Watson * Quickly filter non-trail files. 43106edd2f1SRobert Watson */ 43206edd2f1SRobert Watson if (dp->d_namlen != (FILENAME_LEN - 1) || 43306edd2f1SRobert Watson #ifdef DT_REG 43406edd2f1SRobert Watson dp->d_type != DT_REG || 43506edd2f1SRobert Watson #endif 43606edd2f1SRobert Watson dp->d_name[POSTFIX_LEN] != '.') 43706edd2f1SRobert Watson continue; 43806edd2f1SRobert Watson 43906edd2f1SRobert Watson if (asprintf(&pn, "%s/%s", traildir->dirname, 44006edd2f1SRobert Watson dp->d_name) < 0) { 44106edd2f1SRobert Watson ret = ADE_NOMEM; 44206edd2f1SRobert Watson break; 44306edd2f1SRobert Watson } 44406edd2f1SRobert Watson 44506edd2f1SRobert Watson if (stat(pn, &stbuf) < 0 || !S_ISREG(stbuf.st_mode)) { 44606edd2f1SRobert Watson free(pn); 44706edd2f1SRobert Watson continue; 44806edd2f1SRobert Watson } 44906edd2f1SRobert Watson 45006edd2f1SRobert Watson total_size += stbuf.st_size; 45106edd2f1SRobert Watson 45206edd2f1SRobert Watson /* 45306edd2f1SRobert Watson * If this is the 'current' audit trail then 45406edd2f1SRobert Watson * don't add it to the tail queue. 45506edd2f1SRobert Watson */ 45606edd2f1SRobert Watson if (NULL != afnp && 45706edd2f1SRobert Watson strncmp(dp->d_name, afnp, FILENAME_LEN) == 0) { 45806edd2f1SRobert Watson free(pn); 45906edd2f1SRobert Watson continue; 46006edd2f1SRobert Watson } 46106edd2f1SRobert Watson 46206edd2f1SRobert Watson /* 46306edd2f1SRobert Watson * Get the ending time stamp encoded in the trail 46406edd2f1SRobert Watson * name. If we can't read it or if it is older 46506edd2f1SRobert Watson * than Jan 1, 2000 then use the mtime. 46606edd2f1SRobert Watson */ 46706edd2f1SRobert Watson if (trailname_to_tstamp(dp->d_name, &tstamp) != 0 || 46806edd2f1SRobert Watson tstamp < JAN_01_2000) 46906edd2f1SRobert Watson tstamp = stbuf.st_mtime; 47006edd2f1SRobert Watson 47106edd2f1SRobert Watson /* 47206edd2f1SRobert Watson * If the time stamp is older than Jan 1, 2000 then 47306edd2f1SRobert Watson * update the mtime of the trail file to the current 47406edd2f1SRobert Watson * time. This is so we don't prematurely remove a trail 47506edd2f1SRobert Watson * file that was created while the system clock reset 47606edd2f1SRobert Watson * to the * "beginning of time" but later the system 47706edd2f1SRobert Watson * clock is set to the correct current time. 47806edd2f1SRobert Watson */ 47906edd2f1SRobert Watson if (current_time >= JAN_01_2000 && 48006edd2f1SRobert Watson tstamp < JAN_01_2000) { 48106edd2f1SRobert Watson struct timeval tv[2]; 48206edd2f1SRobert Watson 48306edd2f1SRobert Watson tstamp = stbuf.st_mtime = current_time; 48406edd2f1SRobert Watson TIMESPEC_TO_TIMEVAL(&tv[0], 48506edd2f1SRobert Watson &stbuf.st_atimespec); 48606edd2f1SRobert Watson TIMESPEC_TO_TIMEVAL(&tv[1], 48706edd2f1SRobert Watson &stbuf.st_mtimespec); 48806edd2f1SRobert Watson utimes(pn, tv); 48906edd2f1SRobert Watson } 49006edd2f1SRobert Watson 49106edd2f1SRobert Watson /* 49206edd2f1SRobert Watson * Allocate and populate the new entry. 49306edd2f1SRobert Watson */ 49406edd2f1SRobert Watson new = malloc(sizeof(*new)); 49506edd2f1SRobert Watson if (NULL == new) { 49606edd2f1SRobert Watson free(pn); 49706edd2f1SRobert Watson ret = ADE_NOMEM; 49806edd2f1SRobert Watson break; 49906edd2f1SRobert Watson } 50006edd2f1SRobert Watson new->at_time = tstamp; 50106edd2f1SRobert Watson new->at_size = stbuf.st_size; 50206edd2f1SRobert Watson new->at_path = pn; 50306edd2f1SRobert Watson 50406edd2f1SRobert Watson /* 50506edd2f1SRobert Watson * Check to see if we have a new head. Otherwise, 50606edd2f1SRobert Watson * walk the tailq from the tail first and do a simple 50706edd2f1SRobert Watson * insertion sort. 50806edd2f1SRobert Watson */ 50906edd2f1SRobert Watson if (TAILQ_EMPTY(&head) || 51006edd2f1SRobert Watson (new->at_time <= TAILQ_FIRST(&head)->at_time)) { 51106edd2f1SRobert Watson TAILQ_INSERT_HEAD(&head, new, at_trls); 51206edd2f1SRobert Watson continue; 51306edd2f1SRobert Watson } 51406edd2f1SRobert Watson 51506edd2f1SRobert Watson TAILQ_FOREACH_REVERSE(at, &head, au_trls_head, at_trls) 51606edd2f1SRobert Watson if (new->at_time >= at->at_time) { 51706edd2f1SRobert Watson TAILQ_INSERT_AFTER(&head, at, new, 51806edd2f1SRobert Watson at_trls); 51906edd2f1SRobert Watson break; 52006edd2f1SRobert Watson } 52106edd2f1SRobert Watson 52206edd2f1SRobert Watson } 52306edd2f1SRobert Watson } 52406edd2f1SRobert Watson 52506edd2f1SRobert Watson oldest_time = current_time - expire_age; 52606edd2f1SRobert Watson 52706edd2f1SRobert Watson /* 52806edd2f1SRobert Watson * Expire trail files, oldest (mtime) first, if the given 52906edd2f1SRobert Watson * conditions are met. 53006edd2f1SRobert Watson */ 53106edd2f1SRobert Watson at = TAILQ_FIRST(&head); 53206edd2f1SRobert Watson while (NULL != at) { 53306edd2f1SRobert Watson struct audit_trail *at_next = TAILQ_NEXT(at, at_trls); 53406edd2f1SRobert Watson 53506edd2f1SRobert Watson if (andflg) { 53606edd2f1SRobert Watson if ((expire_size && total_size > expire_size) && 53706edd2f1SRobert Watson (expire_age && at->at_time < oldest_time)) { 53806edd2f1SRobert Watson if (warn_expired) 53906edd2f1SRobert Watson (*warn_expired)(at->at_path); 54006edd2f1SRobert Watson if (unlink(at->at_path) < 0) 54106edd2f1SRobert Watson ret = ADE_EXPIRE; 54206edd2f1SRobert Watson total_size -= at->at_size; 54306edd2f1SRobert Watson } 54406edd2f1SRobert Watson } else { 54506edd2f1SRobert Watson if ((expire_size && total_size > expire_size) || 54606edd2f1SRobert Watson (expire_age && at->at_time < oldest_time)) { 54706edd2f1SRobert Watson if (warn_expired) 54806edd2f1SRobert Watson (*warn_expired)(at->at_path); 54906edd2f1SRobert Watson if (unlink(at->at_path) < 0) 55006edd2f1SRobert Watson ret = ADE_EXPIRE; 55106edd2f1SRobert Watson total_size -= at->at_size; 55206edd2f1SRobert Watson } 55306edd2f1SRobert Watson } 55406edd2f1SRobert Watson 55506edd2f1SRobert Watson free(at->at_path); 55606edd2f1SRobert Watson free(at); 55706edd2f1SRobert Watson at = at_next; 55806edd2f1SRobert Watson } 55906edd2f1SRobert Watson 56006edd2f1SRobert Watson return (ret); 56106edd2f1SRobert Watson } 56206edd2f1SRobert Watson 56306edd2f1SRobert Watson /* 5647a0a89d2SRobert Watson * Parses the "dir" entry in audit_control(5) into an ordered list. Also, will 56506edd2f1SRobert Watson * set the minfree and host values if not already set. Arguments include 56606edd2f1SRobert Watson * function pointers to audit_warn functions for soft and hard limits. Returns: 5677a0a89d2SRobert Watson * ADE_NOERR on success, 5687a0a89d2SRobert Watson * ADE_PARSE error parsing audit_control(5), 5697a0a89d2SRobert Watson * ADE_AUDITON error getting/setting auditon(2) value, 5707a0a89d2SRobert Watson * ADE_NOMEM error allocating memory, 5717a0a89d2SRobert Watson * ADE_SOFTLIM if all the directories are over the soft limit, 5727a0a89d2SRobert Watson * ADE_HARDLIM if all the directories are over the hard limit, 5737a0a89d2SRobert Watson */ 5747a0a89d2SRobert Watson int 5757a0a89d2SRobert Watson auditd_read_dirs(int (*warn_soft)(char *), int (*warn_hard)(char *)) 5767a0a89d2SRobert Watson { 5777a0a89d2SRobert Watson char cur_dir[MAXNAMLEN]; 5787a0a89d2SRobert Watson struct dir_ent *dirent; 5797a0a89d2SRobert Watson struct statfs sfs; 5807a0a89d2SRobert Watson int err; 5817a0a89d2SRobert Watson char soft, hard; 5827a0a89d2SRobert Watson int tcnt = 0; 5837a0a89d2SRobert Watson int scnt = 0; 5847a0a89d2SRobert Watson int hcnt = 0; 5857a0a89d2SRobert Watson 58606edd2f1SRobert Watson if (auditd_minval == -1 && (err = auditd_set_minfree()) != 0) 5877a0a89d2SRobert Watson return (err); 5887a0a89d2SRobert Watson 58906edd2f1SRobert Watson if (auditd_hostlen == -1) 59006edd2f1SRobert Watson auditd_set_host(); 59106edd2f1SRobert Watson 5927a0a89d2SRobert Watson /* 5937a0a89d2SRobert Watson * Init directory q. Force a re-read of the file the next time. 5947a0a89d2SRobert Watson */ 5957a0a89d2SRobert Watson free_dir_q(); 5967a0a89d2SRobert Watson endac(); 5977a0a89d2SRobert Watson 5987a0a89d2SRobert Watson /* 5997a0a89d2SRobert Watson * Read the list of directories into an ordered linked list 6007a0a89d2SRobert Watson * admin's preference, then those over soft limit and, finally, 6017a0a89d2SRobert Watson * those over the hard limit. 6027a0a89d2SRobert Watson * 6037a0a89d2SRobert Watson * XXX We should use the reentrant interfaces once they are 6047a0a89d2SRobert Watson * available. 6057a0a89d2SRobert Watson */ 6067a0a89d2SRobert Watson while (getacdir(cur_dir, MAXNAMLEN) >= 0) { 6077a0a89d2SRobert Watson if (statfs(cur_dir, &sfs) < 0) 6087a0a89d2SRobert Watson continue; /* XXX should warn */ 60906edd2f1SRobert Watson soft = (sfs.f_bfree < (sfs.f_blocks / (100 / auditd_minval))) ? 61006edd2f1SRobert Watson 1 : 0; 6117a0a89d2SRobert Watson hard = (sfs.f_bfree < AUDIT_HARD_LIMIT_FREE_BLOCKS) ? 1 : 0; 6127a0a89d2SRobert Watson if (soft) { 6137a0a89d2SRobert Watson if (warn_soft) 6147a0a89d2SRobert Watson (*warn_soft)(cur_dir); 6157a0a89d2SRobert Watson scnt++; 6167a0a89d2SRobert Watson } 6177a0a89d2SRobert Watson if (hard) { 6187a0a89d2SRobert Watson if (warn_hard) 6197a0a89d2SRobert Watson (*warn_hard)(cur_dir); 6207a0a89d2SRobert Watson hcnt++; 6217a0a89d2SRobert Watson } 6227a0a89d2SRobert Watson dirent = (struct dir_ent *) malloc(sizeof(struct dir_ent)); 6237a0a89d2SRobert Watson if (dirent == NULL) 6247a0a89d2SRobert Watson return (ADE_NOMEM); 6257a0a89d2SRobert Watson dirent->softlim = soft; 6267a0a89d2SRobert Watson dirent->hardlim = hard; 6277a0a89d2SRobert Watson dirent->dirname = (char *) malloc(MAXNAMLEN); 6287a0a89d2SRobert Watson if (dirent->dirname == NULL) { 6297a0a89d2SRobert Watson free(dirent); 6307a0a89d2SRobert Watson return (ADE_NOMEM); 6317a0a89d2SRobert Watson } 6327a0a89d2SRobert Watson strlcpy(dirent->dirname, cur_dir, MAXNAMLEN); 6337a0a89d2SRobert Watson insert_orderly(dirent); 6347a0a89d2SRobert Watson tcnt++; 6357a0a89d2SRobert Watson } 6367a0a89d2SRobert Watson 6377a0a89d2SRobert Watson if (hcnt == tcnt) 6387a0a89d2SRobert Watson return (ADE_HARDLIM); 6397a0a89d2SRobert Watson if (scnt == tcnt) 6407a0a89d2SRobert Watson return (ADE_SOFTLIM); 6417a0a89d2SRobert Watson return (0); 6427a0a89d2SRobert Watson } 6437a0a89d2SRobert Watson 6447a0a89d2SRobert Watson void 6457a0a89d2SRobert Watson auditd_close_dirs(void) 6467a0a89d2SRobert Watson { 6477a0a89d2SRobert Watson free_dir_q(); 64806edd2f1SRobert Watson auditd_minval = -1; 64906edd2f1SRobert Watson auditd_hostlen = -1; 6507a0a89d2SRobert Watson } 6517a0a89d2SRobert Watson 6527a0a89d2SRobert Watson 6537a0a89d2SRobert Watson /* 6547a0a89d2SRobert Watson * Process the audit event file, obtaining a class mapping for each event, and 6557a0a89d2SRobert Watson * set that mapping into the kernel. Return: 6567a0a89d2SRobert Watson * n number of event mappings that were successfully processed, 6577a0a89d2SRobert Watson * ADE_NOMEM if there was an error allocating memory. 6587a0a89d2SRobert Watson */ 6597a0a89d2SRobert Watson int 6607a0a89d2SRobert Watson auditd_set_evcmap(void) 6617a0a89d2SRobert Watson { 6627a0a89d2SRobert Watson au_event_ent_t ev, *evp; 6637a0a89d2SRobert Watson au_evclass_map_t evc_map; 6647a0a89d2SRobert Watson int ctr = 0; 6657a0a89d2SRobert Watson 6667a0a89d2SRobert Watson 6677a0a89d2SRobert Watson /* 6687a0a89d2SRobert Watson * XXX There's a risk here that the BSM library will return NULL 6697a0a89d2SRobert Watson * for an event when it can't properly map it to a class. In that 6707a0a89d2SRobert Watson * case, we will not process any events beyond the one that failed, 6717a0a89d2SRobert Watson * but should. We need a way to get a count of the events. 6727a0a89d2SRobert Watson */ 6737a0a89d2SRobert Watson ev.ae_name = (char *)malloc(AU_EVENT_NAME_MAX); 6747a0a89d2SRobert Watson ev.ae_desc = (char *)malloc(AU_EVENT_DESC_MAX); 6757a0a89d2SRobert Watson if ((ev.ae_name == NULL) || (ev.ae_desc == NULL)) { 6767a0a89d2SRobert Watson if (ev.ae_name != NULL) 6777a0a89d2SRobert Watson free(ev.ae_name); 6787a0a89d2SRobert Watson return (ADE_NOMEM); 6797a0a89d2SRobert Watson } 6807a0a89d2SRobert Watson 6817a0a89d2SRobert Watson /* 6827a0a89d2SRobert Watson * XXXRW: Currently we have no way to remove mappings from the kernel 6837a0a89d2SRobert Watson * when they are removed from the file-based mappings. 6847a0a89d2SRobert Watson */ 6857a0a89d2SRobert Watson evp = &ev; 6867a0a89d2SRobert Watson setauevent(); 6877a0a89d2SRobert Watson while ((evp = getauevent_r(evp)) != NULL) { 6887a0a89d2SRobert Watson evc_map.ec_number = evp->ae_number; 6897a0a89d2SRobert Watson evc_map.ec_class = evp->ae_class; 690c0020399SRobert Watson if (audit_set_class(&evc_map, sizeof(evc_map)) == 0) 6917a0a89d2SRobert Watson ctr++; 6927a0a89d2SRobert Watson } 6937a0a89d2SRobert Watson endauevent(); 6947a0a89d2SRobert Watson free(ev.ae_name); 6957a0a89d2SRobert Watson free(ev.ae_desc); 6967a0a89d2SRobert Watson 6977a0a89d2SRobert Watson return (ctr); 6987a0a89d2SRobert Watson } 6997a0a89d2SRobert Watson 7007a0a89d2SRobert Watson /* 7017a0a89d2SRobert Watson * Get the non-attributable event string and set the kernel mask. Return: 7027a0a89d2SRobert Watson * ADE_NOERR on success, 7037a0a89d2SRobert Watson * ADE_PARSE error parsing audit_control(5), 7047a0a89d2SRobert Watson * ADE_AUDITON error setting the mask using auditon(2). 7057a0a89d2SRobert Watson */ 7067a0a89d2SRobert Watson int 7077a0a89d2SRobert Watson auditd_set_namask(void) 7087a0a89d2SRobert Watson { 7097a0a89d2SRobert Watson au_mask_t aumask; 7107a0a89d2SRobert Watson char naeventstr[NA_EVENT_STR_SIZE]; 7117a0a89d2SRobert Watson 7127a0a89d2SRobert Watson if ((getacna(naeventstr, NA_EVENT_STR_SIZE) != 0) || 7137a0a89d2SRobert Watson (getauditflagsbin(naeventstr, &aumask) != 0)) 7147a0a89d2SRobert Watson return (ADE_PARSE); 7157a0a89d2SRobert Watson 716c0020399SRobert Watson if (audit_set_kmask(&aumask, sizeof(aumask)) != 0) 7177a0a89d2SRobert Watson return (ADE_AUDITON); 7187a0a89d2SRobert Watson 7197a0a89d2SRobert Watson return (ADE_NOERR); 7207a0a89d2SRobert Watson } 7217a0a89d2SRobert Watson 7227a0a89d2SRobert Watson /* 7237a0a89d2SRobert Watson * Set the audit control policy if a policy is configured in audit_control(5), 7247a0a89d2SRobert Watson * implement the policy. However, if one isn't defined or if there is an error 7257a0a89d2SRobert Watson * parsing the control file, set AUDIT_CNT to avoid leaving the system in a 7267a0a89d2SRobert Watson * fragile state. Return: 7277a0a89d2SRobert Watson * ADE_NOERR on success, 7287a0a89d2SRobert Watson * ADE_PARSE error parsing audit_control(5), 7297a0a89d2SRobert Watson * ADE_AUDITON error setting policy using auditon(2). 7307a0a89d2SRobert Watson */ 7317a0a89d2SRobert Watson int 7327a0a89d2SRobert Watson auditd_set_policy(void) 7337a0a89d2SRobert Watson { 734c0020399SRobert Watson int policy; 7357a0a89d2SRobert Watson char polstr[POL_STR_SIZE]; 7367a0a89d2SRobert Watson 7377a0a89d2SRobert Watson if ((getacpol(polstr, POL_STR_SIZE) != 0) || 7387a0a89d2SRobert Watson (au_strtopol(polstr, &policy) != 0)) { 7397a0a89d2SRobert Watson policy = AUDIT_CNT; 740c0020399SRobert Watson if (audit_set_policy(&policy) != 0) 7417a0a89d2SRobert Watson return (ADE_AUDITON); 7427a0a89d2SRobert Watson return (ADE_PARSE); 7437a0a89d2SRobert Watson } 7447a0a89d2SRobert Watson 745c0020399SRobert Watson if (audit_set_policy(&policy) != 0) 7467a0a89d2SRobert Watson return (ADE_AUDITON); 7477a0a89d2SRobert Watson 7487a0a89d2SRobert Watson return (ADE_NOERR); 7497a0a89d2SRobert Watson } 7507a0a89d2SRobert Watson 7517a0a89d2SRobert Watson /* 7527a0a89d2SRobert Watson * Set trail rotation size. Return: 7537a0a89d2SRobert Watson * ADE_NOERR on success, 7547a0a89d2SRobert Watson * ADE_PARSE error parsing audit_control(5), 7557a0a89d2SRobert Watson * ADE_AUDITON error setting file size using auditon(2). 7567a0a89d2SRobert Watson */ 7577a0a89d2SRobert Watson int 7587a0a89d2SRobert Watson auditd_set_fsize(void) 7597a0a89d2SRobert Watson { 7607a0a89d2SRobert Watson size_t filesz; 7617a0a89d2SRobert Watson au_fstat_t au_fstat; 7627a0a89d2SRobert Watson 7637a0a89d2SRobert Watson /* 7647a0a89d2SRobert Watson * Set trail rotation size. 7657a0a89d2SRobert Watson */ 7667a0a89d2SRobert Watson if (getacfilesz(&filesz) != 0) 7677a0a89d2SRobert Watson return (ADE_PARSE); 7687a0a89d2SRobert Watson 7697a0a89d2SRobert Watson bzero(&au_fstat, sizeof(au_fstat)); 7707a0a89d2SRobert Watson au_fstat.af_filesz = filesz; 771c0020399SRobert Watson if (audit_set_fsize(&au_fstat, sizeof(au_fstat)) != 0) 7727a0a89d2SRobert Watson return (ADE_AUDITON); 7737a0a89d2SRobert Watson 7747a0a89d2SRobert Watson return (ADE_NOERR); 7757a0a89d2SRobert Watson } 7767a0a89d2SRobert Watson 7777a0a89d2SRobert Watson /* 7787a0a89d2SRobert Watson * Create the new audit file with appropriate permissions and ownership. Try 7797a0a89d2SRobert Watson * to clean up if something goes wrong. 7807a0a89d2SRobert Watson */ 7817a0a89d2SRobert Watson static int 7827a0a89d2SRobert Watson open_trail(char *fname, gid_t gid) 7837a0a89d2SRobert Watson { 7847a0a89d2SRobert Watson int error, fd; 7857a0a89d2SRobert Watson 7867a0a89d2SRobert Watson fd = open(fname, O_RDONLY | O_CREAT, S_IRUSR | S_IRGRP); 7877a0a89d2SRobert Watson if (fd < 0) 7887a0a89d2SRobert Watson return (-1); 7897a0a89d2SRobert Watson if (fchown(fd, -1, gid) < 0) { 7907a0a89d2SRobert Watson error = errno; 7917a0a89d2SRobert Watson close(fd); 7927a0a89d2SRobert Watson (void)unlink(fname); 7937a0a89d2SRobert Watson errno = error; 7947a0a89d2SRobert Watson return (-1); 7957a0a89d2SRobert Watson } 7967a0a89d2SRobert Watson return (fd); 7977a0a89d2SRobert Watson } 7987a0a89d2SRobert Watson 7997a0a89d2SRobert Watson /* 8007a0a89d2SRobert Watson * Create the new audit trail file, swap with existing audit file. Arguments 8017a0a89d2SRobert Watson * include timestamp for the filename, a pointer to a string for returning the 8027a0a89d2SRobert Watson * new file name, GID for trail file, and audit_warn function pointer for 8037a0a89d2SRobert Watson * 'getacdir()' errors. Returns: 8047a0a89d2SRobert Watson * ADE_NOERR on success, 8057a0a89d2SRobert Watson * ADE_STRERR if the file name string could not be created, 8067a0a89d2SRobert Watson * ADE_SWAPERR if the audit trail file could not be swapped, 8077a0a89d2SRobert Watson * ADE_ACTL if the auditctl(2) call failed but file swap still 8087a0a89d2SRobert Watson * successful. 8097a0a89d2SRobert Watson * ADE_ACTLERR if the auditctl(2) call failed and file swap failed. 8107a0a89d2SRobert Watson * ADE_SYMLINK if symlink(2) failed updating the current link. 8117a0a89d2SRobert Watson */ 8127a0a89d2SRobert Watson int 8137a0a89d2SRobert Watson auditd_swap_trail(char *TS, char **newfile, gid_t gid, 8147a0a89d2SRobert Watson int (*warn_getacdir)(char *)) 8157a0a89d2SRobert Watson { 8167a0a89d2SRobert Watson char timestr[FILENAME_LEN]; 8177a0a89d2SRobert Watson char *fn; 8187a0a89d2SRobert Watson struct dir_ent *dirent; 8197a0a89d2SRobert Watson int fd; 8207a0a89d2SRobert Watson int error; 8217a0a89d2SRobert Watson int saverrno = 0; 8227a0a89d2SRobert Watson 8237a0a89d2SRobert Watson if (strlen(TS) != (TIMESTAMP_LEN - 1) || 8247a0a89d2SRobert Watson snprintf(timestr, FILENAME_LEN, "%s.%s", TS, NOT_TERMINATED) < 0) { 8257a0a89d2SRobert Watson errno = EINVAL; 8267a0a89d2SRobert Watson return (ADE_STRERR); 8277a0a89d2SRobert Watson } 8287a0a89d2SRobert Watson 8297a0a89d2SRobert Watson /* Try until we succeed. */ 83006edd2f1SRobert Watson TAILQ_FOREACH(dirent, &dir_q, dirs) { 8317a0a89d2SRobert Watson if (dirent->hardlim) 8327a0a89d2SRobert Watson continue; 8337a0a89d2SRobert Watson if ((fn = affixdir(timestr, dirent)) == NULL) 8347a0a89d2SRobert Watson return (ADE_STRERR); 8357a0a89d2SRobert Watson 8367a0a89d2SRobert Watson /* 8377a0a89d2SRobert Watson * Create and open the file; then close and pass to the 8387a0a89d2SRobert Watson * kernel if all went well. 8397a0a89d2SRobert Watson */ 8407a0a89d2SRobert Watson fd = open_trail(fn, gid); 8417a0a89d2SRobert Watson if (fd >= 0) { 8427a0a89d2SRobert Watson error = auditctl(fn); 8437a0a89d2SRobert Watson if (error) { 8447a0a89d2SRobert Watson /* 8457a0a89d2SRobert Watson * auditctl failed setting log file. 8467a0a89d2SRobert Watson * Try again. 8477a0a89d2SRobert Watson */ 8487a0a89d2SRobert Watson saverrno = errno; 8497a0a89d2SRobert Watson close(fd); 8507a0a89d2SRobert Watson } else { 8517a0a89d2SRobert Watson /* Success. */ 8527a0a89d2SRobert Watson *newfile = fn; 8537a0a89d2SRobert Watson close(fd); 8547a0a89d2SRobert Watson if (error) 8557a0a89d2SRobert Watson return (error); 8567a0a89d2SRobert Watson if (saverrno) { 8577a0a89d2SRobert Watson /* 8587a0a89d2SRobert Watson * auditctl() failed but still 8597a0a89d2SRobert Watson * successful. Return errno and "soft" 8607a0a89d2SRobert Watson * error. 8617a0a89d2SRobert Watson */ 8627a0a89d2SRobert Watson errno = saverrno; 8637a0a89d2SRobert Watson return (ADE_ACTL); 8647a0a89d2SRobert Watson } 8657a0a89d2SRobert Watson return (ADE_NOERR); 8667a0a89d2SRobert Watson } 8677a0a89d2SRobert Watson } 8687a0a89d2SRobert Watson 8697a0a89d2SRobert Watson /* 8707a0a89d2SRobert Watson * Tell the administrator about lack of permissions for dir. 8717a0a89d2SRobert Watson */ 8727a0a89d2SRobert Watson if (warn_getacdir != NULL) 8737a0a89d2SRobert Watson (*warn_getacdir)(dirent->dirname); 8747a0a89d2SRobert Watson } 8757a0a89d2SRobert Watson if (saverrno) { 8767a0a89d2SRobert Watson errno = saverrno; 8777a0a89d2SRobert Watson return (ADE_ACTLERR); 8787a0a89d2SRobert Watson } else 8797a0a89d2SRobert Watson return (ADE_SWAPERR); 8807a0a89d2SRobert Watson } 8817a0a89d2SRobert Watson 8827a0a89d2SRobert Watson /* 8837a0a89d2SRobert Watson * Mask calling process from being audited. Returns: 8847a0a89d2SRobert Watson * ADE_NOERR on success, 8857a0a89d2SRobert Watson * ADE_SETAUDIT if setaudit(2) fails. 8867a0a89d2SRobert Watson */ 88706edd2f1SRobert Watson #ifdef __APPLE__ 88806edd2f1SRobert Watson int 88906edd2f1SRobert Watson auditd_prevent_audit(void) 89006edd2f1SRobert Watson { 89106edd2f1SRobert Watson auditinfo_addr_t aia; 89206edd2f1SRobert Watson 89306edd2f1SRobert Watson /* 89406edd2f1SRobert Watson * To prevent event feedback cycles and avoid audit becoming stalled if 89506edd2f1SRobert Watson * auditing is suspended we mask this processes events from being 89606edd2f1SRobert Watson * audited. We allow the uid, tid, and mask fields to be implicitly 89706edd2f1SRobert Watson * set to zero, but do set the audit session ID to the PID. 89806edd2f1SRobert Watson * 89906edd2f1SRobert Watson * XXXRW: Is there more to it than this? 90006edd2f1SRobert Watson */ 90106edd2f1SRobert Watson bzero(&aia, sizeof(aia)); 90206edd2f1SRobert Watson aia.ai_asid = AU_ASSIGN_ASID; 90306edd2f1SRobert Watson aia.ai_termid.at_type = AU_IPv4; 90406edd2f1SRobert Watson if (setaudit_addr(&aia, sizeof(aia)) != 0) 90506edd2f1SRobert Watson return (ADE_SETAUDIT); 90606edd2f1SRobert Watson return (ADE_NOERR); 90706edd2f1SRobert Watson } 90806edd2f1SRobert Watson #else 9097a0a89d2SRobert Watson int 9107a0a89d2SRobert Watson auditd_prevent_audit(void) 9117a0a89d2SRobert Watson { 9127a0a89d2SRobert Watson auditinfo_t ai; 9137a0a89d2SRobert Watson 9147a0a89d2SRobert Watson /* 9157a0a89d2SRobert Watson * To prevent event feedback cycles and avoid audit becoming stalled if 9167a0a89d2SRobert Watson * auditing is suspended we mask this processes events from being 9177a0a89d2SRobert Watson * audited. We allow the uid, tid, and mask fields to be implicitly 9187a0a89d2SRobert Watson * set to zero, but do set the audit session ID to the PID. 9197a0a89d2SRobert Watson * 9207a0a89d2SRobert Watson * XXXRW: Is there more to it than this? 9217a0a89d2SRobert Watson */ 9227a0a89d2SRobert Watson bzero(&ai, sizeof(ai)); 9237a0a89d2SRobert Watson ai.ai_asid = getpid(); 9247a0a89d2SRobert Watson if (setaudit(&ai) != 0) 9257a0a89d2SRobert Watson return (ADE_SETAUDIT); 9267a0a89d2SRobert Watson return (ADE_NOERR); 9277a0a89d2SRobert Watson } 92806edd2f1SRobert Watson #endif /* __APPLE__ */ 9297a0a89d2SRobert Watson 9307a0a89d2SRobert Watson /* 9317a0a89d2SRobert Watson * Generate and submit audit record for audit startup or shutdown. The event 9327a0a89d2SRobert Watson * argument can be AUE_audit_recovery, AUE_audit_startup or 9337a0a89d2SRobert Watson * AUE_audit_shutdown. The path argument will add a path token, if not NULL. 9347a0a89d2SRobert Watson * Returns: 9357a0a89d2SRobert Watson * AUE_NOERR on success, 9367a0a89d2SRobert Watson * ADE_NOMEM if memory allocation fails, 9377a0a89d2SRobert Watson * ADE_AU_OPEN if au_open(3) fails, 9387a0a89d2SRobert Watson * ADE_AU_CLOSE if au_close(3) fails. 9397a0a89d2SRobert Watson */ 9407a0a89d2SRobert Watson int 9417a0a89d2SRobert Watson auditd_gen_record(int event, char *path) 9427a0a89d2SRobert Watson { 9437a0a89d2SRobert Watson int aufd; 9447a0a89d2SRobert Watson uid_t uid; 9457a0a89d2SRobert Watson pid_t pid; 9467a0a89d2SRobert Watson char *autext = NULL; 9477a0a89d2SRobert Watson token_t *tok; 9487a0a89d2SRobert Watson struct auditinfo_addr aia; 9497a0a89d2SRobert Watson 9507a0a89d2SRobert Watson if (event == AUE_audit_startup) 9517a0a89d2SRobert Watson asprintf(&autext, "%s::Audit startup", getprogname()); 9527a0a89d2SRobert Watson else if (event == AUE_audit_shutdown) 9537a0a89d2SRobert Watson asprintf(&autext, "%s::Audit shutdown", getprogname()); 9547a0a89d2SRobert Watson else if (event == AUE_audit_recovery) 9557a0a89d2SRobert Watson asprintf(&autext, "%s::Audit recovery", getprogname()); 9567a0a89d2SRobert Watson else 9577a0a89d2SRobert Watson return (ADE_INVAL); 9587a0a89d2SRobert Watson if (autext == NULL) 9597a0a89d2SRobert Watson return (ADE_NOMEM); 9607a0a89d2SRobert Watson 9617a0a89d2SRobert Watson if ((aufd = au_open()) == -1) { 9627a0a89d2SRobert Watson free(autext); 9637a0a89d2SRobert Watson return (ADE_AU_OPEN); 9647a0a89d2SRobert Watson } 9657a0a89d2SRobert Watson bzero(&aia, sizeof(aia)); 9667a0a89d2SRobert Watson uid = getuid(); pid = getpid(); 9677a0a89d2SRobert Watson if ((tok = au_to_subject32_ex(uid, geteuid(), getegid(), uid, getgid(), 9687a0a89d2SRobert Watson pid, pid, &aia.ai_termid)) != NULL) 9697a0a89d2SRobert Watson au_write(aufd, tok); 9707a0a89d2SRobert Watson if ((tok = au_to_text(autext)) != NULL) 9717a0a89d2SRobert Watson au_write(aufd, tok); 9727a0a89d2SRobert Watson free(autext); 9737a0a89d2SRobert Watson if (path != NULL && (tok = au_to_path(path)) != NULL) 9747a0a89d2SRobert Watson au_write(aufd, tok); 9757a0a89d2SRobert Watson if ((tok = au_to_return32(0, 0)) != NULL) 9767a0a89d2SRobert Watson au_write(aufd, tok); 9777a0a89d2SRobert Watson if (au_close(aufd, 1, event) == -1) 9787a0a89d2SRobert Watson return (ADE_AU_CLOSE); 9797a0a89d2SRobert Watson 9807a0a89d2SRobert Watson return (ADE_NOERR); 9817a0a89d2SRobert Watson } 9827a0a89d2SRobert Watson 9837a0a89d2SRobert Watson /* 9847a0a89d2SRobert Watson * Check for a 'current' symlink and do crash recovery, if needed. Create a new 9857a0a89d2SRobert Watson * 'current' symlink. The argument 'curfile' is the file the 'current' symlink 9867a0a89d2SRobert Watson * should point to. Returns: 9877a0a89d2SRobert Watson * ADE_NOERR on success, 9887a0a89d2SRobert Watson * ADE_AU_OPEN if au_open(3) fails, 9897a0a89d2SRobert Watson * ADE_AU_CLOSE if au_close(3) fails. 9907a0a89d2SRobert Watson * ADE_RENAME if error renaming audit trail file, 9917a0a89d2SRobert Watson * ADE_READLINK if error reading the 'current' link, 9927a0a89d2SRobert Watson * ADE_SYMLINK if error creating 'current' link. 9937a0a89d2SRobert Watson */ 9947a0a89d2SRobert Watson int 9957a0a89d2SRobert Watson auditd_new_curlink(char *curfile) 9967a0a89d2SRobert Watson { 9977a0a89d2SRobert Watson int len, err; 9987a0a89d2SRobert Watson char *ptr; 9997a0a89d2SRobert Watson char *path = NULL; 10007a0a89d2SRobert Watson struct stat sb; 10017a0a89d2SRobert Watson char recoveredname[MAXPATHLEN]; 10027a0a89d2SRobert Watson char newname[MAXPATHLEN]; 10037a0a89d2SRobert Watson 10047a0a89d2SRobert Watson /* 10057a0a89d2SRobert Watson * Check to see if audit was shutdown properly. If not, clean up, 10067a0a89d2SRobert Watson * recover previous audit trail file, and generate audit record. 10077a0a89d2SRobert Watson */ 10087a0a89d2SRobert Watson len = readlink(AUDIT_CURRENT_LINK, recoveredname, MAXPATHLEN - 1); 10097a0a89d2SRobert Watson if (len > 0) { 10107a0a89d2SRobert Watson /* 'current' exist but is it pointing at a valid file? */ 10117a0a89d2SRobert Watson recoveredname[len++] = '\0'; 10127a0a89d2SRobert Watson if (stat(recoveredname, &sb) == 0) { 10137a0a89d2SRobert Watson /* Yes, rename it to a crash recovery file. */ 10147a0a89d2SRobert Watson strlcpy(newname, recoveredname, MAXPATHLEN); 10157a0a89d2SRobert Watson 10167a0a89d2SRobert Watson if ((ptr = strstr(newname, NOT_TERMINATED)) != NULL) { 101706edd2f1SRobert Watson memcpy(ptr, CRASH_RECOVERY, POSTFIX_LEN); 10187a0a89d2SRobert Watson if (rename(recoveredname, newname) != 0) 10197a0a89d2SRobert Watson return (ADE_RENAME); 10207a0a89d2SRobert Watson } else 10217a0a89d2SRobert Watson return (ADE_STRERR); 10227a0a89d2SRobert Watson 10237a0a89d2SRobert Watson path = newname; 10247a0a89d2SRobert Watson } 10257a0a89d2SRobert Watson 10267a0a89d2SRobert Watson /* 'current' symlink is (now) invalid so remove it. */ 10277a0a89d2SRobert Watson (void) unlink(AUDIT_CURRENT_LINK); 10287a0a89d2SRobert Watson 10297a0a89d2SRobert Watson /* Note the crash recovery in current audit trail */ 10307a0a89d2SRobert Watson err = auditd_gen_record(AUE_audit_recovery, path); 10317a0a89d2SRobert Watson if (err) 10327a0a89d2SRobert Watson return (err); 10337a0a89d2SRobert Watson } 10347a0a89d2SRobert Watson 10357a0a89d2SRobert Watson if (len < 0 && errno != ENOENT) 10367a0a89d2SRobert Watson return (ADE_READLINK); 10377a0a89d2SRobert Watson 10387a0a89d2SRobert Watson if (symlink(curfile, AUDIT_CURRENT_LINK) != 0) 10397a0a89d2SRobert Watson return (ADE_SYMLINK); 10407a0a89d2SRobert Watson 10417a0a89d2SRobert Watson return (0); 10427a0a89d2SRobert Watson } 10437a0a89d2SRobert Watson 10447a0a89d2SRobert Watson /* 10457a0a89d2SRobert Watson * Do just what we need to quickly start auditing. Assume no system logging or 10467a0a89d2SRobert Watson * notify. Return: 10477a0a89d2SRobert Watson * 0 on success, 10487a0a89d2SRobert Watson * -1 on failure. 10497a0a89d2SRobert Watson */ 10507a0a89d2SRobert Watson int 10517a0a89d2SRobert Watson audit_quick_start(void) 10527a0a89d2SRobert Watson { 10537a0a89d2SRobert Watson int err; 105406edd2f1SRobert Watson char *newfile = NULL; 10557a0a89d2SRobert Watson time_t tt; 10567a0a89d2SRobert Watson char TS[TIMESTAMP_LEN]; 105706edd2f1SRobert Watson int ret = 0; 10587a0a89d2SRobert Watson 10597a0a89d2SRobert Watson /* 10607a0a89d2SRobert Watson * Mask auditing of this process. 10617a0a89d2SRobert Watson */ 10627a0a89d2SRobert Watson if (auditd_prevent_audit() != 0) 10637a0a89d2SRobert Watson return (-1); 10647a0a89d2SRobert Watson 10657a0a89d2SRobert Watson /* 10667a0a89d2SRobert Watson * Read audit_control and get log directories. 10677a0a89d2SRobert Watson */ 10687a0a89d2SRobert Watson err = auditd_read_dirs(NULL, NULL); 10697a0a89d2SRobert Watson if (err != ADE_NOERR && err != ADE_SOFTLIM) 10707a0a89d2SRobert Watson return (-1); 10717a0a89d2SRobert Watson 10727a0a89d2SRobert Watson /* 10737a0a89d2SRobert Watson * Create a new audit trail log. 10747a0a89d2SRobert Watson */ 10757a0a89d2SRobert Watson if (getTSstr(tt, TS, TIMESTAMP_LEN) != 0) 10767a0a89d2SRobert Watson return (-1); 10777a0a89d2SRobert Watson err = auditd_swap_trail(TS, &newfile, getgid(), NULL); 107806edd2f1SRobert Watson if (err != ADE_NOERR && err != ADE_ACTL) { 107906edd2f1SRobert Watson ret = -1; 108006edd2f1SRobert Watson goto out; 108106edd2f1SRobert Watson } 10827a0a89d2SRobert Watson 10837a0a89d2SRobert Watson /* 10847a0a89d2SRobert Watson * Add the current symlink and recover from crash, if needed. 10857a0a89d2SRobert Watson */ 108606edd2f1SRobert Watson if (auditd_new_curlink(newfile) != 0) { 108706edd2f1SRobert Watson ret = -1; 108806edd2f1SRobert Watson goto out; 108906edd2f1SRobert Watson } 10907a0a89d2SRobert Watson 10917a0a89d2SRobert Watson /* 10927a0a89d2SRobert Watson * At this point auditing has started so generate audit start-up record. 10937a0a89d2SRobert Watson */ 109406edd2f1SRobert Watson if (auditd_gen_record(AUE_audit_startup, NULL) != 0) { 109506edd2f1SRobert Watson ret = -1; 109606edd2f1SRobert Watson goto out; 109706edd2f1SRobert Watson } 10987a0a89d2SRobert Watson 10997a0a89d2SRobert Watson /* 11007a0a89d2SRobert Watson * Configure the audit controls. 11017a0a89d2SRobert Watson */ 11027a0a89d2SRobert Watson (void) auditd_set_evcmap(); 11037a0a89d2SRobert Watson (void) auditd_set_namask(); 11047a0a89d2SRobert Watson (void) auditd_set_policy(); 11057a0a89d2SRobert Watson (void) auditd_set_fsize(); 11067a0a89d2SRobert Watson (void) auditd_set_minfree(); 11077a0a89d2SRobert Watson (void) auditd_set_host(); 11087a0a89d2SRobert Watson 110906edd2f1SRobert Watson out: 111006edd2f1SRobert Watson if (newfile != NULL) 111106edd2f1SRobert Watson free(newfile); 111206edd2f1SRobert Watson 111306edd2f1SRobert Watson return (ret); 11147a0a89d2SRobert Watson } 11157a0a89d2SRobert Watson 11167a0a89d2SRobert Watson /* 11177a0a89d2SRobert Watson * Shut down auditing quickly. Assumes that is only called on system shutdown. 11187a0a89d2SRobert Watson * Returns: 11197a0a89d2SRobert Watson * 0 on success, 11207a0a89d2SRobert Watson * -1 on failure. 11217a0a89d2SRobert Watson */ 11227a0a89d2SRobert Watson int 11237a0a89d2SRobert Watson audit_quick_stop(void) 11247a0a89d2SRobert Watson { 11257a0a89d2SRobert Watson int len; 1126c0020399SRobert Watson int cond; 11277a0a89d2SRobert Watson char *ptr; 11287a0a89d2SRobert Watson time_t tt; 11297a0a89d2SRobert Watson char oldname[MAXPATHLEN]; 11307a0a89d2SRobert Watson char newname[MAXPATHLEN]; 11317a0a89d2SRobert Watson char TS[TIMESTAMP_LEN]; 11327a0a89d2SRobert Watson 11337a0a89d2SRobert Watson /* 11347a0a89d2SRobert Watson * Auditing already disabled? 11357a0a89d2SRobert Watson */ 1136c0020399SRobert Watson if (audit_get_cond(&cond) != 0) 11377a0a89d2SRobert Watson return (-1); 1138c74c7b73SRobert Watson if (cond == AUC_NOAUDIT) 11397a0a89d2SRobert Watson return (0); 11407a0a89d2SRobert Watson 11417a0a89d2SRobert Watson /* 11427a0a89d2SRobert Watson * Generate audit shutdown record. 11437a0a89d2SRobert Watson */ 11447a0a89d2SRobert Watson (void) auditd_gen_record(AUE_audit_shutdown, NULL); 11457a0a89d2SRobert Watson 11467a0a89d2SRobert Watson /* 11477a0a89d2SRobert Watson * Shutdown auditing in the kernel. 11487a0a89d2SRobert Watson */ 11497a0a89d2SRobert Watson cond = AUC_DISABLED; 1150c0020399SRobert Watson if (audit_set_cond(&cond) != 0) 11517a0a89d2SRobert Watson return (-1); 11527a0a89d2SRobert Watson #ifdef __BSM_INTERNAL_NOTIFY_KEY 11537a0a89d2SRobert Watson notify_post(__BSM_INTERNAL_NOTIFY_KEY); 11547a0a89d2SRobert Watson #endif 11557a0a89d2SRobert Watson 11567a0a89d2SRobert Watson /* 11577a0a89d2SRobert Watson * Rename last audit trail and remove 'current' link. 11587a0a89d2SRobert Watson */ 11597a0a89d2SRobert Watson len = readlink(AUDIT_CURRENT_LINK, oldname, MAXPATHLEN - 1); 11607a0a89d2SRobert Watson if (len < 0) 11617a0a89d2SRobert Watson return (-1); 11627a0a89d2SRobert Watson oldname[len++] = '\0'; 11637a0a89d2SRobert Watson 11647a0a89d2SRobert Watson if (getTSstr(tt, TS, TIMESTAMP_LEN) != 0) 11657a0a89d2SRobert Watson return (-1); 11667a0a89d2SRobert Watson 11677a0a89d2SRobert Watson strlcpy(newname, oldname, len); 11687a0a89d2SRobert Watson 11697a0a89d2SRobert Watson if ((ptr = strstr(newname, NOT_TERMINATED)) != NULL) { 117006edd2f1SRobert Watson memcpy(ptr, TS, POSTFIX_LEN); 11717a0a89d2SRobert Watson if (rename(oldname, newname) != 0) 11727a0a89d2SRobert Watson return (-1); 11737a0a89d2SRobert Watson } else 11747a0a89d2SRobert Watson return (-1); 11757a0a89d2SRobert Watson 11767a0a89d2SRobert Watson (void) unlink(AUDIT_CURRENT_LINK); 11777a0a89d2SRobert Watson 11787a0a89d2SRobert Watson return (0); 11797a0a89d2SRobert Watson } 1180