bsm_notify.c revision 156283
1193326Sed/*
2193326Sed * Copyright (c) 2004 Apple Computer, Inc.
3193326Sed * All rights reserved.
4193326Sed *
5193326Sed * Redistribution and use in source and binary forms, with or without
6193326Sed * modification, are permitted provided that the following conditions
7193326Sed * are met:
8193326Sed * 1.  Redistributions of source code must retain the above copyright
9193326Sed *     notice, this list of conditions and the following disclaimer.
10193326Sed * 2.  Redistributions in binary form must reproduce the above copyright
11193326Sed *     notice, this list of conditions and the following disclaimer in the
12193326Sed *     documentation and/or other materials provided with the distribution.
13193326Sed * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14193326Sed *     its contributors may be used to endorse or promote products derived
15193326Sed *     from this software without specific prior written permission.
16193326Sed *
17193326Sed * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
18193326Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19193326Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20193326Sed * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
21193326Sed * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22193326Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23193326Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24193326Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25193326Sed * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
26193326Sed * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27193326Sed * POSSIBILITY OF SUCH DAMAGE.
28193326Sed *
29193326Sed * $P4: //depot/projects/trustedbsd/openbsm/libbsm/bsm_notify.c#11 $
30193326Sed */
31193326Sed
32193326Sed/*
33193326Sed * Based on sample code from Marc Majka.
34193326Sed */
35193326Sed#include <sys/types.h>
36193326Sed
37193326Sed#include <config/config.h>
38193326Sed#ifdef HAVE_FULL_QUEUE_H
39193326Sed#include <sys/queue.h>
40193326Sed#else /* !HAVE_FULL_QUEUE_H */
41193326Sed#include <compat/queue.h>
42193326Sed#endif /* !HAVE_FULL_QUEUE_H */
43193326Sed
44193326Sed#include <bsm/audit_internal.h>
45193326Sed#include <bsm/libbsm.h>
46193326Sed
47193326Sed#include <errno.h>
48193326Sed#include <stdint.h>
49193326Sed#include <stdarg.h>
50193326Sed#include <string.h>
51193326Sed#include <syslog.h>
52193326Sed
53193326Sed
54212904Sdim#ifdef __APPLE__
55193326Sed#include <notify.h>
56193326Sed/* If 1, assumes a kernel that sends the right notification. */
57193326Sed#define	AUDIT_NOTIFICATION_ENABLED	1
58218893Sdim
59193326Sed#if AUDIT_NOTIFICATION_ENABLED
60193326Sedstatic int	token = 0;
61193326Sed#endif	/* AUDIT_NOTIFICATION_ENABLED */
62193326Sed
63193326Sedstatic long	au_cond = AUC_UNSET;	/* <bsm/audit.h> */
64193326Sed
65206275Srdivackyuint32_t
66234353Sdimau_notify_initialize(void)
67234353Sdim{
68234353Sdim#if AUDIT_NOTIFICATION_ENABLED
69193326Sed	uint32_t status, ignore_first;
70193326Sed
71193326Sed	status = notify_register_check(__BSM_INTERNAL_NOTIFY_KEY, &token);
72193326Sed	if (status != NOTIFY_STATUS_OK)
73193326Sed		return (status);
74193326Sed	status = notify_check(token, &ignore_first);
75193326Sed	if (status != NOTIFY_STATUS_OK)
76193326Sed		return (status);
77193326Sed#endif
78193326Sed
79193326Sed	if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) {
80193326Sed		syslog(LOG_ERR, "Initial audit status check failed (%s)",
81193326Sed		    strerror(errno));
82193326Sed		if (errno == ENOSYS)	/* auditon() unimplemented. */
83193326Sed			return (AU_UNIMPL);
84193326Sed		return (NOTIFY_STATUS_FAILED);	/* Is there a better code? */
85193326Sed	}
86193326Sed	return (NOTIFY_STATUS_OK);
87193326Sed}
88193326Sed
89193326Sedint
90193326Sedau_notify_terminate(void)
91198092Srdivacky{
92221345Sdim
93221345Sdim#if AUDIT_NOTIFICATION_ENABLED
94239462Sdim	return ((notify_cancel(token) == NOTIFY_STATUS_OK) ? 0 : -1);
95239462Sdim#else
96239462Sdim	return (0);
97239462Sdim#endif
98239462Sdim}
99221345Sdim
100221345Sdim/*
101223017Sdim * On error of any notify(3) call, reset 'au_cond' to ensure we re-run
102223017Sdim * au_notify_initialize() next time 'round--but assume auditing is on.  This
103223017Sdim * is a slight performance hit if auditing is off, but at least the system
104239462Sdim * will behave correctly.  The notification calls are unlikely to fail,
105239462Sdim * anyway.
106239462Sdim */
107239462Sdimint
108221345Sdimau_get_state(void)
109221345Sdim{
110221345Sdim#if AUDIT_NOTIFICATION_ENABLED
111221345Sdim	uint32_t did_notify;
112193326Sed#endif
113193326Sed	int status;
114193326Sed
115193326Sed	/*
116193326Sed	 * Don't make the client initialize this set of routines, but take the
117193326Sed	 * slight performance hit by checking ourselves every time.
118193326Sed	 */
119193326Sed	if (au_cond == AUC_UNSET) {
120193326Sed		status = au_notify_initialize();
121193326Sed		if (status != NOTIFY_STATUS_OK) {
122193326Sed			if (status == AU_UNIMPL)
123193326Sed				return (AU_UNIMPL);
124210299Sed			return (AUC_AUDITING);
125193326Sed		} else
126198092Srdivacky			return (au_cond);
127193326Sed	}
128193326Sed#if AUDIT_NOTIFICATION_ENABLED
129193326Sed	status = notify_check(token, &did_notify);
130212904Sdim	if (status != NOTIFY_STATUS_OK) {
131212904Sdim		au_cond = AUC_UNSET;
132212904Sdim		return (AUC_AUDITING);
133212904Sdim	}
134212904Sdim
135212904Sdim	if (did_notify == 0)
136193326Sed		return (au_cond);
137202879Srdivacky#endif
138234353Sdim
139193326Sed	if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) {
140193326Sed		/* XXX Reset au_cond to AUC_UNSET? */
141193326Sed		syslog(LOG_ERR, "Audit status check failed (%s)",
142193326Sed		    strerror(errno));
143221345Sdim		if (errno == ENOSYS)	/* Function unimplemented. */
144193326Sed			return (AU_UNIMPL);
145198092Srdivacky		return (errno);
146234353Sdim	}
147234353Sdim
148234353Sdim	switch (au_cond) {
149198092Srdivacky	case AUC_NOAUDIT:	/* Auditing suspended. */
150198092Srdivacky	case AUC_DISABLED:	/* Auditing shut off. */
151198092Srdivacky		return (AUC_NOAUDIT);
152198092Srdivacky
153198092Srdivacky	case AUC_UNSET:		/* Uninitialized; shouldn't get here. */
154193326Sed	case AUC_AUDITING:	/* Audit on. */
155208600Srdivacky	default:
156193326Sed		return (AUC_AUDITING);
157193326Sed	}
158193326Sed}
159193326Sed#endif	/* !__APPLE__ */
160207619Srdivacky
161198092Srdivackyint
162193326Sedcannot_audit(int val __unused)
163193326Sed{
164193326Sed#ifdef __APPLE__
165193326Sed	return (!(au_get_state() == AUC_AUDITING));
166198092Srdivacky#else
167198092Srdivacky	unsigned long au_cond;
168198092Srdivacky
169193326Sed	if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) {
170193326Sed		if (errno != ENOSYS) {
171208600Srdivacky			syslog(LOG_ERR, "Audit status check failed (%s)",
172193326Sed			    strerror(errno));
173193326Sed		}
174193326Sed		return (1);
175193326Sed	}
176193326Sed	if (au_cond == AUC_NOAUDIT || au_cond == AUC_DISABLED)
177193326Sed		return (1);
178198092Srdivacky	return (0);
179198092Srdivacky#endif	/* !__APPLE__ */
180193326Sed}
181193326Sed