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