1/*-
2 * Copyright (c) 2008-2009 Apple Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1.  Redistributions of source code must retain the above copyright
9 *     notice, this list of conditions and the following disclaimer.
10 * 2.  Redistributions in binary form must reproduce the above copyright
11 *     notice, this list of conditions and the following disclaimer in the
12 *     documentation and/or other materials provided with the distribution.
13 * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
14 *     its contributors may be used to endorse or promote products derived
15 *     from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
26 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <sys/param.h>
31
32#include <config/config.h>
33
34#include <sys/dirent.h>
35#ifdef HAVE_FULL_QUEUE_H
36#include <sys/queue.h>
37#else /* !HAVE_FULL_QUEUE_H */
38#include <compat/queue.h>
39#endif /* !HAVE_FULL_QUEUE_H */
40#include <sys/mount.h>
41#include <sys/socket.h>
42
43#include <sys/stat.h>
44#include <sys/time.h>
45
46#include <netinet/in.h>
47
48#include <bsm/audit.h>
49#include <bsm/audit_uevents.h>
50#include <bsm/auditd_lib.h>
51#include <bsm/libbsm.h>
52
53#include <assert.h>
54#include <dirent.h>
55#include <err.h>
56#include <errno.h>
57#include <fcntl.h>
58#include <stdio.h>
59#include <string.h>
60#include <stdlib.h>
61#include <time.h>
62#include <unistd.h>
63#include <netdb.h>
64
65#ifdef __APPLE__
66#include <notify.h>
67#ifndef __BSM_INTERNAL_NOTIFY_KEY
68#define	__BSM_INTERNAL_NOTIFY_KEY	"com.apple.audit.change"
69#endif /* __BSM_INTERNAL_NOTIFY_KEY */
70#endif /* __APPLE__ */
71
72/*
73 * XXX This is temporary until this is moved to <bsm/audit.h> and shared with
74 * the kernel.
75 */
76#ifndef	AUDIT_HARD_LIMIT_FREE_BLOCKS
77#define	AUDIT_HARD_LIMIT_FREE_BLOCKS	4
78#endif
79
80/*
81 * Number of seconds to January 1, 2000
82 */
83#define	JAN_01_2000	946598400
84
85struct dir_ent {
86	char			*dirname;
87	uint8_t			 softlim;
88	uint8_t			 hardlim;
89	TAILQ_ENTRY(dir_ent)	 dirs;
90};
91
92static TAILQ_HEAD(, dir_ent)	dir_q;
93
94struct audit_trail {
95	time_t			 at_time;
96	char			*at_path;
97	off_t			 at_size;
98
99	TAILQ_ENTRY(audit_trail) at_trls;
100};
101
102static int auditd_minval = -1;
103static int auditd_dist = 0;
104
105static char auditd_host[MAXHOSTNAMELEN];
106static int auditd_hostlen = -1;
107
108static char *auditd_errmsg[] = {
109	"no error",					/* ADE_NOERR	( 0) */
110	"could not parse audit_control(5) file",	/* ADE_PARSE	( 1) */
111	"auditon(2) failed",				/* ADE_AUDITON	( 2) */
112	"malloc(3) failed",				/* ADE_NOMEM	( 3) */
113	"all audit log directories over soft limit",	/* ADE_SOFTLIM	( 4) */
114	"all audit log directories over hard limit",	/* ADE_HARDLIM	( 5) */
115	"could not create file name string",		/* ADE_STRERR	( 6) */
116	"could not open audit record",			/* ADE_AU_OPEN	( 7) */
117	"could not close audit record",			/* ADE_AU_CLOSE	( 8) */
118	"could not set active audit session state",	/* ADE_SETAUDIT	( 9) */
119	"auditctl(2) failed (trail still swapped)",	/* ADE_ACTL	(10) */
120	"auditctl(2) failed (trail not swapped)",	/* ADE_ACTLERR	(11) */
121	"could not swap audit trail file",		/* ADE_SWAPERR	(12) */
122	"could not rename crash recovery file",		/* ADE_RENAME	(13) */
123	"could not read 'current' link file",		/* ADE_READLINK	(14) */
124	"could not create 'current' link file",		/* ADE_SYMLINK	(15) */
125	"invalid argument",				/* ADE_INVAL	(16) */
126	"could not resolve hostname to address",	/* ADE_GETADDR	(17) */
127	"address family not supported",			/* ADE_ADDRFAM	(18) */
128	"error expiring audit trail files",		/* ADE_EXPIRE	(19) */
129};
130
131#define	MAXERRCODE	(sizeof(auditd_errmsg) / sizeof(auditd_errmsg[0]))
132
133#define	NA_EVENT_STR_SIZE	128
134#define	POL_STR_SIZE		128
135
136
137/*
138 * Look up and return the error string for the given audit error code.
139 */
140const char *
141auditd_strerror(int errcode)
142{
143	int idx = -errcode;
144
145	if (idx < 0 || idx > (int)MAXERRCODE)
146		return ("Invalid auditd error code");
147
148	return (auditd_errmsg[idx]);
149}
150
151
152/*
153 * Free our local list of directory names and init list.
154 */
155static void
156free_dir_q(void)
157{
158	struct dir_ent *d1, *d2;
159
160	d1 = TAILQ_FIRST(&dir_q);
161	while (d1 != NULL) {
162		d2 = TAILQ_NEXT(d1, dirs);
163		free(d1->dirname);
164		free(d1);
165		d1 = d2;
166	}
167	TAILQ_INIT(&dir_q);
168}
169
170/*
171 * Concat the directory name to the given file name.
172 * XXX We should affix the hostname also
173 */
174static char *
175affixdir(char *name, struct dir_ent *dirent)
176{
177	char *fn = NULL;
178
179	/*
180	 * Sanity check on file name.
181	 */
182	if (strlen(name) != FILENAME_LEN) {
183		errno = EINVAL;
184		return (NULL);
185	}
186
187	/*
188	 * If the host is set then also add the hostname to the filename.
189	 */
190	if (auditd_hostlen != -1)
191		asprintf(&fn, "%s/%s.%s", dirent->dirname, name, auditd_host);
192	else
193		asprintf(&fn, "%s/%s", dirent->dirname, name);
194	return (fn);
195}
196
197/*
198 * Insert the directory entry in the list by the way they are ordered in
199 * audit_control(5).  Move the entries that are over the soft and hard limits
200 * toward the tail.
201 */
202static void
203insert_orderly(struct dir_ent *denew)
204{
205	struct dir_ent *dep;
206
207	TAILQ_FOREACH(dep, &dir_q, dirs) {
208		if (dep->softlim == 1 && denew->softlim == 0) {
209			TAILQ_INSERT_BEFORE(dep, denew, dirs);
210			return;
211		}
212		if (dep->hardlim == 1 && denew->hardlim == 0) {
213			TAILQ_INSERT_BEFORE(dep, denew, dirs);
214			return;
215		}
216	}
217	TAILQ_INSERT_TAIL(&dir_q, denew, dirs);
218}
219
220/*
221 * Get the min percentage of free blocks from audit_control(5) and that
222 * value in the kernel.  Return:
223 *	ADE_NOERR	on success,
224 *	ADE_PARSE	error parsing audit_control(5),
225 */
226int
227auditd_set_dist(void)
228{
229	int ret;
230
231	ret = getacdist();
232	if (ret < 0)
233		return (ADE_PARSE);
234
235	auditd_dist = ret;
236
237	return (ADE_NOERR);
238}
239
240/*
241 * Get the host from audit_control(5) and set it in the audit kernel
242 * information.  Return:
243 *	ADE_NOERR	on success.
244 *	ADE_PARSE	error parsing audit_control(5).
245 *	ADE_AUDITON	error getting/setting auditon(2) value.
246 *	ADE_GETADDR	error getting address info for host.
247 *	ADE_ADDRFAM	un-supported address family.
248 */
249int
250auditd_set_host(void)
251{
252	struct sockaddr_in6 *sin6;
253	struct sockaddr_in *sin;
254	struct addrinfo *res;
255	struct auditinfo_addr aia;
256	int error, ret = ADE_NOERR;
257
258	if ((getachost(auditd_host, sizeof(auditd_host)) != 0) ||
259	    ((auditd_hostlen = strlen(auditd_host)) == 0)) {
260		ret = ADE_PARSE;
261
262		/*
263		 * To maintain reverse compatability with older audit_control
264		 * files, simply drop a warning if the host parameter has not
265		 * been set.  However, we will explicitly disable the
266		 * generation of extended audit header by passing in a zeroed
267		 * termid structure.
268		 */
269		bzero(&aia, sizeof(aia));
270		aia.ai_termid.at_type = AU_IPv4;
271		error = audit_set_kaudit(&aia, sizeof(aia));
272		if (error < 0 && errno != ENOSYS)
273			ret = ADE_AUDITON;
274		return (ret);
275	}
276	error = getaddrinfo(auditd_host, NULL, NULL, &res);
277	if (error)
278		return (ADE_GETADDR);
279	switch (res->ai_family) {
280	case PF_INET6:
281		sin6 = (struct sockaddr_in6 *) res->ai_addr;
282		bcopy(&sin6->sin6_addr.s6_addr,
283		    &aia.ai_termid.at_addr[0], sizeof(struct in6_addr));
284		aia.ai_termid.at_type = AU_IPv6;
285		break;
286
287	case PF_INET:
288		sin = (struct sockaddr_in *) res->ai_addr;
289		bcopy(&sin->sin_addr.s_addr,
290		    &aia.ai_termid.at_addr[0], sizeof(struct in_addr));
291		aia.ai_termid.at_type = AU_IPv4;
292		break;
293
294	default:
295		/* Un-supported address family in host parameter. */
296		errno = EAFNOSUPPORT;
297		return (ADE_ADDRFAM);
298	}
299
300	if (audit_set_kaudit(&aia, sizeof(aia)) < 0)
301		ret = ADE_AUDITON;
302
303	return (ret);
304}
305
306/*
307 * Get the min percentage of free blocks from audit_control(5) and that
308 * value in the kernel.  Return:
309 *	ADE_NOERR	on success,
310 *	ADE_PARSE	error parsing audit_control(5),
311 *	ADE_AUDITON	error getting/setting auditon(2) value.
312 */
313int
314auditd_set_minfree(void)
315{
316	au_qctrl_t qctrl;
317
318	if (getacmin(&auditd_minval) != 0)
319		return (ADE_PARSE);
320
321	if (audit_get_qctrl(&qctrl, sizeof(qctrl)) != 0)
322		return (ADE_AUDITON);
323
324	if (qctrl.aq_minfree != auditd_minval) {
325		qctrl.aq_minfree = auditd_minval;
326		if (audit_set_qctrl(&qctrl, sizeof(qctrl)) != 0)
327			return (ADE_AUDITON);
328	}
329
330	return (0);
331}
332
333/*
334 * Convert a trailname into a timestamp (seconds).  Return 0 if the conversion
335 * was successful.
336 */
337static int
338trailname_to_tstamp(char *fn, time_t *tstamp)
339{
340	struct tm tm;
341	char ts[TIMESTAMP_LEN + 1];
342	char *p;
343
344	*tstamp = 0;
345
346	/*
347	 * Get the ending time stamp.
348	 */
349	if ((p = strchr(fn, '.')) == NULL)
350		return (1);
351	strlcpy(ts, ++p, sizeof(ts));
352	if (strlen(ts) != POSTFIX_LEN)
353		return (1);
354
355	bzero(&tm, sizeof(tm));
356
357	/* seconds (0-60) */
358	p = ts + POSTFIX_LEN - 2;
359	tm.tm_sec = atol(p);
360	if (tm.tm_sec < 0 || tm.tm_sec > 60)
361		return (1);
362
363	/* minutes (0-59) */
364	*p = '\0'; p -= 2;
365	tm.tm_min = atol(p);
366	if (tm.tm_min < 0 || tm.tm_min > 59)
367		return (1);
368
369	/* hours (0 - 23) */
370	*p = '\0'; p -= 2;
371	tm.tm_hour = atol(p);
372	if (tm.tm_hour < 0 || tm.tm_hour > 23)
373		return (1);
374
375	/* day of month (1-31) */
376	*p = '\0'; p -= 2;
377	tm.tm_mday = atol(p);
378	if (tm.tm_mday < 1 || tm.tm_mday > 31)
379		return (1);
380
381	/* month (0 - 11) */
382	*p = '\0'; p -= 2;
383	tm.tm_mon = atol(p) - 1;
384	if (tm.tm_mon < 0 || tm.tm_mon > 11)
385		return (1);
386
387	/* year (year - 1900) */
388	*p = '\0'; p -= 4;
389	tm.tm_year = atol(p) - 1900;
390	if (tm.tm_year < 0)
391		return (1);
392
393	*tstamp = timegm(&tm);
394
395	return (0);
396}
397
398/*
399 * Remove audit trails files according to the expiration conditions.  Returns:
400 *	ADE_NOERR	on success or there is nothing to do.
401 *	ADE_PARSE	if error parsing audit_control(5).
402 *	ADE_NOMEM	if could not allocate memory.
403 *	ADE_READLINK	if could not read link file.
404 *	ADE_EXPIRE	if there was an unexpected error.
405 */
406int
407auditd_expire_trails(int (*warn_expired)(char *))
408{
409	int andflg, len, ret = ADE_NOERR;
410	size_t expire_size, total_size = 0L;
411	time_t expire_age, oldest_time, current_time = time(NULL);
412	struct dir_ent *traildir;
413	struct audit_trail *at;
414	char *afnp, *pn;
415	TAILQ_HEAD(au_trls_head, audit_trail) head =
416	    TAILQ_HEAD_INITIALIZER(head);
417	struct stat stbuf;
418	char activefn[MAXPATHLEN];
419
420	/*
421	 * Read the expiration conditions.  If no conditions then return no
422	 * error.
423	 */
424	if (getacexpire(&andflg, &expire_age, &expire_size) < 0)
425		return (ADE_PARSE);
426	if (!expire_age && !expire_size)
427		return (ADE_NOERR);
428
429	/*
430	 * Read the 'current' trail file name.  Trim off directory path.
431	 */
432	activefn[0] = '\0';
433	len = readlink(AUDIT_CURRENT_LINK, activefn, MAXPATHLEN - 1);
434	if (len < 0)
435		return (ADE_READLINK);
436	if ((afnp = strrchr(activefn, '/')) != NULL)
437		afnp++;
438
439
440	/*
441	 * Build tail queue of the trail files.
442	 */
443	TAILQ_FOREACH(traildir, &dir_q, dirs) {
444		DIR *dirp;
445		struct dirent *dp;
446
447		dirp = opendir(traildir->dirname);
448		while ((dp = readdir(dirp)) != NULL) {
449			time_t tstamp = 0;
450			struct audit_trail *new;
451
452			/*
453			 * Quickly filter non-trail files.
454			 */
455			if (dp->d_namlen < FILENAME_LEN ||
456			    dp->d_name[POSTFIX_LEN] != '.')
457				continue;
458
459			if (asprintf(&pn, "%s/%s", traildir->dirname,
460			    dp->d_name) < 0) {
461				ret = ADE_NOMEM;
462				break;
463			}
464
465			if (stat(pn, &stbuf) < 0 || !S_ISREG(stbuf.st_mode)) {
466				free(pn);
467				continue;
468			}
469
470			total_size += stbuf.st_size;
471
472			/*
473			 * If this is the 'current' audit trail then
474			 * don't add it to the tail queue.
475			 */
476			if (NULL != afnp && strcmp(dp->d_name, afnp) == 0) {
477				free(pn);
478				continue;
479			}
480
481			/*
482			 * Get the ending time stamp encoded in the trail
483			 * name.  If we can't read it or if it is older
484			 * than Jan 1, 2000 then use the mtime.
485			 */
486			if (trailname_to_tstamp(dp->d_name, &tstamp) != 0 ||
487			    tstamp < JAN_01_2000)
488				tstamp = stbuf.st_mtime;
489
490			/*
491			 * If the time stamp is older than Jan 1, 2000 then
492			 * update the mtime of the trail file to the current
493			 * time. This is so we don't prematurely remove a trail
494			 * file that was created while the system clock reset
495			 * to the * "beginning of time" but later the system
496			 * clock is set to the correct current time.
497			 */
498			if (current_time >= JAN_01_2000 &&
499			    tstamp < JAN_01_2000) {
500				struct timeval tv[2];
501
502				tstamp = stbuf.st_mtime = current_time;
503				TIMESPEC_TO_TIMEVAL(&tv[0],
504				    &stbuf.st_atimespec);
505				TIMESPEC_TO_TIMEVAL(&tv[1],
506				    &stbuf.st_mtimespec);
507				utimes(pn, tv);
508			}
509
510			/*
511			 * Allocate and populate the new entry.
512			 */
513			new = malloc(sizeof(*new));
514			if (NULL == new) {
515				free(pn);
516				ret = ADE_NOMEM;
517				break;
518			}
519			new->at_time = tstamp;
520			new->at_size = stbuf.st_size;
521			new->at_path = pn;
522
523			/*
524			 * Check to see if we have a new head.  Otherwise,
525			 * walk the tailq from the tail first and do a simple
526			 * insertion sort.
527			 */
528			if (TAILQ_EMPTY(&head) ||
529			    new->at_time <= TAILQ_FIRST(&head)->at_time) {
530				TAILQ_INSERT_HEAD(&head, new, at_trls);
531				continue;
532			}
533
534			TAILQ_FOREACH_REVERSE(at, &head, au_trls_head, at_trls)
535				if (new->at_time >= at->at_time) {
536					TAILQ_INSERT_AFTER(&head, at, new,
537					    at_trls);
538					break;
539				}
540
541		}
542		closedir(dirp);
543	}
544
545	oldest_time = current_time - expire_age;
546
547	/*
548	 * Expire trail files, oldest (mtime) first, if the given
549	 * conditions are met.
550	 */
551	at = TAILQ_FIRST(&head);
552	while (NULL != at) {
553		struct audit_trail *at_next = TAILQ_NEXT(at, at_trls);
554
555		if (andflg) {
556			if ((expire_size && total_size > expire_size) &&
557			    (expire_age && at->at_time < oldest_time)) {
558				if (warn_expired)
559					(*warn_expired)(at->at_path);
560				if (unlink(at->at_path) < 0)
561					ret = ADE_EXPIRE;
562				total_size -= at->at_size;
563			}
564		} else {
565			if ((expire_size && total_size > expire_size) ||
566			    (expire_age && at->at_time < oldest_time)) {
567				if (warn_expired)
568					(*warn_expired)(at->at_path);
569				if (unlink(at->at_path) < 0)
570					ret = ADE_EXPIRE;
571				total_size -= at->at_size;
572			}
573		}
574
575		free(at->at_path);
576		free(at);
577		at = at_next;
578	}
579
580	return (ret);
581}
582
583/*
584 * Parses the "dir" entry in audit_control(5) into an ordered list.  Also, will
585 * set the minfree and host values if not already set.  Arguments include
586 * function pointers to audit_warn functions for soft and hard limits. Returns:
587 *	ADE_NOERR	on success,
588 *	ADE_PARSE	error parsing audit_control(5),
589 *	ADE_AUDITON	error getting/setting auditon(2) value,
590 *	ADE_NOMEM	error allocating memory,
591 *	ADE_SOFTLIM	if all the directories are over the soft limit,
592 *	ADE_HARDLIM	if all the directories are over the hard limit,
593 */
594int
595auditd_read_dirs(int (*warn_soft)(char *), int (*warn_hard)(char *))
596{
597	char cur_dir[MAXNAMLEN];
598	struct dir_ent *dirent;
599	struct statfs sfs;
600	int err;
601	char soft, hard;
602	int tcnt = 0;
603	int scnt = 0;
604	int hcnt = 0;
605
606	if (auditd_minval == -1 && (err = auditd_set_minfree()) != 0)
607		return (err);
608
609	if (auditd_hostlen == -1)
610		auditd_set_host();
611
612	/*
613	 * Init directory q.  Force a re-read of the file the next time.
614	 */
615	free_dir_q();
616	endac();
617
618	/*
619	 * Read the list of directories into an ordered linked list
620	 * admin's preference, then those over soft limit and, finally,
621	 * those over the hard limit.
622	 *
623	 * XXX We should use the reentrant interfaces once they are
624	 * available.
625	 */
626	while (getacdir(cur_dir, MAXNAMLEN) >= 0) {
627		if (statfs(cur_dir, &sfs) < 0)
628			continue;  /* XXX should warn */
629		soft = (sfs.f_bfree < (sfs.f_blocks * auditd_minval / 100 )) ?
630		    1 : 0;
631		hard = (sfs.f_bfree < AUDIT_HARD_LIMIT_FREE_BLOCKS) ? 1 : 0;
632		if (soft) {
633			if (warn_soft)
634				(*warn_soft)(cur_dir);
635			scnt++;
636		}
637		if (hard) {
638			if (warn_hard)
639				(*warn_hard)(cur_dir);
640			hcnt++;
641		}
642		dirent = (struct dir_ent *) malloc(sizeof(struct dir_ent));
643		if (dirent == NULL)
644			return (ADE_NOMEM);
645		dirent->softlim = soft;
646		dirent->hardlim = hard;
647		dirent->dirname = (char *) malloc(MAXNAMLEN);
648		if (dirent->dirname == NULL) {
649			free(dirent);
650			return (ADE_NOMEM);
651		}
652		strlcpy(dirent->dirname, cur_dir, MAXNAMLEN);
653		insert_orderly(dirent);
654		tcnt++;
655	}
656
657	if (hcnt == tcnt)
658		return (ADE_HARDLIM);
659	if (scnt == tcnt)
660		return (ADE_SOFTLIM);
661	return (0);
662}
663
664void
665auditd_close_dirs(void)
666{
667	free_dir_q();
668	auditd_minval = -1;
669	auditd_hostlen = -1;
670}
671
672
673/*
674 * Process the audit event file, obtaining a class mapping for each event, and
675 * set that mapping into the kernel. Return:
676 *	 n	number of event mappings that were successfully processed,
677 *   ADE_NOMEM	if there was an error allocating memory.
678 */
679int
680auditd_set_evcmap(void)
681{
682	au_event_ent_t ev, *evp;
683	au_evclass_map_t evc_map;
684	int ctr = 0;
685
686	/*
687	 * XXX There's a risk here that the BSM library will return NULL
688	 * for an event when it can't properly map it to a class. In that
689	 * case, we will not process any events beyond the one that failed,
690	 * but should. We need a way to get a count of the events.
691	 */
692	ev.ae_name = (char *)malloc(AU_EVENT_NAME_MAX);
693	ev.ae_desc = (char *)malloc(AU_EVENT_DESC_MAX);
694	if (ev.ae_name == NULL || ev.ae_desc == NULL) {
695		if (ev.ae_name != NULL)
696			free(ev.ae_name);
697		return (ADE_NOMEM);
698	}
699
700	/*
701	 * XXXRW: Currently we have no way to remove mappings from the kernel
702	 * when they are removed from the file-based mappings.
703	 */
704	evp = &ev;
705	setauevent();
706	while ((evp = getauevent_r(evp)) != NULL) {
707		evc_map.ec_number = evp->ae_number;
708		evc_map.ec_class = evp->ae_class;
709		if (audit_set_class(&evc_map, sizeof(evc_map)) == 0)
710			ctr++;
711	}
712	endauevent();
713	free(ev.ae_name);
714	free(ev.ae_desc);
715
716	return (ctr);
717}
718
719/*
720 * Get the non-attributable event string and set the kernel mask.  Return:
721 *	ADE_NOERR	on success,
722 *	ADE_PARSE	error parsing audit_control(5),
723 *	ADE_AUDITON	error setting the mask using auditon(2).
724 */
725int
726auditd_set_namask(void)
727{
728	au_mask_t aumask;
729	char naeventstr[NA_EVENT_STR_SIZE];
730
731	if (getacna(naeventstr, NA_EVENT_STR_SIZE) != 0 ||
732	    getauditflagsbin(naeventstr, &aumask) != 0)
733		return (ADE_PARSE);
734
735	if (audit_set_kmask(&aumask, sizeof(aumask)) != 0)
736		return (ADE_AUDITON);
737
738	return (ADE_NOERR);
739}
740
741/*
742 * Set the audit control policy if a policy is configured in audit_control(5),
743 * implement the policy. However, if one isn't defined or if there is an error
744 * parsing the control file, set AUDIT_CNT to avoid leaving the system in a
745 * fragile state.  Return:
746 *	ADE_NOERR	on success,
747 *	ADE_PARSE	error parsing audit_control(5),
748 *	ADE_AUDITON	error setting policy using auditon(2).
749 */
750int
751auditd_set_policy(void)
752{
753	int policy;
754	char polstr[POL_STR_SIZE];
755
756	if (getacpol(polstr, POL_STR_SIZE) != 0 ||
757	    au_strtopol(polstr, &policy) != 0) {
758		policy = AUDIT_CNT;
759		if (audit_set_policy(&policy) != 0)
760			return (ADE_AUDITON);
761		return (ADE_PARSE);
762	}
763
764	if (audit_set_policy(&policy) != 0)
765		return (ADE_AUDITON);
766
767	return (ADE_NOERR);
768}
769
770/*
771 * Set trail rotation size.  Return:
772 *	ADE_NOERR	on success,
773 *	ADE_PARSE	error parsing audit_control(5),
774 *	ADE_AUDITON	error setting file size using auditon(2).
775 */
776int
777auditd_set_fsize(void)
778{
779	size_t filesz;
780	au_fstat_t au_fstat;
781
782	/*
783	 * Set trail rotation size.
784	 */
785	if (getacfilesz(&filesz) != 0)
786		return (ADE_PARSE);
787
788	bzero(&au_fstat, sizeof(au_fstat));
789	au_fstat.af_filesz = filesz;
790	if (audit_set_fsize(&au_fstat, sizeof(au_fstat)) != 0)
791		return (ADE_AUDITON);
792
793	return (ADE_NOERR);
794}
795
796static void
797inject_dist(const char *fromname, char *toname, size_t tonamesize)
798{
799	char *ptr;
800
801	ptr = strrchr(fromname, '/');
802	assert(ptr != NULL);
803	assert(ptr - fromname < (ssize_t)tonamesize);
804	strlcpy(toname, fromname, ptr - fromname + 1);
805	strlcat(toname, "/dist/", tonamesize);
806	strlcat(toname, ptr + 1, tonamesize);
807}
808
809static int
810auditdist_link(const char *filename)
811{
812	char fname[MAXPATHLEN];
813
814	if (auditd_dist) {
815		inject_dist(filename, fname, sizeof(fname));
816		/* Ignore errors. */
817		(void) link(filename, fname);
818	}
819
820	return (0);
821}
822
823int
824auditd_rename(const char *fromname, const char *toname)
825{
826	char fname[MAXPATHLEN], tname[MAXPATHLEN];
827
828	if (auditd_dist) {
829		inject_dist(fromname, fname, sizeof(fname));
830		inject_dist(toname, tname, sizeof(tname));
831		/* Ignore errors. */
832		(void) rename(fname, tname);
833	}
834
835	return (rename(fromname, toname));
836}
837
838/*
839 * Create the new audit file with appropriate permissions and ownership.
840 * Call auditctl(2) for this file.
841 * Try to clean up if something goes wrong.
842 * *errorp is modified only on auditctl(2) failure.
843 */
844static int
845open_trail(char *fname, gid_t gid, int *errorp)
846{
847	int fd;
848
849	/* XXXPJD: What should we do if the file already exists? */
850	fd = open(fname, O_RDONLY | O_CREAT, S_IRUSR);
851	if (fd < 0)
852		return (-1);
853	if (fchown(fd, -1, gid) < 0 || fchmod(fd, S_IRUSR | S_IRGRP) < 0) {
854		(void) close(fd);
855		(void) unlink(fname);
856		return (-1);
857	}
858	(void) close(fd);
859	if (auditctl(fname) < 0) {
860		*errorp = errno;
861		(void) unlink(fname);
862		return (-1);
863	}
864	(void) auditdist_link(fname);
865	return (0);
866}
867
868/*
869 * Create the new audit trail file, swap with existing audit file.  Arguments
870 * include timestamp for the filename, a pointer to a string for returning the
871 * new file name, GID for trail file, and audit_warn function pointer for
872 * 'getacdir()' errors.  Returns:
873 *	ADE_NOERR	on success,
874 *	ADE_STRERR	if the file name string could not be created,
875 *	ADE_SWAPERR	if the audit trail file could not be swapped,
876 *	ADE_ACTL	if the auditctl(2) call failed but file swap still
877 *			successful.
878 *	ADE_ACTLERR	if the auditctl(2) call failed and file swap failed.
879 *	ADE_SYMLINK	if symlink(2) failed updating the current link.
880 */
881int
882auditd_swap_trail(char *TS, char **newfile, gid_t gid,
883    int (*warn_getacdir)(char *))
884{
885	char timestr[FILENAME_LEN + 1];
886	char *fn;
887	struct dir_ent *dirent;
888	int saverrno = 0;
889
890	if (strlen(TS) != TIMESTAMP_LEN ||
891	    snprintf(timestr, sizeof(timestr), "%s.%s", TS,
892	    NOT_TERMINATED) < 0) {
893		errno = EINVAL;
894		return (ADE_STRERR);
895	}
896
897	/* Try until we succeed. */
898	TAILQ_FOREACH(dirent, &dir_q, dirs) {
899		if (dirent->hardlim)
900			continue;
901		if ((fn = affixdir(timestr, dirent)) == NULL)
902			return (ADE_STRERR);
903
904		/*
905		 * Create the file and pass to the kernel if all went well.
906		 */
907		if (open_trail(fn, gid, &saverrno) == 0) {
908			/* Success. */
909			*newfile = fn;
910			if (saverrno) {
911				/*
912				 * auditctl() failed but still
913				 * successful. Return errno and "soft"
914				 * error.
915				 */
916				errno = saverrno;
917				return (ADE_ACTL);
918			}
919			return (ADE_NOERR);
920		}
921		/*
922		 * auditctl failed setting log file. Try again.
923		 */
924		/*
925		 * Tell the administrator about lack of permissions for dir.
926		 */
927		if (warn_getacdir != NULL)
928			(*warn_getacdir)(dirent->dirname);
929	}
930	if (saverrno) {
931		errno = saverrno;
932		return (ADE_ACTLERR);
933	} else
934		return (ADE_SWAPERR);
935}
936
937/*
938 * Mask calling process from being audited. Returns:
939 *	ADE_NOERR	on success,
940 *	ADE_SETAUDIT	if setaudit(2) fails.
941 */
942#ifdef __APPLE__
943int
944auditd_prevent_audit(void)
945{
946	auditinfo_addr_t aia;
947
948	/*
949	 * To prevent event feedback cycles and avoid audit becoming stalled if
950	 * auditing is suspended we mask this processes events from being
951	 * audited.  We allow the uid, tid, and mask fields to be implicitly
952	 * set to zero, but do set the audit session ID to the PID.
953	 *
954	 * XXXRW: Is there more to it than this?
955	 */
956	bzero(&aia, sizeof(aia));
957	aia.ai_asid = AU_ASSIGN_ASID;
958	aia.ai_termid.at_type = AU_IPv4;
959	if (setaudit_addr(&aia, sizeof(aia)) != 0)
960		return (ADE_SETAUDIT);
961	return (ADE_NOERR);
962}
963#else
964int
965auditd_prevent_audit(void)
966{
967	auditinfo_t ai;
968
969	/*
970	 * To prevent event feedback cycles and avoid audit becoming stalled if
971	 * auditing is suspended we mask this processes events from being
972	 * audited.  We allow the uid, tid, and mask fields to be implicitly
973	 * set to zero, but do set the audit session ID to the PID.
974	 *
975	 * XXXRW: Is there more to it than this?
976	 */
977	bzero(&ai, sizeof(ai));
978	ai.ai_asid = getpid();
979	if (setaudit(&ai) != 0)
980		return (ADE_SETAUDIT);
981	return (ADE_NOERR);
982}
983#endif /* !__APPLE__ */
984
985/*
986 * Generate and submit audit record for audit startup or shutdown.  The event
987 * argument can be AUE_audit_recovery, AUE_audit_startup or
988 * AUE_audit_shutdown. The path argument will add a path token, if not NULL.
989 * Returns:
990 *	AUE_NOERR	on success,
991 *	ADE_NOMEM	if memory allocation fails,
992 *	ADE_AU_OPEN	if au_open(3) fails,
993 *	ADE_AU_CLOSE	if au_close(3) fails.
994 */
995int
996auditd_gen_record(int event, char *path)
997{
998	int aufd;
999	uid_t uid;
1000	pid_t pid;
1001	char *autext = NULL;
1002	token_t *tok;
1003	struct auditinfo_addr aia;
1004
1005	if (event == AUE_audit_startup)
1006		asprintf(&autext, "%s::Audit startup", getprogname());
1007	else if (event == AUE_audit_shutdown)
1008		asprintf(&autext, "%s::Audit shutdown", getprogname());
1009	else if (event == AUE_audit_recovery)
1010		asprintf(&autext, "%s::Audit recovery", getprogname());
1011	else
1012		return (ADE_INVAL);
1013	if (autext == NULL)
1014		return (ADE_NOMEM);
1015
1016	if ((aufd = au_open()) == -1) {
1017		free(autext);
1018		return (ADE_AU_OPEN);
1019	}
1020	bzero(&aia, sizeof(aia));
1021	uid = getuid(); pid = getpid();
1022	if ((tok = au_to_subject32_ex(uid, geteuid(), getegid(), uid, getgid(),
1023	    pid, pid, &aia.ai_termid)) != NULL)
1024		au_write(aufd, tok);
1025	if ((tok = au_to_text(autext)) != NULL)
1026		au_write(aufd, tok);
1027	free(autext);
1028	if (path != NULL && (tok = au_to_path(path)) != NULL)
1029		au_write(aufd, tok);
1030	if ((tok = au_to_return32(0, 0)) != NULL)
1031		au_write(aufd, tok);
1032	if (au_close(aufd, 1, event) == -1)
1033		return (ADE_AU_CLOSE);
1034
1035	return (ADE_NOERR);
1036}
1037
1038/*
1039 * Check for a 'current' symlink and do crash recovery, if needed. Create a new
1040 * 'current' symlink. The argument 'curfile' is the file the 'current' symlink
1041 * should point to.  Returns:
1042 *	ADE_NOERR	on success,
1043 *	ADE_AU_OPEN	if au_open(3) fails,
1044 *	ADE_AU_CLOSE	if au_close(3) fails.
1045 *	ADE_RENAME	if error renaming audit trail file,
1046 *	ADE_READLINK	if error reading the 'current' link,
1047 *	ADE_SYMLINK	if error creating 'current' link.
1048 */
1049int
1050auditd_new_curlink(char *curfile)
1051{
1052	int len, err;
1053	char *ptr;
1054	char *path = NULL;
1055	struct stat sb;
1056	char recoveredname[MAXPATHLEN];
1057	char newname[MAXPATHLEN];
1058
1059	/*
1060	 * Check to see if audit was shutdown properly.  If not, clean up,
1061	 * recover previous audit trail file, and generate audit record.
1062	 */
1063	len = readlink(AUDIT_CURRENT_LINK, recoveredname,
1064	    sizeof(recoveredname) - 1);
1065	if (len > 0) {
1066		/* 'current' exist but is it pointing at a valid file?  */
1067		recoveredname[len++] = '\0';
1068		if (stat(recoveredname, &sb) == 0) {
1069			/* Yes, rename it to a crash recovery file. */
1070			strlcpy(newname, recoveredname, sizeof(newname));
1071
1072			if ((ptr = strstr(newname, NOT_TERMINATED)) != NULL) {
1073				memcpy(ptr, CRASH_RECOVERY, POSTFIX_LEN);
1074				if (auditd_rename(recoveredname, newname) != 0)
1075					return (ADE_RENAME);
1076			} else
1077				return (ADE_STRERR);
1078
1079			path = newname;
1080		}
1081
1082		/* 'current' symlink is (now) invalid so remove it. */
1083		(void) unlink(AUDIT_CURRENT_LINK);
1084
1085		/* Note the crash recovery in current audit trail */
1086		err = auditd_gen_record(AUE_audit_recovery, path);
1087		if (err)
1088			return (err);
1089	}
1090
1091	if (len < 0 && errno != ENOENT)
1092		return (ADE_READLINK);
1093
1094	if (symlink(curfile, AUDIT_CURRENT_LINK) != 0)
1095		return (ADE_SYMLINK);
1096
1097	return (0);
1098}
1099
1100/*
1101 * Do just what we need to quickly start auditing.  Assume no system logging or
1102 * notify.  Return:
1103 *   0	 on success,
1104 *  -1   on failure.
1105 */
1106int
1107audit_quick_start(void)
1108{
1109	int err;
1110	char *newfile = NULL;
1111	time_t tt;
1112	char TS[TIMESTAMP_LEN + 1];
1113	int ret = 0;
1114
1115	/*
1116	 * Mask auditing of this process.
1117	 */
1118	if (auditd_prevent_audit() != 0)
1119		return (-1);
1120
1121	/*
1122	 * Read audit_control and get log directories.
1123	 */
1124	err = auditd_read_dirs(NULL, NULL);
1125	if (err != ADE_NOERR && err != ADE_SOFTLIM)
1126		return (-1);
1127
1128	/*
1129	 * Setup trail file distribution.
1130	 */
1131	(void) auditd_set_dist();
1132
1133	/*
1134	 *  Create a new audit trail log.
1135	 */
1136	if (getTSstr(tt, TS, sizeof(TS)) != 0)
1137		return (-1);
1138	err = auditd_swap_trail(TS, &newfile, getgid(), NULL);
1139	if (err != ADE_NOERR && err != ADE_ACTL) {
1140		ret = -1;
1141		goto out;
1142	}
1143
1144	/*
1145	 * Add the current symlink and recover from crash, if needed.
1146	 */
1147	if (auditd_new_curlink(newfile) != 0) {
1148		ret = -1;
1149		goto out;
1150	}
1151
1152	/*
1153	 * At this point auditing has started so generate audit start-up record.
1154	 */
1155	if (auditd_gen_record(AUE_audit_startup, NULL) != 0) {
1156		ret = -1;
1157		goto out;
1158	}
1159
1160	/*
1161	 *  Configure the audit controls.
1162	 */
1163	(void) auditd_set_evcmap();
1164	(void) auditd_set_namask();
1165	(void) auditd_set_policy();
1166	(void) auditd_set_fsize();
1167	(void) auditd_set_minfree();
1168	(void) auditd_set_host();
1169
1170out:
1171	if (newfile != NULL)
1172		free(newfile);
1173
1174	return (ret);
1175}
1176
1177/*
1178 * Shut down auditing quickly.  Assumes that is only called on system shutdown.
1179 * Returns:
1180 *	 0	on success,
1181 *	-1	on failure.
1182 */
1183int
1184audit_quick_stop(void)
1185{
1186	int len;
1187	int cond;
1188	char *ptr;
1189	time_t tt;
1190	char oldname[MAXPATHLEN];
1191	char newname[MAXPATHLEN];
1192	char TS[TIMESTAMP_LEN + 1];
1193
1194	/*
1195	 * Auditing already disabled?
1196	 */
1197	if (audit_get_cond(&cond) != 0)
1198		return (-1);
1199	if (cond == AUC_NOAUDIT)
1200		return (0);
1201
1202	/*
1203	 *  Generate audit shutdown record.
1204	 */
1205	(void) auditd_gen_record(AUE_audit_shutdown, NULL);
1206
1207	/*
1208	 * Shutdown auditing in the kernel.
1209	 */
1210	cond = AUC_DISABLED;
1211	if (audit_set_cond(&cond) != 0)
1212		return (-1);
1213#ifdef	__BSM_INTERNAL_NOTIFY_KEY
1214	notify_post(__BSM_INTERNAL_NOTIFY_KEY);
1215#endif
1216
1217	/*
1218	 * Rename last audit trail and remove 'current' link.
1219	 */
1220	len = readlink(AUDIT_CURRENT_LINK, oldname, sizeof(oldname) - 1);
1221	if (len < 0)
1222		return (-1);
1223	oldname[len++] = '\0';
1224
1225	if (getTSstr(tt, TS, sizeof(TS)) != 0)
1226		return (-1);
1227
1228	strlcpy(newname, oldname, sizeof(newname));
1229
1230	if ((ptr = strstr(newname, NOT_TERMINATED)) != NULL) {
1231		memcpy(ptr, TS, POSTFIX_LEN);
1232		if (auditd_rename(oldname, newname) != 0)
1233			return (-1);
1234	} else
1235		return (-1);
1236
1237	(void) unlink(AUDIT_CURRENT_LINK);
1238
1239	return (0);
1240}
1241