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