xref: /freebsd/contrib/openbsm/libbsm/bsm_notify.c (revision b626f5a73a48f44a31a200291b141e1da408a2ff)
152267f74SRobert Watson /*-
2c0020399SRobert Watson  * Copyright (c) 2004-2009 Apple Inc.
3ca0716f5SRobert Watson  * All rights reserved.
4ca0716f5SRobert Watson  *
5ca0716f5SRobert Watson  * Redistribution and use in source and binary forms, with or without
6ca0716f5SRobert Watson  * modification, are permitted provided that the following conditions
7ca0716f5SRobert Watson  * are met:
8ca0716f5SRobert Watson  * 1.  Redistributions of source code must retain the above copyright
9ca0716f5SRobert Watson  *     notice, this list of conditions and the following disclaimer.
10ca0716f5SRobert Watson  * 2.  Redistributions in binary form must reproduce the above copyright
11ca0716f5SRobert Watson  *     notice, this list of conditions and the following disclaimer in the
12ca0716f5SRobert Watson  *     documentation and/or other materials provided with the distribution.
1352267f74SRobert Watson  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
14ca0716f5SRobert Watson  *     its contributors may be used to endorse or promote products derived
15ca0716f5SRobert Watson  *     from this software without specific prior written permission.
16ca0716f5SRobert Watson  *
17ca0716f5SRobert Watson  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
18ca0716f5SRobert Watson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19ca0716f5SRobert Watson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20ca0716f5SRobert Watson  * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
21ca0716f5SRobert Watson  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22ca0716f5SRobert Watson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23ca0716f5SRobert Watson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24ca0716f5SRobert Watson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25ca0716f5SRobert Watson  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
26ca0716f5SRobert Watson  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27ca0716f5SRobert Watson  * POSSIBILITY OF SUCH DAMAGE.
28ca0716f5SRobert Watson  */
29ca0716f5SRobert Watson 
30ca0716f5SRobert Watson /*
31ca0716f5SRobert Watson  * Based on sample code from Marc Majka.
32ca0716f5SRobert Watson  */
333b97a967SRobert Watson #include <sys/types.h>
343b97a967SRobert Watson 
353b97a967SRobert Watson #include <config/config.h>
363b97a967SRobert Watson #ifdef HAVE_FULL_QUEUE_H
373b97a967SRobert Watson #include <sys/queue.h>
383b97a967SRobert Watson #else /* !HAVE_FULL_QUEUE_H */
393b97a967SRobert Watson #include <compat/queue.h>
403b97a967SRobert Watson #endif /* !HAVE_FULL_QUEUE_H */
413b97a967SRobert Watson 
423b97a967SRobert Watson #include <bsm/audit_internal.h>
43ca0716f5SRobert Watson #include <bsm/libbsm.h>
443b97a967SRobert Watson 
453b97a967SRobert Watson #include <errno.h>
46d9af45c4SRobert Watson #include <inttypes.h>
473b97a967SRobert Watson #include <stdarg.h>
483b97a967SRobert Watson #include <string.h>
493b97a967SRobert Watson #include <syslog.h>
503b97a967SRobert Watson 
51ca0716f5SRobert Watson 
52f4e380b0SRobert Watson #ifdef __APPLE__
53f4e380b0SRobert Watson #include <notify.h>
54ca0716f5SRobert Watson /* If 1, assumes a kernel that sends the right notification. */
55ca0716f5SRobert Watson #define	AUDIT_NOTIFICATION_ENABLED	1
56ca0716f5SRobert Watson 
57ca0716f5SRobert Watson #if AUDIT_NOTIFICATION_ENABLED
58ca0716f5SRobert Watson static int	token = 0;
59ca0716f5SRobert Watson #endif	/* AUDIT_NOTIFICATION_ENABLED */
60ca0716f5SRobert Watson 
61c0020399SRobert Watson static int	au_cond = AUC_UNSET;	/* <bsm/audit.h> */
62ca0716f5SRobert Watson 
63ca0716f5SRobert Watson uint32_t
au_notify_initialize(void)64ca0716f5SRobert Watson au_notify_initialize(void)
65ca0716f5SRobert Watson {
66ca0716f5SRobert Watson #if AUDIT_NOTIFICATION_ENABLED
67bc168a6cSRobert Watson 	uint32_t status;
68bc168a6cSRobert Watson 	int ignore_first;
69ca0716f5SRobert Watson 
70ca0716f5SRobert Watson 	status = notify_register_check(__BSM_INTERNAL_NOTIFY_KEY, &token);
71ca0716f5SRobert Watson 	if (status != NOTIFY_STATUS_OK)
72ca0716f5SRobert Watson 		return (status);
73ca0716f5SRobert Watson 	status = notify_check(token, &ignore_first);
74ca0716f5SRobert Watson 	if (status != NOTIFY_STATUS_OK)
75ca0716f5SRobert Watson 		return (status);
76ca0716f5SRobert Watson #endif
77ca0716f5SRobert Watson 
78c0020399SRobert Watson 	if (audit_get_cond(&au_cond) != 0) {
79ca0716f5SRobert Watson 		syslog(LOG_ERR, "Initial audit status check failed (%s)",
80ca0716f5SRobert Watson 		    strerror(errno));
81ca0716f5SRobert Watson 		if (errno == ENOSYS)	/* auditon() unimplemented. */
82ca0716f5SRobert Watson 			return (AU_UNIMPL);
83ca0716f5SRobert Watson 		return (NOTIFY_STATUS_FAILED);	/* Is there a better code? */
84ca0716f5SRobert Watson 	}
85ca0716f5SRobert Watson 	return (NOTIFY_STATUS_OK);
86ca0716f5SRobert Watson }
87ca0716f5SRobert Watson 
88ca0716f5SRobert Watson int
au_notify_terminate(void)89ca0716f5SRobert Watson au_notify_terminate(void)
90ca0716f5SRobert Watson {
91ca0716f5SRobert Watson 
92ca0716f5SRobert Watson #if AUDIT_NOTIFICATION_ENABLED
93ca0716f5SRobert Watson 	return ((notify_cancel(token) == NOTIFY_STATUS_OK) ? 0 : -1);
94ca0716f5SRobert Watson #else
95ca0716f5SRobert Watson 	return (0);
96ca0716f5SRobert Watson #endif
97ca0716f5SRobert Watson }
98ca0716f5SRobert Watson 
99ca0716f5SRobert Watson /*
100ca0716f5SRobert Watson  * On error of any notify(3) call, reset 'au_cond' to ensure we re-run
101ca0716f5SRobert Watson  * au_notify_initialize() next time 'round--but assume auditing is on.  This
102ca0716f5SRobert Watson  * is a slight performance hit if auditing is off, but at least the system
103ca0716f5SRobert Watson  * will behave correctly.  The notification calls are unlikely to fail,
104ca0716f5SRobert Watson  * anyway.
105ca0716f5SRobert Watson  */
106ca0716f5SRobert Watson int
au_get_state(void)107ca0716f5SRobert Watson au_get_state(void)
108ca0716f5SRobert Watson {
109ca0716f5SRobert Watson #if AUDIT_NOTIFICATION_ENABLED
110bc168a6cSRobert Watson 	int did_notify;
111ca0716f5SRobert Watson #endif
112ca0716f5SRobert Watson 	int status;
113ca0716f5SRobert Watson 
114ca0716f5SRobert Watson 	/*
115ca0716f5SRobert Watson 	 * Don't make the client initialize this set of routines, but take the
116ca0716f5SRobert Watson 	 * slight performance hit by checking ourselves every time.
117ca0716f5SRobert Watson 	 */
118ca0716f5SRobert Watson 	if (au_cond == AUC_UNSET) {
119ca0716f5SRobert Watson 		status = au_notify_initialize();
120ca0716f5SRobert Watson 		if (status != NOTIFY_STATUS_OK) {
121ca0716f5SRobert Watson 			if (status == AU_UNIMPL)
122ca0716f5SRobert Watson 				return (AU_UNIMPL);
123ca0716f5SRobert Watson 			return (AUC_AUDITING);
124ca0716f5SRobert Watson 		} else
125ca0716f5SRobert Watson 			return (au_cond);
126ca0716f5SRobert Watson 	}
127ca0716f5SRobert Watson #if AUDIT_NOTIFICATION_ENABLED
128ca0716f5SRobert Watson 	status = notify_check(token, &did_notify);
129ca0716f5SRobert Watson 	if (status != NOTIFY_STATUS_OK) {
130ca0716f5SRobert Watson 		au_cond = AUC_UNSET;
131ca0716f5SRobert Watson 		return (AUC_AUDITING);
132ca0716f5SRobert Watson 	}
133ca0716f5SRobert Watson 
134ca0716f5SRobert Watson 	if (did_notify == 0)
135ca0716f5SRobert Watson 		return (au_cond);
136ca0716f5SRobert Watson #endif
137ca0716f5SRobert Watson 
138c0020399SRobert Watson 	if (audit_get_cond(&au_cond) != 0) {
139ca0716f5SRobert Watson 		/* XXX Reset au_cond to AUC_UNSET? */
140ca0716f5SRobert Watson 		syslog(LOG_ERR, "Audit status check failed (%s)",
141ca0716f5SRobert Watson 		    strerror(errno));
142ca0716f5SRobert Watson 		if (errno == ENOSYS)	/* Function unimplemented. */
143ca0716f5SRobert Watson 			return (AU_UNIMPL);
144ca0716f5SRobert Watson 		return (errno);
145ca0716f5SRobert Watson 	}
146ca0716f5SRobert Watson 
147ca0716f5SRobert Watson 	switch (au_cond) {
148ca0716f5SRobert Watson 	case AUC_NOAUDIT:	/* Auditing suspended. */
149ca0716f5SRobert Watson 	case AUC_DISABLED:	/* Auditing shut off. */
150ca0716f5SRobert Watson 		return (AUC_NOAUDIT);
151ca0716f5SRobert Watson 
152ca0716f5SRobert Watson 	case AUC_UNSET:		/* Uninitialized; shouldn't get here. */
153ca0716f5SRobert Watson 	case AUC_AUDITING:	/* Audit on. */
154ca0716f5SRobert Watson 	default:
155ca0716f5SRobert Watson 		return (AUC_AUDITING);
156ca0716f5SRobert Watson 	}
157ca0716f5SRobert Watson }
158ca0716f5SRobert Watson #endif	/* !__APPLE__ */
159f4e380b0SRobert Watson 
160f4e380b0SRobert Watson int
cannot_audit(int val __unused)161f4e380b0SRobert Watson cannot_audit(int val __unused)
162f4e380b0SRobert Watson {
163f4e380b0SRobert Watson #ifdef __APPLE__
164f4e380b0SRobert Watson 	return (!(au_get_state() == AUC_AUDITING));
165f4e380b0SRobert Watson #else
166c0020399SRobert Watson 	int cond;
167f4e380b0SRobert Watson 
168c0020399SRobert Watson 	if (audit_get_cond(&cond) != 0) {
169f4e380b0SRobert Watson 		if (errno != ENOSYS) {
170f4e380b0SRobert Watson 			syslog(LOG_ERR, "Audit status check failed (%s)",
171f4e380b0SRobert Watson 			    strerror(errno));
172f4e380b0SRobert Watson 		}
173f4e380b0SRobert Watson 		return (1);
174f4e380b0SRobert Watson 	}
175c0020399SRobert Watson 	if (cond == AUC_NOAUDIT || cond == AUC_DISABLED)
176f4e380b0SRobert Watson 		return (1);
177f4e380b0SRobert Watson 	return (0);
178f4e380b0SRobert Watson #endif	/* !__APPLE__ */
179f4e380b0SRobert Watson }
180