auditd_lib.c revision 187214
1/*-
2 * Copyright (c) 2008 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 * $P4: //depot/projects/trustedbsd/openbsm/libauditd/auditd_lib.c#2 $
30 */
31
32#include <sys/param.h>
33
34#include <config/config.h>
35
36#include <sys/dirent.h>
37#include <sys/mount.h>
38#include <sys/socket.h>
39#ifdef HAVE_FULL_QUEUE_H
40#include <sys/queue.h>
41#else /* !HAVE_FULL_QUEUE_H */
42#include <compat/queue.h>
43#endif /* !HAVE_FULL_QUEUE_H */
44
45#include <sys/stat.h>
46#include <sys/time.h>
47
48#include <netinet/in.h>
49
50#include <bsm/audit.h>
51#include <bsm/audit_uevents.h>
52#include <bsm/auditd_lib.h>
53#include <bsm/libbsm.h>
54
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
80struct dir_ent {
81	char			*dirname;
82	uint8_t			 softlim;
83	uint8_t			 hardlim;
84	TAILQ_ENTRY(dir_ent)	 dirs;
85};
86
87static TAILQ_HEAD(, dir_ent)	dir_q;
88static int minval = -1;
89
90static char *auditd_errmsg[] = {
91	"no error",					/* ADE_NOERR 	( 0) */
92	"could not parse audit_control(5) file",	/* ADE_PARSE 	( 1) */
93	"auditon(2) failed",				/* ADE_AUDITON 	( 2) */
94	"malloc(3) failed",				/* ADE_NOMEM 	( 3) */
95	"all audit log directories over soft limit",	/* ADE_SOFTLIM  ( 4) */
96	"all audit log directories over hard limit",	/* ADE_HARDLIM 	( 5) */
97	"could not create file name string",		/* ADE_STRERR 	( 6) */
98	"could not open audit record", 			/* ADE_AU_OPEN 	( 7) */
99	"could not close audit record",			/* ADE_AU_CLOSE ( 8) */
100	"could not set active audit session state",	/* ADE_SETAUDIT ( 9) */
101	"auditctl(2) failed (trail still swapped)",	/* ADE_ACTL 	(10) */
102	"auditctl(2) failed (trail not swapped)",	/* ADE_ACTLERR  (11) */
103	"could not swap audit trail file",		/* ADE_SWAPERR 	(12) */
104	"could not rename crash recovery file",		/* ADE_RENAME	(13) */
105	"could not read 'current' link file",		/* ADE_READLINK	(14) */
106	"could not create 'current' link file", 	/* ADE_SYMLINK  (15) */
107	"invalid argument",				/* ADE_INVAL	(16) */
108	"could not resolve hostname to address",	/* ADE_GETADDR	(17) */
109	"address family not supported",			/* ADE_ADDRFAM	(18) */
110};
111
112#define MAXERRCODE (sizeof(auditd_errmsg) / sizeof(auditd_errmsg[0]))
113
114#define NA_EVENT_STR_SIZE       25
115#define POL_STR_SIZE            128
116
117
118/*
119 * Look up and return the error string for the given audit error code.
120 */
121const char *
122auditd_strerror(int errcode)
123{
124	int idx = -errcode;
125
126	if (idx < 0 || idx > (int)MAXERRCODE)
127		return ("Invalid auditd error code");
128
129	return (auditd_errmsg[idx]);
130}
131
132
133/*
134 * Free our local list of directory names and init list
135 */
136static void
137free_dir_q(void)
138{
139	struct dir_ent *d1, *d2;
140
141	d1 = TAILQ_FIRST(&dir_q);
142	while (d1 != NULL) {
143		d2 = TAILQ_NEXT(d1, dirs);
144		free(d1->dirname);
145		free(d1);
146		d1 = d2;
147	}
148	TAILQ_INIT(&dir_q);
149}
150
151/*
152 * Concat the directory name to the given file name.
153 * XXX We should affix the hostname also
154 */
155static char *
156affixdir(char *name, struct dir_ent *dirent)
157{
158	char *fn = NULL;
159
160	/*
161	 * Sanity check on file name.
162	 */
163	if (strlen(name) != (FILENAME_LEN - 1)) {
164		errno = EINVAL;
165                return (NULL);
166	}
167
168	asprintf(&fn, "%s/%s", dirent->dirname, name);
169	return (fn);
170}
171
172/*
173 * Insert the directory entry in the list by the way they are ordered in
174 * audit_control(5).  Move the entries that are over the soft and hard limits
175 * toward the tail.
176 */
177static void
178insert_orderly(struct dir_ent *denew)
179{
180	struct dir_ent *dep;
181
182	TAILQ_FOREACH(dep, &dir_q, dirs) {
183		if (dep->softlim == 1 && denew->softlim == 0) {
184			TAILQ_INSERT_BEFORE(dep, denew, dirs);
185			return;
186		}
187		if (dep->hardlim == 1 && denew->hardlim == 0) {
188			TAILQ_INSERT_BEFORE(dep, denew, dirs);
189			return;
190		}
191	}
192	TAILQ_INSERT_TAIL(&dir_q, denew, dirs);
193}
194
195/*
196 * Get the host from audit_control(5) and set it in the audit kernel
197 * information.  Return:
198 *	ADE_NOERR	on success.
199 *	ADE_PARSE	error parsing audit_control(5).
200 *	ADE_AUDITON	error getting/setting auditon(2) value.
201 *	ADE_GETADDR 	error getting address info for host.
202 *	ADE_ADDRFAM	un-supported address family.
203 */
204int
205auditd_set_host(void)
206{
207	char hoststr[MAXHOSTNAMELEN];
208	struct sockaddr_in6 *sin6;
209	struct sockaddr_in *sin;
210	struct addrinfo *res;
211	struct auditinfo_addr aia;
212	int error, ret = ADE_NOERR;
213
214	if (getachost(hoststr, MAXHOSTNAMELEN) != 0) {
215
216		ret = ADE_PARSE;
217
218		/*
219		 * To maintain reverse compatability with older audit_control
220		 * files, simply drop a warning if the host parameter has not
221		 * been set.  However, we will explicitly disable the
222		 * generation of extended audit header by passing in a zeroed
223		 * termid structure.
224		 */
225		bzero(&aia, sizeof(aia));
226		aia.ai_termid.at_type = AU_IPv4;
227		error = auditon(A_SETKAUDIT, &aia, sizeof(aia));
228		if (error < 0 && errno != ENOSYS)
229			ret = ADE_AUDITON;
230		return (ret);
231	}
232	error = getaddrinfo(hoststr, NULL, NULL, &res);
233	if (error)
234		return (ADE_GETADDR);
235	switch (res->ai_family) {
236	case PF_INET6:
237		sin6 = (struct sockaddr_in6 *) res->ai_addr;
238		bcopy(&sin6->sin6_addr.s6_addr,
239		    &aia.ai_termid.at_addr[0], sizeof(struct in6_addr));
240		aia.ai_termid.at_type = AU_IPv6;
241		break;
242
243	case PF_INET:
244		sin = (struct sockaddr_in *) res->ai_addr;
245		bcopy(&sin->sin_addr.s_addr,
246		    &aia.ai_termid.at_addr[0], sizeof(struct in_addr));
247		aia.ai_termid.at_type = AU_IPv4;
248		break;
249
250	default:
251		/* Un-supported address family in host parameter. */
252		errno = EAFNOSUPPORT;
253		return (ADE_ADDRFAM);
254	}
255
256	if (auditon(A_SETKAUDIT, &aia, sizeof(aia)) < 0)
257		ret = ADE_AUDITON;
258
259	return (ret);
260}
261
262/*
263 * Get the min percentage of free blocks from audit_control(5) and that
264 * value in the kernel.  Return:
265 *	ADE_NOERR	on success,
266 *	ADE_PARSE 	error parsing audit_control(5),
267 *	ADE_AUDITON	error getting/setting auditon(2) value.
268 */
269int
270auditd_set_minfree(void)
271{
272	au_qctrl_t qctrl;
273
274	if (getacmin(&minval) != 0)
275		return (ADE_PARSE);
276
277	if (auditon(A_GETQCTRL, &qctrl, sizeof(qctrl)) != 0)
278		return (ADE_AUDITON);
279
280	if (qctrl.aq_minfree != minval) {
281		qctrl.aq_minfree = minval;
282		if (auditon(A_SETQCTRL, &qctrl, sizeof(qctrl)) != 0)
283			return (ADE_AUDITON);
284	}
285
286	return (0);
287}
288
289/*
290 * Parses the "dir" entry in audit_control(5) into an ordered list.  Also, will
291 * set the minfree value if not already set.  Arguments include function
292 * pointers to audit_warn functions for soft and hard limits. Returns:
293 *	ADE_NOERR	on success,
294 *	ADE_PARSE	error parsing audit_control(5),
295 *	ADE_AUDITON	error getting/setting auditon(2) value,
296 *	ADE_NOMEM	error allocating memory,
297 *	ADE_SOFTLIM	if all the directories are over the soft limit,
298 *	ADE_HARDLIM	if all the directories are over the hard limit,
299 */
300int
301auditd_read_dirs(int (*warn_soft)(char *), int (*warn_hard)(char *))
302{
303	char cur_dir[MAXNAMLEN];
304	struct dir_ent *dirent;
305	struct statfs sfs;
306	int err;
307	char soft, hard;
308	int tcnt = 0;
309	int scnt = 0;
310	int hcnt = 0;
311
312	if (minval == -1 && (err = auditd_set_minfree()) != 0)
313		return (err);
314
315        /*
316         * Init directory q.  Force a re-read of the file the next time.
317         */
318	free_dir_q();
319	endac();
320
321	/*
322	 * Read the list of directories into an ordered linked list
323	 * admin's preference, then those over soft limit and, finally,
324	 * those over the hard limit.
325	 *
326         * XXX We should use the reentrant interfaces once they are
327         * available.
328         */
329	while (getacdir(cur_dir, MAXNAMLEN) >= 0) {
330		if (statfs(cur_dir, &sfs) < 0)
331			continue;  /* XXX should warn */
332		soft = (sfs.f_bfree < (sfs.f_blocks / (100 / minval))) ? 1 : 0;
333		hard = (sfs.f_bfree < AUDIT_HARD_LIMIT_FREE_BLOCKS) ? 1 : 0;
334		if (soft) {
335			if (warn_soft)
336				(*warn_soft)(cur_dir);
337			scnt++;
338		}
339		if (hard) {
340			if (warn_hard)
341				(*warn_hard)(cur_dir);
342			hcnt++;
343		}
344		dirent = (struct dir_ent *) malloc(sizeof(struct dir_ent));
345		if (dirent == NULL)
346			return (ADE_NOMEM);
347		dirent->softlim = soft;
348		dirent->hardlim = hard;
349		dirent->dirname = (char *) malloc(MAXNAMLEN);
350		if (dirent->dirname == NULL) {
351			free(dirent);
352			return (ADE_NOMEM);
353		}
354		strlcpy(dirent->dirname, cur_dir, MAXNAMLEN);
355		insert_orderly(dirent);
356		tcnt++;
357	}
358
359	if (hcnt == tcnt)
360		return (ADE_HARDLIM);
361	if (scnt == tcnt)
362		return (ADE_SOFTLIM);
363	return (0);
364}
365
366void
367auditd_close_dirs(void)
368{
369	free_dir_q();
370	minval = -1;
371}
372
373
374/*
375 * Process the audit event file, obtaining a class mapping for each event, and
376 * set that mapping into the kernel. Return:
377 * 	 n	number of event mappings that were successfully processed,
378 *   ADE_NOMEM	if there was an error allocating memory.
379 */
380int
381auditd_set_evcmap(void)
382{
383	au_event_ent_t ev, *evp;
384	au_evclass_map_t evc_map;
385	int ctr = 0;
386
387
388	/*
389	 * XXX There's a risk here that the BSM library will return NULL
390	 * for an event when it can't properly map it to a class. In that
391	 * case, we will not process any events beyond the one that failed,
392	 * but should. We need a way to get a count of the events.
393	 */
394	ev.ae_name = (char *)malloc(AU_EVENT_NAME_MAX);
395	ev.ae_desc = (char *)malloc(AU_EVENT_DESC_MAX);
396	if ((ev.ae_name == NULL) || (ev.ae_desc == NULL)) {
397		if (ev.ae_name != NULL)
398			free(ev.ae_name);
399		return (ADE_NOMEM);
400	}
401
402	/*
403	 * XXXRW: Currently we have no way to remove mappings from the kernel
404	 * when they are removed from the file-based mappings.
405	 */
406	evp = &ev;
407	setauevent();
408	while ((evp = getauevent_r(evp)) != NULL) {
409		evc_map.ec_number = evp->ae_number;
410		evc_map.ec_class = evp->ae_class;
411		if (auditon(A_SETCLASS, &evc_map, sizeof(au_evclass_map_t))
412		    == 0)
413			ctr++;
414	}
415	endauevent();
416	free(ev.ae_name);
417	free(ev.ae_desc);
418
419	return (ctr);
420}
421
422/*
423 * Get the non-attributable event string and set the kernel mask.  Return:
424 *	ADE_NOERR 	on success,
425 *	ADE_PARSE	error parsing audit_control(5),
426 *	ADE_AUDITON	error setting the mask using auditon(2).
427 */
428int
429auditd_set_namask(void)
430{
431	au_mask_t aumask;
432	char naeventstr[NA_EVENT_STR_SIZE];
433
434	if ((getacna(naeventstr, NA_EVENT_STR_SIZE) != 0) ||
435	    (getauditflagsbin(naeventstr, &aumask) != 0))
436		return (ADE_PARSE);
437
438	if (auditon(A_SETKMASK, &aumask, sizeof(au_mask_t)))
439		return (ADE_AUDITON);
440
441	return (ADE_NOERR);
442}
443
444/*
445 * Set the audit control policy if a policy is configured in audit_control(5),
446 * implement the policy. However, if one isn't defined or if there is an error
447 * parsing the control file, set AUDIT_CNT to avoid leaving the system in a
448 * fragile state.  Return:
449 *	ADE_NOERR 	on success,
450 *	ADE_PARSE	error parsing audit_control(5),
451 *	ADE_AUDITON	error setting policy using auditon(2).
452 */
453int
454auditd_set_policy(void)
455{
456	long policy;
457	char polstr[POL_STR_SIZE];
458
459	if ((getacpol(polstr, POL_STR_SIZE) != 0) ||
460            (au_strtopol(polstr, &policy) != 0)) {
461		policy = AUDIT_CNT;
462		if (auditon(A_SETPOLICY, &policy, sizeof(policy)))
463			return (ADE_AUDITON);
464		return (ADE_PARSE);
465        }
466
467	if (auditon(A_SETPOLICY, &policy, sizeof(policy)))
468		return (ADE_AUDITON);
469
470	return (ADE_NOERR);
471}
472
473/*
474 * Set trail rotation size.  Return:
475 *	ADE_NOERR 	on success,
476 *	ADE_PARSE	error parsing audit_control(5),
477 *	ADE_AUDITON	error setting file size using auditon(2).
478 */
479int
480auditd_set_fsize(void)
481{
482	size_t filesz;
483	au_fstat_t au_fstat;
484
485	/*
486	 * Set trail rotation size.
487	 */
488	if (getacfilesz(&filesz) != 0)
489		return (ADE_PARSE);
490
491	bzero(&au_fstat, sizeof(au_fstat));
492	au_fstat.af_filesz = filesz;
493	if (auditon(A_SETFSIZE, &au_fstat, sizeof(au_fstat)) < 0)
494		return (ADE_AUDITON);
495
496        return (ADE_NOERR);
497}
498
499/*
500 * Create the new audit file with appropriate permissions and ownership.  Try
501 * to clean up if something goes wrong.
502 */
503static int
504open_trail(char *fname, gid_t gid)
505{
506	int error, fd;
507
508	fd = open(fname, O_RDONLY | O_CREAT, S_IRUSR | S_IRGRP);
509	if (fd < 0)
510		return (-1);
511	if (fchown(fd, -1, gid) < 0) {
512		error = errno;
513		close(fd);
514		(void)unlink(fname);
515		errno = error;
516		return (-1);
517	}
518	return (fd);
519}
520
521/*
522 * Create the new audit trail file, swap with existing audit file.  Arguments
523 * include timestamp for the filename, a pointer to a string for returning the
524 * new file name, GID for trail file, and audit_warn function pointer for
525 * 'getacdir()' errors.  Returns:
526 *  	ADE_NOERR	on success,
527 *  	ADE_STRERR	if the file name string could not be created,
528 *  	ADE_SWAPERR	if the audit trail file could not be swapped,
529 *	ADE_ACTL 	if the auditctl(2) call failed but file swap still
530 *			successful.
531 *	ADE_ACTLERR	if the auditctl(2) call failed and file swap failed.
532 *	ADE_SYMLINK	if symlink(2) failed updating the current link.
533 */
534int
535auditd_swap_trail(char *TS, char **newfile, gid_t gid,
536    int (*warn_getacdir)(char *))
537{
538	char timestr[FILENAME_LEN];
539	char *fn;
540	struct dir_ent *dirent;
541	int fd;
542	int error;
543	int saverrno = 0;
544
545	if (strlen(TS) !=  (TIMESTAMP_LEN - 1) ||
546	    snprintf(timestr, FILENAME_LEN, "%s.%s", TS, NOT_TERMINATED) < 0) {
547		errno = EINVAL;
548		return (ADE_STRERR);
549	}
550
551	/* Try until we succeed. */
552	while ((dirent = TAILQ_FIRST(&dir_q))) {
553		if (dirent->hardlim)
554			continue;
555		if ((fn = affixdir(timestr, dirent)) == NULL)
556			return (ADE_STRERR);
557
558		/*
559		 * Create and open the file; then close and pass to the
560		 * kernel if all went well.
561		 */
562		fd = open_trail(fn, gid);
563		if (fd >= 0) {
564			error = auditctl(fn);
565			if (error) {
566				/*
567				 * auditctl failed setting log file.
568				 * Try again.
569				 */
570				saverrno = errno;
571                                close(fd);
572                        } else {
573                                /* Success. */
574                                *newfile = fn;
575                                close(fd);
576				if (error)
577					return (error);
578				if (saverrno) {
579					/*
580					 * auditctl() failed but still
581					 * successful. Return errno and "soft"
582					 * error.
583					 */
584					errno = saverrno;
585					return (ADE_ACTL);
586				}
587                                return (ADE_NOERR);
588                        }
589                }
590
591		/*
592		 * Tell the administrator about lack of permissions for dir.
593		 */
594		if (warn_getacdir != NULL)
595			(*warn_getacdir)(dirent->dirname);
596	}
597	if (saverrno) {
598		errno = saverrno;
599		return (ADE_ACTLERR);
600	} else
601		return (ADE_SWAPERR);
602}
603
604/*
605 * Mask calling process from being audited. Returns:
606 *	ADE_NOERR	on success,
607 *	ADE_SETAUDIT	if setaudit(2) fails.
608 */
609int
610auditd_prevent_audit(void)
611{
612	auditinfo_t ai;
613
614	/*
615	 * To prevent event feedback cycles and avoid audit becoming stalled if
616	 * auditing is suspended we mask this processes events from being
617	 * audited.  We allow the uid, tid, and mask fields to be implicitly
618	 * set to zero, but do set the audit session ID to the PID.
619	 *
620	 * XXXRW: Is there more to it than this?
621	 */
622	bzero(&ai, sizeof(ai));
623	ai.ai_asid = getpid();
624	if (setaudit(&ai) != 0)
625		return (ADE_SETAUDIT);
626	return (ADE_NOERR);
627}
628
629/*
630 * Generate and submit audit record for audit startup or shutdown.  The event
631 * argument can be AUE_audit_recovery, AUE_audit_startup or
632 * AUE_audit_shutdown. The path argument will add a path token, if not NULL.
633 * Returns:
634 *	AUE_NOERR	on success,
635 *	ADE_NOMEM	if memory allocation fails,
636 * 	ADE_AU_OPEN	if au_open(3) fails,
637 *	ADE_AU_CLOSE	if au_close(3) fails.
638 */
639int
640auditd_gen_record(int event, char *path)
641{
642	int aufd;
643	uid_t uid;
644	pid_t pid;
645	char *autext = NULL;
646	token_t *tok;
647	struct auditinfo_addr aia;
648
649	if (event == AUE_audit_startup)
650		asprintf(&autext, "%s::Audit startup", getprogname());
651	else if (event == AUE_audit_shutdown)
652		asprintf(&autext, "%s::Audit shutdown", getprogname());
653	else if (event == AUE_audit_recovery)
654		asprintf(&autext, "%s::Audit recovery", getprogname());
655	else
656		return (ADE_INVAL);
657	if (autext == NULL)
658		return (ADE_NOMEM);
659
660	if ((aufd = au_open()) == -1) {
661		free(autext);
662		return (ADE_AU_OPEN);
663	}
664	bzero(&aia, sizeof(aia));
665	uid = getuid(); pid = getpid();
666	if ((tok = au_to_subject32_ex(uid, geteuid(), getegid(), uid, getgid(),
667	     pid, pid, &aia.ai_termid)) != NULL)
668		au_write(aufd, tok);
669	if ((tok = au_to_text(autext)) != NULL)
670		au_write(aufd, tok);
671	free(autext);
672	if (path != NULL && (tok = au_to_path(path)) != NULL)
673		au_write(aufd, tok);
674	if ((tok = au_to_return32(0, 0)) != NULL)
675		au_write(aufd, tok);
676	if (au_close(aufd, 1, event) == -1)
677		return (ADE_AU_CLOSE);
678
679	return (ADE_NOERR);
680}
681
682/*
683 * Check for a 'current' symlink and do crash recovery, if needed. Create a new
684 * 'current' symlink. The argument 'curfile' is the file the 'current' symlink
685 * should point to.  Returns:
686 *	ADE_NOERR	on success,
687 *  	ADE_AU_OPEN	if au_open(3) fails,
688 *  	ADE_AU_CLOSE	if au_close(3) fails.
689 *	ADE_RENAME	if error renaming audit trail file,
690 *	ADE_READLINK	if error reading the 'current' link,
691 *	ADE_SYMLINK	if error creating 'current' link.
692 */
693int
694auditd_new_curlink(char *curfile)
695{
696	int len, err;
697	char *ptr;
698	char *path = NULL;
699	struct stat sb;
700	char recoveredname[MAXPATHLEN];
701	char newname[MAXPATHLEN];
702
703	/*
704	 * Check to see if audit was shutdown properly.  If not, clean up,
705	 * recover previous audit trail file, and generate audit record.
706	 */
707	len = readlink(AUDIT_CURRENT_LINK, recoveredname, MAXPATHLEN - 1);
708	if (len > 0) {
709		/* 'current' exist but is it pointing at a valid file?  */
710		recoveredname[len++] = '\0';
711		if (stat(recoveredname, &sb) == 0) {
712			/* Yes, rename it to a crash recovery file. */
713			strlcpy(newname, recoveredname, MAXPATHLEN);
714
715			if ((ptr = strstr(newname, NOT_TERMINATED)) != NULL) {
716				strlcpy(ptr, CRASH_RECOVERY, TIMESTAMP_LEN);
717				if (rename(recoveredname, newname) != 0)
718					return (ADE_RENAME);
719			} else
720				return (ADE_STRERR);
721
722			path = newname;
723		}
724
725		/* 'current' symlink is (now) invalid so remove it. */
726		(void) unlink(AUDIT_CURRENT_LINK);
727
728		/* Note the crash recovery in current audit trail */
729		err = auditd_gen_record(AUE_audit_recovery, path);
730		if (err)
731			return (err);
732	}
733
734	if (len < 0 && errno != ENOENT)
735		return (ADE_READLINK);
736
737	if (symlink(curfile, AUDIT_CURRENT_LINK) != 0)
738		return (ADE_SYMLINK);
739
740	return (0);
741}
742
743/*
744 * Do just what we need to quickly start auditing.  Assume no system logging or
745 * notify.  Return:
746 *   0	 on success,
747 *  -1   on failure.
748 */
749int
750audit_quick_start(void)
751{
752	int err;
753	char *newfile;
754	time_t tt;
755	char TS[TIMESTAMP_LEN];
756
757	/*
758	 * Mask auditing of this process.
759	 */
760	if (auditd_prevent_audit() != 0)
761		return (-1);
762
763	/*
764	 * Read audit_control and get log directories.
765	 */
766        err = auditd_read_dirs(NULL, NULL);
767	if (err != ADE_NOERR && err != ADE_SOFTLIM)
768		return (-1);
769
770	/*
771	 *  Create a new audit trail log.
772	 */
773	if (getTSstr(tt, TS, TIMESTAMP_LEN) != 0)
774		return (-1);
775	err = auditd_swap_trail(TS, &newfile, getgid(), NULL);
776	if (err != ADE_NOERR && err != ADE_ACTL)
777		return (-1);
778
779	/*
780	 * Add the current symlink and recover from crash, if needed.
781	 */
782	if (auditd_new_curlink(newfile) != 0)
783		return(-1);
784
785	/*
786	 * At this point auditing has started so generate audit start-up record.
787	 */
788	if (auditd_gen_record(AUE_audit_startup, NULL) != 0)
789		return (-1);
790
791	/*
792	 *  Configure the audit controls.
793	 */
794	(void) auditd_set_evcmap();
795	(void) auditd_set_namask();
796	(void) auditd_set_policy();
797	(void) auditd_set_fsize();
798	(void) auditd_set_minfree();
799	(void) auditd_set_host();
800
801	return (0);
802}
803
804/*
805 * Shut down auditing quickly.  Assumes that is only called on system shutdown.
806 * Returns:
807 *	 0	on success,
808 *	-1	on failure.
809 */
810int
811audit_quick_stop(void)
812{
813	int len;
814	long cond;
815	char *ptr;
816	time_t tt;
817	char oldname[MAXPATHLEN];
818	char newname[MAXPATHLEN];
819	char TS[TIMESTAMP_LEN];
820
821	/*
822	 * Auditing already disabled?
823	 */
824	if (auditon(A_GETCOND, &cond, sizeof(cond)) < 0)
825		return (-1);
826	if (cond == AUC_NOAUDIT)
827		return (0);
828
829	/*
830	 *  Generate audit shutdown record.
831	 */
832	(void) auditd_gen_record(AUE_audit_shutdown, NULL);
833
834	/*
835	 * Shutdown auditing in the kernel.
836	 */
837	cond = AUC_DISABLED;
838	if (auditon(A_SETCOND, &cond, sizeof(cond)) != 0)
839		return (-1);
840#ifdef	__BSM_INTERNAL_NOTIFY_KEY
841	notify_post(__BSM_INTERNAL_NOTIFY_KEY);
842#endif
843
844	/*
845	 * Rename last audit trail and remove 'current' link.
846	 */
847	len = readlink(AUDIT_CURRENT_LINK, oldname, MAXPATHLEN - 1);
848	if (len < 0)
849		return (-1);
850	oldname[len++] = '\0';
851
852	if (getTSstr(tt, TS, TIMESTAMP_LEN) != 0)
853		return (-1);
854
855	strlcpy(newname, oldname, len);
856
857	if ((ptr = strstr(newname, NOT_TERMINATED)) != NULL) {
858		strlcpy(ptr, TS, TIMESTAMP_LEN);
859		if (rename(oldname, newname) != 0)
860			return (-1);
861	} else
862		return (-1);
863
864	(void) unlink(AUDIT_CURRENT_LINK);
865
866	return (0);
867}
868