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