bsm_notify.c revision 293161
167754Smsmith/*-
267754Smsmith * Copyright (c) 2004-2009 Apple Inc.
367754Smsmith * All rights reserved.
467754Smsmith *
567754Smsmith * Redistribution and use in source and binary forms, with or without
667754Smsmith * modification, are permitted provided that the following conditions
7217365Sjkim * are met:
8306536Sjkim * 1.  Redistributions of source code must retain the above copyright
970243Smsmith *     notice, this list of conditions and the following disclaimer.
1067754Smsmith * 2.  Redistributions in binary form must reproduce the above copyright
11217365Sjkim *     notice, this list of conditions and the following disclaimer in the
12217365Sjkim *     documentation and/or other materials provided with the distribution.
13217365Sjkim * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
14217365Sjkim *     its contributors may be used to endorse or promote products derived
15217365Sjkim *     from this software without specific prior written permission.
16217365Sjkim *
17217365Sjkim * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
18217365Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19217365Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20217365Sjkim * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
21217365Sjkim * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2567754Smsmith * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
26217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27217365Sjkim * POSSIBILITY OF SUCH DAMAGE.
28217365Sjkim */
2967754Smsmith
30217365Sjkim/*
31217365Sjkim * Based on sample code from Marc Majka.
32217365Sjkim */
33217365Sjkim#include <sys/types.h>
34217365Sjkim
35217365Sjkim#include <config/config.h>
36217365Sjkim#ifdef HAVE_FULL_QUEUE_H
37217365Sjkim#include <sys/queue.h>
38217365Sjkim#else /* !HAVE_FULL_QUEUE_H */
39217365Sjkim#include <compat/queue.h>
40217365Sjkim#endif /* !HAVE_FULL_QUEUE_H */
41217365Sjkim
42217365Sjkim#include <bsm/audit_internal.h>
4367754Smsmith#include <bsm/libbsm.h>
44193341Sjkim
45193341Sjkim#include <errno.h>
46193341Sjkim#include <inttypes.h>
4767754Smsmith#include <stdarg.h>
4867754Smsmith#include <string.h>
4977424Smsmith#include <syslog.h>
5091116Smsmith
5167754Smsmith
5267754Smsmith#ifdef __APPLE__
5367754Smsmith#include <notify.h>
5467754Smsmith/* If 1, assumes a kernel that sends the right notification. */
55281075Sdim#define	AUDIT_NOTIFICATION_ENABLED	1
56281075Sdim
57281075Sdim#if AUDIT_NOTIFICATION_ENABLED
58281075Sdimstatic int	token = 0;
59281075Sdim#endif	/* AUDIT_NOTIFICATION_ENABLED */
60281075Sdim
61281075Sdimstatic int	au_cond = AUC_UNSET;	/* <bsm/audit.h> */
62281075Sdim
63281075Sdimuint32_t
64281075Sdimau_notify_initialize(void)
65281075Sdim{
66281075Sdim#if AUDIT_NOTIFICATION_ENABLED
67281075Sdim	uint32_t status;
68281075Sdim	int ignore_first;
69281075Sdim
70281075Sdim	status = notify_register_check(__BSM_INTERNAL_NOTIFY_KEY, &token);
71281075Sdim	if (status != NOTIFY_STATUS_OK)
72281075Sdim		return (status);
73281075Sdim	status = notify_check(token, &ignore_first);
74281075Sdim	if (status != NOTIFY_STATUS_OK)
75281075Sdim		return (status);
76281075Sdim#endif
77281075Sdim
78281075Sdim	if (audit_get_cond(&au_cond) != 0) {
79281075Sdim		syslog(LOG_ERR, "Initial audit status check failed (%s)",
80281075Sdim		    strerror(errno));
81281075Sdim		if (errno == ENOSYS)	/* auditon() unimplemented. */
82281075Sdim			return (AU_UNIMPL);
83281075Sdim		return (NOTIFY_STATUS_FAILED);	/* Is there a better code? */
84281075Sdim	}
85281075Sdim	return (NOTIFY_STATUS_OK);
86281075Sdim}
87281075Sdim
88281075Sdimint
89281075Sdimau_notify_terminate(void)
90281075Sdim{
91281075Sdim
92151937Sjkim#if AUDIT_NOTIFICATION_ENABLED
93151937Sjkim	return ((notify_cancel(token) == NOTIFY_STATUS_OK) ? 0 : -1);
94167802Sjkim#else
95151937Sjkim	return (0);
96151937Sjkim#endif
97151937Sjkim}
98151937Sjkim
99151937Sjkim/*
100151937Sjkim * On error of any notify(3) call, reset 'au_cond' to ensure we re-run
101151937Sjkim * au_notify_initialize() next time 'round--but assume auditing is on.  This
102253690Sjkim * is a slight performance hit if auditing is off, but at least the system
103151937Sjkim * will behave correctly.  The notification calls are unlikely to fail,
104167802Sjkim * anyway.
105151937Sjkim */
106151937Sjkimint
107151937Sjkimau_get_state(void)
108167802Sjkim{
109167802Sjkim#if AUDIT_NOTIFICATION_ENABLED
110167802Sjkim	int did_notify;
111167802Sjkim#endif
112151937Sjkim	int status;
113254745Sjkim
114151937Sjkim	/*
115151937Sjkim	 * Don't make the client initialize this set of routines, but take the
116151937Sjkim	 * slight performance hit by checking ourselves every time.
117151937Sjkim	 */
118151937Sjkim	if (au_cond == AUC_UNSET) {
119151937Sjkim		status = au_notify_initialize();
120151937Sjkim		if (status != NOTIFY_STATUS_OK) {
121151937Sjkim			if (status == AU_UNIMPL)
122167802Sjkim				return (AU_UNIMPL);
123151937Sjkim			return (AUC_AUDITING);
124151937Sjkim		} else
125151937Sjkim			return (au_cond);
126151937Sjkim	}
127151937Sjkim#if AUDIT_NOTIFICATION_ENABLED
128151937Sjkim	status = notify_check(token, &did_notify);
129151937Sjkim	if (status != NOTIFY_STATUS_OK) {
130167802Sjkim		au_cond = AUC_UNSET;
131151937Sjkim		return (AUC_AUDITING);
132151937Sjkim	}
133151937Sjkim
134151937Sjkim	if (did_notify == 0)
135151937Sjkim		return (au_cond);
136151937Sjkim#endif
137151937Sjkim
138151937Sjkim	if (audit_get_cond(&au_cond) != 0) {
139151937Sjkim		/* XXX Reset au_cond to AUC_UNSET? */
140151937Sjkim		syslog(LOG_ERR, "Audit status check failed (%s)",
141193267Sjkim		    strerror(errno));
14267754Smsmith		if (errno == ENOSYS)	/* Function unimplemented. */
143167802Sjkim			return (AU_UNIMPL);
14467754Smsmith		return (errno);
145167802Sjkim	}
14667754Smsmith
147167802Sjkim	switch (au_cond) {
148241973Sjkim	case AUC_NOAUDIT:	/* Auditing suspended. */
14967754Smsmith	case AUC_DISABLED:	/* Auditing shut off. */
150167802Sjkim		return (AUC_NOAUDIT);
151167802Sjkim
152167802Sjkim	case AUC_UNSET:		/* Uninitialized; shouldn't get here. */
15378986Smsmith	case AUC_AUDITING:	/* Audit on. */
154167802Sjkim	default:
155167802Sjkim		return (AUC_AUDITING);
15678986Smsmith	}
15778986Smsmith}
15867754Smsmith#endif	/* !__APPLE__ */
15978986Smsmith
160167802Sjkimint
161281687Sjkimcannot_audit(int val __unused)
16278986Smsmith{
163167802Sjkim#ifdef __APPLE__
164167802Sjkim	return (!(au_get_state() == AUC_AUDITING));
165167802Sjkim#else
16678986Smsmith	int cond;
16778986Smsmith
168167802Sjkim	if (audit_get_cond(&cond) != 0) {
16978986Smsmith		if (errno != ENOSYS) {
17078986Smsmith			syslog(LOG_ERR, "Audit status check failed (%s)",
171167802Sjkim			    strerror(errno));
17267754Smsmith		}
173167802Sjkim		return (1);
174306536Sjkim	}
175306536Sjkim	if (cond == AUC_NOAUDIT || cond == AUC_DISABLED)
176167802Sjkim		return (1);
17784491Smsmith	return (0);
178167802Sjkim#endif	/* !__APPLE__ */
179204773Sjkim}
180167802Sjkim