bsm_wrappers.c revision 155518
1/*
2 * Copyright (c) 2004 Apple Computer, 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 Computer, 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/libbsm/bsm_wrappers.c#16 $
30 */
31
32#ifdef __APPLE__
33#define	_SYS_AUDIT_H		/* Prevent include of sys/audit.h. */
34#endif
35
36#include <sys/param.h>
37#include <sys/stat.h>
38#include <sys/sysctl.h>
39
40#include <bsm/libbsm.h>
41
42#include <unistd.h>
43#include <syslog.h>
44#include <string.h>
45#include <errno.h>
46
47/* These are not advertised in libbsm.h */
48int audit_set_terminal_port(dev_t *p);
49int audit_set_terminal_host(uint32_t *m);
50
51int
52audit_set_terminal_port(dev_t *p)
53{
54	struct stat st;
55
56	if (p == NULL)
57		return (kAUBadParamErr);
58
59	*p = NODEV;
60
61	/* for /usr/bin/login, try fstat() first */
62	if (fstat(STDIN_FILENO, &st) != 0) {
63		if (errno != EBADF) {
64			syslog(LOG_ERR, "fstat() failed (%s)",
65			    strerror(errno));
66			return (kAUStatErr);
67		}
68		if (stat("/dev/console", &st) != 0) {
69			syslog(LOG_ERR, "stat() failed (%s)",
70			    strerror(errno));
71			return (kAUStatErr);
72		}
73	}
74	*p = st.st_rdev;
75	return (kAUNoErr);
76}
77
78int
79audit_set_terminal_host(uint32_t *m)
80{
81	int name[2] = { CTL_KERN, KERN_HOSTID };
82	size_t len;
83
84	if (m == NULL)
85		return (kAUBadParamErr);
86	*m = 0;
87	len = sizeof(*m);
88	if (sysctl(name, 2, m, &len, NULL, 0) != 0) {
89		syslog(LOG_ERR, "sysctl() failed (%s)", strerror(errno));
90		return (kAUSysctlErr);
91	}
92	return (kAUNoErr);
93}
94
95int
96audit_set_terminal_id(au_tid_t *tid)
97{
98	int ret;
99
100	if (tid == NULL)
101		return (kAUBadParamErr);
102	if ((ret = audit_set_terminal_port(&tid->port)) != kAUNoErr)
103		return (ret);
104	return (audit_set_terminal_host(&tid->machine));
105}
106
107/*
108 * This is OK for those callers who have only one token to write.  If you have
109 * multiple tokens that logically form part of the same audit record, you need
110 * to use the existing au_open()/au_write()/au_close() API:
111 *
112 * aufd = au_open();
113 * tok = au_to_random_token_1(...);
114 * au_write(aufd, tok);
115 * tok = au_to_random_token_2(...);
116 * au_write(aufd, tok);
117 * ...
118 * au_close(aufd, 1, AUE_your_event_type);
119 *
120 * Assumes, like all wrapper calls, that the caller has previously checked
121 * that auditing is enabled via the audit_get_state() call.
122 *
123 * XXX: Should be more robust against bad arguments.
124 */
125int
126audit_write(short event_code, token_t *subject, token_t *misctok, char retval,
127    int errcode)
128{
129	int aufd;
130	char *func = "audit_write()";
131	token_t *rettok;
132
133	if ((aufd = au_open()) == -1) {
134		au_free_token(subject);
135		au_free_token(misctok);
136		syslog(LOG_ERR, "%s: au_open() failed", func);
137		return (kAUOpenErr);
138	}
139
140	/* Save subject. */
141	if (subject && au_write(aufd, subject) == -1) {
142		au_free_token(subject);
143		au_free_token(misctok);
144		(void)au_close(aufd, 0, event_code);
145		syslog(LOG_ERR, "%s: write of subject failed", func);
146		return (kAUWriteSubjectTokErr);
147	}
148
149	/* Save the event-specific token. */
150	if (misctok && au_write(aufd, misctok) == -1) {
151		au_free_token(misctok);
152		(void)au_close(aufd, 0, event_code);
153		syslog(LOG_ERR, "%s: write of caller token failed", func);
154		return (kAUWriteCallerTokErr);
155	}
156
157	/* Tokenize and save the return value. */
158	if ((rettok = au_to_return32(retval, errcode)) == NULL) {
159		(void)au_close(aufd, 0, event_code);
160		syslog(LOG_ERR, "%s: au_to_return32() failed", func);
161		return (kAUMakeReturnTokErr);
162	}
163
164	if (au_write(aufd, rettok) == -1) {
165		au_free_token(rettok);
166		(void)au_close(aufd, 0, event_code);
167		syslog(LOG_ERR, "%s: write of return code failed", func);
168		return (kAUWriteReturnTokErr);
169	}
170
171	/*
172	 * au_close()'s second argument is "keep": if keep == 0, the record is
173	 * discarded.  We assume the caller wouldn't have bothered with this
174	 * function if it hadn't already decided to keep the record.
175	 */
176	if (au_close(aufd, 1, event_code) < 0) {
177		syslog(LOG_ERR, "%s: au_close() failed", func);
178		return (kAUCloseErr);
179	}
180
181	return (kAUNoErr);
182}
183
184/*
185 * Same caveats as audit_write().  In addition, this function explicitly
186 * assumes success; use audit_write_failure() on error.
187 */
188int
189audit_write_success(short event_code, token_t *tok, au_id_t auid, uid_t euid,
190    gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid,
191    au_tid_t *tid)
192{
193	char *func = "audit_write_success()";
194	token_t *subject = NULL;
195
196	/* Tokenize and save subject. */
197	subject = au_to_subject32(auid, euid, egid, ruid, rgid, pid, sid,
198	    tid);
199	if (subject == NULL) {
200		syslog(LOG_ERR, "%s: au_to_subject32() failed", func);
201		return kAUMakeSubjectTokErr;
202	}
203
204	return (audit_write(event_code, subject, tok, 0, 0));
205}
206
207/*
208 * Same caveats as audit_write().  In addition, this function explicitly
209 * assumes success; use audit_write_failure_self() on error.
210 */
211int
212audit_write_success_self(short event_code, token_t *tok)
213{
214	token_t *subject;
215	char *func = "audit_write_success_self()";
216
217	if ((subject = au_to_me()) == NULL) {
218		syslog(LOG_ERR, "%s: au_to_me() failed", func);
219		return (kAUMakeSubjectTokErr);
220	}
221
222	return (audit_write(event_code, subject, tok, 0, 0));
223}
224
225/*
226 * Same caveats as audit_write().  In addition, this function explicitly
227 * assumes failure; use audit_write_success() otherwise.
228 *
229 * XXX  This should let the caller pass an error return value rather than
230 * hard-coding -1.
231 */
232int
233audit_write_failure(short event_code, char *errmsg, int errcode, au_id_t auid,
234    uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid,
235    au_tid_t *tid)
236{
237	char *func = "audit_write_failure()";
238	token_t *subject, *errtok;
239
240	subject = au_to_subject32(auid, euid, egid, ruid, rgid, pid, sid, tid);
241	if (subject == NULL) {
242		syslog(LOG_ERR, "%s: au_to_subject32() failed", func);
243		return (kAUMakeSubjectTokErr);
244	}
245
246	/* tokenize and save the error message */
247	if ((errtok = au_to_text(errmsg)) == NULL) {
248		au_free_token(subject);
249		syslog(LOG_ERR, "%s: au_to_text() failed", func);
250		return (kAUMakeTextTokErr);
251	}
252
253	return (audit_write(event_code, subject, errtok, -1, errcode));
254}
255
256/*
257 * Same caveats as audit_write().  In addition, this function explicitly
258 * assumes failure; use audit_write_success_self() otherwise.
259 *
260 * XXX  This should let the caller pass an error return value rather than
261 * hard-coding -1.
262 */
263int
264audit_write_failure_self(short event_code, char *errmsg, int errret)
265{
266	char *func = "audit_write_failure_self()";
267	token_t *subject, *errtok;
268
269	if ((subject = au_to_me()) == NULL) {
270		syslog(LOG_ERR, "%s: au_to_me() failed", func);
271		return (kAUMakeSubjectTokErr);
272	}
273	/* tokenize and save the error message */
274	if ((errtok = au_to_text(errmsg)) == NULL) {
275		au_free_token(subject);
276		syslog(LOG_ERR, "%s: au_to_text() failed", func);
277		return (kAUMakeTextTokErr);
278	}
279	return (audit_write(event_code, subject, errtok, -1, errret));
280}
281
282/*
283 * For auditing errors during login.  Such errors are implicitly
284 * non-attributable (i.e., not ascribable to any user).
285 *
286 * Assumes, like all wrapper calls, that the caller has previously checked
287 * that auditing is enabled via the audit_get_state() call.
288 */
289int
290audit_write_failure_na(short event_code, char *errmsg, int errret, uid_t euid,
291    uid_t egid, pid_t pid, au_tid_t *tid)
292{
293
294	return (audit_write_failure(event_code, errmsg, errret, -1, euid,
295	    egid, -1, -1, pid, -1, tid));
296}
297
298/* END OF au_write() WRAPPERS */
299
300#ifdef __APPLE__
301void
302audit_token_to_au32(audit_token_t atoken, uid_t *auidp, uid_t *euidp,
303    gid_t *egidp, uid_t *ruidp, gid_t *rgidp, pid_t *pidp, au_asid_t *asidp,
304    au_tid_t *tidp)
305{
306
307	if (auidp != NULL)
308		*auidp = (uid_t)atoken.val[0];
309	if (euidp != NULL)
310		*euidp = (uid_t)atoken.val[1];
311	if (egidp != NULL)
312		*egidp = (gid_t)atoken.val[2];
313	if (ruidp != NULL)
314		*ruidp = (uid_t)atoken.val[3];
315	if (rgidp != NULL)
316		*rgidp = (gid_t)atoken.val[4];
317	if (pidp != NULL)
318		*pidp = (pid_t)atoken.val[5];
319	if (asidp != NULL)
320		*asidp = (au_asid_t)atoken.val[6];
321	if (tidp != NULL) {
322		audit_set_terminal_host(&tidp->machine);
323		tidp->port = (dev_t)atoken.val[7];
324	}
325}
326#endif /* !__APPLE__ */
327